diff options
Diffstat (limited to 'sound/pci')
202 files changed, 35084 insertions, 34852 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index f99fa251228..3a3a3a71088 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -1,10 +1,5 @@ # ALSA PCI drivers -config SND_TEA575X - tristate - depends on SND_FM801_TEA575X_BOOL || SND_ES1968_RADIO || RADIO_SF16FMR2 || RADIO_MAXIRADIO || RADIO_SHARK - default SND_FM801 || SND_ES1968 || RADIO_SF16FMR2 || RADIO_MAXIRADIO || RADIO_SHARK - menuconfig SND_PCI bool "PCI sound devices" depends on PCI @@ -30,6 +25,7 @@ config SND_ALS300 select SND_PCM select SND_AC97_CODEC select SND_OPL3_LIB + select ZONE_DMA help Say 'Y' or 'M' to include support for Avance Logic ALS300/ALS300+ @@ -54,6 +50,7 @@ config SND_ALI5451 tristate "ALi M5451 PCI Audio Controller" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for the integrated AC97 sound device on motherboards using the ALi M5451 Audio Controller @@ -158,6 +155,7 @@ config SND_AZT3328 select SND_PCM select SND_RAWMIDI select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for Aztech AZF3328 (PCI168) soundcards. @@ -259,6 +257,7 @@ config SND_CS46XX tristate "Cirrus Logic (Sound Fusion) CS4280/CS461x/CS462x/CS463x" select SND_RAWMIDI select SND_AC97_CODEC + select FW_LOADER help Say Y here to include support for Cirrus Logic CS4610/CS4612/ CS4614/CS4615/CS4622/CS4624/CS4630/CS4280 chips. @@ -277,7 +276,7 @@ config SND_CS46XX_NEW_DSP config SND_CS5530 tristate "CS5530 Audio" - depends on ISA_DMA_API + depends on ISA_DMA_API && (X86_32 || COMPILE_TEST) select SND_SB16_DSP help Say Y here to include support for audio on Cyrix/NatSemi CS5530 chips. @@ -287,6 +286,7 @@ config SND_CS5530 config SND_CS5535AUDIO tristate "CS5535/CS5536 Audio" + depends on X86_32 || MIPS || COMPILE_TEST select SND_PCM select SND_AC97_CODEC help @@ -463,6 +463,7 @@ config SND_EMU10K1 select SND_HWDEP select SND_RAWMIDI select SND_AC97_CODEC + select ZONE_DMA help Say Y to include support for Sound Blaster PCI 512, Live!, Audigy and E-mu APS (partially supported) soundcards. @@ -478,6 +479,7 @@ config SND_EMU10K1X tristate "Emu10k1X (Dell OEM Version)" select SND_AC97_CODEC select SND_RAWMIDI + select ZONE_DMA help Say Y here to include support for the Dell OEM version of the Sound Blaster Live!. @@ -511,6 +513,7 @@ config SND_ES1938 select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Solo-1 (ES1938, ES1946, ES1969) chips. @@ -522,6 +525,7 @@ config SND_ES1968 tristate "ESS ES1968/1978 (Maestro-1/2/2E)" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Maestro 1/2/2E chips. @@ -542,7 +546,11 @@ config SND_ES1968_INPUT config SND_ES1968_RADIO bool "Enable TEA5757 radio tuner support for es1968" depends on SND_ES1968 + depends on MEDIA_RADIO_SUPPORT depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_ES1968 + select RADIO_ADAPTERS + select RADIO_TEA575X + help Say Y here to include support for TEA5757 radio tuner integrated on some MediaForte cards (e.g. SF64-PCE2). @@ -562,16 +570,18 @@ config SND_FM801 config SND_FM801_TEA575X_BOOL bool "ForteMedia FM801 + TEA5757 tuner" depends on SND_FM801 + depends on MEDIA_RADIO_SUPPORT depends on VIDEO_V4L2=y || VIDEO_V4L2=SND_FM801 + select RADIO_ADAPTERS + select RADIO_TEA575X help Say Y here to include support for soundcards based on the ForteMedia FM801 chip with a TEA5757 tuner (MediaForte SF256-PCS, SF256-PCP and SF64-PCR) into the snd-fm801 driver. -source "sound/pci/hda/Kconfig" - config SND_HDSP tristate "RME Hammerfall DSP Audio" + select FW_LOADER select SND_HWDEP select SND_RAWMIDI select SND_PCM @@ -602,6 +612,7 @@ config SND_ICE1712 select SND_MPU401_UART select SND_AC97_CODEC select BITREVERSE + select ZONE_DMA help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. @@ -630,7 +641,7 @@ config SND_ICE1724 AudioTrak Prodigy 192, 7.1 (HIFI/LT/XT), HD2; Hercules Fortissimo IV; ESI Juli@; Pontis MS300; EGO-SYS WaveTerminal 192M; Albatron K8X800 Pro II; Chaintech ZNF3-150/250, 9CJS, - AV-710; Shuttle SN25P. + AV-710; Shuttle SN25P; Philips PSC724 Ultimate Edge. To compile this driver as a module, choose M here: the module will be called snd-ice1724. @@ -677,6 +688,7 @@ config SND_LOLA config SND_LX6464ES tristate "Digigram LX6464ES" + depends on HAS_IOPORT_MAP select SND_PCM help Say Y here to include support for Digigram LX6464ES boards. @@ -688,6 +700,7 @@ config SND_LX6464ES config SND_MAESTRO3 tristate "ESS Allegro/Maestro3" select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on ESS Maestro 3 (Allegro) chips. @@ -707,6 +720,7 @@ config SND_MAESTRO3_INPUT config SND_MIXART tristate "Digigram miXart" + select FW_LOADER select SND_HWDEP select SND_PCM help @@ -727,6 +741,7 @@ config SND_NM256 config SND_PCXHR tristate "Digigram PCXHR" + select FW_LOADER select SND_PCM select SND_HWDEP help @@ -780,8 +795,9 @@ config SND_RME9652 config SND_SIS7019 tristate "SiS 7019 Audio Accelerator" - depends on X86 && !X86_64 + depends on X86_32 select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for the SiS 7019 Audio Accelerator. @@ -793,6 +809,7 @@ config SND_SONICVIBES select SND_OPL3_LIB select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on the S3 SonicVibes chip. @@ -804,6 +821,7 @@ config SND_TRIDENT tristate "Trident 4D-Wave DX/NX; SiS 7018" select SND_MPU401_UART select SND_AC97_CODEC + select ZONE_DMA help Say Y here to include support for soundcards based on Trident 4D-Wave DX/NX or SiS 7018 chips. @@ -870,3 +888,5 @@ config SND_YMFPCI will be called snd-ymfpci. endif # SND_PCI + +source "sound/pci/hda/Kconfig" diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 8b0f9968830..14ad54b7928 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -175,6 +175,7 @@ static const struct ac97_codec_id snd_ac97_codec_ids[] = { { 0x54524106, 0xffffffff, "TR28026", NULL, NULL }, { 0x54524108, 0xffffffff, "TR28028", patch_tritech_tr28028, NULL }, // added by xin jin [07/09/99] { 0x54524123, 0xffffffff, "TR28602", NULL, NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)] +{ 0x54584e03, 0xffffffff, "TLV320AIC27", NULL, NULL }, { 0x54584e20, 0xffffffff, "TLC320AD9xC", NULL, NULL }, { 0x56494161, 0xffffffff, "VIA1612A", NULL, NULL }, // modified ICE1232 with S/PDIF { 0x56494170, 0xffffffff, "VIA1617A", patch_vt1617a, NULL }, // modified VT1616 with S/PDIF @@ -213,6 +214,12 @@ static void update_power_regs(struct snd_ac97 *ac97); #define ac97_is_power_save_mode(ac97) 0 #endif +#define ac97_err(ac97, fmt, args...) \ + dev_err((ac97)->bus->card->dev, fmt, ##args) +#define ac97_warn(ac97, fmt, args...) \ + dev_warn((ac97)->bus->card->dev, fmt, ##args) +#define ac97_dbg(ac97, fmt, args...) \ + dev_dbg((ac97)->bus->card->dev, fmt, ##args) /* * I/O routines @@ -299,7 +306,7 @@ EXPORT_SYMBOL(snd_ac97_write); * Reads a value from the given register. This will invoke the read * callback directly after the register check. * - * Returns the read value. + * Return: The read value. */ unsigned short snd_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { @@ -352,7 +359,7 @@ EXPORT_SYMBOL(snd_ac97_write_cache); * Compares the value with the register cache and updates the value * only when the value is changed. * - * Returns 1 if the value is changed, 0 if no change, or a negative + * Return: 1 if the value is changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update(struct snd_ac97 *ac97, unsigned short reg, unsigned short value) @@ -384,7 +391,7 @@ EXPORT_SYMBOL(snd_ac97_update); * Updates the masked-bits on the given register only when the value * is changed. * - * Returns 1 if the bits are changed, 0 if no change, or a negative + * Return: 1 if the bits are changed, 0 if no change, or a negative * code on failure. */ int snd_ac97_update_bits(struct snd_ac97 *ac97, unsigned short reg, unsigned short mask, unsigned short value) @@ -1296,7 +1303,7 @@ static int snd_ac97_cmix_new_stereo(struct snd_card *card, const char *pfx, struct snd_ac97 *ac97) { int err; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; unsigned char lo_max, hi_max; if (! snd_ac97_valid_reg(ac97, reg)) @@ -1672,7 +1679,7 @@ static int snd_ac97_modem_build(struct snd_card *card, struct snd_ac97 * ac97) int err, idx; /* - printk(KERN_DEBUG "AC97_GPIO_CFG = %x\n", + ac97_dbg(ac97, "AC97_GPIO_CFG = %x\n", snd_ac97_read(ac97,AC97_GPIO_CFG)); */ snd_ac97_write(ac97, AC97_GPIO_CFG, 0xffff & ~(AC97_GPIO_LINE1_OH)); @@ -1836,7 +1843,7 @@ void snd_ac97_get_name(struct snd_ac97 *ac97, unsigned int id, char *name, int m * snd_ac97_get_short_name - retrieve codec name * @ac97: the codec instance * - * Returns the short identifying name of the codec. + * Return: The short identifying name of the codec. */ const char *snd_ac97_get_short_name(struct snd_ac97 *ac97) { @@ -1910,7 +1917,7 @@ static int ac97_reset_wait(struct snd_ac97 *ac97, int timeout, int with_modem) * The AC97 bus instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_bus(struct snd_card *card, int num, struct snd_ac97_bus_ops *ops, void *private_data, struct snd_ac97_bus **rbus) @@ -1962,7 +1969,7 @@ static int snd_ac97_dev_register(struct snd_device *device) ac97->bus->card->number, ac97->num, snd_ac97_get_short_name(ac97)); if ((err = device_register(&ac97->dev)) < 0) { - snd_printk(KERN_ERR "Can't register ac97 bus\n"); + ac97_err(ac97, "Can't register ac97 bus\n"); ac97->dev.bus = NULL; return err; } @@ -2006,7 +2013,7 @@ static void do_update_power(struct work_struct *work) * The ac97 instance is registered as a low-level device, so you don't * have to release it manually. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, struct snd_ac97 **rac97) { @@ -2088,7 +2095,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, msecs_to_jiffies(500), 1); } if (err < 0) { - snd_printk(KERN_WARNING "AC'97 %d does not respond - RESET\n", ac97->num); + ac97_warn(ac97, "AC'97 %d does not respond - RESET\n", + ac97->num); /* proceed anyway - it's often non-critical */ } } @@ -2097,7 +2105,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, ac97->id |= snd_ac97_read(ac97, AC97_VENDOR_ID2); if (! (ac97->scaps & AC97_SCAP_DETECT_BY_VENDOR) && (ac97->id == 0x00000000 || ac97->id == 0xffffffff)) { - snd_printk(KERN_ERR "AC'97 %d access is not valid [0x%x], removing mixer.\n", ac97->num, ac97->id); + ac97_err(ac97, + "AC'97 %d access is not valid [0x%x], removing mixer.\n", + ac97->num, ac97->id); snd_ac97_free(ac97); return -EIO; } @@ -2130,7 +2140,9 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, if (!ac97_is_audio(ac97) && !ac97_is_modem(ac97)) { if (!(ac97->scaps & (AC97_SCAP_SKIP_AUDIO|AC97_SCAP_SKIP_MODEM))) - snd_printk(KERN_ERR "AC'97 %d access error (not audio or modem codec)\n", ac97->num); + ac97_err(ac97, + "AC'97 %d access error (not audio or modem codec)\n", + ac97->num); snd_ac97_free(ac97); return -EACCES; } @@ -2155,7 +2167,8 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, goto __ready_ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num); + ac97_warn(ac97, + "AC'97 %d analog subsections not ready\n", ac97->num); } /* FIXME: add powerdown control */ @@ -2187,7 +2200,10 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, goto __ready_ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); + ac97_warn(ac97, + "MC'97 %d converters and GPIO not ready (0x%x)\n", + ac97->num, + snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS)); } __ready_ok: @@ -2373,6 +2389,8 @@ static struct ac97_power_reg power_regs[PWIDX_SIZE] = { * @powerup: non-zero when power up the part * * Update the AC97 powerdown register bits of the given part. + * + * Return: Zero. */ int snd_ac97_update_power(struct snd_ac97 *ac97, int reg, int powerup) { @@ -2720,7 +2738,7 @@ static int tune_ad_sharing(struct snd_ac97 *ac97) { unsigned short scfg; if ((ac97->id & 0xffffff00) != 0x41445300) { - snd_printk(KERN_ERR "ac97_quirk AD_SHARING is only for AD codecs\n"); + ac97_err(ac97, "ac97_quirk AD_SHARING is only for AD codecs\n"); return -EINVAL; } /* Turn on OMS bit to route microphone to back panel */ @@ -2736,7 +2754,8 @@ AC97_SINGLE("Jack Detect", AC97_ALC650_CLOCK, 5, 1, 0); static int tune_alc_jack(struct snd_ac97 *ac97) { if ((ac97->id & 0xffffff00) != 0x414c4700) { - snd_printk(KERN_ERR "ac97_quirk ALC_JACK is only for Realtek codecs\n"); + ac97_err(ac97, + "ac97_quirk ALC_JACK is only for Realtek codecs\n"); return -EINVAL; } snd_ac97_update_bits(ac97, 0x7a, 0x20, 0x20); /* select jack detect function */ @@ -2885,7 +2904,7 @@ static int apply_quirk_str(struct snd_ac97 *ac97, const char *typestr) * headphone (true line-out) control as "Master". * The quirk-list must be terminated with a zero-filled entry. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, const char *override) @@ -2896,7 +2915,8 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons if (override && strcmp(override, "-1") && strcmp(override, "default")) { result = apply_quirk_str(ac97, override); if (result < 0) - snd_printk(KERN_ERR "applying quirk type %s failed (%d)\n", override, result); + ac97_err(ac97, "applying quirk type %s failed (%d)\n", + override, result); return result; } @@ -2910,10 +2930,14 @@ int snd_ac97_tune_hardware(struct snd_ac97 *ac97, struct ac97_quirk *quirk, cons quirk->subdevice == (quirk->mask & ac97->subsystem_device)) { if (quirk->codec_id && quirk->codec_id != ac97->id) continue; - snd_printdd("ac97 quirk for %s (%04x:%04x)\n", quirk->name, ac97->subsystem_vendor, ac97->subsystem_device); + ac97_dbg(ac97, "ac97 quirk for %s (%04x:%04x)\n", + quirk->name, ac97->subsystem_vendor, + ac97->subsystem_device); result = apply_quirk(ac97, quirk->type); if (result < 0) - snd_printk(KERN_ERR "applying quirk type %d for %s failed (%d)\n", quirk->type, quirk->name, result); + ac97_err(ac97, + "applying quirk type %d for %s failed (%d)\n", + quirk->type, quirk->name, result); return result; } } diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 66a3bc95fb8..99176221541 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -3477,7 +3477,8 @@ static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name, sctl = snd_ac97_find_mixer_ctl(ac97, *s); if (!sctl) { - snd_printdd("Cannot find slave %s, skipped\n", *s); + dev_dbg(ac97->bus->card->dev, + "Cannot find slave %s, skipped\n", *s); continue; } err = snd_ctl_add_slave(kctl, sctl); diff --git a/sound/pci/ac97/ac97_pcm.c b/sound/pci/ac97/ac97_pcm.c index f1488fc176d..d15297a6880 100644 --- a/sound/pci/ac97/ac97_pcm.c +++ b/sound/pci/ac97/ac97_pcm.c @@ -253,7 +253,7 @@ static int set_spdif_rate(struct snd_ac97 *ac97, unsigned short rate) * AC97_SPDIF is accepted as a pseudo register to modify the SPDIF * status bits. * - * Returns zero if successful, or a negative error code on failure. + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_set_rate(struct snd_ac97 *ac97, int reg, unsigned int rate) { @@ -440,6 +440,8 @@ static unsigned int get_rates(struct ac97_pcm *pcm, unsigned int cidx, unsigned * It assigns available AC97 slots for given PCMs. If none or only * some slots are available, pcm->xxx.slots and pcm->xxx.rslots[] members * are reduced and might be zero. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_assign(struct snd_ac97_bus *bus, unsigned short pcms_count, @@ -562,6 +564,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_assign); * @slots: a subset of allocated slots (snd_ac97_pcm_assign) for this pcm * * It locks the specified slots and sets the given rate to AC97 registers. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, enum ac97_pcm_cfg cfg, unsigned short slots) @@ -600,7 +604,9 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, } if (!ok_flag) { spin_unlock_irq(&pcm->bus->bus_lock); - snd_printk(KERN_ERR "cannot find configuration for AC97 slot %i\n", i); + dev_err(bus->card->dev, + "cannot find configuration for AC97 slot %i\n", + i); err = -EAGAIN; goto error; } @@ -614,15 +620,20 @@ int snd_ac97_pcm_open(struct ac97_pcm *pcm, unsigned int rate, if (pcm->r[r].rslots[cidx] & (1 << i)) { reg = get_slot_reg(pcm, cidx, i, r); if (reg == 0xff) { - snd_printk(KERN_ERR "invalid AC97 slot %i?\n", i); + dev_err(bus->card->dev, + "invalid AC97 slot %i?\n", i); continue; } if (reg_ok[cidx] & (1 << (reg - AC97_PCM_FRONT_DAC_RATE))) continue; - //printk(KERN_DEBUG "setting ac97 reg 0x%x to rate %d\n", reg, rate); + dev_dbg(bus->card->dev, + "setting ac97 reg 0x%x to rate %d\n", + reg, rate); err = snd_ac97_set_rate(pcm->r[r].codec[cidx], reg, rate); if (err < 0) - snd_printk(KERN_ERR "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", cidx, reg, rate, err); + dev_err(bus->card->dev, + "error in snd_ac97_set_rate: cidx=%d, reg=0x%x, rate=%d, err=%d\n", + cidx, reg, rate, err); else reg_ok[cidx] |= (1 << (reg - AC97_PCM_FRONT_DAC_RATE)); } @@ -644,6 +655,8 @@ EXPORT_SYMBOL(snd_ac97_pcm_open); * @pcm: the ac97 pcm instance * * It frees the locked AC97 slots. + * + * Return: Zero. */ int snd_ac97_pcm_close(struct ac97_pcm *pcm) { @@ -718,6 +731,8 @@ static int double_rate_hw_constraint_channels(struct snd_pcm_hw_params *params, * * Installs the hardware constraint rules to prevent using double rates and * more than two channels at the same time. + * + * Return: Zero if successful, or a negative error code on failure. */ int snd_ac97_pcm_double_rate_rules(struct snd_pcm_runtime *runtime) { diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index e672ff4df2d..488f966adde 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c @@ -77,9 +77,6 @@ MODULE_PARM_DESC(ac97_quirk, "AC'97 workaround for strange hardware."); #define DEVNAME "ad1889" #define PFX DEVNAME ": " -/* let's use the global sound debug interfaces */ -#define ad1889_debug(fmt, arg...) snd_printd(KERN_DEBUG fmt, ## arg) - /* keep track of some hw registers */ struct ad1889_register_state { u16 reg; /* reg setup */ @@ -264,11 +261,11 @@ snd_ad1889_ac97_ready(struct snd_ad1889 *chip) && --retry) mdelay(1); if (!retry) { - snd_printk(KERN_ERR PFX "[%s] Link is not ready.\n", - __func__); + dev_err(chip->card->dev, "[%s] Link is not ready.\n", + __func__); return -EIO; } - ad1889_debug("[%s] ready after %d ms\n", __func__, 400 - retry); + dev_dbg(chip->card->dev, "[%s] ready after %d ms\n", __func__, 400 - retry); return 0; } @@ -405,9 +402,9 @@ snd_ad1889_playback_prepare(struct snd_pcm_substream *ss) spin_unlock_irq(&chip->lock); - ad1889_debug("prepare playback: addr = 0x%x, count = %u, " - "size = %u, reg = 0x%x, rate = %u\n", chip->wave.addr, - count, size, reg, rt->rate); + dev_dbg(chip->card->dev, + "prepare playback: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n", + chip->wave.addr, count, size, reg, rt->rate); return 0; } @@ -452,9 +449,9 @@ snd_ad1889_capture_prepare(struct snd_pcm_substream *ss) spin_unlock_irq(&chip->lock); - ad1889_debug("prepare capture: addr = 0x%x, count = %u, " - "size = %u, reg = 0x%x, rate = %u\n", chip->ramc.addr, - count, size, reg, rt->rate); + dev_dbg(chip->card->dev, + "prepare capture: addr = 0x%x, count = %u, size = %u, reg = 0x%x, rate = %u\n", + chip->ramc.addr, count, size, reg, rt->rate); return 0; } @@ -614,7 +611,8 @@ snd_ad1889_interrupt(int irq, void *dev_id) return IRQ_NONE; if (st & (AD_DMA_DISR_PMAI|AD_DMA_DISR_PTAI)) - ad1889_debug("Unexpected master or target abort interrupt!\n"); + dev_dbg(chip->card->dev, + "Unexpected master or target abort interrupt!\n"); if ((st & AD_DMA_DISR_WAVI) && chip->psubs) snd_pcm_period_elapsed(chip->psubs); @@ -624,7 +622,7 @@ snd_ad1889_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit +static int snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) { int err; @@ -656,7 +654,7 @@ snd_ad1889_pcm_init(struct snd_ad1889 *chip, int device, struct snd_pcm **rpcm) BUFFER_BYTES_MAX); if (err < 0) { - snd_printk(KERN_ERR PFX "buffer allocation error: %d\n", err); + dev_err(chip->card->dev, "buffer allocation error: %d\n", err); return err; } @@ -739,7 +737,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe reg = ad1889_readw(chip, AD_DS_WADA); snd_iprintf(buffer, "Right: %s, -%d dB\n", (reg & AD_DS_WADA_RWAM) ? "mute" : "unmute", - ((reg & AD_DS_WADA_RWAA) >> 8) * 3); + (reg & AD_DS_WADA_RWAA) * 3); reg = ad1889_readw(chip, AD_DS_WAS); snd_iprintf(buffer, "Wave samplerate: %u Hz\n", reg); @@ -747,7 +745,7 @@ snd_ad1889_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffe snd_iprintf(buffer, "Resampler samplerate: %u Hz\n", reg); } -static void __devinit +static void snd_ad1889_proc_init(struct snd_ad1889 *chip) { struct snd_info_entry *entry; @@ -767,7 +765,7 @@ static struct ac97_quirk ac97_quirks[] = { { } /* terminator */ }; -static void __devinit +static void snd_ad1889_ac97_xinit(struct snd_ad1889 *chip) { u16 reg; @@ -805,7 +803,7 @@ snd_ad1889_ac97_free(struct snd_ac97 *ac97) chip->ac97 = NULL; } -static int __devinit +static int snd_ad1889_ac97_init(struct snd_ad1889 *chip, const char *quirk_override) { int err; @@ -878,7 +876,7 @@ snd_ad1889_dev_free(struct snd_device *device) return snd_ad1889_free(chip); } -static int __devinit +static int snd_ad1889_init(struct snd_ad1889 *chip) { ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */ @@ -892,7 +890,7 @@ snd_ad1889_init(struct snd_ad1889 *chip) return 0; } -static int __devinit +static int snd_ad1889_create(struct snd_card *card, struct pci_dev *pci, struct snd_ad1889 **rchip) @@ -912,7 +910,7 @@ snd_ad1889_create(struct snd_card *card, /* check PCI availability (32bit DMA) */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - printk(KERN_ERR PFX "error setting 32-bit DMA mask.\n"); + dev_err(card->dev, "error setting 32-bit DMA mask.\n"); pci_disable_device(pci); return -ENXIO; } @@ -935,7 +933,7 @@ snd_ad1889_create(struct snd_card *card, chip->bar = pci_resource_start(pci, 0); chip->iobase = pci_ioremap_bar(pci, 0); if (chip->iobase == NULL) { - printk(KERN_ERR PFX "unable to reserve region.\n"); + dev_err(card->dev, "unable to reserve region.\n"); err = -EBUSY; goto free_and_ret; } @@ -946,7 +944,7 @@ snd_ad1889_create(struct snd_card *card, if (request_irq(pci->irq, snd_ad1889_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR PFX "cannot obtain IRQ %d\n", pci->irq); + dev_err(card->dev, "cannot obtain IRQ %d\n", pci->irq); snd_ad1889_free(chip); return -EBUSY; } @@ -965,8 +963,6 @@ snd_ad1889_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; @@ -978,7 +974,7 @@ free_and_ret: return err; } -static int __devinit +static int snd_ad1889_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -996,7 +992,8 @@ snd_ad1889_probe(struct pci_dev *pci, } /* (2) */ - err = snd_card_create(index[devno], id[devno], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[devno], id[devno], THIS_MODULE, + 0, &card); /* XXX REVISIT: we can probably allocate chip in this call */ if (err < 0) return err; @@ -1042,11 +1039,10 @@ free_and_ret: return err; } -static void __devexit +static void snd_ad1889_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { @@ -1059,7 +1055,7 @@ static struct pci_driver ad1889_pci_driver = { .name = KBUILD_MODNAME, .id_table = snd_ad1889_ids, .probe = snd_ad1889_probe, - .remove = __devexit_p(snd_ad1889_remove), + .remove = snd_ad1889_remove, }; module_pci_driver(ad1889_pci_driver); diff --git a/sound/pci/ak4531_codec.c b/sound/pci/ak4531_codec.c index cadf7b962e3..3bf0dc53360 100644 --- a/sound/pci/ak4531_codec.c +++ b/sound/pci/ak4531_codec.c @@ -274,7 +274,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_master, -6200, 200, 0); static const DECLARE_TLV_DB_SCALE(db_scale_mono, -2800, 400, 0); static const DECLARE_TLV_DB_SCALE(db_scale_input, -5000, 200, 0); -static struct snd_kcontrol_new snd_ak4531_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ak4531_controls[] = { AK4531_DOUBLE_TLV("Master Playback Switch", 0, AK4531_LMASTER, AK4531_RMASTER, 7, 7, 1, 1, @@ -383,9 +383,9 @@ static u8 snd_ak4531_initial_map[0x19 + 1] = { 0x01 /* 19: Mic Amp Setup */ }; -int __devinit snd_ak4531_mixer(struct snd_card *card, - struct snd_ak4531 *_ak4531, - struct snd_ak4531 **rak4531) +int snd_ak4531_mixer(struct snd_card *card, + struct snd_ak4531 *_ak4531, + struct snd_ak4531 **rak4531) { unsigned int idx; int err; @@ -483,7 +483,7 @@ static void snd_ak4531_proc_read(struct snd_info_entry *entry, ak4531->regs[AK4531_MIC_GAIN] & 1 ? "+30dB" : "+0dB"); } -static void __devinit +static void snd_ak4531_proc_init(struct snd_card *card, struct snd_ak4531 *ak4531) { struct snd_info_entry *entry; diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index c7e3c533316..feb29c24cab 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c @@ -65,18 +65,6 @@ module_param(enable, bool, 0444); /* - * Debug part definitions - */ - -/* #define ALI_DEBUG */ - -#ifdef ALI_DEBUG -#define snd_ali_printk(format, args...) printk(KERN_DEBUG format, ##args); -#else -#define snd_ali_printk(format, args...) -#endif - -/* * Constants definition */ @@ -321,7 +309,7 @@ static int snd_ali_codec_ready(struct snd_ali *codec, } snd_ali_5451_poke(codec, port, res & ~0x8000); - snd_printdd("ali_codec_ready: codec is not ready.\n "); + dev_dbg(codec->card->dev, "ali_codec_ready: codec is not ready.\n "); return -EIO; } @@ -342,7 +330,7 @@ static int snd_ali_stimer_ready(struct snd_ali *codec) schedule_timeout_uninterruptible(1); } - snd_printk(KERN_ERR "ali_stimer_read: stimer is not ready.\n"); + dev_err(codec->card->dev, "ali_stimer_read: stimer is not ready.\n"); return -EIO; } @@ -354,7 +342,8 @@ static void snd_ali_codec_poke(struct snd_ali *codec,int secondary, unsigned int port; if (reg >= 0x80) { - snd_printk(KERN_ERR "ali_codec_poke: reg(%xh) invalid.\n", reg); + dev_err(codec->card->dev, + "ali_codec_poke: reg(%xh) invalid.\n", reg); return; } @@ -385,7 +374,8 @@ static unsigned short snd_ali_codec_peek(struct snd_ali *codec, unsigned int port; if (reg >= 0x80) { - snd_printk(KERN_ERR "ali_codec_peek: reg(%xh) invalid.\n", reg); + dev_err(codec->card->dev, + "ali_codec_peek: reg(%xh) invalid.\n", reg); return ~0; } @@ -417,7 +407,7 @@ static void snd_ali_codec_write(struct snd_ac97 *ac97, { struct snd_ali *codec = ac97->private_data; - snd_ali_printk("codec_write: reg=%xh data=%xh.\n", reg, val); + dev_dbg(codec->card->dev, "codec_write: reg=%xh data=%xh.\n", reg, val); if (reg == AC97_GPIO_STATUS) { outl((val << ALI_AC97_GPIO_DATA_SHIFT) | ALI_AC97_GPIO_ENABLE, ALI_REG(codec, ALI_AC97_GPIO)); @@ -433,7 +423,7 @@ static unsigned short snd_ali_codec_read(struct snd_ac97 *ac97, { struct snd_ali *codec = ac97->private_data; - snd_ali_printk("codec_read reg=%xh.\n", reg); + dev_dbg(codec->card->dev, "codec_read reg=%xh.\n", reg); return snd_ali_codec_peek(codec, ac97->num, reg); } @@ -451,10 +441,10 @@ static int snd_ali_reset_5451(struct snd_ali *codec) if (pci_dev) { pci_read_config_dword(pci_dev, 0x7c, &dwVal); pci_write_config_dword(pci_dev, 0x7c, dwVal | 0x08000000); - udelay(5000); + mdelay(5); pci_read_config_dword(pci_dev, 0x7c, &dwVal); pci_write_config_dword(pci_dev, 0x7c, dwVal & 0xf7ffffff); - udelay(5000); + mdelay(5); } pci_dev = codec->pci; @@ -463,18 +453,18 @@ static int snd_ali_reset_5451(struct snd_ali *codec) udelay(500); pci_read_config_dword(pci_dev, 0x44, &dwVal); pci_write_config_dword(pci_dev, 0x44, dwVal & 0xfffbffff); - udelay(5000); + mdelay(5); wCount = 200; while(wCount--) { wReg = snd_ali_codec_peek(codec, 0, AC97_POWERDOWN); if ((wReg & 0x000f) == 0x000f) return 0; - udelay(5000); + mdelay(5); } /* non-fatal if you have a non PM capable codec */ - /* snd_printk(KERN_WARNING "ali5451: reset time out\n"); */ + /* dev_warn(codec->card->dev, "ali5451: reset time out\n"); */ return 0; } @@ -528,7 +518,7 @@ static void snd_ali_disable_voice_irq(struct snd_ali *codec, unsigned int mask; struct snd_ali_channel_control *pchregs = &(codec->chregs); - snd_ali_printk("disable_voice_irq channel=%d\n",channel); + dev_dbg(codec->card->dev, "disable_voice_irq channel=%d\n", channel); mask = 1 << (channel & 0x1f); pchregs->data.ainten = inl(ALI_REG(codec, pchregs->regs.ainten)); @@ -541,7 +531,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel) unsigned int idx = channel & 0x1f; if (codec->synth.chcnt >= ALI_CHANNELS){ - snd_printk(KERN_ERR + dev_err(codec->card->dev, "ali_alloc_pcm_channel: no free channels.\n"); return -1; } @@ -549,7 +539,7 @@ static int snd_ali_alloc_pcm_channel(struct snd_ali *codec, int channel) if (!(codec->synth.chmap & (1 << idx))) { codec->synth.chmap |= 1 << idx; codec->synth.chcnt++; - snd_ali_printk("alloc_pcm_channel no. %d.\n",idx); + dev_dbg(codec->card->dev, "alloc_pcm_channel no. %d.\n", idx); return idx; } return -1; @@ -560,7 +550,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec) int idx; int result = -1; - snd_ali_printk("find_free_channel: for %s\n",rec ? "rec" : "pcm"); + dev_dbg(codec->card->dev, + "find_free_channel: for %s\n", rec ? "rec" : "pcm"); /* recording */ if (rec) { @@ -575,8 +566,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec) if (result >= 0) return result; else { - snd_printk(KERN_ERR "ali_find_free_channel: " - "record channel is busy now.\n"); + dev_err(codec->card->dev, + "ali_find_free_channel: record channel is busy now.\n"); return -1; } } @@ -590,8 +581,8 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec) if (result >= 0) return result; else - snd_printk(KERN_ERR "ali_find_free_channel: " - "S/PDIF out channel is in busy now.\n"); + dev_err(codec->card->dev, + "ali_find_free_channel: S/PDIF out channel is in busy now.\n"); } for (idx = 0; idx < ALI_CHANNELS; idx++) { @@ -599,7 +590,7 @@ static int snd_ali_find_free_channel(struct snd_ali * codec, int rec) if (result >= 0) return result; } - snd_printk(KERN_ERR "ali_find_free_channel: no free channels.\n"); + dev_err(codec->card->dev, "ali_find_free_channel: no free channels.\n"); return -1; } @@ -607,14 +598,15 @@ static void snd_ali_free_channel_pcm(struct snd_ali *codec, int channel) { unsigned int idx = channel & 0x0000001f; - snd_ali_printk("free_channel_pcm channel=%d\n",channel); + dev_dbg(codec->card->dev, "free_channel_pcm channel=%d\n", channel); if (channel < 0 || channel >= ALI_CHANNELS) return; if (!(codec->synth.chmap & (1 << idx))) { - snd_printk(KERN_ERR "ali_free_channel_pcm: " - "channel %d is not in use.\n", channel); + dev_err(codec->card->dev, + "ali_free_channel_pcm: channel %d is not in use.\n", + channel); return; } else { codec->synth.chmap &= ~(1 << idx); @@ -626,7 +618,7 @@ static void snd_ali_stop_voice(struct snd_ali *codec, unsigned int channel) { unsigned int mask = 1 << (channel & 0x1f); - snd_ali_printk("stop_voice: channel=%d\n",channel); + dev_dbg(codec->card->dev, "stop_voice: channel=%d\n", channel); outl(mask, ALI_REG(codec, codec->chregs.regs.stop)); } @@ -667,7 +659,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec) } if (count > 50000) { - snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n"); + dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n"); return; } @@ -682,7 +674,7 @@ static void snd_ali_detect_spdif_rate(struct snd_ali *codec) } if (count > 50000) { - snd_printk(KERN_ERR "ali_detect_spdif_rate: timeout!\n"); + dev_err(codec->card->dev, "ali_detect_spdif_rate: timeout!\n"); return; } @@ -855,12 +847,8 @@ static void snd_ali_disable_spdif_out(struct snd_ali *codec) static void snd_ali_update_ptr(struct snd_ali *codec, int channel) { struct snd_ali_voice *pvoice; - struct snd_pcm_runtime *runtime; struct snd_ali_channel_control *pchregs; unsigned int old, mask; -#ifdef ALI_DEBUG - unsigned int temp, cspf; -#endif pchregs = &(codec->chregs); @@ -872,21 +860,17 @@ static void snd_ali_update_ptr(struct snd_ali *codec, int channel) return; pvoice = &codec->synth.voices[channel]; - runtime = pvoice->substream->runtime; udelay(100); spin_lock(&codec->reg_lock); if (pvoice->pcm && pvoice->substream) { /* pcm interrupt */ -#ifdef ALI_DEBUG - outb((u8)(pvoice->number), ALI_REG(codec, ALI_GC_CIR)); - temp = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); - cspf = (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask; -#endif if (pvoice->running) { - snd_ali_printk("update_ptr: cso=%4.4x cspf=%d.\n", - (u16)temp, cspf); + dev_dbg(codec->card->dev, + "update_ptr: cso=%4.4x cspf=%d.\n", + inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)), + (inl(ALI_REG(codec, ALI_CSPF)) & mask) == mask); spin_unlock(&codec->reg_lock); snd_pcm_period_elapsed(pvoice->substream); spin_lock(&codec->reg_lock); @@ -942,14 +926,14 @@ static struct snd_ali_voice *snd_ali_alloc_voice(struct snd_ali * codec, struct snd_ali_voice *pvoice; int idx; - snd_ali_printk("alloc_voice: type=%d rec=%d\n", type, rec); + dev_dbg(codec->card->dev, "alloc_voice: type=%d rec=%d\n", type, rec); spin_lock_irq(&codec->voice_alloc); if (type == SNDRV_ALI_VOICE_TYPE_PCM) { idx = channel > 0 ? snd_ali_alloc_pcm_channel(codec, channel) : snd_ali_find_free_channel(codec,rec); if (idx < 0) { - snd_printk(KERN_ERR "ali_alloc_voice: err.\n"); + dev_err(codec->card->dev, "ali_alloc_voice: err.\n"); spin_unlock_irq(&codec->voice_alloc); return NULL; } @@ -972,7 +956,7 @@ static void snd_ali_free_voice(struct snd_ali * codec, void (*private_free)(void *); void *private_data; - snd_ali_printk("free_voice: channel=%d\n",pvoice->number); + dev_dbg(codec->card->dev, "free_voice: channel=%d\n", pvoice->number); if (!pvoice->use) return; snd_ali_clear_voices(codec, pvoice->number, pvoice->number); @@ -1155,7 +1139,7 @@ static int snd_ali_trigger(struct snd_pcm_substream *substream, outl(val, ALI_REG(codec, ALI_AINTEN)); if (do_start) outl(what, ALI_REG(codec, ALI_START)); - snd_ali_printk("trigger: what=%xh whati=%xh\n", what, whati); + dev_dbg(codec->card->dev, "trigger: what=%xh whati=%xh\n", what, whati); spin_unlock(&codec->reg_lock); return 0; @@ -1241,7 +1225,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream) unsigned int VOL; unsigned int EC; - snd_ali_printk("playback_prepare ...\n"); + dev_dbg(codec->card->dev, "playback_prepare ...\n"); spin_lock_irq(&codec->reg_lock); @@ -1268,7 +1252,7 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream) /* set target ESO for channel */ pvoice->eso = runtime->buffer_size; - snd_ali_printk("playback_prepare: eso=%xh count=%xh\n", + dev_dbg(codec->card->dev, "playback_prepare: eso=%xh count=%xh\n", pvoice->eso, pvoice->count); /* set ESO to capture first MIDLP interrupt */ @@ -1280,8 +1264,9 @@ static int snd_ali_playback_prepare(struct snd_pcm_substream *substream) PAN = 0; VOL = 0; EC = 0; - snd_ali_printk("playback_prepare:\n"); - snd_ali_printk("ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n", + dev_dbg(codec->card->dev, "playback_prepare:\n"); + dev_dbg(codec->card->dev, + "ch=%d, Rate=%d Delta=%xh,GVSEL=%xh,PAN=%xh,CTRL=%xh\n", pvoice->number,runtime->rate,Delta,GVSEL,PAN,CTRL); snd_ali_write_voice_regs(codec, pvoice->number, @@ -1334,7 +1319,7 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream) spin_lock_irq(&codec->reg_lock); - snd_ali_printk("ali_prepare...\n"); + dev_dbg(codec->card->dev, "ali_prepare...\n"); snd_ali_enable_special_channel(codec,pvoice->number); @@ -1353,15 +1338,16 @@ static int snd_ali_prepare(struct snd_pcm_substream *substream) rate = snd_ali_get_spdif_in_rate(codec); if (rate == 0) { - snd_printk(KERN_WARNING "ali_capture_preapre: " - "spdif rate detect err!\n"); + dev_warn(codec->card->dev, + "ali_capture_preapre: spdif rate detect err!\n"); rate = 48000; } spin_lock_irq(&codec->reg_lock); bValue = inb(ALI_REG(codec,ALI_SPDIF_CTRL)); if (bValue & 0x10) { outb(bValue,ALI_REG(codec,ALI_SPDIF_CTRL)); - printk(KERN_WARNING "clear SPDIF parity error flag.\n"); + dev_warn(codec->card->dev, + "clear SPDIF parity error flag.\n"); } if (rate != 48000) @@ -1420,7 +1406,7 @@ snd_ali_playback_pointer(struct snd_pcm_substream *substream) outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); cso = inw(ALI_REG(codec, ALI_CSO_ALPHA_FMS + 2)); spin_unlock(&codec->reg_lock); - snd_ali_printk("playback pointer returned cso=%xh.\n", cso); + dev_dbg(codec->card->dev, "playback pointer returned cso=%xh.\n", cso); return cso; } @@ -1435,7 +1421,7 @@ static snd_pcm_uframes_t snd_ali_pointer(struct snd_pcm_substream *substream) spin_lock(&codec->reg_lock); if (!pvoice->running) { - spin_unlock_irq(&codec->reg_lock); + spin_unlock(&codec->reg_lock); return 0; } outb(pvoice->number, ALI_REG(codec, ALI_GC_CIR)); @@ -1678,8 +1664,8 @@ static void snd_ali_pcm_free(struct snd_pcm *pcm) } -static int __devinit snd_ali_pcm(struct snd_ali * codec, int device, - struct ali_pcm_description *desc) +static int snd_ali_pcm(struct snd_ali *codec, int device, + struct ali_pcm_description *desc) { struct snd_pcm *pcm; int err; @@ -1687,7 +1673,8 @@ static int __devinit snd_ali_pcm(struct snd_ali * codec, int device, err = snd_pcm_new(codec->card, desc->name, device, desc->playback_num, desc->capture_num, &pcm); if (err < 0) { - snd_printk(KERN_ERR "snd_ali_pcm: err called snd_pcm_new.\n"); + dev_err(codec->card->dev, + "snd_ali_pcm: err called snd_pcm_new.\n"); return err; } pcm->private_data = codec; @@ -1727,7 +1714,7 @@ static struct ali_pcm_description ali_pcms[] = { } }; -static int __devinit snd_ali_build_pcms(struct snd_ali *codec) +static int snd_ali_build_pcms(struct snd_ali *codec) { int i, err; for (i = 0; i < codec->num_of_codecs && i < ARRAY_SIZE(ali_pcms); i++) { @@ -1832,7 +1819,7 @@ static int snd_ali5451_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] = { /* spdif aplayback switch */ /* FIXME: "IEC958 Playback Switch" may conflict with one on ac97_codec */ ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), 0, 0), @@ -1842,7 +1829,7 @@ static struct snd_kcontrol_new snd_ali5451_mixer_spdif[] __devinitdata = { ALI5451_SPDIF(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), 0, 2) }; -static int __devinit snd_ali_mixer(struct snd_ali * codec) +static int snd_ali_mixer(struct snd_ali *codec) { struct snd_ac97_template ac97; unsigned int idx; @@ -1863,7 +1850,7 @@ static int __devinit snd_ali_mixer(struct snd_ali * codec) ac97.num = i; err = snd_ac97_mixer(codec->ac97_bus, &ac97, &codec->ac97[i]); if (err < 0) { - snd_printk(KERN_ERR + dev_err(codec->card->dev, "ali mixer %d creating error.\n", i); if (i == 0) return err; @@ -1949,8 +1936,7 @@ static int ali_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "ali5451: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2015,10 +2001,10 @@ static int snd_ali_chip_init(struct snd_ali *codec) unsigned char temp; struct pci_dev *pci_dev; - snd_ali_printk("chip initializing ... \n"); + dev_dbg(codec->card->dev, "chip initializing ...\n"); if (snd_ali_reset_5451(codec)) { - snd_printk(KERN_ERR "ali_chip_init: reset 5451 error.\n"); + dev_err(codec->card->dev, "ali_chip_init: reset 5451 error.\n"); return -1; } @@ -2064,7 +2050,7 @@ static int snd_ali_chip_init(struct snd_ali *codec) ALI_REG(codec, ALI_SCTRL)); } - snd_ali_printk("chip initialize succeed.\n"); + dev_dbg(codec->card->dev, "chip initialize succeed.\n"); return 0; } @@ -2079,18 +2065,18 @@ static void snd_ali_proc_read(struct snd_info_entry *entry, snd_iprintf(buf, "%02x: %08x\n", i, inl(ALI_REG(codec, i))); } -static void __devinit snd_ali_proc_init(struct snd_ali *codec) +static void snd_ali_proc_init(struct snd_ali *codec) { struct snd_info_entry *entry; if (!snd_card_proc_new(codec->card, "ali5451", &entry)) snd_info_set_text_ops(entry, codec, snd_ali_proc_read); } -static int __devinit snd_ali_resources(struct snd_ali *codec) +static int snd_ali_resources(struct snd_ali *codec) { int err; - snd_ali_printk("resources allocation ...\n"); + dev_dbg(codec->card->dev, "resources allocation ...\n"); err = pci_request_regions(codec->pci, "ALI 5451"); if (err < 0) return err; @@ -2098,11 +2084,11 @@ static int __devinit snd_ali_resources(struct snd_ali *codec) if (request_irq(codec->pci->irq, snd_ali_card_interrupt, IRQF_SHARED, KBUILD_MODNAME, codec)) { - snd_printk(KERN_ERR "Unable to request irq.\n"); + dev_err(codec->card->dev, "Unable to request irq.\n"); return -EBUSY; } codec->irq = codec->pci->irq; - snd_ali_printk("resources allocated.\n"); + dev_dbg(codec->card->dev, "resources allocated.\n"); return 0; } static int snd_ali_dev_free(struct snd_device *device) @@ -2112,11 +2098,11 @@ static int snd_ali_dev_free(struct snd_device *device) return 0; } -static int __devinit snd_ali_create(struct snd_card *card, - struct pci_dev *pci, - int pcm_streams, - int spdif_support, - struct snd_ali ** r_ali) +static int snd_ali_create(struct snd_card *card, + struct pci_dev *pci, + int pcm_streams, + int spdif_support, + struct snd_ali **r_ali) { struct snd_ali *codec; int i, err; @@ -2127,7 +2113,7 @@ static int __devinit snd_ali_create(struct snd_card *card, *r_ali = NULL; - snd_ali_printk("creating ...\n"); + dev_dbg(card->dev, "creating ...\n"); /* enable PCI device */ err = pci_enable_device(pci); @@ -2136,8 +2122,8 @@ static int __devinit snd_ali_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 31 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(31)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(31)) < 0) { - snd_printk(KERN_ERR "architecture does not support " - "31bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 31bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2201,61 +2187,59 @@ static int __devinit snd_ali_create(struct snd_card *card, /* M1533: southbridge */ codec->pci_m1533 = pci_get_device(0x10b9, 0x1533, NULL); if (!codec->pci_m1533) { - snd_printk(KERN_ERR "ali5451: cannot find ALi 1533 chip.\n"); + dev_err(card->dev, "cannot find ALi 1533 chip.\n"); snd_ali_free(codec); return -ENODEV; } /* M7101: power management */ codec->pci_m7101 = pci_get_device(0x10b9, 0x7101, NULL); if (!codec->pci_m7101 && codec->revision == ALI_5451_V02) { - snd_printk(KERN_ERR "ali5451: cannot find ALi 7101 chip.\n"); + dev_err(card->dev, "cannot find ALi 7101 chip.\n"); snd_ali_free(codec); return -ENODEV; } - snd_ali_printk("snd_device_new is called.\n"); + dev_dbg(card->dev, "snd_device_new is called.\n"); err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, codec, &ops); if (err < 0) { snd_ali_free(codec); return err; } - snd_card_set_dev(card, &pci->dev); - /* initialise synth voices*/ for (i = 0; i < ALI_CHANNELS; i++) codec->synth.voices[i].number = i; err = snd_ali_chip_init(codec); if (err < 0) { - snd_printk(KERN_ERR "ali create: chip init error.\n"); + dev_err(card->dev, "ali create: chip init error.\n"); return err; } #ifdef CONFIG_PM_SLEEP codec->image = kmalloc(sizeof(*codec->image), GFP_KERNEL); if (!codec->image) - snd_printk(KERN_WARNING "can't allocate apm buffer\n"); + dev_warn(card->dev, "can't allocate apm buffer\n"); #endif snd_ali_enable_address_interrupt(codec); codec->hw_initialized = 1; *r_ali = codec; - snd_ali_printk("created.\n"); + dev_dbg(card->dev, "created.\n"); return 0; } -static int __devinit snd_ali_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_ali_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct snd_ali *codec; int err; - snd_ali_printk("probe ...\n"); + dev_dbg(&pci->dev, "probe ...\n"); - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -2264,12 +2248,12 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, goto error; card->private_data = codec; - snd_ali_printk("mixer building ...\n"); + dev_dbg(&pci->dev, "mixer building ...\n"); err = snd_ali_mixer(codec); if (err < 0) goto error; - snd_ali_printk("pcm building ...\n"); + dev_dbg(&pci->dev, "pcm building ...\n"); err = snd_ali_build_pcms(codec); if (err < 0) goto error; @@ -2282,7 +2266,7 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, codec->port, codec->irq); - snd_ali_printk("register card.\n"); + dev_dbg(&pci->dev, "register card.\n"); err = snd_card_register(card); if (err < 0) goto error; @@ -2295,17 +2279,16 @@ static int __devinit snd_ali_probe(struct pci_dev *pci, return err; } -static void __devexit snd_ali_remove(struct pci_dev *pci) +static void snd_ali_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ali5451_driver = { .name = KBUILD_MODNAME, .id_table = snd_ali_ids, .probe = snd_ali_probe, - .remove = __devexit_p(snd_ali_remove), + .remove = snd_ali_remove, .driver = { .pm = ALI_PM_OPS, }, diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 00f157a2cf6..cc9a15a1304 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c @@ -87,19 +87,8 @@ #define PLAYBACK_BLOCK_COUNTER 0x9A #define RECORD_BLOCK_COUNTER 0x9B -#define DEBUG_CALLS 0 #define DEBUG_PLAY_REC 0 -#if DEBUG_CALLS -#define snd_als300_dbgcalls(format, args...) printk(KERN_DEBUG format, ##args) -#define snd_als300_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__) -#define snd_als300_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__) -#else -#define snd_als300_dbgcalls(format, args...) -#define snd_als300_dbgcallenter() -#define snd_als300_dbgcallleave() -#endif - #if DEBUG_PLAY_REC #define snd_als300_dbgplay(format, args...) printk(KERN_ERR format, ##args) #else @@ -177,7 +166,6 @@ static inline void snd_als300_gcr_write(unsigned long port, static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd) { u32 tmp = snd_als300_gcr_read(chip->port, MISC_CONTROL); - snd_als300_dbgcallenter(); /* boolean XOR check, since old vs. new hardware have directly reversed bit setting for ENABLE and DISABLE. @@ -188,19 +176,16 @@ static void snd_als300_set_irq_flag(struct snd_als300 *chip, int cmd) else tmp &= ~IRQ_SET_BIT; snd_als300_gcr_write(chip->port, MISC_CONTROL, tmp); - snd_als300_dbgcallleave(); } static int snd_als300_free(struct snd_als300 *chip) { - snd_als300_dbgcallenter(); snd_als300_set_irq_flag(chip, IRQ_DISABLE); if (chip->irq >= 0) free_irq(chip->irq, chip); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); - snd_als300_dbgcallleave(); return 0; } @@ -278,12 +263,9 @@ static irqreturn_t snd_als300plus_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static void __devexit snd_als300_remove(struct pci_dev *pci) +static void snd_als300_remove(struct pci_dev *pci) { - snd_als300_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); - snd_als300_dbgcallleave(); } static unsigned short snd_als300_ac97_read(struct snd_ac97 *ac97, @@ -331,14 +313,12 @@ static int snd_als300_ac97(struct snd_als300 *chip) .read = snd_als300_ac97_read, }; - snd_als300_dbgcallenter(); if ((err = snd_ac97_bus(chip->card, 0, &ops, NULL, &bus)) < 0) return err; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; - snd_als300_dbgcallleave(); return snd_ac97_mixer(bus, &ac97, &chip->ac97); } @@ -394,13 +374,13 @@ static int snd_als300_playback_open(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data = kzalloc(sizeof(*data), GFP_KERNEL); - snd_als300_dbgcallenter(); + if (!data) + return -ENOMEM; chip->playback_substream = substream; runtime->hw = snd_als300_playback_hw; runtime->private_data = data; data->control_register = PLAYBACK_CONTROL; data->block_counter_register = PLAYBACK_BLOCK_COUNTER; - snd_als300_dbgcallleave(); return 0; } @@ -410,11 +390,9 @@ static int snd_als300_playback_close(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data; data = substream->runtime->private_data; - snd_als300_dbgcallenter(); kfree(data); chip->playback_substream = NULL; snd_pcm_lib_free_pages(substream); - snd_als300_dbgcallleave(); return 0; } @@ -425,13 +403,13 @@ static int snd_als300_capture_open(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data = kzalloc(sizeof(*data), GFP_KERNEL); - snd_als300_dbgcallenter(); + if (!data) + return -ENOMEM; chip->capture_substream = substream; runtime->hw = snd_als300_capture_hw; runtime->private_data = data; data->control_register = RECORD_CONTROL; data->block_counter_register = RECORD_BLOCK_COUNTER; - snd_als300_dbgcallleave(); return 0; } @@ -441,11 +419,9 @@ static int snd_als300_capture_close(struct snd_pcm_substream *substream) struct snd_als300_substream_data *data; data = substream->runtime->private_data; - snd_als300_dbgcallenter(); kfree(data); chip->capture_substream = NULL; snd_pcm_lib_free_pages(substream); - snd_als300_dbgcallleave(); return 0; } @@ -469,7 +445,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream) unsigned short period_bytes = snd_pcm_lib_period_bytes(substream); unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - snd_als300_dbgcallenter(); spin_lock_irq(&chip->reg_lock); tmp = snd_als300_gcr_read(chip->port, PLAYBACK_CONTROL); tmp &= ~TRANSFER_START; @@ -488,7 +463,6 @@ static int snd_als300_playback_prepare(struct snd_pcm_substream *substream) snd_als300_gcr_write(chip->port, PLAYBACK_END, runtime->dma_addr + buffer_bytes - 1); spin_unlock_irq(&chip->reg_lock); - snd_als300_dbgcallleave(); return 0; } @@ -500,7 +474,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream) unsigned short period_bytes = snd_pcm_lib_period_bytes(substream); unsigned short buffer_bytes = snd_pcm_lib_buffer_bytes(substream); - snd_als300_dbgcallenter(); spin_lock_irq(&chip->reg_lock); tmp = snd_als300_gcr_read(chip->port, RECORD_CONTROL); tmp &= ~TRANSFER_START; @@ -519,7 +492,6 @@ static int snd_als300_capture_prepare(struct snd_pcm_substream *substream) snd_als300_gcr_write(chip->port, RECORD_END, runtime->dma_addr + buffer_bytes - 1); spin_unlock_irq(&chip->reg_lock); - snd_als300_dbgcallleave(); return 0; } @@ -534,7 +506,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd) data = substream->runtime->private_data; reg = data->control_register; - snd_als300_dbgcallenter(); spin_lock(&chip->reg_lock); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -565,7 +536,6 @@ static int snd_als300_trigger(struct snd_pcm_substream *substream, int cmd) ret = -EINVAL; } spin_unlock(&chip->reg_lock); - snd_als300_dbgcallleave(); return ret; } @@ -579,7 +549,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream) data = substream->runtime->private_data; period_bytes = snd_pcm_lib_period_bytes(substream); - snd_als300_dbgcallenter(); spin_lock(&chip->reg_lock); current_ptr = (u16) snd_als300_gcr_read(chip->port, data->block_counter_register) + 4; @@ -592,7 +561,6 @@ static snd_pcm_uframes_t snd_als300_pointer(struct snd_pcm_substream *substream) if (data->period_flipflop == 0) current_ptr += period_bytes; snd_als300_dbgplay("Pointer (bytes): %d\n", current_ptr); - snd_als300_dbgcallleave(); return bytes_to_frames(substream->runtime, current_ptr); } @@ -618,12 +586,11 @@ static struct snd_pcm_ops snd_als300_capture_ops = { .pointer = snd_als300_pointer, }; -static int __devinit snd_als300_new_pcm(struct snd_als300 *chip) +static int snd_als300_new_pcm(struct snd_als300 *chip) { struct snd_pcm *pcm; int err; - snd_als300_dbgcallenter(); err = snd_pcm_new(chip->card, "ALS300", 0, 1, 1, &pcm); if (err < 0) return err; @@ -640,7 +607,6 @@ static int __devinit snd_als300_new_pcm(struct snd_als300 *chip) /* pre-allocation of buffers */ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 64*1024); - snd_als300_dbgcallleave(); return 0; } @@ -649,7 +615,6 @@ static void snd_als300_init(struct snd_als300 *chip) unsigned long flags; u32 tmp; - snd_als300_dbgcallenter(); spin_lock_irqsave(&chip->reg_lock, flags); chip->revision = (snd_als300_gcr_read(chip->port, MISC_CONTROL) >> 16) & 0x0000000F; @@ -676,12 +641,11 @@ static void snd_als300_init(struct snd_als300 *chip) snd_als300_gcr_write(chip->port, PLAYBACK_CONTROL, tmp & ~TRANSFER_START); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_als300_dbgcallleave(); } -static int __devinit snd_als300_create(struct snd_card *card, - struct pci_dev *pci, int chip_type, - struct snd_als300 **rchip) +static int snd_als300_create(struct snd_card *card, + struct pci_dev *pci, int chip_type, + struct snd_als300 **rchip) { struct snd_als300 *chip; void *irq_handler; @@ -692,13 +656,12 @@ static int __devinit snd_als300_create(struct snd_card *card, }; *rchip = NULL; - snd_als300_dbgcallenter(); if ((err = pci_enable_device(pci)) < 0) return err; if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { - printk(KERN_ERR "error setting 28bit DMA mask\n"); + dev_err(card->dev, "error setting 28bit DMA mask\n"); pci_disable_device(pci); return -ENXIO; } @@ -730,7 +693,7 @@ static int __devinit snd_als300_create(struct snd_card *card, if (request_irq(pci->irq, irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_als300_free(chip); return -EBUSY; } @@ -741,13 +704,13 @@ static int __devinit snd_als300_create(struct snd_card *card, err = snd_als300_ac97(chip); if (err < 0) { - snd_printk(KERN_WARNING "Could not create ac97\n"); + dev_err(card->dev, "Could not create ac97\n"); snd_als300_free(chip); return err; } if ((err = snd_als300_new_pcm(chip)) < 0) { - snd_printk(KERN_WARNING "Could not create PCM\n"); + dev_err(card->dev, "Could not create PCM\n"); snd_als300_free(chip); return err; } @@ -758,10 +721,7 @@ static int __devinit snd_als300_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; - snd_als300_dbgcallleave(); return 0; } @@ -791,8 +751,7 @@ static int snd_als300_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "als300: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -811,7 +770,7 @@ static SIMPLE_DEV_PM_OPS(snd_als300_pm, snd_als300_suspend, snd_als300_resume); #define SND_ALS300_PM_OPS NULL #endif -static int __devinit snd_als300_probe(struct pci_dev *pci, +static int snd_als300_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -826,7 +785,8 @@ static int __devinit snd_als300_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -863,7 +823,7 @@ static struct pci_driver als300_driver = { .name = KBUILD_MODNAME, .id_table = snd_als300_ids, .probe = snd_als300_probe, - .remove = __devexit_p(snd_als300_remove), + .remove = snd_als300_remove, .driver = { .pm = SND_ALS300_PM_OPS, }, diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index feb2a143683..b751c381d25 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c @@ -578,7 +578,7 @@ static irqreturn_t snd_als4000_interrupt(int irq, void *dev_id) snd_als4k_iobase_readb(chip->alt_port, ALS4K_IOB_16_ACK_FOR_CR1E); - /* printk(KERN_INFO "als4000: irq 0x%04x 0x%04x\n", + /* dev_dbg(chip->card->dev, "als4000: irq 0x%04x 0x%04x\n", pci_irqstatus, sb_irqstatus); */ /* only ack the things we actually handled above */ @@ -694,7 +694,7 @@ static struct snd_pcm_ops snd_als4000_capture_ops = { .pointer = snd_als4000_capture_pointer }; -static int __devinit snd_als4000_pcm(struct snd_sb *chip, int device) +static int snd_als4000_pcm(struct snd_sb *chip, int device) { struct snd_pcm *pcm; int err; @@ -770,7 +770,7 @@ static void snd_als4000_configure(struct snd_sb *chip) } #ifdef SUPPORT_JOYSTICK -static int __devinit snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) +static int snd_als4000_create_gameport(struct snd_card_als4000 *acard, int dev) { struct gameport *gp; struct resource *r; @@ -791,13 +791,13 @@ static int __devinit snd_als4000_create_gameport(struct snd_card_als4000 *acard, } if (!r) { - printk(KERN_WARNING "als4000: cannot reserve joystick ports\n"); + dev_warn(&acard->pci->dev, "cannot reserve joystick ports\n"); return -EBUSY; } acard->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "als4000: cannot allocate memory for gameport\n"); + dev_err(&acard->pci->dev, "cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } @@ -847,8 +847,8 @@ static void snd_card_als4000_free( struct snd_card *card ) pci_disable_device(acard->pci); } -static int __devinit snd_card_als4000_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_als4000_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -873,7 +873,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) { - snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); + dev_err(&pci->dev, "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -888,9 +888,9 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, pci_write_config_word(pci, PCI_COMMAND, word | PCI_COMMAND_IO); pci_set_master(pci); - err = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(*acard) /* private_data: acard */, - &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(*acard) /* private_data: acard */, + &card); if (err < 0) { pci_release_regions(pci); pci_disable_device(pci); @@ -920,7 +920,6 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, chip->pci = pci; chip->alt_port = iobase; - snd_card_set_dev(card, &pci->dev); snd_als4000_configure(chip); @@ -934,7 +933,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi)) < 0) { - printk(KERN_ERR "als4000: no MPU-401 device at 0x%lx?\n", + dev_err(&pci->dev, "no MPU-401 device at 0x%lx?\n", iobase + ALS4K_IOB_30_MIDI_DATA); goto out_err; } @@ -955,7 +954,7 @@ static int __devinit snd_card_als4000_probe(struct pci_dev *pci, iobase + ALS4K_IOB_10_ADLIB_ADDR0, iobase + ALS4K_IOB_12_ADLIB_ADDR2, OPL3_HW_AUTO, 1, &opl3) < 0) { - printk(KERN_ERR "als4000: no OPL device at 0x%lx-0x%lx?\n", + dev_err(&pci->dev, "no OPL device at 0x%lx-0x%lx?\n", iobase + ALS4K_IOB_10_ADLIB_ADDR0, iobase + ALS4K_IOB_12_ADLIB_ADDR2); } else { @@ -981,10 +980,9 @@ out: return err; } -static void __devexit snd_card_als4000_remove(struct pci_dev *pci) +static void snd_card_als4000_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP @@ -1016,8 +1014,7 @@ static int snd_als4000_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "als4000: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1046,7 +1043,7 @@ static struct pci_driver als4000_driver = { .name = KBUILD_MODNAME, .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, - .remove = __devexit_p(snd_card_als4000_remove), + .remove = snd_card_als4000_remove, .driver = { .pm = SND_ALS4000_PM_OPS, }, diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index eedc017c1cd..901c9490398 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c @@ -769,7 +769,10 @@ static void snd_card_asihpi_timer_function(unsigned long data) s->number); ds->drained_count++; if (ds->drained_count > 20) { + unsigned long flags; + snd_pcm_stream_lock_irqsave(s, flags); snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock_irqrestore(s, flags); continue; } } else { @@ -966,7 +969,7 @@ static u64 snd_card_asihpi_playback_formats(struct snd_card_asihpi *asihpi, if (!err) err = hpi_outstream_query_format(h_stream, &hpi_format); if (!err && (hpi_to_alsa_formats[format] != -1)) - formats |= (1ULL << hpi_to_alsa_formats[format]); + formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]); } return formats; } @@ -1141,8 +1144,8 @@ static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi, format, sample_rate, 128000, 0); if (!err) err = hpi_instream_query_format(h_stream, &hpi_format); - if (!err) - formats |= (1ULL << hpi_to_alsa_formats[format]); + if (!err && (hpi_to_alsa_formats[format] != -1)) + formats |= pcm_format_to_bits(hpi_to_alsa_formats[format]); } return formats; } @@ -1235,8 +1238,7 @@ static struct snd_pcm_ops snd_card_asihpi_capture_mmap_ops = { .pointer = snd_card_asihpi_capture_pointer, }; -static int __devinit snd_card_asihpi_pcm_new( - struct snd_card_asihpi *asihpi, int device) +static int snd_card_asihpi_pcm_new(struct snd_card_asihpi *asihpi, int device) { struct snd_pcm *pcm; int err; @@ -1251,11 +1253,12 @@ static int __devinit snd_card_asihpi_pcm_new( num_outstreams, num_instreams, &pcm); if (err < 0) return err; + /* pointer to ops struct is stored, dont change ops afterwards! */ - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, - &snd_card_asihpi_playback_mmap_ops); - snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, - &snd_card_asihpi_capture_mmap_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, + &snd_card_asihpi_playback_mmap_ops); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, + &snd_card_asihpi_capture_mmap_ops); pcm->private_data = asihpi; pcm->info_flags = 0; @@ -1279,7 +1282,7 @@ struct hpi_control { u16 dst_node_type; u16 dst_node_index; u16 band; - char name[44]; /* copied to snd_ctl_elem_id.name[44]; */ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; /* copied to snd_ctl_elem_id.name[44]; */ }; static const char * const asihpi_tuner_band_names[] = { @@ -1497,8 +1500,8 @@ static int snd_asihpi_volume_mute_put(struct snd_kcontrol *kcontrol, return change; } -static int __devinit snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_volume_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1593,8 +1596,8 @@ static int snd_asihpi_level_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_level, -1000, 100, 0); -static int __devinit snd_asihpi_level_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_level_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1715,8 +1718,8 @@ static int snd_asihpi_aesebu_rxstatus_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_aesebu_rx_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1753,8 +1756,8 @@ static int snd_asihpi_aesebu_tx_format_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_aesebu_tx_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -1911,6 +1914,7 @@ static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol, struct snd_card_asihpi *asihpi = snd_kcontrol_chip(kcontrol); */ u32 h_control = kcontrol->private_value; + unsigned int idx; u16 band; u16 tuner_bands[HPI_TUNER_BAND_LAST]; u32 num_bands = 0; @@ -1918,7 +1922,10 @@ static int snd_asihpi_tuner_band_put(struct snd_kcontrol *kcontrol, num_bands = asihpi_tuner_band_query(kcontrol, tuner_bands, HPI_TUNER_BAND_LAST); - band = tuner_bands[ucontrol->value.enumerated.item[0]]; + idx = ucontrol->value.enumerated.item[0]; + if (idx >= ARRAY_SIZE(tuner_bands)) + idx = ARRAY_SIZE(tuner_bands) - 1; + band = tuner_bands[idx]; hpi_handle_error(hpi_tuner_set_band(h_control, band)); return 1; @@ -1996,8 +2003,8 @@ static int snd_asihpi_tuner_freq_put(struct snd_kcontrol *kcontrol, } /* Tuner control group initializer */ -static int __devinit snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_tuner_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2100,8 +2107,8 @@ static int snd_asihpi_meter_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_meter_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl, int subidx) +static int snd_asihpi_meter_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl, int subidx) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2214,8 +2221,8 @@ static int snd_asihpi_mux_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_mux_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_mux_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2303,8 +2310,8 @@ static int snd_asihpi_cmode_put(struct snd_kcontrol *kcontrol, } -static int __devinit snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2381,7 +2388,8 @@ static int snd_asihpi_clksrc_put(struct snd_kcontrol *kcontrol, struct snd_card_asihpi *asihpi = (struct snd_card_asihpi *)(kcontrol->private_data); struct clk_cache *clkcache = &asihpi->cc; - int change, item; + unsigned int item; + int change; u32 h_control = kcontrol->private_value; change = 1; @@ -2471,8 +2479,8 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol, return 0; } -static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, - struct hpi_control *hpi_ctl) +static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, + struct hpi_control *hpi_ctl) { struct snd_card *card = asihpi->card; struct snd_kcontrol_new snd_control; @@ -2548,9 +2556,9 @@ static int __devinit snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi, Mixer ------------------------------------------------------------*/ -static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) +static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) { - struct snd_card *card = asihpi->card; + struct snd_card *card; unsigned int idx = 0; unsigned int subindex = 0; int err; @@ -2558,6 +2566,7 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) if (snd_BUG_ON(!asihpi)) return -EINVAL; + card = asihpi->card; strcpy(card->mixername, "Asihpi Mixer"); err = @@ -2722,7 +2731,7 @@ snd_asihpi_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) +static void snd_asihpi_proc_init(struct snd_card_asihpi *asihpi) { struct snd_info_entry *entry; @@ -2764,8 +2773,8 @@ static int snd_asihpi_hpi_ioctl(struct snd_hwdep *hw, struct file *file, /* results in /dev/snd/hwC#D0 file for each card with index # also /proc/asound/hwdep will contain '#-00: asihpi (HPI) for each card' */ -static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, - int device, struct snd_hwdep **rhwdep) +static int snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, + int device, struct snd_hwdep **rhwdep) { struct snd_hwdep *hw; int err; @@ -2789,8 +2798,8 @@ static int __devinit snd_asihpi_hpi_new(struct snd_card_asihpi *asihpi, /*------------------------------------------------------------ CARD ------------------------------------------------------------*/ -static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +static int snd_asihpi_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { int err; struct hpi_adapter *hpi; @@ -2819,17 +2828,13 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, hpi = pci_get_drvdata(pci_dev); adapter_index = hpi->adapter->index; /* first try to give the card the same index as its hardware index */ - err = snd_card_create(adapter_index, - id[adapter_index], THIS_MODULE, - sizeof(struct snd_card_asihpi), - &card); + err = snd_card_new(&pci_dev->dev, adapter_index, id[adapter_index], + THIS_MODULE, sizeof(struct snd_card_asihpi), &card); if (err < 0) { /* if that fails, try the default index==next available */ - err = - snd_card_create(index[dev], id[dev], - THIS_MODULE, - sizeof(struct snd_card_asihpi), - &card); + err = snd_card_new(&pci_dev->dev, index[dev], id[dev], + THIS_MODULE, sizeof(struct snd_card_asihpi), + &card); if (err < 0) return err; snd_printk(KERN_WARNING @@ -2837,8 +2842,6 @@ static int __devinit snd_asihpi_probe(struct pci_dev *pci_dev, adapter_index, card->number); } - snd_card_set_dev(card, &pci_dev->dev); - asihpi = card->private_data; asihpi->card = card; asihpi->pci = pci_dev; @@ -2944,7 +2947,7 @@ __nodev: } -static void __devexit snd_asihpi_remove(struct pci_dev *pci_dev) +static void snd_asihpi_remove(struct pci_dev *pci_dev) { struct hpi_adapter *hpi = pci_get_drvdata(pci_dev); snd_card_free(hpi->snd_card); @@ -2967,7 +2970,7 @@ static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = asihpi_pci_tbl, .probe = snd_asihpi_probe, - .remove = __devexit_p(snd_asihpi_remove), + .remove = snd_asihpi_remove, #ifdef CONFIG_PM_SLEEP /* .suspend = snd_asihpi_suspend, .resume = snd_asihpi_resume, */ diff --git a/sound/pci/asihpi/hpidspcd.c b/sound/pci/asihpi/hpidspcd.c index 456a758f04f..ac916377001 100644 --- a/sound/pci/asihpi/hpidspcd.c +++ b/sound/pci/asihpi/hpidspcd.c @@ -49,14 +49,12 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, err = request_firmware(&firmware, fw_name, &dev->dev); if (err || !firmware) { - dev_printk(KERN_ERR, &dev->dev, - "%d, request_firmware failed for %s\n", err, - fw_name); + dev_err(&dev->dev, "%d, request_firmware failed for %s\n", + err, fw_name); goto error1; } if (firmware->size < sizeof(header)) { - dev_printk(KERN_ERR, &dev->dev, "Header size too small %s\n", - fw_name); + dev_err(&dev->dev, "Header size too small %s\n", fw_name); goto error2; } memcpy(&header, firmware->data, sizeof(header)); @@ -64,7 +62,7 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, if ((header.type != 0x45444F43) || /* "CODE" */ (header.adapter != adapter) || (header.size != firmware->size)) { - dev_printk(KERN_ERR, &dev->dev, + dev_err(&dev->dev, "Invalid firmware header size %d != file %zd\n", header.size, firmware->size); goto error2; @@ -72,17 +70,15 @@ short hpi_dsp_code_open(u32 adapter, void *os_data, struct dsp_code *dsp_code, if ((header.version >> 9) != (HPI_VER >> 9)) { /* Consider even and subsequent odd minor versions to be compatible */ - dev_printk(KERN_ERR, &dev->dev, - "Incompatible firmware version " - "DSP image %X != Driver %X\n", header.version, - HPI_VER); + dev_err(&dev->dev, "Incompatible firmware version DSP image %X != Driver %X\n", + header.version, HPI_VER); goto error2; } if (header.version != HPI_VER) { - dev_printk(KERN_INFO, &dev->dev, - "Firmware: release version mismatch DSP image %X != Driver %X\n", - header.version, HPI_VER); + dev_info(&dev->dev, + "Firmware: release version mismatch DSP image %X != Driver %X\n", + header.version, HPI_VER); } HPI_DEBUG_LOG(DEBUG, "dsp code %s opened\n", fw_name); diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index 60915620556..7f0272032fb 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c @@ -307,8 +307,8 @@ out: return err; } -int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id) +int asihpi_adapter_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id) { int idx, nm; int adapter_index; @@ -326,7 +326,7 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, pci_dev->subsystem_device, pci_dev->devfn); if (pci_enable_device(pci_dev) < 0) { - dev_printk(KERN_ERR, &pci_dev->dev, + dev_err(&pci_dev->dev, "pci_enable_device failed, disabling device\n"); return -EIO; } @@ -398,9 +398,8 @@ int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, mutex_init(&adapters[adapter_index].mutex); pci_set_drvdata(pci_dev, &adapters[adapter_index]); - dev_printk(KERN_INFO, &pci_dev->dev, - "probe succeeded for ASI%04X HPI index %d\n", - adapter.adapter->type, adapter_index); + dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n", + adapter.adapter->type, adapter_index); return 0; @@ -421,7 +420,7 @@ err: return -ENODEV; } -void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) +void asihpi_adapter_remove(struct pci_dev *pci_dev) { int idx; struct hpi_message hm; @@ -446,13 +445,12 @@ void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev) if (pa->p_buffer) vfree(pa->p_buffer); - pci_set_drvdata(pci_dev, NULL); if (1) - dev_printk(KERN_INFO, &pci_dev->dev, - "remove %04x:%04x,%04x:%04x,%04x," " HPI index %d.\n", - pci_dev->vendor, pci_dev->device, - pci_dev->subsystem_vendor, pci_dev->subsystem_device, - pci_dev->devfn, pa->adapter->index); + dev_info(&pci_dev->dev, + "remove %04x:%04x,%04x:%04x,%04x, HPI index %d\n", + pci_dev->vendor, pci_dev->device, + pci_dev->subsystem_vendor, pci_dev->subsystem_device, + pci_dev->devfn, pa->adapter->index); memset(pa, 0, sizeof(*pa)); } diff --git a/sound/pci/asihpi/hpioctl.h b/sound/pci/asihpi/hpioctl.h index 2614aff672e..0d767e10ac4 100644 --- a/sound/pci/asihpi/hpioctl.h +++ b/sound/pci/asihpi/hpioctl.h @@ -19,9 +19,9 @@ Linux HPI ioctl, and shared module init functions *******************************************************************************/ -int __devinit asihpi_adapter_probe(struct pci_dev *pci_dev, - const struct pci_device_id *pci_id); -void __devexit asihpi_adapter_remove(struct pci_dev *pci_dev); +int asihpi_adapter_probe(struct pci_dev *pci_dev, + const struct pci_device_id *pci_id); +void asihpi_adapter_remove(struct pci_dev *pci_dev); void __init asihpi_init(void); void __exit asihpi_exit(void); diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 368df8b0853..ae07b4926dc 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c @@ -296,7 +296,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { MODULE_DEVICE_TABLE(pci, snd_atiixp_ids); -static struct snd_pci_quirk atiixp_quirks[] __devinitdata = { +static struct snd_pci_quirk atiixp_quirks[] = { SND_PCI_QUIRK(0x105b, 0x0c81, "Foxconn RC4107MA-RS2", 0), SND_PCI_QUIRK(0x15bd, 0x3100, "DFI RS482", 0), { } /* terminator */ @@ -432,7 +432,7 @@ static int snd_atiixp_acquire_codec(struct atiixp *chip) while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) { if (! timeout--) { - snd_printk(KERN_WARNING "atiixp: codec acquire timeout\n"); + dev_warn(chip->card->dev, "codec acquire timeout\n"); return -EBUSY; } udelay(1); @@ -463,7 +463,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp *chip, unsigned short } while (--timeout); /* time out may happen during reset */ if (reg < 0x7c) - snd_printk(KERN_WARNING "atiixp: codec read timeout (reg %x)\n", reg); + dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg); return 0xffff; } @@ -523,7 +523,7 @@ static int snd_atiixp_aclink_reset(struct atiixp *chip) mdelay(1); atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET); if (!--timeout) { - snd_printk(KERN_ERR "atiixp: codec reset timeout\n"); + dev_err(chip->card->dev, "codec reset timeout\n"); break; } } @@ -561,21 +561,21 @@ static int snd_atiixp_aclink_down(struct atiixp *chip) ATI_REG_ISR_CODEC2_NOT_READY) #define CODEC_CHECK_BITS (ALL_CODEC_NOT_READY|ATI_REG_ISR_NEW_FRAME) -static int __devinit ac97_probing_bugs(struct pci_dev *pci) +static int ac97_probing_bugs(struct pci_dev *pci) { const struct snd_pci_quirk *q; q = snd_pci_quirk_lookup(pci, atiixp_quirks); if (q) { - snd_printdd(KERN_INFO "Atiixp quirk for %s. " - "Forcing codec %d\n", q->name, q->value); + dev_dbg(&pci->dev, "atiixp quirk for %s. Forcing codec %d\n", + snd_pci_quirk_name(q), q->value); return q->value; } /* this hardware doesn't need workarounds. Probe for codec */ return -1; } -static int __devinit snd_atiixp_codec_detect(struct atiixp *chip) +static int snd_atiixp_codec_detect(struct atiixp *chip) { int timeout; @@ -599,7 +599,7 @@ static int __devinit snd_atiixp_codec_detect(struct atiixp *chip) atiixp_write(chip, IER, 0); /* disable irqs */ if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) { - snd_printk(KERN_ERR "atiixp: no codec detected!\n"); + dev_err(chip->card->dev, "no codec detected!\n"); return -ENXIO; } return 0; @@ -675,7 +675,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr continue; return bytes_to_frames(runtime, curptr); } - snd_printd("atiixp: invalid DMA pointer read 0x%x (buf=%x)\n", + dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n", readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr); return 0; } @@ -687,8 +687,10 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma) { if (! dma->substream || ! dma->running) return; - snd_printdd("atiixp: XRUN detected (DMA %d)\n", dma->ops->type); + dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type); + snd_pcm_stream_lock(dma->substream); snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(dma->substream); } /* @@ -1183,7 +1185,7 @@ static struct snd_pcm_ops snd_atiixp_spdif_ops = { .pointer = snd_atiixp_pcm_pointer, }; -static struct ac97_pcm atiixp_pcm_defs[] __devinitdata = { +static struct ac97_pcm atiixp_pcm_defs[] = { /* front PCM */ { .exclusive = 1, @@ -1247,7 +1249,7 @@ static struct atiixp_dma_ops snd_atiixp_spdif_dma_ops = { }; -static int __devinit snd_atiixp_pcm_new(struct atiixp *chip) +static int snd_atiixp_pcm_new(struct atiixp *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1390,7 +1392,7 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) * ac97 mixer section */ -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { { .subvendor = 0x103c, .subdevice = 0x006b, @@ -1412,8 +1414,8 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { } /* terminator */ }; -static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, - const char *quirk_override) +static int snd_atiixp_mixer_new(struct atiixp *chip, int clock, + const char *quirk_override) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -1450,14 +1452,15 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp *chip, int clock, ac97.scaps |= AC97_SCAP_NO_SPDIF; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ - snd_printdd("atiixp: codec %d not available for audio\n", i); + dev_dbg(chip->card->dev, + "codec %d not available for audio\n", i); continue; } codec_count++; } if (! codec_count) { - snd_printk(KERN_ERR "atiixp: no codec available\n"); + dev_err(chip->card->dev, "no codec available\n"); return -ENODEV; } @@ -1508,8 +1511,7 @@ static int snd_atiixp_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "atiixp: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1560,7 +1562,7 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); } -static void __devinit snd_atiixp_proc_init(struct atiixp *chip) +static void snd_atiixp_proc_init(struct atiixp *chip) { struct snd_info_entry *entry; @@ -1602,9 +1604,9 @@ static int snd_atiixp_dev_free(struct snd_device *device) /* * constructor for chip instance */ -static int __devinit snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp **r_chip) +static int snd_atiixp_create(struct snd_card *card, + struct pci_dev *pci, + struct atiixp **r_chip) { static struct snd_device_ops ops = { .dev_free = snd_atiixp_dev_free, @@ -1634,14 +1636,14 @@ static int __devinit snd_atiixp_create(struct snd_card *card, chip->addr = pci_resource_start(pci, 0); chip->remap_addr = pci_ioremap_bar(pci, 0); if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + dev_err(card->dev, "AC'97 space ioremap problem\n"); snd_atiixp_free(chip); return -EIO; } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; } @@ -1654,21 +1656,19 @@ static int __devinit snd_atiixp_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *r_chip = chip; return 0; } -static int __devinit snd_atiixp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_atiixp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct atiixp *chip; int err; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -1710,17 +1710,16 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, return err; } -static void __devexit snd_atiixp_remove(struct pci_dev *pci) +static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver atiixp_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = __devexit_p(snd_atiixp_remove), + .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, }, diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index 6fc03d9f2cf..b9dc96c5d21 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c @@ -400,7 +400,7 @@ static int snd_atiixp_acquire_codec(struct atiixp_modem *chip) while (atiixp_read(chip, PHYS_OUT_ADDR) & ATI_REG_PHYS_OUT_ADDR_EN) { if (! timeout--) { - snd_printk(KERN_WARNING "atiixp-modem: codec acquire timeout\n"); + dev_warn(chip->card->dev, "codec acquire timeout\n"); return -EBUSY; } udelay(1); @@ -433,7 +433,7 @@ static unsigned short snd_atiixp_codec_read(struct atiixp_modem *chip, } while (--timeout); /* time out may happen during reset */ if (reg < 0x7c) - snd_printk(KERN_WARNING "atiixp-modem: codec read timeout (reg %x)\n", reg); + dev_warn(chip->card->dev, "codec read timeout (reg %x)\n", reg); return 0xffff; } @@ -499,7 +499,7 @@ static int snd_atiixp_aclink_reset(struct atiixp_modem *chip) msleep(1); atiixp_update(chip, CMD, ATI_REG_CMD_AC_RESET, ATI_REG_CMD_AC_RESET); if (!--timeout) { - snd_printk(KERN_ERR "atiixp-modem: codec reset timeout\n"); + dev_err(chip->card->dev, "codec reset timeout\n"); break; } } @@ -553,7 +553,7 @@ static int snd_atiixp_codec_detect(struct atiixp_modem *chip) atiixp_write(chip, IER, 0); /* disable irqs */ if ((chip->codec_not_ready_bits & ALL_CODEC_NOT_READY) == ALL_CODEC_NOT_READY) { - snd_printk(KERN_ERR "atiixp-modem: no codec detected!\n"); + dev_err(chip->card->dev, "no codec detected!\n"); return -ENXIO; } return 0; @@ -624,7 +624,7 @@ static snd_pcm_uframes_t snd_atiixp_pcm_pointer(struct snd_pcm_substream *substr continue; return bytes_to_frames(runtime, curptr); } - snd_printd("atiixp-modem: invalid DMA pointer read 0x%x (buf=%x)\n", + dev_dbg(chip->card->dev, "invalid DMA pointer read 0x%x (buf=%x)\n", readl(chip->remap_addr + dma->ops->dt_cur), dma->buf_addr); return 0; } @@ -637,8 +637,10 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip, { if (! dma->substream || ! dma->running) return; - snd_printdd("atiixp-modem: XRUN detected (DMA %d)\n", dma->ops->type); + dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type); + snd_pcm_stream_lock(dma->substream); snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN); + snd_pcm_stream_unlock(dma->substream); } /* @@ -988,7 +990,7 @@ static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .flush_dma = atiixp_in_flush_dma, }; -static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip) +static int snd_atiixp_pcm_new(struct atiixp_modem *chip) { struct snd_pcm *pcm; int err; @@ -1061,7 +1063,7 @@ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) * ac97 mixer section */ -static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) +static int snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -1096,14 +1098,15 @@ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* to be sure */ - snd_printdd("atiixp-modem: codec %d not available for modem\n", i); + dev_dbg(chip->card->dev, + "codec %d not available for modem\n", i); continue; } codec_count++; } if (! codec_count) { - snd_printk(KERN_ERR "atiixp-modem: no codec available\n"); + dev_err(chip->card->dev, "no codec available\n"); return -ENODEV; } @@ -1148,8 +1151,7 @@ static int snd_atiixp_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "atiixp-modem: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1186,7 +1188,7 @@ static void snd_atiixp_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); } -static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip) +static void snd_atiixp_proc_init(struct atiixp_modem *chip) { struct snd_info_entry *entry; @@ -1228,9 +1230,9 @@ static int snd_atiixp_dev_free(struct snd_device *device) /* * constructor for chip instance */ -static int __devinit snd_atiixp_create(struct snd_card *card, - struct pci_dev *pci, - struct atiixp_modem **r_chip) +static int snd_atiixp_create(struct snd_card *card, + struct pci_dev *pci, + struct atiixp_modem **r_chip) { static struct snd_device_ops ops = { .dev_free = snd_atiixp_dev_free, @@ -1260,14 +1262,14 @@ static int __devinit snd_atiixp_create(struct snd_card *card, chip->addr = pci_resource_start(pci, 0); chip->remap_addr = pci_ioremap_bar(pci, 0); if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + dev_err(card->dev, "AC'97 space ioremap problem\n"); snd_atiixp_free(chip); return -EIO; } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; } @@ -1280,21 +1282,19 @@ static int __devinit snd_atiixp_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *r_chip = chip; return 0; } -static int __devinit snd_atiixp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_atiixp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct atiixp_modem *chip; int err; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -1331,17 +1331,16 @@ static int __devinit snd_atiixp_probe(struct pci_dev *pci, return err; } -static void __devexit snd_atiixp_remove(struct pci_dev *pci) +static void snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver atiixp_modem_driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, - .remove = __devexit_p(snd_atiixp_remove), + .remove = snd_atiixp_remove, .driver = { .pm = SND_ATIIXP_PM_OPS, }, diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c index ffc376f9f4e..afb1b44b741 100644 --- a/sound/pci/au88x0/au88x0.c +++ b/sound/pci/au88x0/au88x0.c @@ -78,7 +78,7 @@ static void vortex_fix_agp_bridge(struct pci_dev *via) } } -static void __devinit snd_vortex_workaround(struct pci_dev *vortex, int fix) +static void snd_vortex_workaround(struct pci_dev *vortex, int fix) { struct pci_dev *via = NULL; @@ -137,7 +137,7 @@ static int snd_vortex_dev_free(struct snd_device *device) // chip-specific constructor // (see "Management of Cards and Components") -static int __devinit +static int snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) { vortex_t *chip; @@ -211,8 +211,6 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) goto alloc_out; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; @@ -234,7 +232,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip) } // constructor -- see "Constructor" sub-section -static int __devinit +static int snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -250,7 +248,8 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return -ENOENT; } // (2) - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -368,10 +367,9 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) } // destructor -- see "Destructor" sub-section -static void __devexit snd_vortex_remove(struct pci_dev *pci) +static void snd_vortex_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } // pci_driver definition @@ -379,7 +377,7 @@ static struct pci_driver vortex_driver = { .name = KBUILD_MODNAME, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, - .remove = __devexit_p(snd_vortex_remove), + .remove = snd_vortex_remove, }; module_pci_driver(vortex_driver); diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c index 9ae8b3b1765..aad831acbb1 100644 --- a/sound/pci/au88x0/au88x0_a3d.c +++ b/sound/pci/au88x0/au88x0_a3d.c @@ -594,7 +594,7 @@ static int Vort3DRend_Initialize(vortex_t * v, unsigned short mode) static int vortex_a3d_register_controls(vortex_t * vortex); static void vortex_a3d_unregister_controls(vortex_t * vortex); /* A3D base support init/shudown */ -static void __devinit vortex_Vort3D_enable(vortex_t * v) +static void vortex_Vort3D_enable(vortex_t *v) { int i; @@ -845,7 +845,7 @@ snd_vortex_a3d_filter_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_a3d_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Playback PCM advanced processing", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -855,7 +855,7 @@ static struct snd_kcontrol_new vortex_a3d_kcontrol __devinitdata = { }; /* Control (un)registration. */ -static int __devinit vortex_a3d_register_controls(vortex_t * vortex) +static int vortex_a3d_register_controls(vortex_t *vortex) { struct snd_kcontrol *kcontrol; int err, i; diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 525f881f040..ae59dbaa53d 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c @@ -2461,7 +2461,12 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) #ifndef CHIP_AU8810 for (i = 0; i < NR_WT; i++) { if (vortex->dma_wt[i].fifo_status == FIFO_START) { - if (vortex_wtdma_bufshift(vortex, i)) ; + /* FIXME: we ignore the return value from + * vortex_wtdma_bufshift() below as the delta + * calculation seems not working for wavetable + * by some reason + */ + vortex_wtdma_bufshift(vortex, i); spin_unlock(&vortex->lock); snd_pcm_period_elapsed(vortex->dma_wt[i]. substream); @@ -2675,7 +2680,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode) /* Initialization */ -static int __devinit vortex_core_init(vortex_t * vortex) +static int vortex_core_init(vortex_t *vortex) { printk(KERN_INFO "Vortex: init.... "); diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c index 278ed8189fc..e7220533ecf 100644 --- a/sound/pci/au88x0/au88x0_eq.c +++ b/sound/pci/au88x0/au88x0_eq.c @@ -757,7 +757,7 @@ snd_vortex_eqtoggle_put(struct snd_kcontrol *kcontrol, return 1; /* Allways changes */ } -static struct snd_kcontrol_new vortex_eqtoggle_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_eqtoggle_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "EQ Enable", .index = 0, @@ -815,7 +815,7 @@ snd_vortex_eq_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucon return changed; } -static struct snd_kcontrol_new vortex_eq_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_eq_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = " .", .index = 0, @@ -854,7 +854,7 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u return 0; } -static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = { +static struct snd_kcontrol_new vortex_levels_kcontrol = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "EQ Peaks", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -863,7 +863,7 @@ static struct snd_kcontrol_new vortex_levels_kcontrol __devinitdata = { }; /* EQ band gain labels. */ -static char *EqBandLabels[10] __devinitdata = { +static char *EqBandLabels[10] = { "EQ0 31Hz\0", "EQ1 63Hz\0", "EQ2 125Hz\0", @@ -877,7 +877,7 @@ static char *EqBandLabels[10] __devinitdata = { }; /* ALSA driver entry points. Init and exit. */ -static int __devinit vortex_eq_init(vortex_t * vortex) +static int vortex_eq_init(vortex_t *vortex) { struct snd_kcontrol *kcontrol; int err, i; diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c index 30a456700d8..280f86de223 100644 --- a/sound/pci/au88x0/au88x0_game.c +++ b/sound/pci/au88x0/au88x0_game.c @@ -92,7 +92,7 @@ static int vortex_game_open(struct gameport *gameport, int mode) return 0; } -static int __devinit vortex_gameport_register(vortex_t * vortex) +static int vortex_gameport_register(vortex_t *vortex) { struct gameport *gp; diff --git a/sound/pci/au88x0/au88x0_mixer.c b/sound/pci/au88x0/au88x0_mixer.c index fa13efbebda..a58298cfe7e 100644 --- a/sound/pci/au88x0/au88x0_mixer.c +++ b/sound/pci/au88x0/au88x0_mixer.c @@ -19,7 +19,7 @@ static int remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static int __devinit snd_vortex_mixer(vortex_t * vortex) +static int snd_vortex_mixer(vortex_t *vortex) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c index e6c6a0febb7..29e5945eef6 100644 --- a/sound/pci/au88x0/au88x0_mpu401.c +++ b/sound/pci/au88x0/au88x0_mpu401.c @@ -41,7 +41,7 @@ #define MPU401_ENTER_UART 0x3f #define MPU401_ACK 0xfe -static int __devinit snd_vortex_midi(vortex_t * vortex) +static int snd_vortex_midi(vortex_t *vortex) { struct snd_rawmidi *rmidi; int temp, mode; diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c index b2405020284..9fb03b4ea92 100644 --- a/sound/pci/au88x0/au88x0_pcm.c +++ b/sound/pci/au88x0/au88x0_pcm.c @@ -516,7 +516,7 @@ static int snd_vortex_spdif_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el } /* spdif controls */ -static struct snd_kcontrol_new snd_vortex_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_vortex_mixer_spdif[] = { { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -598,7 +598,7 @@ static int snd_vortex_pcm_vol_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_MINMAX(vortex_pcm_vol_db_scale, -9600, 2400); -static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { +static struct snd_kcontrol_new snd_vortex_pcm_vol = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -611,7 +611,7 @@ static struct snd_kcontrol_new snd_vortex_pcm_vol __devinitdata = { }; /* create a pcm device */ -static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) +static int snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; @@ -650,6 +650,29 @@ static int __devinit snd_vortex_new_pcm(vortex_t *chip, int idx, int nr) snd_dma_pci_data(chip->pci_dev), 0x10000, 0x10000); + switch (VORTEX_PCM_TYPE(pcm)) { + case VORTEX_PCM_ADB: + err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + snd_pcm_std_chmaps, + VORTEX_IS_QUAD(chip) ? 4 : 2, + 0, NULL); + if (err < 0) + return err; + err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_CAPTURE, + snd_pcm_std_chmaps, 2, 0, NULL); + if (err < 0) + return err; + break; +#ifdef CHIP_AU8830 + case VORTEX_PCM_A3D: + err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, + snd_pcm_std_chmaps, 1, 0, NULL); + if (err < 0) + return err; + break; +#endif + } + if (VORTEX_PCM_TYPE(pcm) == VORTEX_PCM_SPDIF) { for (i = 0; i < ARRAY_SIZE(snd_vortex_mixer_spdif); i++) { kctl = snd_ctl_new1(&snd_vortex_mixer_spdif[i], chip); diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c index 2805e34bd41..922a84bba2e 100644 --- a/sound/pci/au88x0/au88x0_synth.c +++ b/sound/pci/au88x0/au88x0_synth.c @@ -58,7 +58,7 @@ static void vortex_wt_setdsout(vortex_t * vortex, u32 wt, int en) if (en) temp |= (1 << (wt & 0x1f)); else - temp &= (1 << ~(wt & 0x1f)); + temp &= ~(1 << (wt & 0x1f)); hwwrite(vortex->mmio, WT_DSREG((wt >= 0x20) ? 1 : 0), temp); } @@ -219,7 +219,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_RUN(wt), val); return 0xc; - break; case 1: /* param 0 */ /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", @@ -227,7 +226,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_PARM(wt, 0), val); return 0xc; - break; case 2: /* param 1 */ /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", @@ -235,7 +233,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_PARM(wt, 1), val); return 0xc; - break; case 3: /* param 2 */ /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", @@ -243,7 +240,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_PARM(wt, 2), val); return 0xc; - break; case 4: /* param 3 */ /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", @@ -251,7 +247,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_PARM(wt, 3), val); return 0xc; - break; case 6: /* mute */ /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", @@ -259,20 +254,17 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, */ hwwrite(vortex->mmio, WT_MUTE(wt), val); return 0xc; - break; case 0xb: - { /* delay */ - /* - printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", - WT_DELAY(wt,0), (int)val); - */ - hwwrite(vortex->mmio, WT_DELAY(wt, 3), val); - hwwrite(vortex->mmio, WT_DELAY(wt, 2), val); - hwwrite(vortex->mmio, WT_DELAY(wt, 1), val); - hwwrite(vortex->mmio, WT_DELAY(wt, 0), val); - return 0xc; - } - break; + /* delay */ + /* + printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", + WT_DELAY(wt,0), (int)val); + */ + hwwrite(vortex->mmio, WT_DELAY(wt, 3), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 2), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 1), val); + hwwrite(vortex->mmio, WT_DELAY(wt, 0), val); + return 0xc; /* Global WT block parameters */ case 5: /* sramp */ ecx = WT_SRAMP(wt); @@ -291,7 +283,6 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt, break; default: return 0; - break; } /* printk(KERN_DEBUG "vortex: WT SetReg(0x%x) = 0x%08x\n", ecx, (int)val); diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 0f804741825..120d0d320a6 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c @@ -113,11 +113,11 @@ struct aw2 { * FUNCTION DECLARATIONS ********************************/ static int snd_aw2_dev_free(struct snd_device *device); -static int __devinit snd_aw2_create(struct snd_card *card, - struct pci_dev *pci, struct aw2 **rchip); -static int __devinit snd_aw2_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id); -static void __devexit snd_aw2_remove(struct pci_dev *pci); +static int snd_aw2_create(struct snd_card *card, + struct pci_dev *pci, struct aw2 **rchip); +static int snd_aw2_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id); +static void snd_aw2_remove(struct pci_dev *pci); static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream); static int snd_aw2_pcm_playback_close(struct snd_pcm_substream *substream); static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream); @@ -135,7 +135,7 @@ static snd_pcm_uframes_t snd_aw2_pcm_pointer_playback(struct snd_pcm_substream *substream); static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream *substream); -static int __devinit snd_aw2_new_pcm(struct aw2 *chip); +static int snd_aw2_new_pcm(struct aw2 *chip); static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); @@ -173,7 +173,7 @@ static struct pci_driver aw2_driver = { .name = KBUILD_MODNAME, .id_table = snd_aw2_ids, .probe = snd_aw2_probe, - .remove = __devexit_p(snd_aw2_remove), + .remove = snd_aw2_remove, }; module_pci_driver(aw2_driver); @@ -202,7 +202,7 @@ static struct snd_pcm_ops snd_aw2_capture_ops = { .pointer = snd_aw2_pcm_pointer_capture, }; -static struct snd_kcontrol_new aw2_control __devinitdata = { +static struct snd_kcontrol_new aw2_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Capture Route", .index = 0, @@ -242,8 +242,8 @@ static int snd_aw2_dev_free(struct snd_device *device) } /* chip-specific constructor */ -static int __devinit snd_aw2_create(struct snd_card *card, - struct pci_dev *pci, struct aw2 **rchip) +static int snd_aw2_create(struct snd_card *card, + struct pci_dev *pci, struct aw2 **rchip) { struct aw2 *chip; int err; @@ -262,7 +262,7 @@ static int __devinit snd_aw2_create(struct snd_card *card, /* check PCI availability (32bit DMA) */ if ((pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) || (pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0)) { - printk(KERN_ERR "aw2: Impossible to set 32bit mask DMA\n"); + dev_err(card->dev, "Impossible to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -290,7 +290,7 @@ static int __devinit snd_aw2_create(struct snd_card *card, pci_resource_len(pci, 0)); if (chip->iobase_virt == NULL) { - printk(KERN_ERR "aw2: unable to remap memory region"); + dev_err(card->dev, "unable to remap memory region"); pci_release_regions(pci); pci_disable_device(pci); kfree(chip); @@ -302,7 +302,7 @@ static int __devinit snd_aw2_create(struct snd_card *card, if (request_irq(pci->irq, snd_aw2_saa7146_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR "aw2: Cannot grab irq %d\n", pci->irq); + dev_err(card->dev, "Cannot grab irq %d\n", pci->irq); iounmap(chip->iobase_virt); pci_release_regions(chip->pci); @@ -322,18 +322,16 @@ static int __devinit snd_aw2_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); *rchip = chip; - printk(KERN_INFO - "Audiowerk 2 sound card (saa7146 chipset) detected and " - "managed\n"); + dev_info(card->dev, + "Audiowerk 2 sound card (saa7146 chipset) detected and managed\n"); return 0; } /* constructor */ -static int __devinit snd_aw2_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_aw2_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -349,7 +347,8 @@ static int __devinit snd_aw2_probe(struct pci_dev *pci, } /* (2) Create card instance */ - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -389,10 +388,9 @@ static int __devinit snd_aw2_probe(struct pci_dev *pci, } /* destructor */ -static void __devexit snd_aw2_remove(struct pci_dev *pci) +static void snd_aw2_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* open callback */ @@ -400,7 +398,7 @@ static int snd_aw2_pcm_playback_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_printdd(KERN_DEBUG "aw2: Playback_open\n"); + dev_dbg(substream->pcm->card->dev, "Playback_open\n"); runtime->hw = snd_aw2_playback_hw; return 0; } @@ -416,7 +414,7 @@ static int snd_aw2_pcm_capture_open(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; - snd_printdd(KERN_DEBUG "aw2: Capture_open\n"); + dev_dbg(substream->pcm->card->dev, "Capture_open\n"); runtime->hw = snd_aw2_capture_hw; return 0; } @@ -591,7 +589,7 @@ static snd_pcm_uframes_t snd_aw2_pcm_pointer_capture(struct snd_pcm_substream } /* create a pcm device */ -static int __devinit snd_aw2_new_pcm(struct aw2 *chip) +static int snd_aw2_new_pcm(struct aw2 *chip) { struct snd_pcm *pcm_playback_ana; struct snd_pcm *pcm_playback_num; @@ -604,7 +602,7 @@ static int __devinit snd_aw2_new_pcm(struct aw2 *chip) err = snd_pcm_new(chip->card, "Audiowerk2 analog playback", 0, 1, 0, &pcm_playback_ana); if (err < 0) { - printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err); + dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err); return err; } @@ -634,14 +632,15 @@ static int __devinit snd_aw2_new_pcm(struct aw2 *chip) (chip->pci), 64 * 1024, 64 * 1024); if (err) - printk(KERN_ERR "aw2: snd_pcm_lib_preallocate_pages_for_all " - "error (0x%X)\n", err); + dev_err(chip->card->dev, + "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", + err); err = snd_pcm_new(chip->card, "Audiowerk2 digital playback", 1, 1, 0, &pcm_playback_num); if (err < 0) { - printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err); + dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err); return err; } /* Creation ok */ @@ -670,17 +669,15 @@ static int __devinit snd_aw2_new_pcm(struct aw2 *chip) (chip->pci), 64 * 1024, 64 * 1024); if (err) - printk(KERN_ERR - "aw2: snd_pcm_lib_preallocate_pages_for_all error " - "(0x%X)\n", err); - - + dev_err(chip->card->dev, + "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", + err); err = snd_pcm_new(chip->card, "Audiowerk2 capture", 2, 0, 1, &pcm_capture); if (err < 0) { - printk(KERN_ERR "aw2: snd_pcm_new error (0x%X)\n", err); + dev_err(chip->card->dev, "snd_pcm_new error (0x%X)\n", err); return err; } @@ -710,15 +707,15 @@ static int __devinit snd_aw2_new_pcm(struct aw2 *chip) (chip->pci), 64 * 1024, 64 * 1024); if (err) - printk(KERN_ERR - "aw2: snd_pcm_lib_preallocate_pages_for_all error " - "(0x%X)\n", err); + dev_err(chip->card->dev, + "snd_pcm_lib_preallocate_pages_for_all error (0x%X)\n", + err); /* Create control */ err = snd_ctl_add(chip->card, snd_ctl_new1(&aw2_control, chip)); if (err < 0) { - printk(KERN_ERR "aw2: snd_ctl_add error (0x%X)\n", err); + dev_err(chip->card->dev, "snd_ctl_add error (0x%X)\n", err); return err; } diff --git a/sound/pci/aw2/aw2-saa7146.c b/sound/pci/aw2/aw2-saa7146.c index 4439636971e..6d24e953677 100644 --- a/sound/pci/aw2/aw2-saa7146.c +++ b/sound/pci/aw2/aw2-saa7146.c @@ -204,8 +204,7 @@ void snd_aw2_saa7146_pcm_init_playback(struct snd_aw2_saa7146 *chip, /* Define upper limit for DMA access */ WRITEREG(dma_addr + buffer_size, ProtA1_out); } else { - printk(KERN_ERR - "aw2: snd_aw2_saa7146_pcm_init_playback: " + pr_err("aw2: snd_aw2_saa7146_pcm_init_playback: " "Substream number is not 0 or 1 -> not managed\n"); } } @@ -251,8 +250,7 @@ void snd_aw2_saa7146_pcm_init_capture(struct snd_aw2_saa7146 *chip, /* Define upper limit for DMA access */ WRITEREG(dma_addr + buffer_size, ProtA1_in); } else { - printk(KERN_ERR - "aw2: snd_aw2_saa7146_pcm_init_capture: " + pr_err("aw2: snd_aw2_saa7146_pcm_init_capture: " "Substream number is not 0 -> not managed\n"); } } diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index c03b66b784a..c9216c0a9c8 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -238,61 +238,6 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); 2>/dev/null */ -#define DEBUG_MISC 0 -#define DEBUG_CALLS 0 -#define DEBUG_MIXER 0 -#define DEBUG_CODEC 0 -#define DEBUG_TIMER 0 -#define DEBUG_GAME 0 -#define DEBUG_PM 0 -#define MIXER_TESTING 0 - -#if DEBUG_MISC -#define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbgmisc(format, args...) -#endif - -#if DEBUG_CALLS -#define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) -#define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__) -#define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__) -#else -#define snd_azf3328_dbgcalls(format, args...) -#define snd_azf3328_dbgcallenter() -#define snd_azf3328_dbgcallleave() -#endif - -#if DEBUG_MIXER -#define snd_azf3328_dbgmixer(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbgmixer(format, args...) -#endif - -#if DEBUG_CODEC -#define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbgcodec(format, args...) -#endif - -#if DEBUG_MISC -#define snd_azf3328_dbgtimer(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbgtimer(format, args...) -#endif - -#if DEBUG_GAME -#define snd_azf3328_dbggame(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbggame(format, args...) -#endif - -#if DEBUG_PM -#define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args) -#else -#define snd_azf3328_dbgpm(format, args...) -#endif - static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); @@ -475,6 +420,12 @@ snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg) return inb(chip->ctrl_io + reg); } +static inline u16 +snd_azf3328_ctrl_inw(const struct snd_azf3328 *chip, unsigned reg) +{ + return inw(chip->ctrl_io + reg); +} + static inline void snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) { @@ -578,11 +529,12 @@ snd_azf3328_mixer_reset(const struct snd_azf3328 *chip) #ifdef AZF_USE_AC97_LAYER static inline void -snd_azf3328_mixer_ac97_map_unsupported(unsigned short reg, const char *mode) +snd_azf3328_mixer_ac97_map_unsupported(const struct snd_azf3328 *chip, + unsigned short reg, const char *mode) { /* need to add some more or less clever emulation? */ - printk(KERN_WARNING - "azt3328: missing %s emulation for AC97 register 0x%02x!\n", + dev_warn(chip->card->dev, + "missing %s emulation for AC97 register 0x%02x!\n", mode, reg); } @@ -715,14 +667,12 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97) const struct snd_azf3328 *chip = ac97->private_data; unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97); unsigned short reg_val = 0; - bool unsupported = 0; + bool unsupported = false; - snd_azf3328_dbgmixer( - "snd_azf3328_mixer_ac97_read reg_ac97 %u\n", - reg_ac97 - ); + dev_dbg(chip->card->dev, "snd_azf3328_mixer_ac97_read reg_ac97 %u\n", + reg_ac97); if (reg_azf & AZF_AC97_REG_UNSUPPORTED) - unsupported = 1; + unsupported = true; else { if (reg_azf & AZF_AC97_REG_REAL_IO_READ) reg_val = snd_azf3328_mixer_inw(chip, @@ -759,13 +709,13 @@ snd_azf3328_mixer_ac97_read(struct snd_ac97 *ac97, unsigned short reg_ac97) reg_val = azf_emulated_ac97_vendor_id & 0xffff; break; default: - unsupported = 1; + unsupported = true; break; } } } if (unsupported) - snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "read"); + snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "read"); return reg_val; } @@ -776,14 +726,13 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97, { const struct snd_azf3328 *chip = ac97->private_data; unsigned short reg_azf = snd_azf3328_mixer_ac97_map_reg_idx(reg_ac97); - bool unsupported = 0; + bool unsupported = false; - snd_azf3328_dbgmixer( + dev_dbg(chip->card->dev, "snd_azf3328_mixer_ac97_write reg_ac97 %u val %u\n", - reg_ac97, val - ); + reg_ac97, val); if (reg_azf & AZF_AC97_REG_UNSUPPORTED) - unsupported = 1; + unsupported = true; else { if (reg_azf & AZF_AC97_REG_REAL_IO_WRITE) snd_azf3328_mixer_outw( @@ -808,16 +757,16 @@ snd_azf3328_mixer_ac97_write(struct snd_ac97 *ac97, */ break; default: - unsupported = 1; + unsupported = true; break; } } } if (unsupported) - snd_azf3328_mixer_ac97_map_unsupported(reg_ac97, "write"); + snd_azf3328_mixer_ac97_map_unsupported(chip, reg_ac97, "write"); } -static int __devinit +static int snd_azf3328_mixer_new(struct snd_azf3328 *chip) { struct snd_ac97_bus *bus; @@ -850,7 +799,7 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) * due to this card being a very quirky AC97 "lookalike". */ if (rc) - printk(KERN_ERR "azt3328: AC97 init failed, err %d!\n", rc); + dev_err(chip->card->dev, "AC97 init failed, err %d!\n", rc); /* If we return an error here, then snd_card_free() should * free up any ac97 codecs that got created, as well as the bus. @@ -870,8 +819,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, unsigned char curr_vol_left = 0, curr_vol_right = 0; int left_change = 0, right_change = 0; - snd_azf3328_dbgcallenter(); - if (chan_sel & SET_CHAN_LEFT) { curr_vol_left = inb(portbase + 1); @@ -912,7 +859,6 @@ snd_azf3328_mixer_write_volume_gradually(const struct snd_azf3328 *chip, if (delay) mdelay(delay); } while ((left_change) || (right_change)); - snd_azf3328_dbgcallleave(); } /* @@ -990,14 +936,12 @@ snd_azf3328_info_mixer(struct snd_kcontrol *kcontrol, { struct azf3328_mixer_reg reg; - snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); uinfo->type = reg.mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = reg.stereo + 1; uinfo->value.integer.min = 0; uinfo->value.integer.max = reg.mask; - snd_azf3328_dbgcallleave(); return 0; } @@ -1009,7 +953,6 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol, struct azf3328_mixer_reg reg; u16 oreg, val; - snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); oreg = snd_azf3328_mixer_inw(chip, reg.reg); @@ -1023,12 +966,11 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol, val = reg.mask - val; ucontrol->value.integer.value[1] = val; } - snd_azf3328_dbgmixer("get: %02x is %04x -> vol %02lx|%02lx " - "(shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", + dev_dbg(chip->card->dev, + "get: %02x is %04x -> vol %02lx|%02lx (shift %02d|%02d, mask %02x, inv. %d, stereo %d)\n", reg.reg, oreg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], reg.lchan_shift, reg.rchan_shift, reg.mask, reg.invert, reg.stereo); - snd_azf3328_dbgcallleave(); return 0; } @@ -1040,7 +982,6 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol, struct azf3328_mixer_reg reg; u16 oreg, nreg, val; - snd_azf3328_dbgcallenter(); snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); oreg = snd_azf3328_mixer_inw(chip, reg.reg); val = ucontrol->value.integer.value[0] & reg.mask; @@ -1064,12 +1005,11 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol, else snd_azf3328_mixer_outw(chip, reg.reg, nreg); - snd_azf3328_dbgmixer("put: %02x to %02lx|%02lx, " - "oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", + dev_dbg(chip->card->dev, + "put: %02x to %02lx|%02lx, oreg %04x; shift %02d|%02d -> nreg %04x; after: %04x\n", reg.reg, ucontrol->value.integer.value[0], ucontrol->value.integer.value[1], oreg, reg.lchan_shift, reg.rchan_shift, nreg, snd_azf3328_mixer_inw(chip, reg.reg)); - snd_azf3328_dbgcallleave(); return (nreg != oreg); } @@ -1135,7 +1075,8 @@ snd_azf3328_get_mixer_enum(struct snd_kcontrol *kcontrol, } else ucontrol->value.enumerated.item[0] = (val >> reg.lchan_shift) & (reg.enum_c - 1); - snd_azf3328_dbgmixer("get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", + dev_dbg(chip->card->dev, + "get_enum: %02x is %04x -> %d|%d (shift %02d, enum_c %d)\n", reg.reg, val, ucontrol->value.enumerated.item[0], ucontrol->value.enumerated.item[1], reg.lchan_shift, reg.enum_c); return 0; @@ -1167,11 +1108,12 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, snd_azf3328_mixer_outw(chip, reg.reg, val); nreg = val; - snd_azf3328_dbgmixer("put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg); + dev_dbg(chip->card->dev, + "put_enum: %02x to %04x, oreg %04x\n", reg.reg, val, oreg); return (nreg != oreg); } -static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_azf3328_mixer_controls[] = { AZF3328_MIXER_SWITCH("Master Playback Switch", IDX_MIXER_PLAY_MASTER, 15, 1), AZF3328_MIXER_VOL_STEREO("Master Playback Volume", IDX_MIXER_PLAY_MASTER, 0x1f, 1), AZF3328_MIXER_SWITCH("PCM Playback Switch", IDX_MIXER_WAVEOUT, 15, 1), @@ -1229,7 +1171,7 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { #endif }; -static u16 __devinitdata snd_azf3328_init_values[][2] = { +static u16 snd_azf3328_init_values[][2] = { { IDX_MIXER_PLAY_MASTER, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_MODEMOUT, MIXER_MUTE_MASK|0x1f1f }, { IDX_MIXER_BASSTREBLE, 0x0000 }, @@ -1245,7 +1187,7 @@ static u16 __devinitdata snd_azf3328_init_values[][2] = { { IDX_MIXER_REC_VOLUME, MIXER_MUTE_MASK|0x0707 }, }; -static int __devinit +static int snd_azf3328_mixer_new(struct snd_azf3328 *chip) { struct snd_card *card; @@ -1253,7 +1195,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) unsigned int idx; int err; - snd_azf3328_dbgcallenter(); if (snd_BUG_ON(!chip || !chip->card)) return -EINVAL; @@ -1279,7 +1220,6 @@ snd_azf3328_mixer_new(struct snd_azf3328 *chip) snd_component_add(card, "AZF3328 mixer"); strcpy(card->mixername, "AZF3328 mixer"); - snd_azf3328_dbgcallleave(); return 0; } #endif /* AZF_USE_AC97_LAYER */ @@ -1288,19 +1228,13 @@ static int snd_azf3328_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params) { - int res; - snd_azf3328_dbgcallenter(); - res = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); - snd_azf3328_dbgcallleave(); - return res; + return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); } static int snd_azf3328_hw_free(struct snd_pcm_substream *substream) { - snd_azf3328_dbgcallenter(); snd_pcm_lib_free_pages(substream); - snd_azf3328_dbgcallleave(); return 0; } @@ -1315,7 +1249,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, u16 val = 0xff00; u8 freq = 0; - snd_azf3328_dbgcallenter(); switch (bitrate) { case AZF_FREQ_4000: freq = SOUNDFORMAT_FREQ_SUSPECTED_4000; break; case AZF_FREQ_4800: freq = SOUNDFORMAT_FREQ_SUSPECTED_4800; break; @@ -1379,7 +1312,6 @@ snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, ); spin_unlock_irqrestore(codec->lock, flags); - snd_azf3328_dbgcallleave(); } static inline void @@ -1404,15 +1336,16 @@ snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, chip->shadow_reg_ctrl_6AH |= bitmask; else chip->shadow_reg_ctrl_6AH &= ~bitmask; - snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n", - bitmask, do_mask, chip->shadow_reg_ctrl_6AH); + dev_dbg(chip->card->dev, + "6AH_update mask 0x%04x do_mask %d: val 0x%04x\n", + bitmask, do_mask, chip->shadow_reg_ctrl_6AH); snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); } static inline void snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) { - snd_azf3328_dbgcodec("codec_enable %d\n", enable); + dev_dbg(chip->card->dev, "codec_enable %d\n", enable); /* no idea what exactly is being done here, but I strongly assume it's * PM related */ snd_azf3328_ctrl_reg_6AH_update( @@ -1429,7 +1362,7 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; bool need_change = (codec->running != enable); - snd_azf3328_dbgcodec( + dev_dbg(chip->card->dev, "codec_activity: %s codec, enable %d, need_change %d\n", codec->name, enable, need_change ); @@ -1470,13 +1403,13 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, } static void -snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, - unsigned long addr, - unsigned int period_bytes, - unsigned int buffer_bytes +snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, + struct snd_azf3328_codec_data *codec, + unsigned long addr, + unsigned int period_bytes, + unsigned int buffer_bytes ) { - snd_azf3328_dbgcallenter(); WARN_ONCE(period_bytes & 1, "odd period length!?\n"); WARN_ONCE(buffer_bytes != 2 * period_bytes, "missed our input expectations! %u vs. %u\n", @@ -1499,7 +1432,7 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, setup_io.dma_start_1 = addr; setup_io.dma_start_2 = addr+area_length; - snd_azf3328_dbgcodec( + dev_dbg(chip->card->dev, "setdma: buffers %08x[%u] / %08x[%u], %u, %u\n", setup_io.dma_start_1, area_length, setup_io.dma_start_2, area_length, @@ -1522,7 +1455,6 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, ); spin_unlock_irqrestore(codec->lock, flags); } - snd_azf3328_dbgcallleave(); } static int @@ -1535,8 +1467,6 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream) unsigned int count = snd_pcm_lib_period_bytes(substream); #endif - snd_azf3328_dbgcallenter(); - codec->dma_base = runtime->dma_addr; #if 0 @@ -1544,10 +1474,9 @@ snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream) runtime->rate, snd_pcm_format_width(runtime->format), runtime->channels); - snd_azf3328_codec_setdmaa(codec, + snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr, count, size); #endif - snd_azf3328_dbgcallleave(); return 0; } @@ -1559,14 +1488,12 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct snd_azf3328_codec_data *codec = runtime->private_data; int result = 0; u16 flags1; - bool previously_muted = 0; + bool previously_muted = false; bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type); - snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd); - switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_azf3328_dbgcodec("START %s\n", codec->name); + dev_dbg(chip->card->dev, "START PCM %s\n", codec->name); if (is_main_mixer_playback_codec) { /* mute WaveOut (avoid clicking during setup) */ @@ -1593,7 +1520,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); spin_unlock(codec->lock); - snd_azf3328_codec_setdmaa(codec, runtime->dma_addr, + snd_azf3328_codec_setdmaa(chip, codec, runtime->dma_addr, snd_pcm_lib_period_bytes(substream), snd_pcm_lib_buffer_bytes(substream) ); @@ -1633,10 +1560,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ); } - snd_azf3328_dbgcodec("STARTED %s\n", codec->name); + dev_dbg(chip->card->dev, "PCM STARTED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_RESUME: - snd_azf3328_dbgcodec("RESUME %s\n", codec->name); + dev_dbg(chip->card->dev, "PCM RESUME %s\n", codec->name); /* resume codec if we were active */ spin_lock(codec->lock); if (codec->running) @@ -1648,7 +1575,7 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) spin_unlock(codec->lock); break; case SNDRV_PCM_TRIGGER_STOP: - snd_azf3328_dbgcodec("STOP %s\n", codec->name); + dev_dbg(chip->card->dev, "PCM STOP %s\n", codec->name); if (is_main_mixer_playback_codec) { /* mute WaveOut (avoid clicking during setup) */ @@ -1684,10 +1611,10 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ); } - snd_azf3328_dbgcodec("STOPPED %s\n", codec->name); + dev_dbg(chip->card->dev, "PCM STOPPED %s\n", codec->name); break; case SNDRV_PCM_TRIGGER_SUSPEND: - snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name); + dev_dbg(chip->card->dev, "PCM SUSPEND %s\n", codec->name); /* make sure codec is stopped */ snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, snd_azf3328_codec_inw( @@ -1696,17 +1623,16 @@ snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); + WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); + WARN(1, "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); break; default: - snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n"); + WARN(1, "FIXME: unknown trigger mode!\n"); return -EINVAL; } - snd_azf3328_dbgcallleave(); return result; } @@ -1728,8 +1654,8 @@ snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream result -= codec->dma_base; #endif frmres = bytes_to_frames( substream->runtime, result); - snd_azf3328_dbgcodec("%08li %s @ 0x%8lx, frames %8ld\n", - jiffies, codec->name, result, frmres); + dev_dbg(substream->pcm->card->dev, "%08li %s @ 0x%8lx, frames %8ld\n", + jiffies, codec->name, result, frmres); return frmres; } @@ -1792,7 +1718,7 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) * skeleton handler only * (we do not want axis reading in interrupt handler - too much load!) */ - snd_azf3328_dbggame("gameport irq\n"); + dev_dbg(chip->card->dev, "gameport irq\n"); /* this should ACK the gameport IRQ properly, hopefully. */ snd_azf3328_game_inw(chip, IDX_GAME_AXIS_VALUE); @@ -1804,7 +1730,7 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode) struct snd_azf3328 *chip = gameport_get_port_data(gameport); int res; - snd_azf3328_dbggame("gameport_open, mode %d\n", mode); + dev_dbg(chip->card->dev, "gameport_open, mode %d\n", mode); switch (mode) { case GAMEPORT_MODE_COOKED: case GAMEPORT_MODE_RAW: @@ -1827,7 +1753,7 @@ snd_azf3328_gameport_close(struct gameport *gameport) { struct snd_azf3328 *chip = gameport_get_port_data(gameport); - snd_azf3328_dbggame("gameport_close\n"); + dev_dbg(chip->card->dev, "gameport_close\n"); snd_azf3328_gameport_set_counter_frequency(chip, GAME_HWCFG_ADC_COUNTER_FREQ_1_200); snd_azf3328_gameport_axis_circuit_enable(chip, 0); @@ -1892,21 +1818,20 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, axes[i] = -1; } - snd_azf3328_dbggame("cooked_read: axes %d %d %d %d buttons %d\n", - axes[0], axes[1], axes[2], axes[3], *buttons - ); + dev_dbg(chip->card->dev, "cooked_read: axes %d %d %d %d buttons %d\n", + axes[0], axes[1], axes[2], axes[3], *buttons); return 0; } -static int __devinit +static int snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "azt3328: cannot alloc memory for gameport\n"); + dev_err(chip->card->dev, "cannot alloc memory for gameport\n"); return -ENOMEM; } @@ -1950,23 +1875,23 @@ snd_azf3328_gameport_free(struct snd_azf3328 *chip) { } static inline void snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) { - printk(KERN_WARNING "huh, game port IRQ occurred!?\n"); + dev_warn(chip->card->dev, "huh, game port IRQ occurred!?\n"); } #endif /* SUPPORT_GAMEPORT */ /******************************************************************/ static inline void -snd_azf3328_irq_log_unknown_type(u8 which) +snd_azf3328_irq_log_unknown_type(struct snd_azf3328 *chip, u8 which) { - snd_azf3328_dbgcodec( - "azt3328: unknown IRQ type (%x) occurred, please report!\n", - which - ); + dev_dbg(chip->card->dev, + "unknown IRQ type (%x) occurred, please report!\n", + which); } static inline void -snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec, +snd_azf3328_pcm_interrupt(struct snd_azf3328 *chip, + const struct snd_azf3328_codec_data *first_codec, u8 status ) { @@ -1990,17 +1915,15 @@ snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec, if (codec->substream) { snd_pcm_period_elapsed(codec->substream); - snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", + dev_dbg(chip->card->dev, "%s period done (#%x), @ %x\n", codec->name, which, snd_azf3328_codec_inl( - codec, IDX_IO_CODEC_DMA_CURRPOS - ) - ); + codec, IDX_IO_CODEC_DMA_CURRPOS)); } else - printk(KERN_WARNING "azt3328: irq handler problem!\n"); + dev_warn(chip->card->dev, "irq handler problem!\n"); if (which & IRQ_SOMETHING) - snd_azf3328_irq_log_unknown_type(which); + snd_azf3328_irq_log_unknown_type(chip, which); } } @@ -2009,9 +1932,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) { struct snd_azf3328 *chip = dev_id; u8 status; -#if DEBUG_CODEC static unsigned long irq_count; -#endif status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS); @@ -2022,14 +1943,13 @@ snd_azf3328_interrupt(int irq, void *dev_id) )) return IRQ_NONE; /* must be interrupt for another device */ - snd_azf3328_dbgcodec( + dev_dbg(chip->card->dev, "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", irq_count++ /* debug-only */, - status - ); + status); if (status & IRQ_TIMER) { - /* snd_azf3328_dbgcodec("timer %ld\n", + /* dev_dbg(chip->card->dev, "timer %ld\n", snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) & TIMER_VALUE_MASK ); */ @@ -2039,11 +1959,11 @@ snd_azf3328_interrupt(int irq, void *dev_id) spin_lock(&chip->reg_lock); snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); spin_unlock(&chip->reg_lock); - snd_azf3328_dbgcodec("azt3328: timer IRQ\n"); + dev_dbg(chip->card->dev, "timer IRQ\n"); } if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) - snd_azf3328_pcm_interrupt(chip->codecs, status); + snd_azf3328_pcm_interrupt(chip, chip->codecs, status); if (status & IRQ_GAMEPORT) snd_azf3328_gameport_interrupt(chip); @@ -2055,7 +1975,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) /* hmm, do we have to ack the IRQ here somehow? * If so, then I don't know how yet... */ - snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n"); + dev_dbg(chip->card->dev, "MPU401 IRQ\n"); } return IRQ_HANDLED; } @@ -2133,7 +2053,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; - snd_azf3328_dbgcallenter(); codec->substream = substream; /* same parameters for all our codecs - at least we think so... */ @@ -2142,7 +2061,6 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream, snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &snd_azf3328_hw_constraints_rates); runtime->private_data = codec; - snd_azf3328_dbgcallleave(); return 0; } @@ -2171,9 +2089,7 @@ snd_azf3328_pcm_close(struct snd_pcm_substream *substream struct snd_azf3328_codec_data *codec = substream->runtime->private_data; - snd_azf3328_dbgcallenter(); codec->substream = NULL; - snd_azf3328_dbgcallleave(); return 0; } @@ -2212,7 +2128,7 @@ static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { .pointer = snd_azf3328_pcm_pointer }; -static int __devinit +static int snd_azf3328_pcm(struct snd_azf3328 *chip) { enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ @@ -2220,8 +2136,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ struct snd_pcm *pcm; int err; - snd_azf3328_dbgcallenter(); - err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD, 1, 1, &pcm); if (err < 0) @@ -2258,7 +2172,6 @@ enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ snd_dma_pci_data(chip->pci), 64*1024, 64*1024); - snd_azf3328_dbgcallleave(); return 0; } @@ -2281,7 +2194,6 @@ snd_azf3328_timer_start(struct snd_timer *timer) unsigned long flags; unsigned int delay; - snd_azf3328_dbgcallenter(); chip = snd_timer_chip(timer); delay = ((timer->sticks * seqtimer_scaling) - 1) & TIMER_VALUE_MASK; if (delay < 49) { @@ -2289,15 +2201,14 @@ snd_azf3328_timer_start(struct snd_timer *timer) * this timing tweak * (we need to do it to avoid a lockup, though) */ - snd_azf3328_dbgtimer("delay was too low (%d)!\n", delay); + dev_dbg(chip->card->dev, "delay was too low (%d)!\n", delay); delay = 49; /* minimum time is 49 ticks */ } - snd_azf3328_dbgtimer("setting timer countdown value %d\n", delay); + dev_dbg(chip->card->dev, "setting timer countdown value %d\n", delay); delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; spin_lock_irqsave(&chip->reg_lock, flags); snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_azf3328_dbgcallleave(); return 0; } @@ -2307,7 +2218,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer) struct snd_azf3328 *chip; unsigned long flags; - snd_azf3328_dbgcallenter(); chip = snd_timer_chip(timer); spin_lock_irqsave(&chip->reg_lock, flags); /* disable timer countdown and interrupt */ @@ -2319,7 +2229,6 @@ snd_azf3328_timer_stop(struct snd_timer *timer) the hardware/ALSA interrupt activity. */ snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x04); spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_azf3328_dbgcallleave(); return 0; } @@ -2328,10 +2237,8 @@ static int snd_azf3328_timer_precise_resolution(struct snd_timer *timer, unsigned long *num, unsigned long *den) { - snd_azf3328_dbgcallenter(); *num = 1; *den = 1024000 / seqtimer_scaling; - snd_azf3328_dbgcallleave(); return 0; } @@ -2344,14 +2251,13 @@ static struct snd_timer_hardware snd_azf3328_timer_hw = { .precise_resolution = snd_azf3328_timer_precise_resolution, }; -static int __devinit +static int snd_azf3328_timer(struct snd_azf3328 *chip, int device) { struct snd_timer *timer = NULL; struct snd_timer_id tid; int err; - snd_azf3328_dbgcallenter(); tid.dev_class = SNDRV_TIMER_CLASS_CARD; tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; tid.card = chip->card->number; @@ -2376,7 +2282,6 @@ snd_azf3328_timer(struct snd_azf3328 *chip, int device) err = 0; out: - snd_azf3328_dbgcallleave(); return err; } @@ -2438,34 +2343,34 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit) static inline void snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) { -#if DEBUG_MISC u16 tmp; - snd_azf3328_dbgmisc( + dev_dbg(chip->card->dev, "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", chip->ctrl_io, chip->game_io, chip->mpu_io, - chip->opl3_io, chip->mixer_io, chip->irq - ); + chip->opl3_io, chip->mixer_io, chip->irq); - snd_azf3328_dbgmisc("game %02x %02x %02x %02x %02x %02x\n", + dev_dbg(chip->card->dev, + "game %02x %02x %02x %02x %02x %02x\n", snd_azf3328_game_inb(chip, 0), snd_azf3328_game_inb(chip, 1), snd_azf3328_game_inb(chip, 2), snd_azf3328_game_inb(chip, 3), snd_azf3328_game_inb(chip, 4), - snd_azf3328_game_inb(chip, 5) - ); + snd_azf3328_game_inb(chip, 5)); for (tmp = 0; tmp < 0x07; tmp += 1) - snd_azf3328_dbgmisc("mpu_io 0x%04x\n", inb(chip->mpu_io + tmp)); + dev_dbg(chip->card->dev, + "mpu_io 0x%04x\n", inb(chip->mpu_io + tmp)); for (tmp = 0; tmp <= 0x07; tmp += 1) - snd_azf3328_dbgmisc("0x%02x: game200 0x%04x, game208 0x%04x\n", + dev_dbg(chip->card->dev, + "0x%02x: game200 0x%04x, game208 0x%04x\n", tmp, inb(0x200 + tmp), inb(0x208 + tmp)); for (tmp = 0; tmp <= 0x01; tmp += 1) - snd_azf3328_dbgmisc( + dev_dbg(chip->card->dev, "0x%02x: mpu300 0x%04x, mpu310 0x%04x, mpu320 0x%04x, " "mpu330 0x%04x opl388 0x%04x opl38c 0x%04x\n", tmp, @@ -2474,22 +2379,20 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) inb(0x320 + tmp), inb(0x330 + tmp), inb(0x388 + tmp), - inb(0x38c + tmp) - ); + inb(0x38c + tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2) - snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n", - tmp, snd_azf3328_ctrl_inw(chip, tmp) - ); + dev_dbg(chip->card->dev, + "ctrl 0x%02x: 0x%04x\n", + tmp, snd_azf3328_ctrl_inw(chip, tmp)); for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) - snd_azf3328_dbgmisc("mixer 0x%02x: 0x%04x\n", - tmp, snd_azf3328_mixer_inw(chip, tmp) - ); -#endif /* DEBUG_MISC */ + dev_dbg(chip->card->dev, + "mixer 0x%02x: 0x%04x\n", + tmp, snd_azf3328_mixer_inw(chip, tmp)); } -static int __devinit +static int snd_azf3328_create(struct snd_card *card, struct pci_dev *pci, unsigned long device_type, @@ -2523,8 +2426,8 @@ snd_azf3328_create(struct snd_card *card, /* check if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) { - snd_printk(KERN_ERR "architecture does not support " - "24bit PCI busmaster DMA\n" + dev_err(card->dev, + "architecture does not support 24bit PCI busmaster DMA\n" ); err = -ENXIO; goto out_err; @@ -2560,7 +2463,7 @@ snd_azf3328_create(struct snd_card *card, if (request_irq(pci->irq, snd_azf3328_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto out_err; } @@ -2599,8 +2502,6 @@ snd_azf3328_create(struct snd_card *card, spin_unlock_irq(codec->lock); } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; err = 0; @@ -2615,7 +2516,7 @@ out: return err; } -static int __devinit +static int snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2624,7 +2525,6 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) struct snd_opl3 *opl3; int err; - snd_azf3328_dbgcallenter(); if (dev >= SNDRV_CARDS) { err = -ENODEV; goto out; @@ -2635,7 +2535,8 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) goto out; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) goto out; @@ -2657,7 +2558,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) -1, &chip->rmidi ); if (err < 0) { - snd_printk(KERN_ERR "azf3328: no MPU-401 device at 0x%lx?\n", + dev_err(card->dev, "no MPU-401 device at 0x%lx?\n", chip->mpu_io ); goto out_err; @@ -2673,7 +2574,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) if (snd_opl3_create(card, chip->opl3_io, chip->opl3_io+2, OPL3_HW_AUTO, 1, &opl3) < 0) { - snd_printk(KERN_ERR "azf3328: no OPL3 device at 0x%lx-0x%lx?\n", + dev_err(card->dev, "no OPL3 device at 0x%lx-0x%lx?\n", chip->opl3_io, chip->opl3_io+2 ); } else { @@ -2695,12 +2596,15 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) goto out_err; #ifdef MODULE - printk(KERN_INFO -"azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" -"azt3328: Hardware was completely undocumented, unfortunately.\n" -"azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" -"azt3328: User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n", - 1024000 / seqtimer_scaling, seqtimer_scaling); + dev_info(card->dev, + "Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n"); + dev_info(card->dev, + "Hardware was completely undocumented, unfortunately.\n"); + dev_info(card->dev, + "Feel free to contact andi AT lisas.de for bug reports etc.!\n"); + dev_info(card->dev, + "User-scalable sequencer timer set to %dHz (1024000Hz / %d).\n", + 1024000 / seqtimer_scaling, seqtimer_scaling); #endif snd_azf3328_gameport(chip, dev); @@ -2712,32 +2616,29 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) goto out; out_err: - snd_printk(KERN_ERR "azf3328: something failed, exiting\n"); + dev_err(card->dev, "something failed, exiting\n"); snd_card_free(card); out: - snd_azf3328_dbgcallleave(); return err; } -static void __devexit +static void snd_azf3328_remove(struct pci_dev *pci) { - snd_azf3328_dbgcallenter(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); - snd_azf3328_dbgcallleave(); } #ifdef CONFIG_PM_SLEEP static inline void -snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs) +snd_azf3328_suspend_regs(const struct snd_azf3328 *chip, + unsigned long io_addr, unsigned count, u32 *saved_regs) { unsigned reg; for (reg = 0; reg < count; ++reg) { *saved_regs = inl(io_addr); - snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n", + dev_dbg(chip->card->dev, "suspend: io 0x%04lx: 0x%08x\n", io_addr, *saved_regs); ++saved_regs; io_addr += sizeof(*saved_regs); @@ -2745,7 +2646,8 @@ snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs) } static inline void -snd_azf3328_resume_regs(const u32 *saved_regs, +snd_azf3328_resume_regs(const struct snd_azf3328 *chip, + const u32 *saved_regs, unsigned long io_addr, unsigned count ) @@ -2754,7 +2656,8 @@ snd_azf3328_resume_regs(const u32 *saved_regs, for (reg = 0; reg < count; ++reg) { outl(*saved_regs, io_addr); - snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n", + dev_dbg(chip->card->dev, + "resume: io 0x%04lx: 0x%08x --> 0x%08x\n", io_addr, *saved_regs, inl(io_addr)); ++saved_regs; io_addr += sizeof(*saved_regs); @@ -2767,7 +2670,7 @@ snd_azf3328_suspend_ac97(struct snd_azf3328 *chip) #ifdef AZF_USE_AC97_LAYER snd_ac97_suspend(chip->ac97); #else - snd_azf3328_suspend_regs(chip->mixer_io, + snd_azf3328_suspend_regs(chip, chip->mixer_io, ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer); /* make sure to disable master volume etc. to prevent looping sound */ @@ -2782,7 +2685,7 @@ snd_azf3328_resume_ac97(const struct snd_azf3328 *chip) #ifdef AZF_USE_AC97_LAYER snd_ac97_resume(chip->ac97); #else - snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, + snd_azf3328_resume_regs(chip, chip->saved_regs_mixer, chip->mixer_io, ARRAY_SIZE(chip->saved_regs_mixer)); /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02) @@ -2809,18 +2712,18 @@ snd_azf3328_suspend(struct device *dev) snd_azf3328_suspend_ac97(chip); - snd_azf3328_suspend_regs(chip->ctrl_io, + snd_azf3328_suspend_regs(chip, chip->ctrl_io, ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); /* manually store the one currently relevant write-only reg, too */ saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl; saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; - snd_azf3328_suspend_regs(chip->game_io, + snd_azf3328_suspend_regs(chip, chip->game_io, ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game); - snd_azf3328_suspend_regs(chip->mpu_io, + snd_azf3328_suspend_regs(chip, chip->mpu_io, ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); - snd_azf3328_suspend_regs(chip->opl3_io, + snd_azf3328_suspend_regs(chip, chip->opl3_io, ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); pci_disable_device(pci); @@ -2839,23 +2742,22 @@ snd_azf3328_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "azt3328: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); - snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io, + snd_azf3328_resume_regs(chip, chip->saved_regs_game, chip->game_io, ARRAY_SIZE(chip->saved_regs_game)); - snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io, + snd_azf3328_resume_regs(chip, chip->saved_regs_mpu, chip->mpu_io, ARRAY_SIZE(chip->saved_regs_mpu)); - snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, + snd_azf3328_resume_regs(chip, chip->saved_regs_opl3, chip->opl3_io, ARRAY_SIZE(chip->saved_regs_opl3)); snd_azf3328_resume_ac97(chip); - snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io, + snd_azf3328_resume_regs(chip, chip->saved_regs_ctrl, chip->ctrl_io, ARRAY_SIZE(chip->saved_regs_ctrl)); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2872,7 +2774,7 @@ static struct pci_driver azf3328_driver = { .name = KBUILD_MODNAME, .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, - .remove = __devexit_p(snd_azf3328_remove), + .remove = snd_azf3328_remove, .driver = { .pm = SND_AZF3328_PM_OPS, }, diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index b6a95eeca09..70951fd9b35 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c @@ -164,7 +164,7 @@ struct snd_bt87x_board { unsigned no_digital:1; /* No digital input */ }; -static __devinitdata struct snd_bt87x_board snd_bt87x_boards[] = { +static struct snd_bt87x_board snd_bt87x_boards[] = { [SND_BT87X_BOARD_UNKNOWN] = { .dig_rate = 32000, /* just a guess */ }, @@ -293,17 +293,23 @@ static void snd_bt87x_pci_error(struct snd_bt87x *chip, unsigned int status) PCI_STATUS_SIG_SYSTEM_ERROR | PCI_STATUS_DETECTED_PARITY; pci_write_config_word(chip->pci, PCI_STATUS, pci_status); if (pci_status != PCI_STATUS_DETECTED_PARITY) - snd_printk(KERN_ERR "Aieee - PCI error! status %#08x, PCI status %#04x\n", + dev_err(chip->card->dev, + "Aieee - PCI error! status %#08x, PCI status %#04x\n", status & ERROR_INTERRUPTS, pci_status); else { - snd_printk(KERN_ERR "Aieee - PCI parity error detected!\n"); + dev_err(chip->card->dev, + "Aieee - PCI parity error detected!\n"); /* error 'handling' similar to aic7xxx_pci.c: */ chip->pci_parity_errors++; if (chip->pci_parity_errors > 20) { - snd_printk(KERN_ERR "Too many PCI parity errors observed.\n"); - snd_printk(KERN_ERR "Some device on this bus is generating bad parity.\n"); - snd_printk(KERN_ERR "This is an error *observed by*, not *generated by*, this card.\n"); - snd_printk(KERN_ERR "PCI parity error checking has been disabled.\n"); + dev_err(chip->card->dev, + "Too many PCI parity errors observed.\n"); + dev_err(chip->card->dev, + "Some device on this bus is generating bad parity.\n"); + dev_err(chip->card->dev, + "This is an error *observed by*, not *generated by*, this card.\n"); + dev_err(chip->card->dev, + "PCI parity error checking has been disabled.\n"); chip->interrupt_mask &= ~(INT_PPERR | INT_RIPERR); snd_bt87x_writel(chip, REG_INT_MASK, chip->interrupt_mask); } @@ -323,9 +329,11 @@ static irqreturn_t snd_bt87x_interrupt(int irq, void *dev_id) if (irq_status & ERROR_INTERRUPTS) { if (irq_status & (INT_FBUS | INT_FTRGT)) - snd_printk(KERN_WARNING "FIFO overrun, status %#08x\n", status); + dev_warn(chip->card->dev, + "FIFO overrun, status %#08x\n", status); if (irq_status & INT_OCERR) - snd_printk(KERN_ERR "internal RISC error, status %#08x\n", status); + dev_err(chip->card->dev, + "internal RISC error, status %#08x\n", status); if (irq_status & (INT_PPERR | INT_RIPERR | INT_PABORT)) snd_bt87x_pci_error(chip, irq_status); } @@ -435,7 +443,7 @@ static int snd_bt87x_pcm_open(struct snd_pcm_substream *substream) _error: clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return err; } @@ -450,7 +458,7 @@ static int snd_bt87x_close(struct snd_pcm_substream *substream) chip->substream = NULL; clear_bit(0, &chip->opened); - smp_mb__after_clear_bit(); + smp_mb__after_atomic(); return 0; } @@ -696,7 +704,7 @@ static int snd_bt87x_dev_free(struct snd_device *device) return snd_bt87x_free(chip); } -static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) +static int snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *name) { int err; struct snd_pcm *pcm; @@ -714,9 +722,9 @@ static int __devinit snd_bt87x_pcm(struct snd_bt87x *chip, int device, char *nam ALIGN(255 * 4092, 1024)); } -static int __devinit snd_bt87x_create(struct snd_card *card, - struct pci_dev *pci, - struct snd_bt87x **rchip) +static int snd_bt87x_create(struct snd_card *card, + struct pci_dev *pci, + struct snd_bt87x **rchip) { struct snd_bt87x *chip; int err; @@ -747,7 +755,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card, } chip->mmio = pci_ioremap_bar(pci, 0); if (!chip->mmio) { - snd_printk(KERN_ERR "cannot remap io memory\n"); + dev_err(card->dev, "cannot remap io memory\n"); err = -ENOMEM; goto fail; } @@ -762,7 +770,7 @@ static int __devinit snd_bt87x_create(struct snd_card *card, err = request_irq(pci->irq, snd_bt87x_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip); if (err < 0) { - snd_printk(KERN_ERR "cannot grab irq %d\n", pci->irq); + dev_err(card->dev, "cannot grab irq %d\n", pci->irq); goto fail; } chip->irq = pci->irq; @@ -773,7 +781,6 @@ static int __devinit snd_bt87x_create(struct snd_card *card, if (err < 0) goto fail; - snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; @@ -822,7 +829,7 @@ MODULE_DEVICE_TABLE(pci, snd_bt87x_ids); * (DVB cards use the audio function to transfer MPEG data) */ static struct { unsigned short subvendor, subdevice; -} blacklist[] __devinitdata = { +} blacklist[] = { {0x0071, 0x0101}, /* Nebula Electronics DigiTV */ {0x11bd, 0x001c}, /* Pinnacle PCTV Sat */ {0x11bd, 0x0026}, /* Pinnacle PCTV SAT CI */ @@ -836,8 +843,10 @@ static struct { {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */ }; +static struct pci_driver driver; + /* return the id of the card, or a negative value if it's blacklisted */ -static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) +static int snd_bt87x_detect_card(struct pci_dev *pci) { int i; const struct pci_device_id *supported; @@ -849,21 +858,22 @@ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) for (i = 0; i < ARRAY_SIZE(blacklist); ++i) if (blacklist[i].subvendor == pci->subsystem_vendor && blacklist[i].subdevice == pci->subsystem_device) { - snd_printdd(KERN_INFO "card %#04x-%#04x:%#04x has no audio\n", + dev_dbg(&pci->dev, + "card %#04x-%#04x:%#04x has no audio\n", pci->device, pci->subsystem_vendor, pci->subsystem_device); return -EBUSY; } - snd_printk(KERN_INFO "unknown card %#04x-%#04x:%#04x\n", + dev_info(&pci->dev, "unknown card %#04x-%#04x:%#04x\n", pci->device, pci->subsystem_vendor, pci->subsystem_device); - snd_printk(KERN_DEBUG "please mail id, board name, and, " + dev_info(&pci->dev, "please mail id, board name, and, " "if it works, the correct digital_rate option to " "<alsa-devel@alsa-project.org>\n"); return SND_BT87X_BOARD_UNKNOWN; } -static int __devinit snd_bt87x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_bt87x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -886,7 +896,8 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -923,7 +934,7 @@ static int __devinit snd_bt87x_probe(struct pci_dev *pci, if (err < 0) goto _error; } - snd_printk(KERN_INFO "bt87x%d: Using board %d, %sanalog, %sdigital " + dev_info(card->dev, "bt87x%d: Using board %d, %sanalog, %sdigital " "(rate %d Hz)\n", dev, boardid, chip->board.no_analog ? "no " : "", chip->board.no_digital ? "no " : "", chip->board.dig_rate); @@ -948,10 +959,9 @@ _error: return err; } -static void __devexit snd_bt87x_remove(struct pci_dev *pci) +static void snd_bt87x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* default entries for all Bt87x cards - it's not exported */ @@ -962,11 +972,24 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { { } }; -static struct pci_driver bt87x_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, - .remove = __devexit_p(snd_bt87x_remove), + .remove = snd_bt87x_remove, }; -module_pci_driver(bt87x_driver); +static int __init alsa_card_bt87x_init(void) +{ + if (load_all) + driver.id_table = snd_bt87x_default_ids; + return pci_register_driver(&driver); +} + +static void __exit alsa_card_bt87x_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_bt87x_init) +module_exit(alsa_card_bt87x_exit) diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 65c55910566..f94cc6e97d4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c @@ -417,13 +417,13 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, int status; int retry; if ((reg > 0x7f) || (value > 0x1ff)) { - snd_printk(KERN_ERR "i2c_write: invalid values.\n"); + dev_err(emu->card->dev, "i2c_write: invalid values.\n"); return -EINVAL; } tmp = reg << 25 | value << 16; /* - snd_printk(KERN_DEBUG "I2C-write:reg=0x%x, value=0x%x\n", reg, value); + dev_dbg(emu->card->dev, "I2C-write:reg=0x%x, value=0x%x\n", reg, value); */ /* Not sure what this I2C channel controls. */ /* snd_ca0106_ptr_write(emu, I2C_D0, 0, tmp); */ @@ -442,7 +442,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, /* Wait till the transaction ends */ while (1) { status = snd_ca0106_ptr_read(emu, I2C_A, 0); - /*snd_printk(KERN_DEBUG "I2C:status=0x%x\n", status);*/ + /*dev_dbg(emu->card->dev, "I2C:status=0x%x\n", status);*/ timeout++; if ((status & I2C_A_ADC_START) == 0) break; @@ -456,7 +456,7 @@ int snd_ca0106_i2c_write(struct snd_ca0106 *emu, } if (retry == 10) { - snd_printk(KERN_ERR "Writing to ADC failed!\n"); + dev_err(emu->card->dev, "Writing to ADC failed!\n"); return -EINVAL; } @@ -516,7 +516,8 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) } } -static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, +static int snd_ca0106_channel_dac(struct snd_ca0106 *chip, + struct snd_ca0106_details *details, int channel_id) { switch (channel_id) { @@ -529,7 +530,7 @@ static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, case PCM_UNKNOWN_CHANNEL: return (details->spi_dac & 0x000f) >> (4 * 0); default: - snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", + dev_dbg(chip->card->dev, "ca0106: unknown channel_id %d\n", channel_id); } return 0; @@ -539,7 +540,7 @@ static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, int power) { if (chip->details->spi_dac) { - const int dac = snd_ca0106_channel_dac(chip->details, + const int dac = snd_ca0106_channel_dac(chip, chip->details, channel_id); const int reg = spi_dacd_reg[dac]; const int bit = spi_dacd_bit[dac]; @@ -583,7 +584,7 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr channel->use = 1; /* - printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n", + dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", channel_id, chip, channel); */ //channel->interrupt = snd_ca0106_pcm_channel_interrupt; @@ -660,7 +661,8 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) { - snd_printk(KERN_ERR "open_capture_channel: failed epcm alloc\n"); + dev_err(chip->card->dev, + "open_capture_channel: failed epcm alloc\n"); return -ENOMEM; } epcm->emu = chip; @@ -677,7 +679,7 @@ static int snd_ca0106_pcm_open_capture_channel(struct snd_pcm_substream *substre channel->use = 1; /* - printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n", + dev_dbg(chip->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", channel_id, chip, channel); */ //channel->interrupt = snd_ca0106_pcm_channel_interrupt; @@ -771,7 +773,7 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream) int i; #if 0 /* debug */ - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "prepare:channel_number=%d, rate=%d, format=0x%x, " "channels=%d, buffer_size=%ld, period_size=%ld, " "periods=%u, frames_to_bytes=%d\n", @@ -779,9 +781,11 @@ static int snd_ca0106_pcm_prepare_playback(struct snd_pcm_substream *substream) runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, table_base=%p\n", runtime->dma_addr, runtime->dma_area, table_base); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); #endif /* debug */ /* Rate can be set per channel. */ @@ -876,7 +880,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) u32 reg71; #if 0 /* debug */ - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "prepare:channel_number=%d, rate=%d, format=0x%x, " "channels=%d, buffer_size=%ld, period_size=%ld, " "periods=%u, frames_to_bytes=%d\n", @@ -884,9 +888,11 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, table_base=%p\n", runtime->dma_addr, runtime->dma_area, table_base); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", emu->buffer.addr, emu->buffer.area, emu->buffer.bytes); #endif /* debug */ /* reg71 controls ADC rate. */ @@ -934,7 +940,7 @@ static int snd_ca0106_pcm_prepare_capture(struct snd_pcm_substream *substream) /* - printk(KERN_DEBUG + dev_dbg(emu->card->dev, "prepare:channel_number=%d, rate=%d, format=0x%x, channels=%d, " "buffer_size=%ld, period_size=%ld, frames_to_bytes=%d\n", channel, runtime->rate, runtime->format, runtime->channels, @@ -982,13 +988,13 @@ static int snd_ca0106_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = epcm->channel_id; - /* snd_printk(KERN_DEBUG "channel=%d\n", channel); */ + /* dev_dbg(emu->card->dev, "channel=%d\n", channel); */ epcm->running = running; basic |= (0x1 << channel); extended |= (0x10 << channel); snd_pcm_trigger_done(s, substream); } - /* snd_printk(KERN_DEBUG "basic=0x%x, extended=0x%x\n",basic, extended); */ + /* dev_dbg(emu->card->dev, "basic=0x%x, extended=0x%x\n",basic, extended); */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -1070,7 +1076,7 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) return ptr; prev_ptr = ptr; } while (--timeout); - snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); + dev_warn(emu->card->dev, "ca0106: unstable DMA pointer!\n"); return 0; } @@ -1093,7 +1099,7 @@ snd_ca0106_pcm_pointer_capture(struct snd_pcm_substream *substream) if (ptr >= runtime->buffer_size) ptr -= runtime->buffer_size; /* - printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " + dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, @@ -1284,9 +1290,9 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) stat76 = snd_ca0106_ptr_read(chip, EXTENDED_INT, 0); /* - snd_printk(KERN_DEBUG "interrupt status = 0x%08x, stat76=0x%08x\n", + dev_dbg(emu->card->dev, "interrupt status = 0x%08x, stat76=0x%08x\n", status, stat76); - snd_printk(KERN_DEBUG "ptr=0x%08x\n", + dev_dbg(emu->card->dev, "ptr=0x%08x\n", snd_ca0106_ptr_read(chip, PLAYBACK_POINTER, 0)); */ mask = 0x11; /* 0x1 for one half, 0x10 for the other half period. */ @@ -1296,11 +1302,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) /* FIXME: Select the correct substream for period elapsed */ if(pchannel->use) { snd_pcm_period_elapsed(pchannel->epcm->substream); - //printk(KERN_INFO "interrupt [%d] used\n", i); + /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */ } } - //printk(KERN_INFO "channel=%p\n",pchannel); - //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); + /* + dev_dbg(emu->card->dev, "channel=%p\n", pchannel); + dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); + */ mask <<= 1; } mask = 0x110000; /* 0x1 for one half, 0x10 for the other half period. */ @@ -1310,11 +1318,13 @@ static irqreturn_t snd_ca0106_interrupt(int irq, void *dev_id) /* FIXME: Select the correct substream for period elapsed */ if(pchannel->use) { snd_pcm_period_elapsed(pchannel->epcm->substream); - //printk(KERN_INFO "interrupt [%d] used\n", i); + /* dev_dbg(emu->card->dev, "interrupt [%d] used\n", i); */ } } - //printk(KERN_INFO "channel=%p\n",pchannel); - //printk(KERN_INFO "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); + /* + dev_dbg(emu->card->dev, "channel=%p\n", pchannel); + dev_dbg(emu->card->dev, "interrupt stat76[%d] = %08x, use=%d, channel=%d\n", i, stat76, pchannel->use, pchannel->number); + */ mask <<= 1; } @@ -1352,7 +1362,7 @@ static const struct snd_pcm_chmap_elem side_map[] = { { } }; -static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) +static int snd_ca0106_pcm(struct snd_ca0106 *emu, int device) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1603,7 +1613,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) int size, n; size = ARRAY_SIZE(i2c_adc_init); - /* snd_printk(KERN_DEBUG "I2C:array size=0x%x\n", size); */ + /* dev_dbg(emu->card->dev, "I2C:array size=0x%x\n", size); */ for (n = 0; n < size; n++) snd_ca0106_i2c_write(chip, i2c_adc_init[n][0], i2c_adc_init[n][1]); @@ -1650,7 +1660,7 @@ static void ca0106_stop_chip(struct snd_ca0106 *chip) */ } -static int __devinit snd_ca0106_create(int dev, struct snd_card *card, +static int snd_ca0106_create(int dev, struct snd_card *card, struct pci_dev *pci, struct snd_ca0106 **rchip) { @@ -1668,7 +1678,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, return err; if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - printk(KERN_ERR "error to set 32bit mask DMA\n"); + dev_err(card->dev, "error to set 32bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1689,14 +1699,14 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, chip->res_port = request_region(chip->port, 0x20, "snd_ca0106"); if (!chip->res_port) { snd_ca0106_free(chip); - printk(KERN_ERR "cannot allocate the port\n"); + dev_err(card->dev, "cannot allocate the port\n"); return -EBUSY; } if (request_irq(pci->irq, snd_ca0106_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { snd_ca0106_free(chip); - printk(KERN_ERR "cannot grab irq\n"); + dev_err(card->dev, "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; @@ -1712,7 +1722,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, /* read serial */ pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); - printk(KERN_INFO "snd-ca0106: Model %04x Rev %08x Serial %08x\n", + dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model, pci->revision, chip->serial); strcpy(card->driver, "CA0106"); strcpy(card->shortname, "CA0106"); @@ -1726,7 +1736,7 @@ static int __devinit snd_ca0106_create(int dev, struct snd_card *card, } chip->details = c; if (subsystem[dev]) { - printk(KERN_INFO "snd-ca0106: Sound card name=%s, " + dev_info(card->dev, "Sound card name=%s, " "subsystem=0x%x. Forced to subsystem=0x%x\n", c->name, chip->serial, subsystem[dev]); } @@ -1777,7 +1787,7 @@ static int ca0106_dev_id_port(void *dev_id) return ((struct snd_ca0106 *)dev_id)->port; } -static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) +static int snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int channel) { struct snd_ca_midi *midi; char *name; @@ -1828,7 +1838,7 @@ static int __devinit snd_ca0106_midi(struct snd_ca0106 *chip, unsigned int chann } -static int __devinit snd_ca0106_probe(struct pci_dev *pci, +static int snd_ca0106_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -1843,7 +1853,8 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -1868,18 +1879,16 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, if (err < 0) goto error; - snd_printdd("ca0106: probe for MIDI channel A ..."); + dev_dbg(card->dev, "probe for MIDI channel A ..."); err = snd_ca0106_midi(chip, CA0106_MIDI_CHAN_A); if (err < 0) goto error; - snd_printdd(" done.\n"); + dev_dbg(card->dev, " done.\n"); #ifdef CONFIG_PROC_FS snd_ca0106_proc_init(chip); #endif - snd_card_set_dev(card, &pci->dev); - err = snd_card_register(card); if (err < 0) goto error; @@ -1893,10 +1902,9 @@ static int __devinit snd_ca0106_probe(struct pci_dev *pci, return err; } -static void __devexit snd_ca0106_remove(struct pci_dev *pci) +static void snd_ca0106_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP @@ -1971,7 +1979,7 @@ static struct pci_driver ca0106_driver = { .name = KBUILD_MODNAME, .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, - .remove = __devexit_p(snd_ca0106_remove), + .remove = snd_ca0106_remove, .driver = { .pm = SND_CA0106_PM_OPS, }, diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index 68eacf7002d..27de0de9001 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -325,7 +325,7 @@ static int snd_ca0106_capture_mic_line_in_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = +static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Shared Mic/Line in Capture Switch", @@ -334,7 +334,7 @@ static struct snd_kcontrol_new snd_ca0106_capture_mic_line_in __devinitdata = .put = snd_ca0106_capture_mic_line_in_put }; -static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out __devinitdata = +static struct snd_kcontrol_new snd_ca0106_capture_line_in_side_out = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Shared Line in/Side out Capture Switch", @@ -588,7 +588,7 @@ static int spi_mute_put(struct snd_kcontrol *kcontrol, .private_value = ((chid) << 8) | (reg) \ } -static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_ca0106_volume_ctls[] = { CA_VOLUME("Analog Front Playback Volume", CONTROL_FRONT_CHANNEL, PLAYBACK_VOLUME2), CA_VOLUME("Analog Rear Playback Volume", @@ -669,7 +669,7 @@ static struct snd_kcontrol_new snd_ca0106_volume_ctls[] __devinitdata = { .private_value = chid \ } -static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_ca0106_volume_i2c_adc_ctls[] = { I2C_VOLUME("Phone Capture Volume", 0), I2C_VOLUME("Mic Capture Volume", 1), I2C_VOLUME("Line in Capture Volume", 2), @@ -691,7 +691,7 @@ static const int spi_dmute_bit[] = { SPI_DMUTE4_BIT, }; -static struct snd_kcontrol_new __devinit +static struct snd_kcontrol_new snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, int channel_id) { @@ -735,7 +735,7 @@ snd_ca0106_volume_spi_dac_ctl(struct snd_ca0106_details *details, return spi_switch; } -static int __devinit remove_ctl(struct snd_card *card, const char *name) +static int remove_ctl(struct snd_card *card, const char *name) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); @@ -744,7 +744,7 @@ static int __devinit remove_ctl(struct snd_card *card, const char *name) return snd_ctl_remove_id(card, &id); } -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -754,7 +754,7 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, const char return snd_ctl_find_id(card, &sid); } -static int __devinit rename_ctl(struct snd_card *card, const char *src, const char *dst) +static int rename_ctl(struct snd_card *card, const char *src, const char *dst) { struct snd_kcontrol *kctl = ctl_find(card, src); if (kctl) { @@ -774,10 +774,10 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch } \ } while (0) -static __devinitdata +static DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { "Analog Front Playback Volume", "Analog Rear Playback Volume", "Analog Center/LFE Playback Volume", @@ -790,7 +790,7 @@ static char *slave_vols[] __devinitdata = { NULL }; -static char *slave_sws[] __devinitdata = { +static char *slave_sws[] = { "Analog Front Playback Switch", "Analog Rear Playback Switch", "Analog Center/LFE Playback Switch", @@ -799,7 +799,7 @@ static char *slave_sws[] __devinitdata = { NULL }; -static void __devinit add_slaves(struct snd_card *card, +static void add_slaves(struct snd_card *card, struct snd_kcontrol *master, char **list) { for (; *list; list++) { @@ -809,7 +809,7 @@ static void __devinit add_slaves(struct snd_card *card, } } -int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) +int snd_ca0106_mixer(struct snd_ca0106 *emu) { int err; struct snd_card *card = emu->card; diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c694464b116..4f9c2821bb3 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -424,7 +424,7 @@ static void snd_ca0106_proc_i2c_write(struct snd_info_entry *entry, } } -int __devinit snd_ca0106_proc_init(struct snd_ca0106 * emu) +int snd_ca0106_proc_init(struct snd_ca0106 *emu) { struct snd_info_entry *entry; diff --git a/sound/pci/ca0106/ca_midi.c b/sound/pci/ca0106/ca_midi.c index c7885117da3..b91c7f6d19f 100644 --- a/sound/pci/ca0106/ca_midi.c +++ b/sound/pci/ca0106/ca_midi.c @@ -46,7 +46,7 @@ static void ca_midi_clear_rx(struct snd_ca_midi *midi) ca_midi_read_data(midi); #ifdef CONFIG_SND_DEBUG if (timeout <= 0) - snd_printk(KERN_ERR "ca_midi_clear_rx: timeout (status = 0x%x)\n", + pr_err("ca_midi_clear_rx: timeout (status = 0x%x)\n", ca_midi_read_stat(midi)); #endif } @@ -113,7 +113,7 @@ static void ca_midi_cmd(struct snd_ca_midi *midi, unsigned char cmd, int ack) } spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) - snd_printk(KERN_ERR "ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n", + pr_err("ca_midi_cmd: 0x%x failed at 0x%x (status = 0x%x, data = 0x%x)!!!\n", cmd, midi->get_dev_id_port(midi->dev_id), ca_midi_read_stat(midi), @@ -286,7 +286,7 @@ static void ca_rmidi_free(struct snd_rawmidi *rmidi) ca_midi_free(rmidi->private_data); } -int __devinit ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) +int ca_midi_init(void *dev_id, struct snd_ca_midi *midi, int device, char *name) { struct snd_rawmidi *rmidi; int err; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 22122ff26e3..12c318e175f 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -796,7 +796,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, if (runtime->channels > 1) rec->fmt |= 0x01; if (rec->is_dac && set_dac_channels(cm, rec, runtime->channels) < 0) { - snd_printd("cannot set dac channels\n"); + dev_dbg(cm->card->dev, "cannot set dac channels\n"); return -EINVAL; } @@ -827,7 +827,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, else cm->ctrl |= val; snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); - //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); + /* dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl); */ /* set sample rate */ freq = 0; @@ -850,7 +850,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, val |= (freq << CM_ASFC_SHIFT) & CM_ASFC_MASK; } snd_cmipci_write(cm, CM_REG_FUNCTRL1, val); - //snd_printd("cmipci: functrl1 = %08x\n", val); + dev_dbg(cm->card->dev, "functrl1 = %08x\n", val); /* set format */ val = snd_cmipci_read(cm, CM_REG_CHFORMAT); @@ -866,7 +866,7 @@ static int snd_cmipci_pcm_prepare(struct cmipci *cm, struct cmipci_pcm *rec, val |= freq_ext << (rec->ch * 2); } snd_cmipci_write(cm, CM_REG_CHFORMAT, val); - //snd_printd("cmipci: chformat = %08x\n", val); + dev_dbg(cm->card->dev, "chformat = %08x\n", val); if (!rec->is_dac && cm->chip_version) { if (runtime->rate > 44100) @@ -904,7 +904,7 @@ static int snd_cmipci_pcm_trigger(struct cmipci *cm, struct cmipci_pcm *rec, cm->ctrl |= chen; /* enable channel */ snd_cmipci_write(cm, CM_REG_FUNCTRL0, cm->ctrl); - //snd_printd("cmipci: functrl0 = %08x\n", cm->ctrl); + dev_dbg(cm->card->dev, "functrl0 = %08x\n", cm->ctrl); break; case SNDRV_PCM_TRIGGER_STOP: rec->running = 0; @@ -952,7 +952,7 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci if (rem < rec->dma_size) goto ok; } - printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem); + dev_err(cm->card->dev, "invalid PCM pointer: %#x\n", rem); return SNDRV_PCM_POS_XRUN; ok: ptr = (rec->dma_size - (rem + 1)) >> rec->shift; @@ -1045,7 +1045,7 @@ static int snd_cmipci_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_cmipci_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1072,7 +1072,7 @@ static int snd_cmipci_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_cmipci_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1119,7 +1119,7 @@ static int snd_cmipci_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_cmipci_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_cmipci_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1897,7 +1897,7 @@ static struct snd_pcm_ops snd_cmipci_capture_spdif_ops = { /* */ -static int __devinit snd_cmipci_pcm_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -1920,7 +1920,7 @@ static int __devinit snd_cmipci_pcm_new(struct cmipci *cm, int device) return 0; } -static int __devinit snd_cmipci_pcm2_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm2_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -1942,7 +1942,7 @@ static int __devinit snd_cmipci_pcm2_new(struct cmipci *cm, int device) return 0; } -static int __devinit snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) +static int snd_cmipci_pcm_spdif_new(struct cmipci *cm, int device) { struct snd_pcm *pcm; int err; @@ -2290,7 +2290,7 @@ static int snd_cmipci_put_native_mixer_sensitive(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_mixers[] = { CMIPCI_SB_VOL_STEREO("Master Playback Volume", SB_DSP4_MASTER_DEV, 3, 31), CMIPCI_MIXER_SW_MONO("3D Control - Switch", CM_REG_MIXER1, CM_X3DEN_SHIFT, 0), CMIPCI_SB_VOL_STEREO("PCM Playback Volume", SB_DSP4_PCM_DEV, 3, 31), @@ -2601,7 +2601,7 @@ static int snd_cmipci_mic_in_mode_put(struct snd_kcontrol *kcontrol, } /* both for CM8338/8738 */ -static struct snd_kcontrol_new snd_cmipci_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_mixer_switches[] = { DEFINE_MIXER_SWITCH("Four Channel Mode", fourch), { .name = "Line-In Mode", @@ -2613,11 +2613,11 @@ static struct snd_kcontrol_new snd_cmipci_mixer_switches[] __devinitdata = { }; /* for non-multichannel chips */ -static struct snd_kcontrol_new snd_cmipci_nomulti_switch __devinitdata = +static struct snd_kcontrol_new snd_cmipci_nomulti_switch = DEFINE_MIXER_SWITCH("Exchange DAC", exchange_dac); /* only for CM8738 */ -static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] = { #if 0 /* controlled in pcm device */ DEFINE_MIXER_SWITCH("IEC958 In Record", spdif_in), DEFINE_MIXER_SWITCH("IEC958 Out", spdif_out), @@ -2639,14 +2639,14 @@ static struct snd_kcontrol_new snd_cmipci_8738_mixer_switches[] __devinitdata = }; /* only for model 033/037 */ -static struct snd_kcontrol_new snd_cmipci_old_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_old_mixer_switches[] = { DEFINE_MIXER_SWITCH("IEC958 Mix Analog", spdif_dac_out), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase), DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel1), }; /* only for model 039 or later */ -static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = { +static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] = { DEFINE_MIXER_SWITCH("IEC958 In Select", spdif_in_sel2), DEFINE_MIXER_SWITCH("IEC958 In Phase Inverse", spdi_phase2), { @@ -2659,11 +2659,11 @@ static struct snd_kcontrol_new snd_cmipci_extra_mixer_switches[] __devinitdata = }; /* card control switches */ -static struct snd_kcontrol_new snd_cmipci_modem_switch __devinitdata = +static struct snd_kcontrol_new snd_cmipci_modem_switch = DEFINE_CARD_SWITCH("Modem", modem); -static int __devinit snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) +static int snd_cmipci_mixer_new(struct cmipci *cm, int pcm_spdif_device) { struct snd_card *card; struct snd_kcontrol_new *sw; @@ -2791,7 +2791,7 @@ static void snd_cmipci_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static void __devinit snd_cmipci_proc_init(struct cmipci *cm) +static void snd_cmipci_proc_init(struct cmipci *cm) { struct snd_info_entry *entry; @@ -2817,7 +2817,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { * check chip version and capabilities * driver name is modified according to the chip model */ -static void __devinit query_chip(struct cmipci *cm) +static void query_chip(struct cmipci *cm) { unsigned int detect; @@ -2866,7 +2866,7 @@ static void __devinit query_chip(struct cmipci *cm) } #ifdef SUPPORT_JOYSTICK -static int __devinit snd_cmipci_create_gameport(struct cmipci *cm, int dev) +static int snd_cmipci_create_gameport(struct cmipci *cm, int dev) { static int ports[] = { 0x201, 0x200, 0 }; /* FIXME: majority is 0x201? */ struct gameport *gp; @@ -2889,13 +2889,13 @@ static int __devinit snd_cmipci_create_gameport(struct cmipci *cm, int dev) } if (!r) { - printk(KERN_WARNING "cmipci: cannot reserve joystick ports\n"); + dev_warn(cm->card->dev, "cannot reserve joystick ports\n"); return -EBUSY; } cm->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "cmipci: cannot allocate memory for gameport\n"); + dev_err(cm->card->dev, "cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } @@ -2959,7 +2959,7 @@ static int snd_cmipci_dev_free(struct snd_device *device) return snd_cmipci_free(cm); } -static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) +static int snd_cmipci_create_fm(struct cmipci *cm, long fm_port) { long iosynth; unsigned int val; @@ -2995,13 +2995,14 @@ static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) if (snd_opl3_create(cm->card, iosynth, iosynth + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - printk(KERN_ERR "cmipci: no OPL device at %#lx, " - "skipping...\n", iosynth); + dev_err(cm->card->dev, + "no OPL device at %#lx, skipping...\n", + iosynth); goto disable_fm; } } if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { - printk(KERN_ERR "cmipci: cannot create OPL3 hwdep\n"); + dev_err(cm->card->dev, "cannot create OPL3 hwdep\n"); return err; } return 0; @@ -3012,8 +3013,8 @@ static int __devinit snd_cmipci_create_fm(struct cmipci *cm, long fm_port) return 0; } -static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, - int dev, struct cmipci **rcmipci) +static int snd_cmipci_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct cmipci **rcmipci) { struct cmipci *cm; int err; @@ -3060,7 +3061,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc if (request_irq(pci->irq, snd_cmipci_interrupt, IRQF_SHARED, KBUILD_MODNAME, cm)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_cmipci_free(cm); return -EBUSY; } @@ -3192,8 +3193,9 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc /* enable UART */ snd_cmipci_set_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); if (inb(iomidi + 1) == 0xff) { - snd_printk(KERN_ERR "cannot enable MPU-401 port" - " at %#lx\n", iomidi); + dev_err(cm->card->dev, + "cannot enable MPU-401 port at %#lx\n", + iomidi); snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_UART_EN); iomidi = 0; @@ -3237,7 +3239,8 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc MPU401_INFO_INTEGRATED : 0) | MPU401_INFO_IRQ_HOOK, -1, &cm->rmidi)) < 0) { - printk(KERN_ERR "cmipci: no UART401 device at 0x%lx\n", iomidi); + dev_err(cm->card->dev, + "no UART401 device at 0x%lx\n", iomidi); } } @@ -3254,8 +3257,6 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc if (snd_cmipci_create_gameport(cm, dev) < 0) snd_cmipci_clear_bit(cm, CM_REG_FUNCTRL1, CM_JYSTK_EN); - snd_card_set_dev(card, &pci->dev); - *rcmipci = cm; return 0; } @@ -3265,8 +3266,8 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc MODULE_DEVICE_TABLE(pci, snd_cmipci_ids); -static int __devinit snd_cmipci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cmipci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -3280,7 +3281,8 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -3314,10 +3316,9 @@ static int __devinit snd_cmipci_probe(struct pci_dev *pci, } -static void __devexit snd_cmipci_remove(struct pci_dev *pci) +static void snd_cmipci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -3382,8 +3383,7 @@ static int snd_cmipci_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "cmipci: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -3415,7 +3415,7 @@ static struct pci_driver cmipci_driver = { .name = KBUILD_MODNAME, .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, - .remove = __devexit_p(snd_cmipci_remove), + .remove = snd_cmipci_remove, .driver = { .pm = SND_CMIPCI_PM_OPS, }, diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index 8e86ec0031f..43d1f912c64 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c @@ -564,7 +564,8 @@ static void snd_cs4281_ac97_write(struct snd_ac97 *ac97, return; } } - snd_printk(KERN_ERR "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); + dev_err(chip->card->dev, + "AC'97 write problem, reg = 0x%x, val = 0x%x\n", reg, val); } static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97, @@ -624,7 +625,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97, goto __ok1; } - snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); + dev_err(chip->card->dev, + "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); result = 0xffff; goto __end; @@ -643,7 +645,8 @@ static unsigned short snd_cs4281_ac97_read(struct snd_ac97 *ac97, udelay(10); } - snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); + dev_err(chip->card->dev, + "AC'97 read problem (ACSTS_VSTS), reg = 0x%x\n", reg); result = 0xffff; goto __end; @@ -835,8 +838,9 @@ static snd_pcm_uframes_t snd_cs4281_pointer(struct snd_pcm_substream *substream) struct cs4281 *chip = snd_pcm_substream_chip(substream); /* - printk(KERN_DEBUG "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", - snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, + dev_dbg(chip->card->dev, + "DCC = 0x%x, buffer_size = 0x%x, jiffies = %li\n", + snd_cs4281_peekBA0(chip, dma->regDCC), runtime->buffer_size, jiffies); */ return runtime->buffer_size - @@ -969,8 +973,8 @@ static struct snd_pcm_ops snd_cs4281_capture_ops = { .pointer = snd_cs4281_pointer, }; -static int __devinit snd_cs4281_pcm(struct cs4281 * chip, int device, - struct snd_pcm ** rpcm) +static int snd_cs4281_pcm(struct cs4281 *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1093,7 +1097,7 @@ static void snd_cs4281_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97 = NULL; } -static int __devinit snd_cs4281_mixer(struct cs4281 * chip) +static int snd_cs4281_mixer(struct cs4281 *chip) { struct snd_card *card = chip->card; struct snd_ac97_template ac97; @@ -1171,7 +1175,7 @@ static struct snd_info_entry_ops snd_cs4281_proc_ops_BA1 = { .read = snd_cs4281_BA1_read, }; -static void __devinit snd_cs4281_proc_init(struct cs4281 * chip) +static void snd_cs4281_proc_init(struct cs4281 *chip) { struct snd_info_entry *entry; @@ -1259,13 +1263,14 @@ static int snd_cs4281_gameport_open(struct gameport *gameport, int mode) return 0; } -static int __devinit snd_cs4281_create_gameport(struct cs4281 *chip) +static int snd_cs4281_create_gameport(struct cs4281 *chip) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "cs4281: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -1312,7 +1317,7 @@ static int snd_cs4281_free(struct cs4281 *chip) /* Sound System Power Management - Turn Everything OFF */ snd_cs4281_pokeBA0(chip, BA0_SSPM, 0); /* PCI interface - D3 state */ - pci_set_power_state(chip->pci, 3); + pci_set_power_state(chip->pci, PCI_D3hot); if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -1335,10 +1340,10 @@ static int snd_cs4281_dev_free(struct snd_device *device) static int snd_cs4281_chip_init(struct cs4281 *chip); /* defined below */ -static int __devinit snd_cs4281_create(struct snd_card *card, - struct pci_dev *pci, - struct cs4281 ** rchip, - int dual_codec) +static int snd_cs4281_create(struct snd_card *card, + struct pci_dev *pci, + struct cs4281 **rchip, + int dual_codec) { struct cs4281 *chip; unsigned int tmp; @@ -1361,7 +1366,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card, chip->irq = -1; pci_set_master(pci); if (dual_codec < 0 || dual_codec > 3) { - snd_printk(KERN_ERR "invalid dual_codec option %d\n", dual_codec); + dev_err(card->dev, "invalid dual_codec option %d\n", dual_codec); dual_codec = 0; } chip->dual_codec = dual_codec; @@ -1383,7 +1388,7 @@ static int __devinit snd_cs4281_create(struct snd_card *card, if (request_irq(pci->irq, snd_cs4281_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_cs4281_free(chip); return -ENOMEM; } @@ -1402,8 +1407,6 @@ static int __devinit snd_cs4281_create(struct snd_card *card, snd_cs4281_proc_init(chip); - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } @@ -1425,7 +1428,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) snd_cs4281_pokeBA0(chip, BA0_CFLR, BA0_CFLR_DEFAULT); tmp = snd_cs4281_peekBA0(chip, BA0_CFLR); if (tmp != BA0_CFLR_DEFAULT) { - snd_printk(KERN_ERR "CFLR setup failed (0x%x)\n", tmp); + dev_err(chip->card->dev, + "CFLR setup failed (0x%x)\n", tmp); return -EIO; } } @@ -1436,11 +1440,13 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) snd_cs4281_pokeBA0(chip, BA0_CWPR, 0x4281); if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC1)) != (BA0_SERC1_SO1EN | BA0_SERC1_AC97)) { - snd_printk(KERN_ERR "SERC1 AC'97 check failed (0x%x)\n", tmp); + dev_err(chip->card->dev, + "SERC1 AC'97 check failed (0x%x)\n", tmp); return -EIO; } if ((tmp = snd_cs4281_peekBA0(chip, BA0_SERC2)) != (BA0_SERC2_SI1EN | BA0_SERC2_AC97)) { - snd_printk(KERN_ERR "SERC2 AC'97 check failed (0x%x)\n", tmp); + dev_err(chip->card->dev, + "SERC2 AC'97 check failed (0x%x)\n", tmp); return -EIO; } @@ -1502,7 +1508,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "DLLRDY not seen\n"); + dev_err(chip->card->dev, "DLLRDY not seen\n"); return -EIO; __ok0: @@ -1528,7 +1534,9 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "never read codec ready from AC'97 (0x%x)\n", snd_cs4281_peekBA0(chip, BA0_ACSTS)); + dev_err(chip->card->dev, + "never read codec ready from AC'97 (0x%x)\n", + snd_cs4281_peekBA0(chip, BA0_ACSTS)); return -EIO; __ok1: @@ -1539,7 +1547,8 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) goto __codec2_ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_INFO "secondary codec doesn't respond. disable it...\n"); + dev_info(chip->card->dev, + "secondary codec doesn't respond. disable it...\n"); chip->dual_codec = 0; __codec2_ok: ; } @@ -1569,7 +1578,7 @@ static int snd_cs4281_chip_init(struct cs4281 *chip) if (--retry_count > 0) goto __retry; - snd_printk(KERN_ERR "never read ISV3 and ISV4 from AC'97\n"); + dev_err(chip->card->dev, "never read ISV3 and ISV4 from AC'97\n"); return -EIO; __ok2: @@ -1779,8 +1788,8 @@ static struct snd_rawmidi_ops snd_cs4281_midi_input = .trigger = snd_cs4281_midi_input_trigger, }; -static int __devinit snd_cs4281_midi(struct cs4281 * chip, int device, - struct snd_rawmidi **rrawmidi) +static int snd_cs4281_midi(struct cs4281 *chip, int device, + struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -1901,8 +1910,8 @@ static void snd_cs4281_opl3_command(struct snd_opl3 *opl3, unsigned short cmd, spin_unlock_irqrestore(&opl3->reg_lock, flags); } -static int __devinit snd_cs4281_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs4281_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1917,7 +1926,8 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -1968,10 +1978,9 @@ static int __devinit snd_cs4281_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_cs4281_remove(struct pci_dev *pci) +static void snd_cs4281_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* @@ -2056,8 +2065,7 @@ static int cs4281_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "cs4281: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2095,7 +2103,7 @@ static struct pci_driver cs4281_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, - .remove = __devexit_p(snd_cs4281_remove), + .remove = snd_cs4281_remove, .driver = { .pm = CS4281_PM_OPS, }, diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 575bed0836f..af0eacbc8bd 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c @@ -73,8 +73,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { MODULE_DEVICE_TABLE(pci, snd_cs46xx_ids); -static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_cs46xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -88,7 +88,8 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; if ((err = snd_cs46xx_create(card, pci, @@ -155,17 +156,16 @@ static int __devinit snd_card_cs46xx_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) +static void snd_card_cs46xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver cs46xx_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, - .remove = __devexit_p(snd_card_cs46xx_remove), + .remove = snd_card_cs46xx_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_cs46xx_pm, diff --git a/sound/pci/cs46xx/cs46xx.h b/sound/pci/cs46xx/cs46xx.h index fc339ef0a0a..c49a082c378 100644 --- a/sound/pci/cs46xx/cs46xx.h +++ b/sound/pci/cs46xx/cs46xx.h @@ -1716,9 +1716,14 @@ struct snd_cs46xx { struct snd_pcm *pcm_rear; struct snd_pcm *pcm_center_lfe; struct snd_pcm *pcm_iec958; + +#define CS46XX_DSP_MODULES 5 + struct dsp_module_desc *modules[CS46XX_DSP_MODULES]; #else /* for compatibility */ struct snd_cs46xx_pcm *playback_pcm; unsigned int play_ctl; + + struct ba1_struct *ba1; #endif #ifdef CONFIG_PM_SLEEP diff --git a/sound/pci/cs46xx/cs46xx_image.h b/sound/pci/cs46xx/cs46xx_image.h deleted file mode 100644 index dc93f62db2c..00000000000 --- a/sound/pci/cs46xx/cs46xx_image.h +++ /dev/null @@ -1,3468 +0,0 @@ -struct BA1struct { - struct { - unsigned long offset; - unsigned long size; - } memory[BA1_MEMORY_COUNT]; - u32 map[BA1_DWORD_SIZE]; -}; - - -static struct BA1struct BA1Struct = { -{{ 0x00000000, 0x00003000 },{ 0x00010000, 0x00003800 },{ 0x00020000, 0x00007000 }}, -{0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000163,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00200040,0x00008010,0x00000000, -0x00000000,0x80000001,0x00000001,0x00060000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00900080,0x00000173,0x00000000, -0x00000000,0x00000010,0x00800000,0x00900000, -0xf2c0000f,0x00000200,0x00000000,0x00010600, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000163,0x330300c2, -0x06000000,0x00000000,0x80008000,0x80008000, -0x3fc0000f,0x00000301,0x00010400,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00b00000,0x00d0806d,0x330480c3, -0x04800000,0x00000001,0x00800001,0x0000ffff, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x066a0600,0x06350070,0x0000929d,0x929d929d, -0x00000000,0x0000735a,0x00000600,0x00000000, -0x929d735a,0x8734abfe,0x00010000,0x735a735a, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x0000804f,0x000000c3, -0x05000000,0x00a00010,0x00000000,0x80008000, -0x00000000,0x00000000,0x00000700,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000080,0x00a00000,0x0000809a,0x000000c2, -0x07400000,0x00000000,0x80008000,0xffffffff, -0x00c80028,0x00005555,0x00000000,0x000107a0, -0x00c80028,0x000000c2,0x06800000,0x00000000, -0x06e00080,0x00300000,0x000080bb,0x000000c9, -0x07a00000,0x04000000,0x80008000,0xffffffff, -0x00c80028,0x00005555,0x00000000,0x00000780, -0x00c80028,0x000000c5,0xff800000,0x00000000, -0x00640080,0x00c00000,0x00008197,0x000000c9, -0x07800000,0x04000000,0x80008000,0xffffffff, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x0000805e,0x000000c1, -0x00000000,0x00800000,0x80008000,0x80008000, -0x00020000,0x0000ffff,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x929d0600,0x929d929d,0x929d929d,0x929d0000, -0x929d929d,0x929d929d,0x929d929d,0x929d929d, -0x929d929d,0x00100635,0x060b013f,0x00000004, -0x00000001,0x007a0002,0x00000000,0x066e0610, -0x0105929d,0x929d929d,0x929d929d,0x929d929d, -0x929d929d,0xa431ac75,0x0001735a,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0x735a0051, -0x00000000,0x929d929d,0x929d929d,0x929d929d, -0x929d929d,0x929d929d,0x929d929d,0x929d929d, -0x929d929d,0x929d929d,0x00000000,0x06400136, -0x0000270f,0x00010000,0x007a0000,0x00000000, -0x068e0645,0x0105929d,0x929d929d,0x929d929d, -0x929d929d,0x929d929d,0xa431ac75,0x0001735a, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0xa431ac75,0xa431ac75,0xa431ac75,0xa431ac75, -0x735a0100,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00010004, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00001705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00009705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00011705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00019705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00021705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00029705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00031705,0x00001400,0x000a411e,0x00001003, -0x00040730,0x00001002,0x000f619e,0x00001003, -0x00039705,0x00001400,0x000a411e,0x00001003, -0x000fe19e,0x00001003,0x0009c730,0x00001003, -0x0008e19c,0x00001003,0x000083c1,0x00093040, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00009705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00011705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00019705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00021705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00029705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00031705,0x00001400,0x000a211e,0x00001003, -0x00098730,0x00001002,0x000ee19e,0x00001003, -0x00039705,0x00001400,0x000a211e,0x00001003, -0x0000a730,0x00001008,0x000e2730,0x00001002, -0x0000a731,0x00001002,0x0000a731,0x00001002, -0x0000a731,0x00001002,0x0000a731,0x00001002, -0x0000a731,0x00001002,0x0000a731,0x00001002, -0x00000000,0x00000000,0x000f619c,0x00001003, -0x0007f801,0x000c0000,0x00000037,0x00001000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x000c0000,0x00000000,0x00000000, -0x0000373c,0x00001000,0x00000000,0x00000000, -0x000ee19c,0x00001003,0x0007f801,0x000c0000, -0x00000037,0x00001000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x0000273c,0x00001000, -0x00000033,0x00001000,0x000e679e,0x00001003, -0x00007705,0x00001400,0x000ac71e,0x00001003, -0x00087fc1,0x000c3be0,0x0007f801,0x000c0000, -0x00000037,0x00001000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x0000a730,0x00001003, -0x00000033,0x00001000,0x0007f801,0x000c0000, -0x00000037,0x00001000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x000c0000, -0x00000032,0x00001000,0x0000273d,0x00001000, -0x0004a730,0x00001003,0x00000f41,0x00097140, -0x0000a841,0x0009b240,0x0000a0c1,0x0009f040, -0x0001c641,0x00093540,0x0001cec1,0x0009b5c0, -0x00000000,0x00000000,0x0001bf05,0x0003fc40, -0x00002725,0x000aa400,0x00013705,0x00093a00, -0x0000002e,0x0009d6c0,0x00038630,0x00001004, -0x0004ef0a,0x000eb785,0x0003fc8a,0x00000000, -0x00000000,0x000c70e0,0x0007d182,0x0002c640, -0x00000630,0x00001004,0x000799b8,0x0002c6c0, -0x00031705,0x00092240,0x00039f05,0x000932c0, -0x0003520a,0x00000000,0x00040731,0x0000100b, -0x00010705,0x000b20c0,0x00000000,0x000eba44, -0x00032108,0x000c60c4,0x00065208,0x000c2917, -0x000406b0,0x00001007,0x00012f05,0x00036880, -0x0002818e,0x000c0000,0x0004410a,0x00000000, -0x00040630,0x00001007,0x00029705,0x000c0000, -0x00000000,0x00000000,0x00003fc1,0x0003fc40, -0x000037c1,0x00091b40,0x00003fc1,0x000911c0, -0x000037c1,0x000957c0,0x00003fc1,0x000951c0, -0x000037c1,0x00000000,0x00003fc1,0x000991c0, -0x000037c1,0x00000000,0x00003fc1,0x0009d1c0, -0x000037c1,0x00000000,0x0001ccc1,0x000915c0, -0x0001c441,0x0009d800,0x0009cdc1,0x00091240, -0x0001c541,0x00091d00,0x0009cfc1,0x00095240, -0x0001c741,0x00095c80,0x000e8ca9,0x00099240, -0x000e85ad,0x00095640,0x00069ca9,0x00099d80, -0x000e952d,0x00099640,0x000eaca9,0x0009d6c0, -0x000ea5ad,0x00091a40,0x0006bca9,0x0009de80, -0x000eb52d,0x00095a40,0x000ecca9,0x00099ac0, -0x000ec5ad,0x0009da40,0x000edca9,0x0009d300, -0x000a6e0a,0x00001000,0x000ed52d,0x00091e40, -0x000eeca9,0x00095ec0,0x000ee5ad,0x00099e40, -0x0006fca9,0x00002500,0x000fb208,0x000c59a0, -0x000ef52d,0x0009de40,0x00068ca9,0x000912c1, -0x000683ad,0x00095241,0x00020f05,0x000991c1, -0x00000000,0x00000000,0x00086f88,0x00001000, -0x0009cf81,0x000b5340,0x0009c701,0x000b92c0, -0x0009de81,0x000bd300,0x0009d601,0x000b1700, -0x0001fd81,0x000b9d80,0x0009f501,0x000b57c0, -0x000a0f81,0x000bd740,0x00020701,0x000b5c80, -0x000a1681,0x000b97c0,0x00021601,0x00002500, -0x000a0701,0x000b9b40,0x000a0f81,0x000b1bc0, -0x00021681,0x00002d00,0x00020f81,0x000bd800, -0x000a0701,0x000b5bc0,0x00021601,0x00003500, -0x000a0f81,0x000b5f40,0x000a0701,0x000bdbc0, -0x00021681,0x00003d00,0x00020f81,0x000b1d00, -0x000a0701,0x000b1fc0,0x00021601,0x00020500, -0x00020f81,0x000b1341,0x000a0701,0x000b9fc0, -0x00021681,0x00020d00,0x00020f81,0x000bde80, -0x000a0701,0x000bdfc0,0x00021601,0x00021500, -0x00020f81,0x000b9341,0x00020701,0x000b53c1, -0x00021681,0x00021d00,0x000a0f81,0x000d0380, -0x0000b601,0x000b15c0,0x00007b01,0x00000000, -0x00007b81,0x000bd1c0,0x00007b01,0x00000000, -0x00007b81,0x000b91c0,0x00007b01,0x000b57c0, -0x00007b81,0x000b51c0,0x00007b01,0x000b1b40, -0x00007b81,0x000b11c0,0x00087b01,0x000c3dc0, -0x0007e488,0x000d7e45,0x00000000,0x000d7a44, -0x0007e48a,0x00000000,0x00011f05,0x00084080, -0x00000000,0x00000000,0x00001705,0x000b3540, -0x00008a01,0x000bf040,0x00007081,0x000bb5c0, -0x00055488,0x00000000,0x0000d482,0x0003fc40, -0x0003fc88,0x00000000,0x0001e401,0x000b3a00, -0x0001ec81,0x000bd6c0,0x0004ef08,0x000eb784, -0x000c86b0,0x00001007,0x00008281,0x000bb240, -0x0000b801,0x000b7140,0x00007888,0x00000000, -0x0000073c,0x00001000,0x0007f188,0x000c0000, -0x00000000,0x00000000,0x00055288,0x000c555c, -0x0005528a,0x000c0000,0x0009fa88,0x000c5d00, -0x0000fa88,0x00000000,0x00000032,0x00001000, -0x0000073d,0x00001000,0x0007f188,0x000c0000, -0x00000000,0x00000000,0x0008c01c,0x00001003, -0x00002705,0x00001008,0x0008b201,0x000c1392, -0x0000ba01,0x00000000,0x00008731,0x00001400, -0x0004c108,0x000fe0c4,0x00057488,0x00000000, -0x000a6388,0x00001001,0x0008b334,0x000bc141, -0x0003020e,0x00000000,0x000886b0,0x00001008, -0x00003625,0x000c5dfa,0x000a638a,0x00001001, -0x0008020e,0x00001002,0x0008a6b0,0x00001008, -0x0007f301,0x00000000,0x00000000,0x00000000, -0x00002725,0x000a8c40,0x000000ae,0x00000000, -0x000d8630,0x00001008,0x00000000,0x000c74e0, -0x0007d182,0x0002d640,0x000a8630,0x00001008, -0x000799b8,0x0002d6c0,0x0000748a,0x000c3ec5, -0x0007420a,0x000c0000,0x00062208,0x000c4117, -0x00070630,0x00001009,0x00000000,0x000c0000, -0x0001022e,0x00000000,0x0003a630,0x00001009, -0x00000000,0x000c0000,0x00000036,0x00001000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x0002a730,0x00001008,0x0007f801,0x000c0000, -0x00000037,0x00001000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x0002a730,0x00001008, -0x00000033,0x00001000,0x0002a705,0x00001008, -0x00007a01,0x000c0000,0x000e6288,0x000d550a, -0x0006428a,0x00000000,0x00060730,0x0000100a, -0x00000000,0x000c0000,0x00000000,0x00000000, -0x0007aab0,0x00034880,0x00078fb0,0x0000100b, -0x00057488,0x00000000,0x00033b94,0x00081140, -0x000183ae,0x00000000,0x000786b0,0x0000100b, -0x00022f05,0x000c3545,0x0000eb8a,0x00000000, -0x00042731,0x00001003,0x0007aab0,0x00034880, -0x00048fb0,0x0000100a,0x00057488,0x00000000, -0x00033b94,0x00081140,0x000183ae,0x00000000, -0x000806b0,0x0000100b,0x00022f05,0x00000000, -0x00007401,0x00091140,0x00048f05,0x000951c0, -0x00042731,0x00001003,0x0000473d,0x00001000, -0x000f19b0,0x000bbc47,0x00080000,0x000bffc7, -0x000fe19e,0x00001003,0x00000000,0x00000000, -0x0008e19c,0x00001003,0x000083c1,0x00093040, -0x00000f41,0x00097140,0x0000a841,0x0009b240, -0x0000a0c1,0x0009f040,0x0001c641,0x00093540, -0x0001cec1,0x0009b5c0,0x00000000,0x000fdc44, -0x00055208,0x00000000,0x00010705,0x000a2880, -0x0000a23a,0x00093a00,0x0003fc8a,0x000df6c5, -0x0004ef0a,0x000c0000,0x00012f05,0x00036880, -0x00065308,0x000c2997,0x000d86b0,0x0000100a, -0x0004410a,0x000d40c7,0x00000000,0x00000000, -0x00080730,0x00001004,0x00056f0a,0x000ea105, -0x00000000,0x00000000,0x0000473d,0x00001000, -0x000f19b0,0x000bbc47,0x00080000,0x000bffc7, -0x0000273d,0x00001000,0x00000000,0x000eba44, -0x00048f05,0x0000f440,0x00007401,0x0000f7c0, -0x00000734,0x00001000,0x00010705,0x000a6880, -0x00006a88,0x000c75c4,0x00000000,0x000e5084, -0x00000000,0x000eba44,0x00087401,0x000e4782, -0x00000734,0x00001000,0x00010705,0x000a6880, -0x00006a88,0x000c75c4,0x0007c108,0x000c0000, -0x0007e721,0x000bed40,0x00005f25,0x000badc0, -0x0003ba97,0x000beb80,0x00065590,0x000b2e00, -0x00033217,0x00003ec0,0x00065590,0x000b8e40, -0x0003ed80,0x000491c0,0x00073fb0,0x00074c80, -0x000283a0,0x0000100c,0x000ee388,0x00042970, -0x00008301,0x00021ef2,0x000b8f14,0x0000000f, -0x000c4d8d,0x0000001b,0x000d6dc2,0x000e06c6, -0x000032ac,0x000c3916,0x0004edc2,0x00074c80, -0x00078898,0x00001000,0x00038894,0x00000032, -0x000c4d8d,0x00092e1b,0x000d6dc2,0x000e06c6, -0x0004edc2,0x000c1956,0x0000722c,0x00034a00, -0x00041705,0x0009ed40,0x00058730,0x00001400, -0x000d7488,0x000c3a00,0x00048f05,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000, -0x00000000,0x00000000,0x00000000,0x00000000} - }; diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index a2bb8c91ebe..32b44f25b5c 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c @@ -54,7 +54,9 @@ #include <linux/gameport.h> #include <linux/mutex.h> #include <linux/export.h> - +#include <linux/module.h> +#include <linux/firmware.h> +#include <linux/vmalloc.h> #include <sound/core.h> #include <sound/control.h> @@ -114,7 +116,7 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip, tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL); if ((tmp & ACCTL_VFRM) == 0) { - snd_printk(KERN_WARNING "cs46xx: ACCTL_VFRM not set 0x%x\n",tmp); + dev_warn(chip->card->dev, "ACCTL_VFRM not set 0x%x\n", tmp); snd_cs46xx_pokeBA0(chip, BA0_ACCTL, (tmp & (~ACCTL_ESYN)) | ACCTL_VFRM ); msleep(50); tmp = snd_cs46xx_peekBA0(chip, BA0_ACCTL + offset); @@ -166,7 +168,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip, goto ok1; } - snd_printk(KERN_ERR "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); + dev_err(chip->card->dev, + "AC'97 read problem (ACCTL_DCV), reg = 0x%x\n", reg); result = 0xffff; goto end; @@ -185,7 +188,9 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip, udelay(10); } - snd_printk(KERN_ERR "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", codec_index, reg); + dev_err(chip->card->dev, + "AC'97 read problem (ACSTS_VSTS), codec_index %d, reg = 0x%x\n", + codec_index, reg); result = 0xffff; goto end; @@ -195,7 +200,8 @@ static unsigned short snd_cs46xx_codec_read(struct snd_cs46xx *chip, * ACSDA = Status Data Register = 474h */ #if 0 - printk(KERN_DEBUG "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, + dev_dbg(chip->card->dev, + "e) reg = 0x%x, val = 0x%x, BA0_ACCAD = 0x%x\n", reg, snd_cs46xx_peekBA0(chip, BA0_ACSDA), snd_cs46xx_peekBA0(chip, BA0_ACCAD)); #endif @@ -284,7 +290,9 @@ static void snd_cs46xx_codec_write(struct snd_cs46xx *chip, goto end; } } - snd_printk(KERN_ERR "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", codec_index, reg, val); + dev_err(chip->card->dev, + "AC'97 write problem, codec_index = %d, reg = 0x%x, val = 0x%x\n", + codec_index, reg, val); end: chip->active_ctrl(chip, -1); } @@ -330,13 +338,147 @@ int snd_cs46xx_download(struct snd_cs46xx *chip, return 0; } +static inline void memcpy_le32(void *dst, const void *src, unsigned int len) +{ +#ifdef __LITTLE_ENDIAN + memcpy(dst, src, len); +#else + u32 *_dst = dst; + const __le32 *_src = src; + len /= 4; + while (len-- > 0) + *_dst++ = le32_to_cpu(*_src++); +#endif +} + #ifdef CONFIG_SND_CS46XX_NEW_DSP -#include "imgs/cwc4630.h" -#include "imgs/cwcasync.h" -#include "imgs/cwcsnoop.h" -#include "imgs/cwcbinhack.h" -#include "imgs/cwcdma.h" +static const char *module_names[CS46XX_DSP_MODULES] = { + "cwc4630", "cwcasync", "cwcsnoop", "cwcbinhack", "cwcdma" +}; + +MODULE_FIRMWARE("cs46xx/cwc4630"); +MODULE_FIRMWARE("cs46xx/cwcasync"); +MODULE_FIRMWARE("cs46xx/cwcsnoop"); +MODULE_FIRMWARE("cs46xx/cwcbinhack"); +MODULE_FIRMWARE("cs46xx/cwcdma"); + +static void free_module_desc(struct dsp_module_desc *module) +{ + if (!module) + return; + kfree(module->module_name); + kfree(module->symbol_table.symbols); + if (module->segments) { + int i; + for (i = 0; i < module->nsegments; i++) + kfree(module->segments[i].data); + kfree(module->segments); + } + kfree(module); +} + +/* firmware binary format: + * le32 nsymbols; + * struct { + * le32 address; + * char symbol_name[DSP_MAX_SYMBOL_NAME]; + * le32 symbol_type; + * } symbols[nsymbols]; + * le32 nsegments; + * struct { + * le32 segment_type; + * le32 offset; + * le32 size; + * le32 data[size]; + * } segments[nsegments]; + */ + +static int load_firmware(struct snd_cs46xx *chip, + struct dsp_module_desc **module_ret, + const char *fw_name) +{ + int i, err; + unsigned int nums, fwlen, fwsize; + const __le32 *fwdat; + struct dsp_module_desc *module = NULL; + const struct firmware *fw; + char fw_path[32]; + + sprintf(fw_path, "cs46xx/%s", fw_name); + err = request_firmware(&fw, fw_path, &chip->pci->dev); + if (err < 0) + return err; + fwsize = fw->size / 4; + if (fwsize < 2) { + err = -EINVAL; + goto error; + } + + err = -ENOMEM; + module = kzalloc(sizeof(*module), GFP_KERNEL); + if (!module) + goto error; + module->module_name = kstrdup(fw_name, GFP_KERNEL); + if (!module->module_name) + goto error; + + fwlen = 0; + fwdat = (const __le32 *)fw->data; + nums = module->symbol_table.nsymbols = le32_to_cpu(fwdat[fwlen++]); + if (nums >= 40) + goto error_inval; + module->symbol_table.symbols = + kcalloc(nums, sizeof(struct dsp_symbol_entry), GFP_KERNEL); + if (!module->symbol_table.symbols) + goto error; + for (i = 0; i < nums; i++) { + struct dsp_symbol_entry *entry = + &module->symbol_table.symbols[i]; + if (fwlen + 2 + DSP_MAX_SYMBOL_NAME / 4 > fwsize) + goto error_inval; + entry->address = le32_to_cpu(fwdat[fwlen++]); + memcpy(entry->symbol_name, &fwdat[fwlen], DSP_MAX_SYMBOL_NAME - 1); + fwlen += DSP_MAX_SYMBOL_NAME / 4; + entry->symbol_type = le32_to_cpu(fwdat[fwlen++]); + } + + if (fwlen >= fwsize) + goto error_inval; + nums = module->nsegments = le32_to_cpu(fwdat[fwlen++]); + if (nums > 10) + goto error_inval; + module->segments = + kcalloc(nums, sizeof(struct dsp_segment_desc), GFP_KERNEL); + if (!module->segments) + goto error; + for (i = 0; i < nums; i++) { + struct dsp_segment_desc *entry = &module->segments[i]; + if (fwlen + 3 > fwsize) + goto error_inval; + entry->segment_type = le32_to_cpu(fwdat[fwlen++]); + entry->offset = le32_to_cpu(fwdat[fwlen++]); + entry->size = le32_to_cpu(fwdat[fwlen++]); + if (fwlen + entry->size > fwsize) + goto error_inval; + entry->data = kmalloc(entry->size * 4, GFP_KERNEL); + if (!entry->data) + goto error; + memcpy_le32(entry->data, &fwdat[fwlen], entry->size * 4); + fwlen += entry->size; + } + + *module_ret = module; + release_firmware(fw); + return 0; + + error_inval: + err = -EINVAL; + error: + free_module_desc(module); + release_firmware(fw); + return err; +} int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip, unsigned long offset, @@ -361,20 +503,63 @@ int snd_cs46xx_clear_BA1(struct snd_cs46xx *chip, #else /* old DSP image */ -#include "cs46xx_image.h" +struct ba1_struct { + struct { + u32 offset; + u32 size; + } memory[BA1_MEMORY_COUNT]; + u32 map[BA1_DWORD_SIZE]; +}; + +MODULE_FIRMWARE("cs46xx/ba1"); + +static int load_firmware(struct snd_cs46xx *chip) +{ + const struct firmware *fw; + int i, size, err; + + err = request_firmware(&fw, "cs46xx/ba1", &chip->pci->dev); + if (err < 0) + return err; + if (fw->size != sizeof(*chip->ba1)) { + err = -EINVAL; + goto error; + } + + chip->ba1 = vmalloc(sizeof(*chip->ba1)); + if (!chip->ba1) { + err = -ENOMEM; + goto error; + } + + memcpy_le32(chip->ba1, fw->data, sizeof(*chip->ba1)); + + /* sanity check */ + size = 0; + for (i = 0; i < BA1_MEMORY_COUNT; i++) + size += chip->ba1->memory[i].size; + if (size > BA1_DWORD_SIZE * 4) + err = -EINVAL; + + error: + release_firmware(fw); + return err; +} int snd_cs46xx_download_image(struct snd_cs46xx *chip) { int idx, err; - unsigned long offset = 0; + unsigned int offset = 0; + struct ba1_struct *ba1 = chip->ba1; for (idx = 0; idx < BA1_MEMORY_COUNT; idx++) { - if ((err = snd_cs46xx_download(chip, - &BA1Struct.map[offset], - BA1Struct.memory[idx].offset, - BA1Struct.memory[idx].size)) < 0) + err = snd_cs46xx_download(chip, + &ba1->map[offset], + ba1->memory[idx].offset, + ba1->memory[idx].size); + if (err < 0) return err; - offset += BA1Struct.memory[idx].size >> 2; + offset += ba1->memory[idx].size >> 2; } return 0; } @@ -429,8 +614,8 @@ static int cs46xx_wait_for_fifo(struct snd_cs46xx * chip,int retry_timeout) } if(status & SERBST_WBSY) { - snd_printk(KERN_ERR "cs46xx: failure waiting for " - "FIFO command to complete\n"); + dev_err(chip->card->dev, + "failure waiting for FIFO command to complete\n"); return -EINVAL; } @@ -467,7 +652,9 @@ static void snd_cs46xx_clear_serial_FIFOs(struct snd_cs46xx *chip) * Make sure the previous FIFO write operation has completed. */ if (cs46xx_wait_for_fifo(chip,1)) { - snd_printdd ("failed waiting for FIFO at addr (%02X)\n",idx); + dev_dbg(chip->card->dev, + "failed waiting for FIFO at addr (%02X)\n", + idx); if (powerdown) snd_cs46xx_pokeBA0(chip, BA0_CLKCR1, tmp); @@ -515,7 +702,7 @@ static void snd_cs46xx_proc_start(struct snd_cs46xx *chip) } if (snd_cs46xx_peek(chip, BA1_SPCR) & SPCR_RUNFR) - snd_printk(KERN_ERR "SPCR_RUNFR never reset\n"); + dev_err(chip->card->dev, "SPCR_RUNFR never reset\n"); } static void snd_cs46xx_proc_stop(struct snd_cs46xx *chip) @@ -875,7 +1062,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, cpcm->hw_buf.addr,cpcm->pcm_channel_id); if (cpcm->pcm_channel == NULL) { - snd_printk(KERN_ERR "cs46xx: failed to create virtual PCM channel\n"); + dev_err(chip->card->dev, + "failed to create virtual PCM channel\n"); return -ENOMEM; } cpcm->pcm_channel->sample_rate = sample_rate; @@ -888,7 +1076,8 @@ static int _cs46xx_adjust_sample_rate (struct snd_cs46xx *chip, struct snd_cs46x if ( (cpcm->pcm_channel = cs46xx_dsp_create_pcm_channel (chip, sample_rate, cpcm, cpcm->hw_buf.addr, cpcm->pcm_channel_id)) == NULL) { - snd_printk(KERN_ERR "cs46xx: failed to re-create virtual PCM channel\n"); + dev_err(chip->card->dev, + "failed to re-create virtual PCM channel\n"); return -ENOMEM; } @@ -937,7 +1126,8 @@ static int snd_cs46xx_playback_hw_params(struct snd_pcm_substream *substream, return -EINVAL; } - snd_printdd ("period_size (%d), periods (%d) buffer_size(%d)\n", + dev_dbg(chip->card->dev, + "period_size (%d), periods (%d) buffer_size(%d)\n", period_size, params_periods(hw_params), params_buffer_bytes(hw_params)); #endif @@ -1352,22 +1542,20 @@ static int _cs46xx_playback_open_channel (struct snd_pcm_substream *substream,in static int snd_cs46xx_playback_open(struct snd_pcm_substream *substream) { - snd_printdd("open front channel\n"); + dev_dbg(substream->pcm->card->dev, "open front channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_MAIN_CHANNEL); } #ifdef CONFIG_SND_CS46XX_NEW_DSP static int snd_cs46xx_playback_open_rear(struct snd_pcm_substream *substream) { - snd_printdd("open rear channel\n"); - + dev_dbg(substream->pcm->card->dev, "open rear channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_REAR_CHANNEL); } static int snd_cs46xx_playback_open_clfe(struct snd_pcm_substream *substream) { - snd_printdd("open center - LFE channel\n"); - + dev_dbg(substream->pcm->card->dev, "open center - LFE channel\n"); return _cs46xx_playback_open_channel(substream,DSP_PCM_CENTER_LFE_CHANNEL); } @@ -1375,7 +1563,7 @@ static int snd_cs46xx_playback_open_iec958(struct snd_pcm_substream *substream) { struct snd_cs46xx *chip = snd_pcm_substream_chip(substream); - snd_printdd("open raw iec958 channel\n"); + dev_dbg(chip->card->dev, "open raw iec958 channel\n"); mutex_lock(&chip->spos_mutex); cs46xx_iec958_pre_open (chip); @@ -1391,7 +1579,7 @@ static int snd_cs46xx_playback_close_iec958(struct snd_pcm_substream *substream) int err; struct snd_cs46xx *chip = snd_pcm_substream_chip(substream); - snd_printdd("close raw iec958 channel\n"); + dev_dbg(chip->card->dev, "close raw iec958 channel\n"); err = snd_cs46xx_playback_close(substream); @@ -1590,7 +1778,7 @@ static struct snd_pcm_ops snd_cs46xx_capture_indirect_ops = { #define MAX_PLAYBACK_CHANNELS 1 #endif -int __devinit snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1621,7 +1809,8 @@ int __devinit snd_cs46xx_pcm(struct snd_cs46xx *chip, int device, struct snd_pcm #ifdef CONFIG_SND_CS46XX_NEW_DSP -int __devinit snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1650,7 +1839,8 @@ int __devinit snd_cs46xx_pcm_rear(struct snd_cs46xx *chip, int device, struct sn return 0; } -int __devinit snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1679,7 +1869,8 @@ int __devinit snd_cs46xx_pcm_center_lfe(struct snd_cs46xx *chip, int device, str return 0; } -int __devinit snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, struct snd_pcm ** rpcm) +int snd_cs46xx_pcm_iec958(struct snd_cs46xx *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -2092,7 +2283,7 @@ static int snd_cs46xx_spdif_stream_put(struct snd_kcontrol *kcontrol, #endif /* CONFIG_SND_CS46XX_NEW_DSP */ -static struct snd_kcontrol_new snd_cs46xx_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_cs46xx_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DAC Volume", @@ -2239,10 +2430,10 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) /* set the desired CODEC mode */ if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { - snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0); + dev_dbg(ac97->bus->card->dev, "CODEC1 mode %04x\n", 0x0); snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0); } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { - snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3); + dev_dbg(ac97->bus->card->dev, "CODEC2 mode %04x\n", 0x3); snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3); } else { snd_BUG(); /* should never happen ... */ @@ -2274,11 +2465,12 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) msleep(10); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "CS46xx secondary codec doesn't respond!\n"); + dev_err(ac97->bus->card->dev, + "CS46xx secondary codec doesn't respond!\n"); } #endif -static int __devinit cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) +static int cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) { int idx, err; struct snd_ac97_template ac97; @@ -2294,7 +2486,8 @@ static int __devinit cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) snd_cs46xx_codec_write(chip, AC97_RESET, 0, codec); udelay(10); if (snd_cs46xx_codec_read(chip, AC97_RESET, codec) & 0x8000) { - snd_printdd("snd_cs46xx: seconadry codec not present\n"); + dev_dbg(chip->card->dev, + "seconadry codec not present\n"); return -ENXIO; } } @@ -2307,11 +2500,11 @@ static int __devinit cs46xx_detect_codec(struct snd_cs46xx *chip, int codec) } msleep(10); } - snd_printdd("snd_cs46xx: codec %d detection timeout\n", codec); + dev_dbg(chip->card->dev, "codec %d detection timeout\n", codec); return -ENXIO; } -int __devinit snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) +int snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) { struct snd_card *card = chip->card; struct snd_ctl_elem_id id; @@ -2327,7 +2520,7 @@ int __devinit snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) /* detect primary codec */ chip->nr_ac97_codecs = 0; - snd_printdd("snd_cs46xx: detecting primary codec\n"); + dev_dbg(chip->card->dev, "detecting primary codec\n"); if ((err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus)) < 0) return err; chip->ac97_bus->private_free = snd_cs46xx_mixer_free_ac97_bus; @@ -2337,7 +2530,7 @@ int __devinit snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) chip->nr_ac97_codecs = 1; #ifdef CONFIG_SND_CS46XX_NEW_DSP - snd_printdd("snd_cs46xx: detecting seconadry codec\n"); + dev_dbg(chip->card->dev, "detecting seconadry codec\n"); /* try detect a secondary codec */ if (! cs46xx_detect_codec(chip, CS46XX_SECONDARY_CODEC_INDEX)) chip->nr_ac97_codecs = 2; @@ -2372,7 +2565,7 @@ int __devinit snd_cs46xx_mixer(struct snd_cs46xx *chip, int spdif_device) } /* do soundcard specific mixer setup */ if (chip->mixer_init) { - snd_printdd ("calling chip->mixer_init(chip);\n"); + dev_dbg(chip->card->dev, "calling chip->mixer_init(chip);\n"); chip->mixer_init(chip); } #endif @@ -2531,7 +2724,7 @@ static struct snd_rawmidi_ops snd_cs46xx_midi_input = .trigger = snd_cs46xx_midi_input_trigger, }; -int __devinit snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) +int snd_cs46xx_midi(struct snd_cs46xx *chip, int device, struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -2613,13 +2806,14 @@ static int snd_cs46xx_gameport_open(struct gameport *gameport, int mode) return 0; } -int __devinit snd_cs46xx_gameport(struct snd_cs46xx *chip) +int snd_cs46xx_gameport(struct snd_cs46xx *chip) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "cs46xx: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -2649,7 +2843,7 @@ static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) } } #else -int __devinit snd_cs46xx_gameport(struct snd_cs46xx *chip) { return -ENOSYS; } +int snd_cs46xx_gameport(struct snd_cs46xx *chip) { return -ENOSYS; } static inline void snd_cs46xx_remove_gameport(struct snd_cs46xx *chip) { } #endif /* CONFIG_GAMEPORT */ @@ -2674,7 +2868,7 @@ static struct snd_info_entry_ops snd_cs46xx_proc_io_ops = { .read = snd_cs46xx_io_read, }; -static int __devinit snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip) +static int snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip) { struct snd_info_entry *entry; int idx; @@ -2795,6 +2989,10 @@ static int snd_cs46xx_free(struct snd_cs46xx *chip) cs46xx_dsp_spos_destroy(chip); chip->dsp_spos_instance = NULL; } + for (idx = 0; idx < CS46XX_DSP_MODULES; idx++) + free_module_desc(chip->modules[idx]); +#else + vfree(chip->ba1); #endif #ifdef CONFIG_PM_SLEEP @@ -2952,8 +3150,10 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip) } - snd_printk(KERN_ERR "create - never read codec ready from AC'97\n"); - snd_printk(KERN_ERR "it is not probably bug, try to use CS4236 driver\n"); + dev_err(chip->card->dev, + "create - never read codec ready from AC'97\n"); + dev_err(chip->card->dev, + "it is not probably bug, try to use CS4236 driver\n"); return -EIO; ok1: #ifdef CONFIG_SND_CS46XX_NEW_DSP @@ -2971,7 +3171,8 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip) * Make sure CODEC is READY. */ if (!(snd_cs46xx_peekBA0(chip, BA0_ACSTS2) & ACSTS_CRDY)) - snd_printdd("cs46xx: never read card ready from secondary AC'97\n"); + dev_dbg(chip->card->dev, + "never read card ready from secondary AC'97\n"); } #endif @@ -3001,17 +3202,21 @@ static int snd_cs46xx_chip_init(struct snd_cs46xx *chip) } #ifndef CONFIG_SND_CS46XX_NEW_DSP - snd_printk(KERN_ERR "create - never read ISV3 & ISV4 from AC'97\n"); + dev_err(chip->card->dev, + "create - never read ISV3 & ISV4 from AC'97\n"); return -EIO; #else /* This may happen on a cold boot with a Terratec SiXPack 5.1. Reloading the driver may help, if there's other soundcards with the same problem I would like to know. (Benny) */ - snd_printk(KERN_ERR "ERROR: snd-cs46xx: never read ISV3 & ISV4 from AC'97\n"); - snd_printk(KERN_ERR " Try reloading the ALSA driver, if you find something\n"); - snd_printk(KERN_ERR " broken or not working on your soundcard upon\n"); - snd_printk(KERN_ERR " this message please report to alsa-devel@alsa-project.org\n"); + dev_err(chip->card->dev, "never read ISV3 & ISV4 from AC'97\n"); + dev_err(chip->card->dev, + "Try reloading the ALSA driver, if you find something\n"); + dev_err(chip->card->dev, + "broken or not working on your soundcard upon\n"); + dev_err(chip->card->dev, + "this message please report to alsa-devel@alsa-project.org\n"); return -EIO; #endif @@ -3061,9 +3266,14 @@ static void cs46xx_enable_stream_irqs(struct snd_cs46xx *chip) snd_cs46xx_poke(chip, BA1_CIE, tmp); /* capture interrupt enable */ } -int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) +int snd_cs46xx_start_dsp(struct snd_cs46xx *chip) { unsigned int tmp; +#ifdef CONFIG_SND_CS46XX_NEW_DSP + int i; +#endif + int err; + /* * Reset the processor. */ @@ -3072,45 +3282,33 @@ int __devinit snd_cs46xx_start_dsp(struct snd_cs46xx *chip) * Download the image to the processor. */ #ifdef CONFIG_SND_CS46XX_NEW_DSP -#if 0 - if (cs46xx_dsp_load_module(chip, &cwcemb80_module) < 0) { - snd_printk(KERN_ERR "image download error\n"); - return -EIO; - } -#endif - - if (cs46xx_dsp_load_module(chip, &cwc4630_module) < 0) { - snd_printk(KERN_ERR "image download error [cwc4630]\n"); - return -EIO; - } - - if (cs46xx_dsp_load_module(chip, &cwcasync_module) < 0) { - snd_printk(KERN_ERR "image download error [cwcasync]\n"); - return -EIO; - } - - if (cs46xx_dsp_load_module(chip, &cwcsnoop_module) < 0) { - snd_printk(KERN_ERR "image download error [cwcsnoop]\n"); - return -EIO; - } - - if (cs46xx_dsp_load_module(chip, &cwcbinhack_module) < 0) { - snd_printk(KERN_ERR "image download error [cwcbinhack]\n"); - return -EIO; - } - - if (cs46xx_dsp_load_module(chip, &cwcdma_module) < 0) { - snd_printk(KERN_ERR "image download error [cwcdma]\n"); - return -EIO; + for (i = 0; i < CS46XX_DSP_MODULES; i++) { + err = load_firmware(chip, &chip->modules[i], module_names[i]); + if (err < 0) { + dev_err(chip->card->dev, "firmware load error [%s]\n", + module_names[i]); + return err; + } + err = cs46xx_dsp_load_module(chip, chip->modules[i]); + if (err < 0) { + dev_err(chip->card->dev, "image download error [%s]\n", + module_names[i]); + return err; + } } if (cs46xx_dsp_scb_and_task_init(chip) < 0) return -EIO; #else + err = load_firmware(chip); + if (err < 0) + return err; + /* old image */ - if (snd_cs46xx_download_image(chip) < 0) { - snd_printk(KERN_ERR "image download error\n"); - return -EIO; + err = snd_cs46xx_download_image(chip); + if (err < 0) { + dev_err(chip->card->dev, "image download error\n"); + return err; } /* @@ -3162,7 +3360,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip) u32 idx, valid_slots,tmp,powerdown = 0; u16 modem_power,pin_config,logic_type; - snd_printdd ("cs46xx: cs46xx_setup_eapd_slot()+\n"); + dev_dbg(chip->card->dev, "cs46xx_setup_eapd_slot()+\n"); /* * See if the devices are powered down. If so, we must power them up first @@ -3180,7 +3378,8 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip) * stuff. */ if(chip->nr_ac97_codecs != 2) { - snd_printk (KERN_ERR "cs46xx: cs46xx_setup_eapd_slot() - no secondary codec configured\n"); + dev_err(chip->card->dev, + "cs46xx_setup_eapd_slot() - no secondary codec configured\n"); return -EINVAL; } @@ -3221,7 +3420,7 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip) snd_cs46xx_pokeBA0(chip, BA0_ACOSV, valid_slots); if ( cs46xx_wait_for_fifo(chip,1) ) { - snd_printdd("FIFO is busy\n"); + dev_dbg(chip->card->dev, "FIFO is busy\n"); return -EINVAL; } @@ -3242,7 +3441,9 @@ static int voyetra_setup_eapd_slot(struct snd_cs46xx *chip) * Wait for command to complete */ if ( cs46xx_wait_for_fifo(chip,200) ) { - snd_printdd("failed waiting for FIFO at addr (%02X)\n",idx); + dev_dbg(chip->card->dev, + "failed waiting for FIFO at addr (%02X)\n", + idx); return -EINVAL; } @@ -3331,14 +3532,14 @@ static void amp_hercules(struct snd_cs46xx *chip, int change) chip->amplifier += change; if (chip->amplifier && !old) { - snd_printdd ("Hercules amplifier ON\n"); + dev_dbg(chip->card->dev, "Hercules amplifier ON\n"); snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE2 | val1); /* enable EGPIO2 output */ snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, EGPIOPTR_GPPT2 | val2); /* open-drain on output */ } else if (old && !chip->amplifier) { - snd_printdd ("Hercules amplifier OFF\n"); + dev_dbg(chip->card->dev, "Hercules amplifier OFF\n"); snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, val1 & ~EGPIODR_GPOE2); /* disable */ snd_cs46xx_pokeBA0(chip, BA0_EGPIOPTR, val2 & ~EGPIOPTR_GPPT2); /* disable */ } @@ -3346,7 +3547,7 @@ static void amp_hercules(struct snd_cs46xx *chip, int change) static void voyetra_mixer_init (struct snd_cs46xx *chip) { - snd_printdd ("initializing Voyetra mixer\n"); + dev_dbg(chip->card->dev, "initializing Voyetra mixer\n"); /* Enable SPDIF out */ snd_cs46xx_pokeBA0(chip, BA0_EGPIODR, EGPIODR_GPOE0); @@ -3364,7 +3565,7 @@ static void hercules_mixer_init (struct snd_cs46xx *chip) /* set EGPIO to default */ hercules_init(chip); - snd_printdd ("initializing Hercules mixer\n"); + dev_dbg(chip->card->dev, "initializing Hercules mixer\n"); #ifdef CONFIG_SND_CS46XX_NEW_DSP if (chip->in_suspend) @@ -3375,7 +3576,9 @@ static void hercules_mixer_init (struct snd_cs46xx *chip) kctl = snd_ctl_new1(&snd_hercules_controls[idx], chip); if ((err = snd_ctl_add(card, kctl)) < 0) { - printk (KERN_ERR "cs46xx: failed to initialize Hercules mixer (%d)\n",err); + dev_err(card->dev, + "failed to initialize Hercules mixer (%d)\n", + err); break; } } @@ -3477,7 +3680,7 @@ struct cs_card_type void (*mixer_init)(struct snd_cs46xx *); }; -static struct cs_card_type __devinitdata cards[] = { +static struct cs_card_type cards[] = { { .vendor = 0x1489, .id = 0x7001, @@ -3647,8 +3850,7 @@ static int snd_cs46xx_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "cs46xx: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -3717,10 +3919,10 @@ SIMPLE_DEV_PM_OPS(snd_cs46xx_pm, snd_cs46xx_suspend, snd_cs46xx_resume); /* */ -int __devinit snd_cs46xx_create(struct snd_card *card, - struct pci_dev * pci, +int snd_cs46xx_create(struct snd_card *card, + struct pci_dev *pci, int external_amp, int thinkpad, - struct snd_cs46xx ** rchip) + struct snd_cs46xx **rchip) { struct snd_cs46xx *chip; int err, idx; @@ -3753,7 +3955,8 @@ int __devinit snd_cs46xx_create(struct snd_card *card, chip->ba1_addr = pci_resource_start(pci, 1); if (chip->ba0_addr == 0 || chip->ba0_addr == (unsigned long)~0 || chip->ba1_addr == 0 || chip->ba1_addr == (unsigned long)~0) { - snd_printk(KERN_ERR "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n", + dev_err(chip->card->dev, + "wrong address(es) - ba0 = 0x%lx, ba1 = 0x%lx\n", chip->ba0_addr, chip->ba1_addr); snd_cs46xx_free(chip); return -ENOMEM; @@ -3790,7 +3993,8 @@ int __devinit snd_cs46xx_create(struct snd_card *card, for (cp = &cards[0]; cp->name; cp++) { if (cp->vendor == ss_vendor && cp->id == ss_card) { - snd_printdd ("hack for %s enabled\n", cp->name); + dev_dbg(chip->card->dev, "hack for %s enabled\n", + cp->name); chip->amplifier_ctrl = cp->amp; chip->active_ctrl = cp->active; @@ -3803,12 +4007,14 @@ int __devinit snd_cs46xx_create(struct snd_card *card, } if (external_amp) { - snd_printk(KERN_INFO "Crystal EAPD support forced on.\n"); + dev_info(chip->card->dev, + "Crystal EAPD support forced on.\n"); chip->amplifier_ctrl = amp_voyetra; } if (thinkpad) { - snd_printk(KERN_INFO "Activating CLKRUN hack for Thinkpad.\n"); + dev_info(chip->card->dev, + "Activating CLKRUN hack for Thinkpad.\n"); chip->active_ctrl = clkrun_hack; clkrun_init(chip); } @@ -3826,14 +4032,16 @@ int __devinit snd_cs46xx_create(struct snd_card *card, region = &chip->region.idx[idx]; if ((region->resource = request_mem_region(region->base, region->size, region->name)) == NULL) { - snd_printk(KERN_ERR "unable to request memory region 0x%lx-0x%lx\n", + dev_err(chip->card->dev, + "unable to request memory region 0x%lx-0x%lx\n", region->base, region->base + region->size - 1); snd_cs46xx_free(chip); return -EBUSY; } region->remap_addr = ioremap_nocache(region->base, region->size); if (region->remap_addr == NULL) { - snd_printk(KERN_ERR "%s ioremap problem\n", region->name); + dev_err(chip->card->dev, + "%s ioremap problem\n", region->name); snd_cs46xx_free(chip); return -ENOMEM; } @@ -3841,7 +4049,7 @@ int __devinit snd_cs46xx_create(struct snd_card *card, if (request_irq(pci->irq, snd_cs46xx_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq); snd_cs46xx_free(chip); return -EBUSY; } @@ -3879,8 +4087,6 @@ int __devinit snd_cs46xx_create(struct snd_card *card, chip->active_ctrl(chip, -1); /* disable CLKRUN */ - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index 1686b4f4c44..1c4a0fb3ffe 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c @@ -85,12 +85,15 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 address = (hival & 0x00FFF) << 5; address |= loval >> 15; - snd_printdd("handle_wideop[1]: %05x:%05x addr %04x\n",hival,loval,address); + dev_dbg(chip->card->dev, + "handle_wideop[1]: %05x:%05x addr %04x\n", + hival, loval, address); if ( !(address & 0x8000) ) { address += (ins->code.offset / 2) - overlay_begin_address; } else { - snd_printdd("handle_wideop[1]: ROM symbol not reallocated\n"); + dev_dbg(chip->card->dev, + "handle_wideop[1]: ROM symbol not reallocated\n"); } hival &= 0xFF000; @@ -102,8 +105,9 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 address = (hival & 0x00FFF) << 5; address |= loval >> 15; - snd_printdd("handle_wideop:[2] %05x:%05x addr %04x\n",hival,loval,address); - nreallocated ++; + dev_dbg(chip->card->dev, + "handle_wideop:[2] %05x:%05x addr %04x\n", + hival, loval, address); nreallocated++; } /* wide_opcodes[j] == wide_op */ } /* for */ } /* mod_type == 0 ... */ @@ -113,7 +117,8 @@ static int shadow_and_reallocate_code (struct snd_cs46xx * chip, u32 * data, u32 ins->code.data[ins->code.size++] = hival; } - snd_printdd("dsp_spos: %d instructions reallocated\n",nreallocated); + dev_dbg(chip->card->dev, + "dsp_spos: %d instructions reallocated\n", nreallocated); return nreallocated; } @@ -157,7 +162,8 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul for (i = 0;i < module->symbol_table.nsymbols; ++i) { if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) { - snd_printk(KERN_ERR "dsp_spos: symbol table is full\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol table is full\n"); return -ENOMEM; } @@ -176,8 +182,11 @@ static int add_symbols (struct snd_cs46xx * chip, struct dsp_module_desc * modul ins->symbol_table.nsymbols++; } else { - /* if (0) printk ("dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n", - module->symbol_table.symbols[i].symbol_name); */ +#if 0 + dev_dbg(chip->card->dev, + "dsp_spos: symbol <%s> duplicated, probably nothing wrong with that (Cirrus?)\n", + module->symbol_table.symbols[i].symbol_name); */ +#endif } } @@ -192,14 +201,15 @@ add_symbol (struct snd_cs46xx * chip, char * symbol_name, u32 address, int type) int index; if (ins->symbol_table.nsymbols == (DSP_MAX_SYMBOLS - 1)) { - snd_printk(KERN_ERR "dsp_spos: symbol table is full\n"); + dev_err(chip->card->dev, "dsp_spos: symbol table is full\n"); return NULL; } if (cs46xx_dsp_lookup_symbol(chip, symbol_name, type) != NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol <%s> duplicated\n", symbol_name); + dev_err(chip->card->dev, + "dsp_spos: symbol <%s> duplicated\n", symbol_name); return NULL; } @@ -305,19 +315,20 @@ static int dsp_load_parameter(struct snd_cs46xx *chip, u32 doffset, dsize; if (!parameter) { - snd_printdd("dsp_spos: module got no parameter segment\n"); + dev_dbg(chip->card->dev, + "dsp_spos: module got no parameter segment\n"); return 0; } doffset = (parameter->offset * 4 + DSP_PARAMETER_BYTE_OFFSET); dsize = parameter->size * 4; - snd_printdd("dsp_spos: " - "downloading parameter data to chip (%08x-%08x)\n", + dev_dbg(chip->card->dev, + "dsp_spos: downloading parameter data to chip (%08x-%08x)\n", doffset,doffset + dsize); if (snd_cs46xx_download (chip, parameter->data, doffset, dsize)) { - snd_printk(KERN_ERR "dsp_spos: " - "failed to download parameter data to DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to download parameter data to DSP\n"); return -EINVAL; } return 0; @@ -329,18 +340,21 @@ static int dsp_load_sample(struct snd_cs46xx *chip, u32 doffset, dsize; if (!sample) { - snd_printdd("dsp_spos: module got no sample segment\n"); + dev_dbg(chip->card->dev, + "dsp_spos: module got no sample segment\n"); return 0; } doffset = (sample->offset * 4 + DSP_SAMPLE_BYTE_OFFSET); dsize = sample->size * 4; - snd_printdd("dsp_spos: downloading sample data to chip (%08x-%08x)\n", + dev_dbg(chip->card->dev, + "dsp_spos: downloading sample data to chip (%08x-%08x)\n", doffset,doffset + dsize); if (snd_cs46xx_download (chip,sample->data,doffset,dsize)) { - snd_printk(KERN_ERR "dsp_spos: failed to sample data to DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to sample data to DSP\n"); return -EINVAL; } return 0; @@ -354,14 +368,16 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m int err; if (ins->nmodules == DSP_MAX_MODULES - 1) { - snd_printk(KERN_ERR "dsp_spos: to many modules loaded into DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: to many modules loaded into DSP\n"); return -ENOMEM; } - snd_printdd("dsp_spos: loading module %s into DSP\n", module->module_name); + dev_dbg(chip->card->dev, + "dsp_spos: loading module %s into DSP\n", module->module_name); if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing parameter area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing parameter area\n"); snd_cs46xx_clear_BA1(chip, DSP_PARAMETER_BYTE_OFFSET, DSP_PARAMETER_BYTE_SIZE); } @@ -371,7 +387,7 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m return err; if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing sample area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing sample area\n"); snd_cs46xx_clear_BA1(chip, DSP_SAMPLE_BYTE_OFFSET, DSP_SAMPLE_BYTE_SIZE); } @@ -381,15 +397,17 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m return err; if (ins->nmodules == 0) { - snd_printdd("dsp_spos: clearing code area\n"); + dev_dbg(chip->card->dev, "dsp_spos: clearing code area\n"); snd_cs46xx_clear_BA1(chip, DSP_CODE_BYTE_OFFSET, DSP_CODE_BYTE_SIZE); } if (code == NULL) { - snd_printdd("dsp_spos: module got no code segment\n"); + dev_dbg(chip->card->dev, + "dsp_spos: module got no code segment\n"); } else { if (ins->code.offset + code->size > DSP_CODE_BYTE_SIZE) { - snd_printk(KERN_ERR "dsp_spos: no space available in DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: no space available in DSP\n"); return -ENOMEM; } @@ -401,19 +419,22 @@ int cs46xx_dsp_load_module (struct snd_cs46xx * chip, struct dsp_module_desc * m if (snd_BUG_ON(!module->symbol_table.symbols)) return -ENOMEM; if (add_symbols(chip,module)) { - snd_printk(KERN_ERR "dsp_spos: failed to load symbol table\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to load symbol table\n"); return -ENOMEM; } doffset = (code->offset * 4 + ins->code.offset * 4 + DSP_CODE_BYTE_OFFSET); dsize = code->size * 4; - snd_printdd("dsp_spos: downloading code to chip (%08x-%08x)\n", + dev_dbg(chip->card->dev, + "dsp_spos: downloading code to chip (%08x-%08x)\n", doffset,doffset + dsize); module->nfixups = shadow_and_reallocate_code(chip,code->data,code->size,module->overlay_begin_address); if (snd_cs46xx_download (chip,(ins->code.data + ins->code.offset),doffset,dsize)) { - snd_printk(KERN_ERR "dsp_spos: failed to download code to DSP\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to download code to DSP\n"); return -EINVAL; } @@ -447,7 +468,7 @@ cs46xx_dsp_lookup_symbol (struct snd_cs46xx * chip, char * symbol_name, int symb } #if 0 - printk ("dsp_spos: symbol <%s> type %02x not found\n", + dev_err(chip->card->dev, "dsp_spos: symbol <%s> type %02x not found\n", symbol_name,symbol_type); #endif @@ -910,7 +931,6 @@ int cs46xx_dsp_proc_done (struct snd_cs46xx *chip) } #endif /* CONFIG_PROC_FS */ -static int debug_tree; static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data, u32 dest, int size) { @@ -919,13 +939,13 @@ static void _dsp_create_task_tree (struct snd_cs46xx *chip, u32 * task_data, int i; for (i = 0; i < size; ++i) { - if (debug_tree) printk ("addr %p, val %08x\n",spdst,task_data[i]); + dev_dbg(chip->card->dev, "addr %p, val %08x\n", + spdst, task_data[i]); writel(task_data[i],spdst); spdst += sizeof(u32); } } -static int debug_scb; static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest) { void __iomem *spdst = chip->region.idx[1].remap_addr + @@ -933,7 +953,8 @@ static void _dsp_create_scb (struct snd_cs46xx *chip, u32 * scb_data, u32 dest) int i; for (i = 0; i < 0x10; ++i) { - if (debug_scb) printk ("addr %p, val %08x\n",spdst,scb_data[i]); + dev_dbg(chip->card->dev, "addr %p, val %08x\n", + spdst, scb_data[i]); writel(scb_data[i],spdst); spdst += sizeof(u32); } @@ -960,7 +981,8 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam int index; if (ins->nscb == DSP_MAX_SCB_DESC - 1) { - snd_printk(KERN_ERR "dsp_spos: got no place for other SCB\n"); + dev_err(chip->card->dev, + "dsp_spos: got no place for other SCB\n"); return NULL; } @@ -991,7 +1013,8 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) struct dsp_task_descriptor * desc = NULL; if (ins->ntask == DSP_MAX_TASK_DESC - 1) { - snd_printk(KERN_ERR "dsp_spos: got no place for other TASK\n"); + dev_err(chip->card->dev, + "dsp_spos: got no place for other TASK\n"); return NULL; } @@ -1031,7 +1054,7 @@ cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 desc->data = scb_data; _dsp_create_scb(chip,scb_data,dest); } else { - snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); + dev_err(chip->card->dev, "dsp_spos: failed to map SCB\n"); #ifdef CONFIG_PM_SLEEP kfree(scb_data); #endif @@ -1052,7 +1075,7 @@ cs46xx_dsp_create_task_tree (struct snd_cs46xx *chip, char * name, u32 * task_da desc->data = task_data; _dsp_create_task_tree(chip,task_data,dest,size); } else { - snd_printk(KERN_ERR "dsp_spos: failed to map TASK\n"); + dev_err(chip->card->dev, "dsp_spos: failed to map TASK\n"); } return desc; @@ -1105,31 +1128,36 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) null_algorithm = cs46xx_dsp_lookup_symbol(chip, "NULLALGORITHM", SYMBOL_CODE); if (null_algorithm == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol NULLALGORITHM not found\n"); return -EIO; } fg_task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "FGTASKTREEHEADERCODE", SYMBOL_CODE); if (fg_task_tree_header_code == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol FGTASKTREEHEADERCODE not found\n"); return -EIO; } task_tree_header_code = cs46xx_dsp_lookup_symbol(chip, "TASKTREEHEADERCODE", SYMBOL_CODE); if (task_tree_header_code == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol TASKTREEHEADERCODE not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol TASKTREEHEADERCODE not found\n"); return -EIO; } task_tree_thread = cs46xx_dsp_lookup_symbol(chip, "TASKTREETHREAD", SYMBOL_CODE); if (task_tree_thread == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol TASKTREETHREAD not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol TASKTREETHREAD not found\n"); return -EIO; } magic_snoop_task = cs46xx_dsp_lookup_symbol(chip, "MAGICSNOOPTASK", SYMBOL_CODE); if (magic_snoop_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol MAGICSNOOPTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol MAGICSNOOPTASK not found\n"); return -EIO; } @@ -1476,7 +1504,7 @@ int cs46xx_dsp_scb_and_task_init (struct snd_cs46xx *chip) return 0; _fail_end: - snd_printk(KERN_ERR "dsp_spos: failed to setup SCB's in DSP\n"); + dev_err(chip->card->dev, "dsp_spos: failed to setup SCB's in DSP\n"); return -EINVAL; } @@ -1491,18 +1519,21 @@ static int cs46xx_dsp_async_init (struct snd_cs46xx *chip, s16_async_codec_input_task = cs46xx_dsp_lookup_symbol(chip, "S16_ASYNCCODECINPUTTASK", SYMBOL_CODE); if (s16_async_codec_input_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol S16_ASYNCCODECINPUTTASK not found\n"); return -EIO; } spdifo_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFOTASK", SYMBOL_CODE); if (spdifo_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol SPDIFOTASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol SPDIFOTASK not found\n"); return -EIO; } spdifi_task = cs46xx_dsp_lookup_symbol(chip, "SPDIFITASK", SYMBOL_CODE); if (spdifi_task == NULL) { - snd_printk(KERN_ERR "dsp_spos: symbol SPDIFITASK not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol SPDIFITASK not found\n"); return -EIO; } @@ -1883,7 +1914,8 @@ int cs46xx_poke_via_dsp (struct snd_cs46xx *chip, u32 address, u32 data) } if (i == 25) { - snd_printk(KERN_ERR "dsp_spos: SPIOWriteTask not responding\n"); + dev_err(chip->card->dev, + "dsp_spos: SPIOWriteTask not responding\n"); return -EBUSY; } diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 409e8764fbe..8284bc9b585 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c @@ -233,8 +233,11 @@ void cs46xx_dsp_proc_free_scb_desc (struct dsp_scb_descriptor * scb) { if (scb->proc_info) { struct proc_scb_info * scb_info = scb->proc_info->private_data; + struct snd_cs46xx *chip = scb_info->chip; - snd_printdd("cs46xx_dsp_proc_free_scb_desc: freeing %s\n",scb->scb_name); + dev_dbg(chip->card->dev, + "cs46xx_dsp_proc_free_scb_desc: freeing %s\n", + scb->scb_name); snd_info_free_entry(scb->proc_info); scb->proc_info = NULL; @@ -305,7 +308,7 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u scb_data[SCBfuncEntryPtr] &= 0xFFFF0000; scb_data[SCBfuncEntryPtr] |= task_entry->address; - snd_printdd("dsp_spos: creating SCB <%s>\n",name); + dev_dbg(chip->card->dev, "dsp_spos: creating SCB <%s>\n", name); scb = cs46xx_dsp_create_scb(chip,name,scb_data,dest); @@ -320,9 +323,15 @@ _dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u /* update parent SCB */ if (scb->parent_scb_ptr) { #if 0 - printk ("scb->parent_scb_ptr = %s\n",scb->parent_scb_ptr->scb_name); - printk ("scb->parent_scb_ptr->next_scb_ptr = %s\n",scb->parent_scb_ptr->next_scb_ptr->scb_name); - printk ("scb->parent_scb_ptr->sub_list_ptr = %s\n",scb->parent_scb_ptr->sub_list_ptr->scb_name); + dev_dbg(chip->card->dev, + "scb->parent_scb_ptr = %s\n", + scb->parent_scb_ptr->scb_name); + dev_dbg(chip->card->dev, + "scb->parent_scb_ptr->next_scb_ptr = %s\n", + scb->parent_scb_ptr->next_scb_ptr->scb_name); + dev_dbg(chip->card->dev, + "scb->parent_scb_ptr->sub_list_ptr = %s\n", + scb->parent_scb_ptr->sub_list_ptr->scb_name); #endif /* link to parent SCB */ if (scb_child_type == SCB_ON_PARENT_NEXT_SCB) { @@ -368,7 +377,8 @@ cs46xx_dsp_create_generic_scb (struct snd_cs46xx *chip, char * name, u32 * scb_d SYMBOL_CODE); if (task_entry == NULL) { - snd_printk (KERN_ERR "dsp_spos: symbol %s not found\n",task_entry_name); + dev_err(chip->card->dev, + "dsp_spos: symbol %s not found\n", task_entry_name); return NULL; } @@ -582,7 +592,8 @@ cs46xx_dsp_create_pcm_reader_scb(struct snd_cs46xx * chip, char * scb_name, SYMBOL_CODE); if (ins->null_algorithm == NULL) { - snd_printk (KERN_ERR "dsp_spos: symbol NULLALGORITHM not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol NULLALGORITHM not found\n"); return NULL; } } @@ -612,7 +623,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name, unsigned int phiIncr; unsigned int correctionPerGOF, correctionPerSec; - snd_printdd( "dsp_spos: setting %s rate to %u\n",scb_name,rate); + dev_dbg(chip->card->dev, "dsp_spos: setting %s rate to %u\n", + scb_name, rate); /* * Compute the values used to drive the actual sample rate conversion. @@ -670,7 +682,8 @@ cs46xx_dsp_create_src_task_scb(struct snd_cs46xx * chip, char * scb_name, SYMBOL_CODE); if (ins->s16_up == NULL) { - snd_printk (KERN_ERR "dsp_spos: symbol S16_UPSRC not found\n"); + dev_err(chip->card->dev, + "dsp_spos: symbol S16_UPSRC not found\n"); return NULL; } } @@ -1265,7 +1278,7 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, the Sample Rate Converted (which could alter the raw data stream ...) */ if (sample_rate == 48000) { - snd_printdd ("IEC958 pass through\n"); + dev_dbg(chip->card->dev, "IEC958 pass through\n"); /* Hack to bypass creating a new SRC */ pass_through = 1; } @@ -1299,13 +1312,14 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, } if (pcm_index == -1) { - snd_printk (KERN_ERR "dsp_spos: no free PCM channel\n"); + dev_err(chip->card->dev, "dsp_spos: no free PCM channel\n"); return NULL; } if (src_scb == NULL) { if (ins->nsrc_scb >= DSP_MAX_SRC_NR) { - snd_printk(KERN_ERR "dsp_spos: to many SRC instances\n!"); + dev_err(chip->card->dev, + "dsp_spos: to many SRC instances\n!"); return NULL; } @@ -1331,7 +1345,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, snprintf (scb_name,DSP_MAX_SCB_NAME,"SrcTask_SCB%d",src_index); - snd_printdd( "dsp_spos: creating SRC \"%s\"\n",scb_name); + dev_dbg(chip->card->dev, + "dsp_spos: creating SRC \"%s\"\n", scb_name); src_scb = cs46xx_dsp_create_src_task_scb(chip,scb_name, sample_rate, src_output_buffer_addr[src_index], @@ -1343,7 +1358,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, pass_through); if (!src_scb) { - snd_printk (KERN_ERR "dsp_spos: failed to create SRCtaskSCB\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to create SRCtaskSCB\n"); return NULL; } @@ -1355,8 +1371,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, snprintf (scb_name,DSP_MAX_SCB_NAME,"PCMReader_SCB%d",pcm_index); - snd_printdd( "dsp_spos: creating PCM \"%s\" (%d)\n",scb_name, - pcm_channel_id); + dev_dbg(chip->card->dev, "dsp_spos: creating PCM \"%s\" (%d)\n", + scb_name, pcm_channel_id); pcm_scb = cs46xx_dsp_create_pcm_reader_scb(chip,scb_name, pcm_reader_buffer_addr[pcm_index], @@ -1369,7 +1385,8 @@ cs46xx_dsp_create_pcm_channel (struct snd_cs46xx * chip, ); if (!pcm_scb) { - snd_printk (KERN_ERR "dsp_spos: failed to create PCMreaderSCB\n"); + dev_err(chip->card->dev, + "dsp_spos: failed to create PCMreaderSCB\n"); return NULL; } @@ -1419,7 +1436,8 @@ int cs46xx_dsp_pcm_channel_set_period (struct snd_cs46xx * chip, temp |= DMA_RQ_C1_SOURCE_MOD16; break; default: - snd_printdd ("period size (%d) not supported by HW\n", period_size); + dev_dbg(chip->card->dev, + "period size (%d) not supported by HW\n", period_size); return -EINVAL; } @@ -1457,7 +1475,8 @@ int cs46xx_dsp_pcm_ostream_set_period (struct snd_cs46xx * chip, temp |= DMA_RQ_C1_DEST_MOD16; break; default: - snd_printdd ("period size (%d) not supported by HW\n", period_size); + dev_dbg(chip->card->dev, + "period size (%d) not supported by HW\n", period_size); return -EINVAL; } diff --git a/sound/pci/cs46xx/imgs/cwc4630.h b/sound/pci/cs46xx/imgs/cwc4630.h deleted file mode 100644 index 37c4f1318dc..00000000000 --- a/sound/pci/cs46xx/imgs/cwc4630.h +++ /dev/null @@ -1,320 +0,0 @@ -/* generated from cwc4630.osp DO NOT MODIFY */ - -#ifndef __HEADER_cwc4630_H__ -#define __HEADER_cwc4630_H__ - -static struct dsp_symbol_entry cwc4630_symbols[] = { - { 0x0000, "BEGINADDRESS",0x00 }, - { 0x8000, "EXECCHILD",0x03 }, - { 0x8001, "EXECCHILD_98",0x03 }, - { 0x8003, "EXECCHILD_PUSH1IND",0x03 }, - { 0x8008, "EXECSIBLING",0x03 }, - { 0x800a, "EXECSIBLING_298",0x03 }, - { 0x800b, "EXECSIBLING_2IND1",0x03 }, - { 0x8010, "TIMINGMASTER",0x03 }, - { 0x804f, "S16_CODECINPUTTASK",0x03 }, - { 0x805e, "PCMSERIALINPUTTASK",0x03 }, - { 0x806d, "S16_MIX_TO_OSTREAM",0x03 }, - { 0x809a, "S16_MIX",0x03 }, - { 0x80bb, "S16_UPSRC",0x03 }, - { 0x813b, "MIX3_EXP",0x03 }, - { 0x8164, "DECIMATEBYPOW2",0x03 }, - { 0x8197, "VARIDECIMATE",0x03 }, - { 0x81f2, "_3DINPUTTASK",0x03 }, - { 0x820a, "_3DPRLGCINPTASK",0x03 }, - { 0x8227, "_3DSTEREOINPUTTASK",0x03 }, - { 0x8242, "_3DOUTPUTTASK",0x03 }, - { 0x82c4, "HRTF_MORPH_TASK",0x03 }, - { 0x82c6, "WAIT4DATA",0x03 }, - { 0x82fa, "PROLOGIC",0x03 }, - { 0x8496, "DECORRELATOR",0x03 }, - { 0x84a4, "STEREO2MONO",0x03 }, - { 0x0070, "SPOSCB",0x02 }, - { 0x0107, "TASKTREETHREAD",0x03 }, - { 0x013c, "TASKTREEHEADERCODE",0x03 }, - { 0x0145, "FGTASKTREEHEADERCODE",0x03 }, - { 0x0169, "NULLALGORITHM",0x03 }, - { 0x016d, "HFGEXECCHILD",0x03 }, - { 0x016e, "HFGEXECCHILD_98",0x03 }, - { 0x0170, "HFGEXECCHILD_PUSH1IND",0x03 }, - { 0x0173, "HFGEXECSIBLING",0x03 }, - { 0x0175, "HFGEXECSIBLING_298",0x03 }, - { 0x0176, "HFGEXECSIBLING_2IND1",0x03 }, - { 0x0179, "S16_CODECOUTPUTTASK",0x03 }, - { 0x0194, "#CODE_END",0x00 }, -}; /* cwc4630 symbols */ - -static u32 cwc4630_code[] = { -/* BEGINADDRESS */ -/* 0000 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 0002 */ 0x00001705,0x00001400,0x000a411e,0x00001003, -/* 0004 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 0006 */ 0x00009705,0x00001400,0x000a411e,0x00001003, -/* 0008 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 000A */ 0x00011705,0x00001400,0x000a411e,0x00001003, -/* 000C */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 000E */ 0x00019705,0x00001400,0x000a411e,0x00001003, -/* 0010 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 0012 */ 0x00021705,0x00001400,0x000a411e,0x00001003, -/* 0014 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 0016 */ 0x00029705,0x00001400,0x000a411e,0x00001003, -/* 0018 */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 001A */ 0x00031705,0x00001400,0x000a411e,0x00001003, -/* 001C */ 0x00040730,0x00001002,0x000f619e,0x00001003, -/* 001E */ 0x00039705,0x00001400,0x000a411e,0x00001003, -/* 0020 */ 0x000fe19e,0x00001003,0x0009c730,0x00001003, -/* 0022 */ 0x0008e19c,0x00001003,0x000083c1,0x00093040, -/* 0024 */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 0026 */ 0x00009705,0x00001400,0x000a211e,0x00001003, -/* 0028 */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 002A */ 0x00011705,0x00001400,0x000a211e,0x00001003, -/* 002C */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 002E */ 0x00019705,0x00001400,0x000a211e,0x00001003, -/* 0030 */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 0032 */ 0x00021705,0x00001400,0x000a211e,0x00001003, -/* 0034 */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 0036 */ 0x00029705,0x00001400,0x000a211e,0x00001003, -/* 0038 */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 003A */ 0x00031705,0x00001400,0x000a211e,0x00001003, -/* 003C */ 0x00098730,0x00001002,0x000ee19e,0x00001003, -/* 003E */ 0x00039705,0x00001400,0x000a211e,0x00001003, -/* 0040 */ 0x0001a730,0x00001008,0x000e2730,0x00001002, -/* 0042 */ 0x0000a731,0x00001002,0x0000a731,0x00001002, -/* 0044 */ 0x0000a731,0x00001002,0x0000a731,0x00001002, -/* 0046 */ 0x0000a731,0x00001002,0x0000a731,0x00001002, -/* 0048 */ 0x00000000,0x00000000,0x000f619c,0x00001003, -/* 004A */ 0x0007f801,0x000c0000,0x00000037,0x00001000, -/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 004E */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0050 */ 0x00000000,0x000c0000,0x00000000,0x00000000, -/* 0052 */ 0x0000373c,0x00001000,0x00000000,0x00000000, -/* 0054 */ 0x000ee19c,0x00001003,0x0007f801,0x000c0000, -/* 0056 */ 0x00000037,0x00001000,0x00000000,0x00000000, -/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 005A */ 0x00000000,0x00000000,0x0000273c,0x00001000, -/* 005C */ 0x00000033,0x00001000,0x000e679e,0x00001003, -/* 005E */ 0x00007705,0x00001400,0x000ac71e,0x00001003, -/* 0060 */ 0x00087fc1,0x000c3be0,0x0007f801,0x000c0000, -/* 0062 */ 0x00000037,0x00001000,0x00000000,0x00000000, -/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0066 */ 0x00000000,0x00000000,0x0000a730,0x00001003, -/* 0068 */ 0x00000033,0x00001000,0x0007f801,0x000c0000, -/* 006A */ 0x00000037,0x00001000,0x00000000,0x00000000, -/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 006E */ 0x00000000,0x00000000,0x00000000,0x000c0000, -/* 0070 */ 0x00000032,0x00001000,0x0000273d,0x00001000, -/* 0072 */ 0x0004a730,0x00001003,0x00000f41,0x00097140, -/* 0074 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040, -/* 0076 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0, -/* 0078 */ 0x00000000,0x00000000,0x0001bf05,0x0003fc40, -/* 007A */ 0x00002725,0x000aa400,0x00013705,0x00093a00, -/* 007C */ 0x0000002e,0x0009d6c0,0x0002ef8a,0x00000000, -/* 007E */ 0x00040630,0x00001004,0x0004ef0a,0x000eb785, -/* 0080 */ 0x0003fc8a,0x00000000,0x00000000,0x000c70e0, -/* 0082 */ 0x0007d182,0x0002c640,0x00008630,0x00001004, -/* 0084 */ 0x000799b8,0x0002c6c0,0x00031705,0x00092240, -/* 0086 */ 0x00039f05,0x000932c0,0x0003520a,0x00000000, -/* 0088 */ 0x00070731,0x0000100b,0x00010705,0x000b20c0, -/* 008A */ 0x00000000,0x000eba44,0x00032108,0x000c60c4, -/* 008C */ 0x00065208,0x000c2917,0x000486b0,0x00001007, -/* 008E */ 0x00012f05,0x00036880,0x0002818e,0x000c0000, -/* 0090 */ 0x0004410a,0x00000000,0x00048630,0x00001007, -/* 0092 */ 0x00029705,0x000c0000,0x00000000,0x00000000, -/* 0094 */ 0x00003fc1,0x0003fc40,0x000037c1,0x00091b40, -/* 0096 */ 0x00003fc1,0x000911c0,0x000037c1,0x000957c0, -/* 0098 */ 0x00003fc1,0x000951c0,0x000037c1,0x00000000, -/* 009A */ 0x00003fc1,0x000991c0,0x000037c1,0x00000000, -/* 009C */ 0x00003fc1,0x0009d1c0,0x000037c1,0x00000000, -/* 009E */ 0x0001ccc1,0x000915c0,0x0001c441,0x0009d800, -/* 00A0 */ 0x0009cdc1,0x00091240,0x0001c541,0x00091d00, -/* 00A2 */ 0x0009cfc1,0x00095240,0x0001c741,0x00095c80, -/* 00A4 */ 0x000e8ca9,0x00099240,0x000e85ad,0x00095640, -/* 00A6 */ 0x00069ca9,0x00099d80,0x000e952d,0x00099640, -/* 00A8 */ 0x000eaca9,0x0009d6c0,0x000ea5ad,0x00091a40, -/* 00AA */ 0x0006bca9,0x0009de80,0x000eb52d,0x00095a40, -/* 00AC */ 0x000ecca9,0x00099ac0,0x000ec5ad,0x0009da40, -/* 00AE */ 0x000edca9,0x0009d300,0x000a6e0a,0x00001000, -/* 00B0 */ 0x000ed52d,0x00091e40,0x000eeca9,0x00095ec0, -/* 00B2 */ 0x000ee5ad,0x00099e40,0x0006fca9,0x00002500, -/* 00B4 */ 0x000fb208,0x000c59a0,0x000ef52d,0x0009de40, -/* 00B6 */ 0x00068ca9,0x000912c1,0x000683ad,0x00095241, -/* 00B8 */ 0x00020f05,0x000991c1,0x00000000,0x00000000, -/* 00BA */ 0x00086f88,0x00001000,0x0009cf81,0x000b5340, -/* 00BC */ 0x0009c701,0x000b92c0,0x0009de81,0x000bd300, -/* 00BE */ 0x0009d601,0x000b1700,0x0001fd81,0x000b9d80, -/* 00C0 */ 0x0009f501,0x000b57c0,0x000a0f81,0x000bd740, -/* 00C2 */ 0x00020701,0x000b5c80,0x000a1681,0x000b97c0, -/* 00C4 */ 0x00021601,0x00002500,0x000a0701,0x000b9b40, -/* 00C6 */ 0x000a0f81,0x000b1bc0,0x00021681,0x00002d00, -/* 00C8 */ 0x00020f81,0x000bd800,0x000a0701,0x000b5bc0, -/* 00CA */ 0x00021601,0x00003500,0x000a0f81,0x000b5f40, -/* 00CC */ 0x000a0701,0x000bdbc0,0x00021681,0x00003d00, -/* 00CE */ 0x00020f81,0x000b1d00,0x000a0701,0x000b1fc0, -/* 00D0 */ 0x00021601,0x00020500,0x00020f81,0x000b1341, -/* 00D2 */ 0x000a0701,0x000b9fc0,0x00021681,0x00020d00, -/* 00D4 */ 0x00020f81,0x000bde80,0x000a0701,0x000bdfc0, -/* 00D6 */ 0x00021601,0x00021500,0x00020f81,0x000b9341, -/* 00D8 */ 0x00020701,0x000b53c1,0x00021681,0x00021d00, -/* 00DA */ 0x000a0f81,0x000d0380,0x0000b601,0x000b15c0, -/* 00DC */ 0x00007b01,0x00000000,0x00007b81,0x000bd1c0, -/* 00DE */ 0x00007b01,0x00000000,0x00007b81,0x000b91c0, -/* 00E0 */ 0x00007b01,0x000b57c0,0x00007b81,0x000b51c0, -/* 00E2 */ 0x00007b01,0x000b1b40,0x00007b81,0x000b11c0, -/* 00E4 */ 0x00087b01,0x000c3dc0,0x0007e488,0x000d7e45, -/* 00E6 */ 0x00000000,0x000d7a44,0x0007e48a,0x00000000, -/* 00E8 */ 0x00011f05,0x00084080,0x00000000,0x00000000, -/* 00EA */ 0x00001705,0x000b3540,0x00008a01,0x000bf040, -/* 00EC */ 0x00007081,0x000bb5c0,0x00055488,0x00000000, -/* 00EE */ 0x0000d482,0x0003fc40,0x0003fc88,0x00000000, -/* 00F0 */ 0x0001e401,0x000b3a00,0x0001ec81,0x000bd6c0, -/* 00F2 */ 0x0002ef88,0x000e7784,0x00056f08,0x00000000, -/* 00F4 */ 0x000d86b0,0x00001007,0x00008281,0x000bb240, -/* 00F6 */ 0x0000b801,0x000b7140,0x00007888,0x00000000, -/* 00F8 */ 0x0000073c,0x00001000,0x0007f188,0x000c0000, -/* 00FA */ 0x00000000,0x00000000,0x00055288,0x000c555c, -/* 00FC */ 0x0005528a,0x000c0000,0x0009fa88,0x000c5d00, -/* 00FE */ 0x0000fa88,0x00000000,0x00000032,0x00001000, -/* 0100 */ 0x0000073d,0x00001000,0x0007f188,0x000c0000, -/* 0102 */ 0x00000000,0x00000000,0x0008c01c,0x00001003, -/* 0104 */ 0x00002705,0x00001008,0x0008b201,0x000c1392, -/* 0106 */ 0x0000ba01,0x00000000, -/* TASKTREETHREAD */ -/* 0107 */ 0x00008731,0x00001400,0x0004c108,0x000fe0c4, -/* 0109 */ 0x00057488,0x00000000,0x000a6388,0x00001001, -/* 010B */ 0x0008b334,0x000bc141,0x0003020e,0x00000000, -/* 010D */ 0x000986b0,0x00001008,0x00003625,0x000c5dfa, -/* 010F */ 0x000a638a,0x00001001,0x0008020e,0x00001002, -/* 0111 */ 0x0009a6b0,0x00001008,0x0007f301,0x00000000, -/* 0113 */ 0x00000000,0x00000000,0x00002725,0x000a8c40, -/* 0115 */ 0x000000ae,0x00000000,0x000e8630,0x00001008, -/* 0117 */ 0x00000000,0x000c74e0,0x0007d182,0x0002d640, -/* 0119 */ 0x000b8630,0x00001008,0x000799b8,0x0002d6c0, -/* 011B */ 0x0000748a,0x000c3ec5,0x0007420a,0x000c0000, -/* 011D */ 0x00062208,0x000c4117,0x000a0630,0x00001009, -/* 011F */ 0x00000000,0x000c0000,0x0001022e,0x00000000, -/* 0121 */ 0x0006a630,0x00001009,0x00000032,0x00001000, -/* 0123 */ 0x000ca21c,0x00001003,0x00005a02,0x00000000, -/* 0125 */ 0x0001a630,0x00001009,0x00000000,0x000c0000, -/* 0127 */ 0x00000036,0x00001000,0x00000000,0x00000000, -/* 0129 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 012B */ 0x00000000,0x00000000,0x0003a730,0x00001008, -/* 012D */ 0x0007f801,0x000c0000,0x00000037,0x00001000, -/* 012F */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0131 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0133 */ 0x0003a730,0x00001008,0x00000033,0x00001000, -/* 0135 */ 0x0003a705,0x00001008,0x00007a01,0x000c0000, -/* 0137 */ 0x000e6288,0x000d550a,0x0006428a,0x00000000, -/* 0139 */ 0x00090730,0x0000100a,0x00000000,0x000c0000, -/* 013B */ 0x00000000,0x00000000, -/* TASKTREEHEADERCODE */ -/* 013C */ 0x0007aab0,0x00034880,0x000a8fb0,0x0000100b, -/* 013E */ 0x00057488,0x00000000,0x00033b94,0x00081140, -/* 0140 */ 0x000183ae,0x00000000,0x000a86b0,0x0000100b, -/* 0142 */ 0x00022f05,0x000c3545,0x0000eb8a,0x00000000, -/* 0144 */ 0x00042731,0x00001003, -/* FGTASKTREEHEADERCODE */ -/* 0145 */ 0x0007aab0,0x00034880,0x00078fb0,0x0000100a, -/* 0147 */ 0x00057488,0x00000000,0x00033b94,0x00081140, -/* 0149 */ 0x000183ae,0x00000000,0x000b06b0,0x0000100b, -/* 014B */ 0x00022f05,0x00000000,0x00007401,0x00091140, -/* 014D */ 0x00048f05,0x000951c0,0x00042731,0x00001003, -/* 014F */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47, -/* 0151 */ 0x00080000,0x000bffc7,0x000fe19e,0x00001003, -/* 0153 */ 0x00000000,0x00000000,0x0008e19c,0x00001003, -/* 0155 */ 0x000083c1,0x00093040,0x00000f41,0x00097140, -/* 0157 */ 0x0000a841,0x0009b240,0x0000a0c1,0x0009f040, -/* 0159 */ 0x0001c641,0x00093540,0x0001cec1,0x0009b5c0, -/* 015B */ 0x00000000,0x000fdc44,0x00055208,0x00000000, -/* 015D */ 0x00010705,0x000a2880,0x0000a23a,0x00093a00, -/* 015F */ 0x0003fc8a,0x000df6c5,0x0004ef0a,0x000c0000, -/* 0161 */ 0x00012f05,0x00036880,0x00065308,0x000c2997, -/* 0163 */ 0x000086b0,0x0000100b,0x0004410a,0x000d40c7, -/* 0165 */ 0x00000000,0x00000000,0x00088730,0x00001004, -/* 0167 */ 0x00056f0a,0x000ea105,0x00000000,0x00000000, -/* NULLALGORITHM */ -/* 0169 */ 0x0000473d,0x00001000,0x000f19b0,0x000bbc47, -/* 016B */ 0x00080000,0x000bffc7,0x0000273d,0x00001000, -/* HFGEXECCHILD */ -/* 016D */ 0x00000000,0x000eba44, -/* HFGEXECCHILD_98 */ -/* 016E */ 0x00048f05,0x0000f440,0x00007401,0x0000f7c0, -/* HFGEXECCHILD_PUSH1IND */ -/* 0170 */ 0x00000734,0x00001000,0x00010705,0x000a6880, -/* 0172 */ 0x00006a88,0x000c75c4, -/* HFGEXECSIBLING */ -/* 0173 */ 0x00000000,0x000e5084,0x00000000,0x000eba44, -/* HFGEXECSIBLING_298 */ -/* 0175 */ 0x00087401,0x000e4782, -/* HFGEXECSIBLING_2IND1 */ -/* 0176 */ 0x00000734,0x00001000,0x00010705,0x000a6880, -/* 0178 */ 0x00006a88,0x000c75c4, -/* S16_CODECOUTPUTTASK */ -/* 0179 */ 0x0007c108,0x000c0000,0x0007e721,0x000bed40, -/* 017B */ 0x00005f25,0x000badc0,0x0003ba97,0x000beb80, -/* 017D */ 0x00065590,0x000b2e00,0x00033217,0x00003ec0, -/* 017F */ 0x00065590,0x000b8e40,0x0003ed80,0x000491c0, -/* 0181 */ 0x00073fb0,0x00074c80,0x000583a0,0x0000100c, -/* 0183 */ 0x000ee388,0x00042970,0x00008301,0x00021ef2, -/* 0185 */ 0x000b8f14,0x0000000f,0x000c4d8d,0x0000001b, -/* 0187 */ 0x000d6dc2,0x000e06c6,0x000032ac,0x000c3916, -/* 0189 */ 0x0004edc2,0x00074c80,0x00078898,0x00001000, -/* 018B */ 0x00038894,0x00000032,0x000c4d8d,0x00092e1b, -/* 018D */ 0x000d6dc2,0x000e06c6,0x0004edc2,0x000c1956, -/* 018F */ 0x0000722c,0x00034a00,0x00041705,0x0009ed40, -/* 0191 */ 0x00058730,0x00001400,0x000d7488,0x000c3a00, -/* 0193 */ 0x00048f05,0x00000000 -}; -/* #CODE_END */ - -static u32 cwc4630_parameter[] = { -/* 0000 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0004 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0008 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 000C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0010 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0014 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0018 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 001C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0020 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0024 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0028 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 002C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0030 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0034 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0038 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 003C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0040 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0044 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0048 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 004C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0050 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0054 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0058 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 005C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0060 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0064 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0068 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 006C */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0070 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0074 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 0078 */ 0x00000000,0x00000000,0x00000000,0x00000000, -/* 007C */ 0x00000000,0x00000000,0x00000000,0x00000000 -}; /* #PARAMETER_END */ - - -static struct dsp_segment_desc cwc4630_segments[] = { - { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000328, cwc4630_code }, - { SEGTYPE_SP_PARAMETER, 0x00000000, 0x00000080, cwc4630_parameter }, -}; - -static struct dsp_module_desc cwc4630_module = { - "cwc4630", - { - 38, - cwc4630_symbols - }, - 2, - cwc4630_segments, -}; - -#endif /* __HEADER_cwc4630_H__ */ diff --git a/sound/pci/cs46xx/imgs/cwcasync.h b/sound/pci/cs46xx/imgs/cwcasync.h deleted file mode 100644 index 70e63e13c2b..00000000000 --- a/sound/pci/cs46xx/imgs/cwcasync.h +++ /dev/null @@ -1,176 +0,0 @@ -/* generated from cwcasync.osp DO NOT MODIFY */ - -#ifndef __HEADER_cwcasync_H__ -#define __HEADER_cwcasync_H__ - -static struct dsp_symbol_entry cwcasync_symbols[] = { - { 0x8000, "EXECCHILD",0x03 }, - { 0x8001, "EXECCHILD_98",0x03 }, - { 0x8003, "EXECCHILD_PUSH1IND",0x03 }, - { 0x8008, "EXECSIBLING",0x03 }, - { 0x800a, "EXECSIBLING_298",0x03 }, - { 0x800b, "EXECSIBLING_2IND1",0x03 }, - { 0x8010, "TIMINGMASTER",0x03 }, - { 0x804f, "S16_CODECINPUTTASK",0x03 }, - { 0x805e, "PCMSERIALINPUTTASK",0x03 }, - { 0x806d, "S16_MIX_TO_OSTREAM",0x03 }, - { 0x809a, "S16_MIX",0x03 }, - { 0x80bb, "S16_UPSRC",0x03 }, - { 0x813b, "MIX3_EXP",0x03 }, - { 0x8164, "DECIMATEBYPOW2",0x03 }, - { 0x8197, "VARIDECIMATE",0x03 }, - { 0x81f2, "_3DINPUTTASK",0x03 }, - { 0x820a, "_3DPRLGCINPTASK",0x03 }, - { 0x8227, "_3DSTEREOINPUTTASK",0x03 }, - { 0x8242, "_3DOUTPUTTASK",0x03 }, - { 0x82c4, "HRTF_MORPH_TASK",0x03 }, - { 0x82c6, "WAIT4DATA",0x03 }, - { 0x82fa, "PROLOGIC",0x03 }, - { 0x8496, "DECORRELATOR",0x03 }, - { 0x84a4, "STEREO2MONO",0x03 }, - { 0x0000, "OVERLAYBEGINADDRESS",0x00 }, - { 0x0000, "SPIOWRITE",0x03 }, - { 0x000d, "S16_ASYNCCODECINPUTTASK",0x03 }, - { 0x0043, "SPDIFITASK",0x03 }, - { 0x007b, "SPDIFOTASK",0x03 }, - { 0x0097, "ASYNCHFGTXCODE",0x03 }, - { 0x00be, "ASYNCHFGRXCODE",0x03 }, - { 0x00db, "#CODE_END",0x00 }, -}; /* cwcasync symbols */ - -static u32 cwcasync_code[] = { -/* OVERLAYBEGINADDRESS */ -/* 0000 */ 0x00002731,0x00001400,0x00003725,0x000a8440, -/* 0002 */ 0x000000ae,0x00000000,0x00060630,0x00001000, -/* 0004 */ 0x00000000,0x000c7560,0x00075282,0x0002d640, -/* 0006 */ 0x00021705,0x00000000,0x00072ab8,0x0002d6c0, -/* 0008 */ 0x00020630,0x00001000,0x000c74c2,0x000d4b82, -/* 000A */ 0x000475c2,0x00000000,0x0003430a,0x000c0000, -/* 000C */ 0x00042730,0x00001400, -/* S16_ASYNCCODECINPUTTASK */ -/* 000D */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x00000000, -/* 000F */ 0x000fa418,0x0000101f,0x0005d402,0x0001c500, -/* 0011 */ 0x000f0630,0x00001000,0x00004418,0x00001380, -/* 0013 */ 0x000e243d,0x000d394a,0x00049705,0x00000000, -/* 0015 */ 0x0007d530,0x000b4240,0x000e00f2,0x00001000, -/* 0017 */ 0x00009134,0x000ca20a,0x00004c90,0x00001000, -/* 0019 */ 0x0005d705,0x00000000,0x00004f25,0x00098240, -/* 001B */ 0x00004725,0x00000000,0x0000e48a,0x00000000, -/* 001D */ 0x00027295,0x0009c2c0,0x0003df25,0x00000000, -/* 001F */ 0x000e8030,0x00001001,0x0005f718,0x000ac600, -/* 0021 */ 0x0007cf30,0x000c2a01,0x00082630,0x00001001, -/* 0023 */ 0x000504a0,0x00001001,0x00029314,0x000bcb80, -/* 0025 */ 0x0003cf25,0x000b0e00,0x0004f5c0,0x00000000, -/* 0027 */ 0x00049118,0x000d888a,0x0007dd02,0x000c6efa, -/* 0029 */ 0x00000000,0x00000000,0x0004f5c0,0x00069c80, -/* 002B */ 0x0000d402,0x00000000,0x000e8630,0x00001001, -/* 002D */ 0x00079130,0x00000000,0x00049118,0x00090e00, -/* 002F */ 0x0006c10a,0x00000000,0x00000000,0x000c0000, -/* 0031 */ 0x0007cf30,0x00030580,0x00005725,0x00000000, -/* 0033 */ 0x000d84a0,0x00001001,0x00029314,0x000b4780, -/* 0035 */ 0x0003cf25,0x000b8600,0x00000000,0x00000000, -/* 0037 */ 0x00000000,0x000c0000,0x00000000,0x00042c80, -/* 0039 */ 0x0001dec1,0x000e488c,0x00031114,0x00000000, -/* 003B */ 0x0004f5c2,0x00000000,0x0003640a,0x00000000, -/* 003D */ 0x00000000,0x000e5084,0x00000000,0x000eb844, -/* 003F */ 0x00007001,0x00000000,0x00000734,0x00001000, -/* 0041 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4, -/* SPDIFITASK */ -/* 0043 */ 0x0006a108,0x000cf2c4,0x0004f4c0,0x000d5384, -/* 0045 */ 0x0007e48a,0x00000000,0x00067718,0x00001000, -/* 0047 */ 0x0007a418,0x00001000,0x0007221a,0x00000000, -/* 0049 */ 0x0005d402,0x00014500,0x000b8630,0x00001002, -/* 004B */ 0x00004418,0x00001780,0x000e243d,0x000d394a, -/* 004D */ 0x00049705,0x00000000,0x0007d530,0x000b4240, -/* 004F */ 0x000ac0f2,0x00001002,0x00014414,0x00000000, -/* 0051 */ 0x00004c90,0x00001000,0x0005d705,0x00000000, -/* 0053 */ 0x00004f25,0x00098240,0x00004725,0x00000000, -/* 0055 */ 0x0000e48a,0x00000000,0x00027295,0x0009c2c0, -/* 0057 */ 0x0007df25,0x00000000,0x000ac030,0x00001003, -/* 0059 */ 0x0005f718,0x000fe798,0x00029314,0x000bcb80, -/* 005B */ 0x00000930,0x000b0e00,0x0004f5c0,0x000de204, -/* 005D */ 0x000884a0,0x00001003,0x0007cf25,0x000e3560, -/* 005F */ 0x00049118,0x00000000,0x00049118,0x000d888a, -/* 0061 */ 0x0007dd02,0x000c6efa,0x0000c434,0x00030040, -/* 0063 */ 0x000fda82,0x000c2312,0x000fdc0e,0x00001001, -/* 0065 */ 0x00083402,0x000c2b92,0x000706b0,0x00001003, -/* 0067 */ 0x00075a82,0x00000000,0x0000d625,0x000b0940, -/* 0069 */ 0x0000840e,0x00001002,0x0000aabc,0x000c511e, -/* 006B */ 0x00078730,0x00001003,0x0000aaf4,0x000e910a, -/* 006D */ 0x0004628a,0x00000000,0x00006aca,0x00000000, -/* 006F */ 0x00000930,0x00000000,0x0004f5c0,0x00069c80, -/* 0071 */ 0x00046ac0,0x00000000,0x0003c40a,0x000fc898, -/* 0073 */ 0x00049118,0x00090e00,0x0006c10a,0x00000000, -/* 0075 */ 0x00000000,0x000e5084,0x00000000,0x000eb844, -/* 0077 */ 0x00007001,0x00000000,0x00000734,0x00001000, -/* 0079 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4, -/* SPDIFOTASK */ -/* 007B */ 0x0006a108,0x000c0000,0x0004f4c0,0x000c3245, -/* 007D */ 0x0000a418,0x00001000,0x0003a20a,0x00000000, -/* 007F */ 0x00004418,0x00001380,0x000e243d,0x000d394a, -/* 0081 */ 0x000c9705,0x000def92,0x0008c030,0x00001004, -/* 0083 */ 0x0005f718,0x000fe798,0x00000000,0x000c0000, -/* 0085 */ 0x00005725,0x00000000,0x000704a0,0x00001004, -/* 0087 */ 0x00029314,0x000b4780,0x0003cf25,0x000b8600, -/* 0089 */ 0x00000000,0x00000000,0x00000000,0x000c0000, -/* 008B */ 0x00000000,0x00042c80,0x0001dec1,0x000e488c, -/* 008D */ 0x00031114,0x00000000,0x0004f5c2,0x00000000, -/* 008F */ 0x0004a918,0x00098600,0x0006c28a,0x00000000, -/* 0091 */ 0x00000000,0x000e5084,0x00000000,0x000eb844, -/* 0093 */ 0x00007001,0x00000000,0x00000734,0x00001000, -/* 0095 */ 0x00010705,0x000a6880,0x00006a88,0x000c75c4, -/* ASYNCHFGTXCODE */ -/* 0097 */ 0x0002a880,0x000b4e40,0x00042214,0x000e5548, -/* 0099 */ 0x000542bf,0x00000000,0x00000000,0x000481c0, -/* 009B */ 0x00000000,0x00000000,0x00000000,0x00000030, -/* 009D */ 0x0000072d,0x000fbf8a,0x00077f94,0x000ea7df, -/* 009F */ 0x0002ac95,0x000d3145,0x00002731,0x00001400, -/* 00A1 */ 0x00006288,0x000c71c4,0x00014108,0x000e6044, -/* 00A3 */ 0x00035408,0x00000000,0x00025418,0x000a0ec0, -/* 00A5 */ 0x0001443d,0x000ca21e,0x00046595,0x000d730c, -/* 00A7 */ 0x0006538e,0x00000000,0x00064630,0x00001005, -/* 00A9 */ 0x000e7b0e,0x000df782,0x000746b0,0x00001005, -/* 00AB */ 0x00036f05,0x000c0000,0x00043695,0x000d598c, -/* 00AD */ 0x0005331a,0x000f2185,0x00000000,0x00000000, -/* 00AF */ 0x000007ae,0x000bdb00,0x00040630,0x00001400, -/* 00B1 */ 0x0005e708,0x000c0000,0x0007ef30,0x000b1c00, -/* 00B3 */ 0x000d86a0,0x00001005,0x00066408,0x000c0000, -/* 00B5 */ 0x00000000,0x00000000,0x00021843,0x00000000, -/* 00B7 */ 0x00000cac,0x00062c00,0x00001dac,0x00063400, -/* 00B9 */ 0x00002cac,0x0006cc80,0x000db943,0x000e5ca1, -/* 00BB */ 0x00000000,0x00000000,0x0006680a,0x000f3205, -/* 00BD */ 0x00042730,0x00001400, -/* ASYNCHFGRXCODE */ -/* 00BE */ 0x00014108,0x000f2204,0x00025418,0x000a2ec0, -/* 00C0 */ 0x00015dbd,0x00038100,0x00015dbc,0x00000000, -/* 00C2 */ 0x0005e415,0x00034880,0x0001258a,0x000d730c, -/* 00C4 */ 0x0006538e,0x000baa40,0x00060630,0x00001006, -/* 00C6 */ 0x00067b0e,0x000ac380,0x0003ef05,0x00000000, -/* 00C8 */ 0x0000f734,0x0001c300,0x000586b0,0x00001400, -/* 00CA */ 0x000b6f05,0x000c3a00,0x00048f05,0x00000000, -/* 00CC */ 0x0005b695,0x0008c380,0x0002058e,0x00000000, -/* 00CE */ 0x000500b0,0x00001400,0x0002b318,0x000e998d, -/* 00D0 */ 0x0006430a,0x00000000,0x00000000,0x000ef384, -/* 00D2 */ 0x00004725,0x000c0000,0x00000000,0x000f3204, -/* 00D4 */ 0x00004f25,0x000c0000,0x00080000,0x000e5ca1, -/* 00D6 */ 0x000cb943,0x000e5ca1,0x0004b943,0x00000000, -/* 00D8 */ 0x00040730,0x00001400,0x000cb943,0x000e5ca1, -/* 00DA */ 0x0004b943,0x00000000 -}; -/* #CODE_END */ - -static struct dsp_segment_desc cwcasync_segments[] = { - { SEGTYPE_SP_PROGRAM, 0x00000000, 0x000001b6, cwcasync_code }, -}; - -static struct dsp_module_desc cwcasync_module = { - "cwcasync", - { - 32, - cwcasync_symbols - }, - 1, - cwcasync_segments, -}; - -#endif /* __HEADER_cwcasync_H__ */ diff --git a/sound/pci/cs46xx/imgs/cwcbinhack.h b/sound/pci/cs46xx/imgs/cwcbinhack.h deleted file mode 100644 index f4d93689cd4..00000000000 --- a/sound/pci/cs46xx/imgs/cwcbinhack.h +++ /dev/null @@ -1,48 +0,0 @@ -/* generated by Benny - MODIFY ON YOUR OWN RISK */ - -#ifndef __HEADER_cwcbinhack_H__ -#define __HEADER_cwcbinhack_H__ - -static struct dsp_symbol_entry cwcbinhack_symbols[] = { - { 0x02c8, "OVERLAYBEGINADDRESS",0x00 }, - { 0x02c8, "MAGICSNOOPTASK",0x03 }, - { 0x0308, "#CODE_END",0x00 }, -}; /* cwcbinhack symbols */ - -static u32 cwcbinhack_code[] = { - /* 0x02c8 */ - 0x0007bfb0,0x000bc240,0x00000c2e,0x000c6084, /* 1 */ - 0x000b8630,0x00001016,0x00006408,0x000efb84, /* 2 */ - 0x00016008,0x00000000,0x0001c088,0x000c0000, /* 3 */ - 0x000fc908,0x000e3392,0x0005f488,0x000efb84, /* 4 */ - 0x0001d402,0x000b2e00,0x0003d418,0x00001000, /* 5 */ - 0x0008d574,0x000c4293,0x00065625,0x000ea30e, /* 6 */ - 0x00096c01,0x000c6f92,0x0001a58a,0x000c6085, /* 7 */ - 0x00002f43,0x00000000,0x000e03a0,0x00001016, /* 8 */ - 0x0005e608,0x000c0000,0x00000000,0x00000000, /* 9 */ - 0x000ca108,0x000dcca1,0x00003bac,0x000c3205, /* 10 */ - 0x00073843,0x00000000,0x00010730,0x00001017, /* 11 */ - 0x0001600a,0x000c0000,0x00057488,0x00000000, /* 12 */ - 0x00000000,0x000e5084,0x00000000,0x000eba44, /* 13 */ - 0x00087401,0x000e4782,0x00000734,0x00001000, /* 14 */ - 0x00010705,0x000a6880,0x00006a88,0x000c75c4, /* 15 */ - 0x00000000,0x00000000,0x00000000,0x00000000, /* 16 */ -}; -/* #CODE_END */ - -static struct dsp_segment_desc cwcbinhack_segments[] = { - { SEGTYPE_SP_PROGRAM, 0x00000000, 64, cwcbinhack_code }, -}; - -static struct dsp_module_desc cwcbinhack_module = { - "cwcbinhack", - { - 3, - cwcbinhack_symbols - }, - 1, - cwcbinhack_segments, -}; - -#endif /* __HEADER_cwcbinhack_H__ */ diff --git a/sound/pci/cs46xx/imgs/cwcdma.asp b/sound/pci/cs46xx/imgs/cwcdma.asp deleted file mode 100644 index a65e1193c89..00000000000 --- a/sound/pci/cs46xx/imgs/cwcdma.asp +++ /dev/null @@ -1,170 +0,0 @@ -// -// Copyright(c) by Benny Sjostrand (benny@hostmobility.com) -// -// 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 Free Software Foundation; either version 2 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -// - - -// -// This code runs inside the DSP (cs4610, cs4612, cs4624, or cs4630), -// to compile it you need a tool named SPASM 3.0 and DSP code owned by -// Cirrus Logic(R). The SPASM program will generate a object file (cwcdma.osp), -// the "ospparser" tool will genereate the cwcdma.h file it's included from -// the cs46xx_lib.c file. -// -// -// The purpose of this code is very simple: make it possible to tranfser -// the samples 'as they are' with no alteration from a PCMreader -// SCB (DMA from host) to any other SCB. This is useful for AC3 through SPDIF. -// SRC (source rate converters) task always alters the samples in somehow, -// however it's from 48khz -> 48khz. -// The alterations are not audible, but AC3 wont work. -// -// ... -// | -// +---------------+ -// | AsynchFGTxSCB | -// +---------------+ -// | -// subListPtr -// | -// +--------------+ -// | DMAReader | -// +--------------+ -// | -// subListPtr -// | -// +-------------+ -// | PCMReader | -// +-------------+ -// (DMA from host) -// - -struct dmaSCB - { - long dma_reserved1[3]; - - short dma_reserved2:dma_outBufPtr; - - short dma_unused1:dma_unused2; - - long dma_reserved3[4]; - - short dma_subListPtr:dma_nextSCB; - short dma_SPBptr:dma_entryPoint; - - long dma_strmRsConfig; - long dma_strmBufPtr; - - long dma_reserved4; - - VolumeControl s2m_volume; - }; - -#export DMAReader -void DMAReader() -{ - execChild(); - r2 = r0->dma_subListPtr; - r1 = r0->nextSCB; - - rsConfig01 = r2->strmRsConfig; - // Load rsConfig for input buffer - - rsDMA01 = r2->basicReq.daw, , tb = Z(0 - rf); - // Load rsDMA in case input buffer is a DMA buffer Test to see if there is any data to transfer - - if (tb) goto execSibling_2ind1 after { - r5 = rf + (-1); - r6 = r1->dma_entryPoint; // r6 = entry point of sibling task - r1 = r1->dma_SPBptr, // r1 = pointer to sibling task's SPB - , ind = r6; // Load entry point of sibling task - } - - rsConfig23 = r0->dma_strmRsConfig; - // Load rsConfig for output buffer (never a DMA buffer) - - r4 = r0->dma_outBufPtr; - - rsa0 = r2->strmBufPtr; - // rsa0 = input buffer pointer - - for (i = r5; i >= 0; --i) - after { - rsa2 = r4; - // rsa2 = output buffer pointer - - nop; - nop; - } - //***************************** - // TODO: cycles to this point * - //***************************** - { - acc0 = (rsd0 = *rsa0++1); - // get sample - - nop; // Those "nop"'s are really uggly, but there's - nop; // something with DSP's pipelines which I don't - nop; // understand, resulting this code to fail without - // having those "nop"'s (Benny) - - rsa0?reqDMA = r2; - // Trigger DMA transfer on input stream, - // if needed to replenish input buffer - - nop; - // Yet another magic "nop" to make stuff work - - ,,r98 = acc0 $+>> 0; - // store sample in ALU - - nop; - // latency on load register. - // (this one is understandable) - - *rsa2++1 = r98; - // store sample in output buffer - - nop; // The same story - nop; // as above again ... - nop; - } - // TODO: cycles per loop iteration - - r2->strmBufPtr = rsa0,, ; - // Update the modified buffer pointers - - r4 = rsa2; - // Load output pointer position into r4 - - r2 = r0->nextSCB; - // Sibling task - - goto execSibling_2ind1 // takes 6 cycles - after { - r98 = r2->thisSPB:entryPoint; - // Load child routine entry and data address - - r1 = r9; - // r9 is r2->thisSPB - - r0->dma_outBufPtr = r4,, - // Store updated output buffer pointer - - ind = r8; - // r8 is r2->entryPoint - } -} diff --git a/sound/pci/cs46xx/imgs/cwcdma.h b/sound/pci/cs46xx/imgs/cwcdma.h deleted file mode 100644 index 7ff0d458716..00000000000 --- a/sound/pci/cs46xx/imgs/cwcdma.h +++ /dev/null @@ -1,68 +0,0 @@ -/* generated from cwcdma.osp DO NOT MODIFY */ - -#ifndef __HEADER_cwcdma_H__ -#define __HEADER_cwcdma_H__ - -static struct dsp_symbol_entry cwcdma_symbols[] = { - { 0x8000, "EXECCHILD",0x03 }, - { 0x8001, "EXECCHILD_98",0x03 }, - { 0x8003, "EXECCHILD_PUSH1IND",0x03 }, - { 0x8008, "EXECSIBLING",0x03 }, - { 0x800a, "EXECSIBLING_298",0x03 }, - { 0x800b, "EXECSIBLING_2IND1",0x03 }, - { 0x8010, "TIMINGMASTER",0x03 }, - { 0x804f, "S16_CODECINPUTTASK",0x03 }, - { 0x805e, "PCMSERIALINPUTTASK",0x03 }, - { 0x806d, "S16_MIX_TO_OSTREAM",0x03 }, - { 0x809a, "S16_MIX",0x03 }, - { 0x80bb, "S16_UPSRC",0x03 }, - { 0x813b, "MIX3_EXP",0x03 }, - { 0x8164, "DECIMATEBYPOW2",0x03 }, - { 0x8197, "VARIDECIMATE",0x03 }, - { 0x81f2, "_3DINPUTTASK",0x03 }, - { 0x820a, "_3DPRLGCINPTASK",0x03 }, - { 0x8227, "_3DSTEREOINPUTTASK",0x03 }, - { 0x8242, "_3DOUTPUTTASK",0x03 }, - { 0x82c4, "HRTF_MORPH_TASK",0x03 }, - { 0x82c6, "WAIT4DATA",0x03 }, - { 0x82fa, "PROLOGIC",0x03 }, - { 0x8496, "DECORRELATOR",0x03 }, - { 0x84a4, "STEREO2MONO",0x03 }, - { 0x0000, "OVERLAYBEGINADDRESS",0x00 }, - { 0x0000, "DMAREADER",0x03 }, - { 0x0018, "#CODE_END",0x00 }, -}; /* cwcdma symbols */ - -static u32 cwcdma_code[] = { -/* OVERLAYBEGINADDRESS */ -/* 0000 */ 0x00002731,0x00001400,0x0004c108,0x000e5044, -/* 0002 */ 0x0005f608,0x00000000,0x000007ae,0x000be300, -/* 0004 */ 0x00058630,0x00001400,0x0007afb0,0x000e9584, -/* 0006 */ 0x00007301,0x000a9840,0x0005e708,0x000cd104, -/* 0008 */ 0x00067008,0x00000000,0x000902a0,0x00001000, -/* 000A */ 0x00012a01,0x000c0000,0x00000000,0x00000000, -/* 000C */ 0x00021843,0x000c0000,0x00000000,0x000c0000, -/* 000E */ 0x0000e101,0x000c0000,0x00000cac,0x00000000, -/* 0010 */ 0x00080000,0x000e5ca1,0x00000000,0x000c0000, -/* 0012 */ 0x00000000,0x00000000,0x00000000,0x00092c00, -/* 0014 */ 0x000122c1,0x000e5084,0x00058730,0x00001400, -/* 0016 */ 0x000d7488,0x000e4782,0x00007401,0x0001c100 -}; - -/* #CODE_END */ - -static struct dsp_segment_desc cwcdma_segments[] = { - { SEGTYPE_SP_PROGRAM, 0x00000000, 0x00000030, cwcdma_code }, -}; - -static struct dsp_module_desc cwcdma_module = { - "cwcdma", - { - 27, - cwcdma_symbols - }, - 1, - cwcdma_segments, -}; - -#endif /* __HEADER_cwcdma_H__ */ diff --git a/sound/pci/cs46xx/imgs/cwcsnoop.h b/sound/pci/cs46xx/imgs/cwcsnoop.h deleted file mode 100644 index 6929d0a5a3f..00000000000 --- a/sound/pci/cs46xx/imgs/cwcsnoop.h +++ /dev/null @@ -1,46 +0,0 @@ -/* generated from cwcsnoop.osp DO NOT MODIFY */ - -#ifndef __HEADER_cwcsnoop_H__ -#define __HEADER_cwcsnoop_H__ - -static struct dsp_symbol_entry cwcsnoop_symbols[] = { - { 0x0500, "OVERLAYBEGINADDRESS",0x00 }, - { 0x0500, "OUTPUTSNOOP",0x03 }, - { 0x051f, "#CODE_END",0x00 }, -}; /* cwcsnoop symbols */ - -static u32 cwcsnoop_code[] = { -/* 0000 */ 0x0007bfb0,0x000b4e40,0x0007c088,0x000c0617, -/* 0002 */ 0x00049705,0x00000000,0x00080630,0x00001028, -/* 0004 */ 0x00076408,0x000efb84,0x00066008,0x00000000, -/* 0006 */ 0x0007c908,0x000c0000,0x00046725,0x000efa44, -/* 0008 */ 0x0005f708,0x00000000,0x0001d402,0x000b2e00, -/* 000A */ 0x0003d418,0x00001000,0x0008d574,0x000c4293, -/* 000C */ 0x00065625,0x000ea30e,0x00096c01,0x000c6f92, -/* 000E */ 0x0006a58a,0x000f6085,0x00002f43,0x00000000, -/* 0010 */ 0x000a83a0,0x00001028,0x0005e608,0x000c0000, -/* 0012 */ 0x00000000,0x00000000,0x000ca108,0x000dcca1, -/* 0014 */ 0x00003bac,0x000fb205,0x00073843,0x00000000, -/* 0016 */ 0x000d8730,0x00001028,0x0006600a,0x000c0000, -/* 0018 */ 0x00057488,0x00000000,0x00000000,0x000e5084, -/* 001A */ 0x00000000,0x000eba44,0x00087401,0x000e4782, -/* 001C */ 0x00000734,0x00001000,0x00010705,0x000a6880, -/* 001E */ 0x00006a88,0x000c75c4 -}; -/* #CODE_END */ - -static struct dsp_segment_desc cwcsnoop_segments[] = { - { SEGTYPE_SP_PROGRAM, 0x00000000, 0x0000003e, cwcsnoop_code }, -}; - -static struct dsp_module_desc cwcsnoop_module = { - "cwcsnoop", - { - 3, - cwcsnoop_symbols - }, - 1, - cwcsnoop_segments, -}; - -#endif /* __HEADER_cwcsnoop_H__ */ diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index d1cca283157..b4e0ff6a99a 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c @@ -88,13 +88,12 @@ static int snd_cs5530_dev_free(struct snd_device *device) return snd_cs5530_free(chip); } -static void __devexit snd_cs5530_remove(struct pci_dev *pci) +static void snd_cs5530_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } -static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg) +static u8 snd_cs5530_mixer_read(unsigned long io, u8 reg) { outb(reg, io + 4); udelay(20); @@ -103,9 +102,9 @@ static u8 __devinit snd_cs5530_mixer_read(unsigned long io, u8 reg) return reg; } -static int __devinit snd_cs5530_create(struct snd_card *card, - struct pci_dev *pci, - struct snd_cs5530 **rchip) +static int snd_cs5530_create(struct snd_card *card, + struct pci_dev *pci, + struct snd_cs5530 **rchip) { struct snd_cs5530 *chip; unsigned long sb_base; @@ -161,17 +160,17 @@ static int __devinit snd_cs5530_create(struct snd_card *card, sb_base = 0x220 + 0x20 * (map & 3); if (map & (1<<2)) - printk(KERN_INFO "CS5530: XpressAudio at 0x%lx\n", sb_base); + dev_info(card->dev, "XpressAudio at 0x%lx\n", sb_base); else { - printk(KERN_ERR "Could not find XpressAudio!\n"); + dev_err(card->dev, "Could not find XpressAudio!\n"); snd_cs5530_free(chip); return -ENODEV; } if (map & (1<<5)) - printk(KERN_INFO "CS5530: MPU at 0x300\n"); + dev_info(card->dev, "MPU at 0x300\n"); else if (map & (1<<6)) - printk(KERN_INFO "CS5530: MPU at 0x330\n"); + dev_info(card->dev, "MPU at 0x330\n"); irq = snd_cs5530_mixer_read(sb_base, 0x80) & 0x0F; dma8 = snd_cs5530_mixer_read(sb_base, 0x81); @@ -183,7 +182,7 @@ static int __devinit snd_cs5530_create(struct snd_card *card, else if (dma8 & 0x80) dma16 = 7; else { - printk(KERN_ERR "CS5530: No 16bit DMA enabled\n"); + dev_err(card->dev, "No 16bit DMA enabled\n"); snd_cs5530_free(chip); return -ENODEV; } @@ -195,7 +194,7 @@ static int __devinit snd_cs5530_create(struct snd_card *card, else if (dma8 & 0x08) dma8 = 3; else { - printk(KERN_ERR "CS5530: No 8bit DMA enabled\n"); + dev_err(card->dev, "No 8bit DMA enabled\n"); snd_cs5530_free(chip); return -ENODEV; } @@ -209,32 +208,31 @@ static int __devinit snd_cs5530_create(struct snd_card *card, else if (irq & 8) irq = 10; else { - printk(KERN_ERR "CS5530: SoundBlaster IRQ not set\n"); + dev_err(card->dev, "SoundBlaster IRQ not set\n"); snd_cs5530_free(chip); return -ENODEV; } - printk(KERN_INFO "CS5530: IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, - dma16); + dev_info(card->dev, "IRQ: %d DMA8: %d DMA16: %d\n", irq, dma8, dma16); err = snd_sbdsp_create(card, sb_base, irq, snd_sb16dsp_interrupt, dma8, dma16, SB_HW_CS5530, &chip->sb); if (err < 0) { - printk(KERN_ERR "CS5530: Could not create SoundBlaster\n"); + dev_err(card->dev, "Could not create SoundBlaster\n"); snd_cs5530_free(chip); return err; } err = snd_sb16dsp_pcm(chip->sb, 0, &chip->sb->pcm); if (err < 0) { - printk(KERN_ERR "CS5530: Could not create PCM\n"); + dev_err(card->dev, "Could not create PCM\n"); snd_cs5530_free(chip); return err; } err = snd_sbmixer_new(chip->sb); if (err < 0) { - printk(KERN_ERR "CS5530: Could not create Mixer\n"); + dev_err(card->dev, "Could not create Mixer\n"); snd_cs5530_free(chip); return err; } @@ -245,13 +243,12 @@ static int __devinit snd_cs5530_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); *rchip = chip; return 0; } -static int __devinit snd_cs5530_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs5530_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -265,7 +262,8 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -294,7 +292,7 @@ static struct pci_driver cs5530_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5530_ids, .probe = snd_cs5530_probe, - .remove = __devexit_p(snd_cs5530_remove), + .remove = snd_cs5530_remove, }; module_pci_driver(cs5530_driver); diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 4915efa551f..edcbbda5c48 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -43,7 +43,7 @@ static char *ac97_quirk; module_param(ac97_quirk, charp, 0444); MODULE_PARM_DESC(ac97_quirk, "AC'97 board specific workarounds."); -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { #if 0 /* Not yet confirmed if all 5536 boards are HP only */ { .subvendor = PCI_VENDOR_ID_AMD, @@ -84,7 +84,8 @@ static void wait_till_cmd_acked(struct cs5535audio *cs5535au, unsigned long time udelay(1); } while (--timeout); if (!timeout) - snd_printk(KERN_ERR "Failure writing to cs5535 codec\n"); + dev_err(cs5535au->card->dev, + "Failure writing to cs5535 codec\n"); } static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au, @@ -109,8 +110,9 @@ static unsigned short snd_cs5535audio_codec_read(struct cs5535audio *cs5535au, udelay(1); } while (--timeout); if (!timeout) - snd_printk(KERN_ERR "Failure reading codec reg 0x%x," - "Last value=0x%x\n", reg, val); + dev_err(cs5535au->card->dev, + "Failure reading codec reg 0x%x, Last value=0x%x\n", + reg, val); return (unsigned short) val; } @@ -144,7 +146,7 @@ static unsigned short snd_cs5535audio_ac97_codec_read(struct snd_ac97 *ac97, return snd_cs5535audio_codec_read(cs5535au, reg); } -static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) +static int snd_cs5535audio_mixer(struct cs5535audio *cs5535au) { struct snd_card *card = cs5535au->card; struct snd_ac97_bus *pbus; @@ -168,7 +170,7 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) olpc_prequirks(card, &ac97); if ((err = snd_ac97_mixer(pbus, &ac97, &cs5535au->ac97)) < 0) { - snd_printk(KERN_ERR "mixer failed\n"); + dev_err(card->dev, "mixer failed\n"); return err; } @@ -176,7 +178,7 @@ static int __devinit snd_cs5535audio_mixer(struct cs5535audio *cs5535au) err = olpc_quirks(card, cs5535au->ac97); if (err < 0) { - snd_printk(KERN_ERR "olpc quirks failed\n"); + dev_err(card->dev, "olpc quirks failed\n"); return err; } @@ -194,8 +196,9 @@ static void process_bm0_irq(struct cs5535audio *cs5535au) dma = cs5535au->playback_substream->runtime->private_data; snd_pcm_period_elapsed(cs5535au->playback_substream); } else { - snd_printk(KERN_ERR "unexpected bm0 irq src, bm_stat=%x\n", - bm_stat); + dev_err(cs5535au->card->dev, + "unexpected bm0 irq src, bm_stat=%x\n", + bm_stat); } } @@ -241,8 +244,9 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) process_bm1_irq(cs5535au); break; default: - snd_printk(KERN_ERR "Unexpected irq src: " - "0x%x\n", acc_irq_stat); + dev_err(cs5535au->card->dev, + "Unexpected irq src: 0x%x\n", + acc_irq_stat); break; } } @@ -253,7 +257,7 @@ static irqreturn_t snd_cs5535audio_interrupt(int irq, void *dev_id) static int snd_cs5535audio_free(struct cs5535audio *cs5535au) { synchronize_irq(cs5535au->irq); - pci_set_power_state(cs5535au->pci, 3); + pci_set_power_state(cs5535au->pci, PCI_D3hot); if (cs5535au->irq >= 0) free_irq(cs5535au->irq, cs5535au); @@ -270,9 +274,9 @@ static int snd_cs5535audio_dev_free(struct snd_device *device) return snd_cs5535audio_free(cs5535au); } -static int __devinit snd_cs5535audio_create(struct snd_card *card, - struct pci_dev *pci, - struct cs5535audio **rcs5535au) +static int snd_cs5535audio_create(struct snd_card *card, + struct pci_dev *pci, + struct cs5535audio **rcs5535au) { struct cs5535audio *cs5535au; @@ -287,7 +291,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card, if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - printk(KERN_WARNING "unable to get 32bit dma\n"); + dev_warn(card->dev, "unable to get 32bit dma\n"); err = -ENXIO; goto pcifail; } @@ -312,7 +316,7 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card, if (request_irq(pci->irq, snd_cs5535audio_interrupt, IRQF_SHARED, KBUILD_MODNAME, cs5535au)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto sndfail; } @@ -324,8 +328,6 @@ static int __devinit snd_cs5535audio_create(struct snd_card *card, cs5535au, &ops)) < 0) goto sndfail; - snd_card_set_dev(card, &pci->dev); - *rcs5535au = cs5535au; return 0; @@ -338,8 +340,8 @@ pcifail: return err; } -static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_cs5535audio_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -353,7 +355,8 @@ static int __devinit snd_cs5535audio_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -387,18 +390,17 @@ probefail_out: return err; } -static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) +static void snd_cs5535audio_remove(struct pci_dev *pci) { olpc_quirks_cleanup(); snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver cs5535audio_driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5535audio_ids, .probe = snd_cs5535audio_probe, - .remove = __devexit_p(snd_cs5535audio_remove), + .remove = snd_cs5535audio_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_cs5535audio_pm, diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index bb3cc641130..0579daa6221 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -97,10 +97,10 @@ struct cs5535audio { extern const struct dev_pm_ops snd_cs5535audio_pm; #ifdef CONFIG_OLPC -void __devinit olpc_prequirks(struct snd_card *card, - struct snd_ac97_template *ac97); -int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); -void __devexit olpc_quirks_cleanup(void); +void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97); +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97); +void olpc_quirks_cleanup(void); void olpc_analog_input(struct snd_ac97 *ac97, int on); void olpc_mic_bias(struct snd_ac97 *ac97, int on); @@ -133,7 +133,7 @@ static inline void olpc_capture_open(struct snd_ac97 *ac97) { } static inline void olpc_capture_close(struct snd_ac97 *ac97) { } #endif -int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); +int snd_cs5535audio_pcm(struct cs5535audio *cs5535audio); #endif /* __SOUND_CS5535AUDIO_H */ diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 50da49be9ae..3b0fdaca8dc 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -36,7 +36,8 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) err = snd_ac97_update_bits(ac97, AC97_AD_TEST2, 1 << AC97_AD_HPFD_SHIFT, on << AC97_AD_HPFD_SHIFT); if (err < 0) { - snd_printk(KERN_ERR "setting High Pass Filter - %d\n", err); + dev_err(ac97->bus->card->dev, + "setting High Pass Filter - %d\n", err); return; } @@ -58,7 +59,7 @@ void olpc_mic_bias(struct snd_ac97 *ac97, int on) err = snd_ac97_update_bits(ac97, AC97_AD_MISC, 1 << AC97_AD_VREFD_SHIFT, on << AC97_AD_VREFD_SHIFT); if (err < 0) - snd_printk(KERN_ERR "setting MIC Bias - %d\n", err); + dev_err(ac97->bus->card->dev, "setting MIC Bias - %d\n", err); } static int olpc_dc_info(struct snd_kcontrol *kctl, @@ -114,7 +115,7 @@ static int olpc_mic_put(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) return 1; } -static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { +static struct snd_kcontrol_new olpc_cs5535audio_ctls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "DC Mode Enable", @@ -133,8 +134,8 @@ static struct snd_kcontrol_new olpc_cs5535audio_ctls[] __devinitdata = { }, }; -void __devinit olpc_prequirks(struct snd_card *card, - struct snd_ac97_template *ac97) +void olpc_prequirks(struct snd_card *card, + struct snd_ac97_template *ac97) { if (!machine_is_olpc()) return; @@ -144,7 +145,7 @@ void __devinit olpc_prequirks(struct snd_card *card, ac97->scaps |= AC97_SCAP_INV_EAPD; } -int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) +int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { struct snd_ctl_elem_id elem; int i, err; @@ -153,7 +154,7 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return 0; if (gpio_request(OLPC_GPIO_MIC_AC, DRV_NAME)) { - printk(KERN_ERR DRV_NAME ": unable to allocate MIC GPIO\n"); + dev_err(card->dev, "unable to allocate MIC GPIO\n"); return -EIO; } gpio_direction_output(OLPC_GPIO_MIC_AC, 0); @@ -161,13 +162,13 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) /* drop the original AD1888 HPF control */ memset(&elem, 0, sizeof(elem)); elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strncpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); + strlcpy(elem.name, "High Pass Filter Enable", sizeof(elem.name)); snd_ctl_remove_id(card, &elem); /* drop the original V_REFOUT control */ memset(&elem, 0, sizeof(elem)); elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - strncpy(elem.name, "V_REFOUT Enable", sizeof(elem.name)); + strlcpy(elem.name, "V_REFOUT Enable", sizeof(elem.name)); snd_ctl_remove_id(card, &elem); /* add the OLPC-specific controls */ @@ -185,7 +186,7 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) return 0; } -void __devexit olpc_quirks_cleanup(void) +void olpc_quirks_cleanup(void) { gpio_free(OLPC_GPIO_MIC_AC); } diff --git a/sound/pci/cs5535audio/cs5535audio_pcm.c b/sound/pci/cs5535audio/cs5535audio_pcm.c index dbf94b189e7..9c2dc911d8d 100644 --- a/sound/pci/cs5535audio/cs5535audio_pcm.c +++ b/sound/pci/cs5535audio/cs5535audio_pcm.c @@ -317,7 +317,7 @@ static int snd_cs5535audio_trigger(struct snd_pcm_substream *substream, int cmd) dma->ops->disable_dma(cs5535au); break; default: - snd_printk(KERN_ERR "unhandled trigger\n"); + dev_err(cs5535au->card->dev, "unhandled trigger\n"); err = -EINVAL; break; } @@ -335,13 +335,13 @@ static snd_pcm_uframes_t snd_cs5535audio_pcm_pointer(struct snd_pcm_substream dma = substream->runtime->private_data; curdma = dma->ops->read_dma_pntr(cs5535au); if (curdma < dma->buf_addr) { - snd_printk(KERN_ERR "curdma=%x < %x bufaddr.\n", + dev_err(cs5535au->card->dev, "curdma=%x < %x bufaddr.\n", curdma, dma->buf_addr); return 0; } curdma -= dma->buf_addr; if (curdma >= dma->buf_bytes) { - snd_printk(KERN_ERR "diff=%x >= %x buf_bytes.\n", + dev_err(cs5535au->card->dev, "diff=%x >= %x buf_bytes.\n", curdma, dma->buf_bytes); return 0; } @@ -422,7 +422,7 @@ static struct cs5535audio_dma_ops snd_cs5535audio_capture_dma_ops = { .read_dma_pntr = cs5535audio_capture_read_dma_pntr, }; -int __devinit snd_cs5535audio_pcm(struct cs5535audio *cs5535au) +int snd_cs5535audio_pcm(struct cs5535audio *cs5535au) { struct snd_pcm *pcm; int err; diff --git a/sound/pci/cs5535audio/cs5535audio_pm.c b/sound/pci/cs5535audio/cs5535audio_pm.c index 6c34def5986..34cc60057d0 100644 --- a/sound/pci/cs5535audio/cs5535audio_pm.c +++ b/sound/pci/cs5535audio/cs5535audio_pm.c @@ -74,7 +74,7 @@ static int snd_cs5535audio_suspend(struct device *dev) snd_cs5535audio_stop_hardware(cs5535au); if (pci_save_state(pci)) { - printk(KERN_ERR "cs5535audio: pci_save_state failed!\n"); + dev_err(dev, "pci_save_state failed!\n"); return -EIO; } pci_disable_device(pci); @@ -94,8 +94,7 @@ static int snd_cs5535audio_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "cs5535audio: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -113,7 +112,7 @@ static int snd_cs5535audio_resume(struct device *dev) } while (--timeout); if (!timeout) - snd_printk(KERN_ERR "Failure getting AC Link ready\n"); + dev_err(cs5535au->card->dev, "Failure getting AC Link ready\n"); /* set up rate regs, dma. actual initiation is done in trig */ for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index a2f997a9977..af632bd0832 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -38,7 +38,7 @@ | (0x10 << 16) \ | ((IEC958_AES3_CON_FS_48000) << 24)) -static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { +static struct snd_pci_quirk subsys_20k1_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), @@ -48,7 +48,7 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { { } /* terminator */ }; -static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { +static struct snd_pci_quirk subsys_20k2_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, "SB0760", CTSB0760), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, @@ -435,6 +435,11 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) return 0; position = src->ops->get_ca(src); + if (position < apcm->vm_block->addr) { + snd_printdd("ctxfi: bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", position, apcm->vm_block->addr, apcm->vm_block->size); + position = apcm->vm_block->addr; + } + size = apcm->vm_block->size; max_cisz = src->multi * src->rsc.msr; max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); @@ -1249,7 +1254,7 @@ static int atc_dev_free(struct snd_device *dev) return ct_atc_destroy(atc); } -static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) +static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) { const struct snd_pci_quirk *p; const struct snd_pci_quirk *list; @@ -1296,7 +1301,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) return 0; } -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) +int ct_atc_create_alsa_devs(struct ct_atc *atc) { enum CTALSADEVS i; int err; @@ -1319,7 +1324,7 @@ int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) return 0; } -static int __devinit atc_create_hw_devs(struct ct_atc *atc) +static int atc_create_hw_devs(struct ct_atc *atc) { struct hw *hw; struct card_conf info = {0}; @@ -1614,7 +1619,7 @@ static int atc_resume(struct ct_atc *atc) } #endif -static struct ct_atc atc_preset __devinitdata = { +static struct ct_atc atc_preset = { .map_audio_buffer = ct_map_audio_buffer, .unmap_audio_buffer = ct_unmap_audio_buffer, .pcm_playback_prepare = atc_pcm_playback_prepare, @@ -1665,10 +1670,10 @@ static struct ct_atc atc_preset __devinitdata = { * Returns 0 if succeeds, or negative error code if fails. */ -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, - int chip_type, unsigned int ssid, - struct ct_atc **ratc) +int ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, + int chip_type, unsigned int ssid, + struct ct_atc **ratc) { struct ct_atc *atc; static struct snd_device_ops ops = { @@ -1734,8 +1739,6 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, if (err < 0) goto error1; - snd_card_set_dev(card, &pci->dev); - *ratc = atc; return 0; diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 69b51f9d345..5f11ca22fcd 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h @@ -152,9 +152,9 @@ struct ct_atc { }; -int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, - unsigned int rsr, unsigned int msr, int chip_type, - unsigned int subsysid, struct ct_atc **ratc); -int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); +int ct_atc_create(struct snd_card *card, struct pci_dev *pci, + unsigned int rsr, unsigned int msr, int chip_type, + unsigned int subsysid, struct ct_atc **ratc); +int ct_atc_create_alsa_devs(struct ct_atc *atc); #endif /* CTATC_H */ diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c index 0c00eb4088e..84f86bf63b8 100644 --- a/sound/pci/ctxfi/ctdaio.c +++ b/sound/pci/ctxfi/ctdaio.c @@ -33,7 +33,7 @@ struct daio_rsc_idx { unsigned short right; }; -struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { +static struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { [LINEO1] = {.left = 0x00, .right = 0x01}, [LINEO2] = {.left = 0x18, .right = 0x19}, [LINEO3] = {.left = 0x08, .right = 0x09}, @@ -44,7 +44,7 @@ struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { [SPDIFI1] = {.left = 0x95, .right = 0x9d}, }; -struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { +static struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { [LINEO1] = {.left = 0x40, .right = 0x41}, [LINEO2] = {.left = 0x60, .right = 0x61}, [LINEO3] = {.left = 0x50, .right = 0x51}, diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c index 8e64f4862e8..a689f255270 100644 --- a/sound/pci/ctxfi/cthardware.c +++ b/sound/pci/ctxfi/cthardware.c @@ -20,8 +20,8 @@ #include "cthw20k2.h" #include <linux/bug.h> -int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, - enum CTCARDS model, struct hw **rhw) +int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, + enum CTCARDS model, struct hw **rhw) { int err; @@ -69,7 +69,8 @@ unsigned int get_field(unsigned int data, unsigned int field) { int i; - BUG_ON(!field); + if (WARN_ON(!field)) + return 0; /* @field should always be greater than 0 */ for (i = 0; !(field & (1 << i)); ) i++; @@ -81,7 +82,8 @@ void set_field(unsigned int *data, unsigned int field, unsigned int value) { int i; - BUG_ON(!field); + if (WARN_ON(!field)) + return; /* @field should always be greater than 0 */ for (i = 0; !(field & (1 << i)); ) i++; diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c index 4507f7088b2..6ac40beb49d 100644 --- a/sound/pci/ctxfi/cthw20k1.c +++ b/sound/pci/ctxfi/cthw20k1.c @@ -2171,7 +2171,7 @@ static void hw_write_pci(struct hw *hw, u32 reg, u32 data) &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); } -static struct hw ct20k1_preset __devinitdata = { +static struct hw ct20k1_preset = { .irq = -1, .card_init = hw_card_init, @@ -2275,7 +2275,7 @@ static struct hw ct20k1_preset __devinitdata = { .get_wc = get_wc, }; -int __devinit create_20k1_hw_obj(struct hw **rhw) +int create_20k1_hw_obj(struct hw **rhw) { struct hw20k1 *hw20k1; diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c index b9c9349058b..b1438861d38 100644 --- a/sound/pci/ctxfi/cthw20k2.c +++ b/sound/pci/ctxfi/cthw20k2.c @@ -2237,7 +2237,7 @@ static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) writel(data, (void *)(hw->mem_base + reg)); } -static struct hw ct20k2_preset __devinitdata = { +static struct hw ct20k2_preset = { .irq = -1, .card_init = hw_card_init, @@ -2345,7 +2345,7 @@ static struct hw ct20k2_preset __devinitdata = { .get_wc = get_wc, }; -int __devinit create_20k2_hw_obj(struct hw **rhw) +int create_20k2_hw_obj(struct hw **rhw) { struct hw20k2 *hw20k2; diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 07c07d752fd..98426d09c8b 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c @@ -56,7 +56,7 @@ static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { }; MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids); -static int __devinit +static int ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -71,7 +71,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) dev++; return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err) return err; if ((reference_rate != 48000) && (reference_rate != 44100)) { @@ -119,10 +120,9 @@ error: return err; } -static void __devexit ct_card_remove(struct pci_dev *pci) +static void ct_card_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP @@ -152,7 +152,7 @@ static struct pci_driver ct_driver = { .name = KBUILD_MODNAME, .id_table = ct_pci_dev_ids, .probe = ct_card_probe, - .remove = __devexit_p(ct_card_remove), + .remove = ct_card_remove, .driver = { .pm = CT_CARD_PM_OPS, }, diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index abb0b86c41c..9f10c9e0df5 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c @@ -58,7 +58,8 @@ static int get_firmware(const struct firmware **fw_entry, snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); err = request_firmware(fw_entry, name, pci_device(chip)); if (err < 0) - snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); + dev_err(chip->card->dev, + "get_firmware(): Firmware not available (%d)\n", err); #ifdef CONFIG_PM_SLEEP else chip->fw_cache[fw_index] = *fw_entry; @@ -563,7 +564,7 @@ static int init_engine(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); if (err < 0) { - snd_printk(KERN_ERR "malloc_pages err=%d\n", err); + dev_err(chip->card->dev, "malloc_pages err=%d\n", err); spin_lock_irq(&chip->lock); free_pipes(chip, pipe); spin_unlock_irq(&chip->lock); @@ -907,7 +908,7 @@ static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) /*<--snd_echo_probe() */ -static int __devinit snd_echo_new_pcm(struct echoaudio *chip) +static int snd_echo_new_pcm(struct echoaudio *chip) { struct snd_pcm *pcm; int err; @@ -1050,7 +1051,7 @@ static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, #ifdef ECHOCARD_HAS_LINE_OUT_GAIN /* On the Mia this one controls the line-out volume */ -static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_line_output_gain = { .name = "Line Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1061,7 +1062,7 @@ static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { .tlv = {.p = db_scale_output_gain}, }; #else -static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_pcm_output_gain = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1131,7 +1132,7 @@ static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); -static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { +static struct snd_kcontrol_new snd_echo_line_input_gain = { .name = "Line Capture Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1195,7 +1196,7 @@ static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = { +static struct snd_kcontrol_new snd_echo_output_nominal_level = { .name = "Line Playback Switch (-10dBV)", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_echo_output_nominal_info, @@ -1261,7 +1262,7 @@ static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = { +static struct snd_kcontrol_new snd_echo_intput_nominal_level = { .name = "Line Capture Switch (-10dBV)", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_echo_input_nominal_info, @@ -1327,7 +1328,7 @@ static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { +static struct snd_kcontrol_new snd_echo_monitor_mixer = { .name = "Monitor Mixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1395,7 +1396,7 @@ static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { +static struct snd_kcontrol_new snd_echo_vmixer = { .name = "VMixer Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -1490,7 +1491,7 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_digital_mode_switch = { .name = "Digital mode Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_digital_mode_info, @@ -1547,7 +1548,7 @@ static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_spdif_mode_switch = { .name = "S/PDIF mode Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_spdif_mode_info, @@ -1626,7 +1627,7 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_clock_source_switch = { .name = "Sample Clock Source", .iface = SNDRV_CTL_ELEM_IFACE_PCM, .info = snd_echo_clock_source_info, @@ -1669,7 +1670,7 @@ static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_phantom_power_switch = { .name = "Phantom power Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_phantom_power_info, @@ -1712,7 +1713,7 @@ static int snd_echo_automute_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_automute_switch = { .name = "Digital Capture Switch (automute)", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = snd_echo_automute_info, @@ -1739,7 +1740,7 @@ static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, return 1; } -static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = { +static struct snd_kcontrol_new snd_echo_vumeters_switch = { .name = "VU-meters Switch", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .access = SNDRV_CTL_ELEM_ACCESS_WRITE, @@ -1780,7 +1781,7 @@ static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { +static struct snd_kcontrol_new snd_echo_vumeters = { .name = "VU-meters", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = SNDRV_CTL_ELEM_ACCESS_READ | @@ -1836,7 +1837,7 @@ static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = { +static struct snd_kcontrol_new snd_echo_channels_info = { .name = "Channels info", .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -1940,9 +1941,9 @@ static int snd_echo_dev_free(struct snd_device *device) /* <--snd_echo_probe() */ -static __devinit int snd_echo_create(struct snd_card *card, - struct pci_dev *pci, - struct echoaudio **rchip) +static int snd_echo_create(struct snd_card *card, + struct pci_dev *pci, + struct echoaudio **rchip) { struct echoaudio *chip; int err; @@ -1989,8 +1990,8 @@ static __devinit int snd_echo_create(struct snd_card *card, if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz, ECHOCARD_NAME)) == NULL) { + dev_err(chip->card->dev, "cannot get memory region\n"); snd_echo_free(chip); - snd_printk(KERN_ERR "cannot get memory region\n"); return -EBUSY; } chip->dsp_registers = (volatile u32 __iomem *) @@ -1998,8 +1999,8 @@ static __devinit int snd_echo_create(struct snd_card *card, if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { + dev_err(chip->card->dev, "cannot grab irq\n"); snd_echo_free(chip); - snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; @@ -2011,8 +2012,8 @@ static __devinit int snd_echo_create(struct snd_card *card, if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), sizeof(struct comm_page), &chip->commpage_dma_buf) < 0) { + dev_err(chip->card->dev, "cannot allocate the comm page\n"); snd_echo_free(chip); - snd_printk(KERN_ERR "cannot allocate the comm page\n"); return -ENOMEM; } chip->comm_page_phys = chip->commpage_dma_buf.addr; @@ -2040,8 +2041,8 @@ static __devinit int snd_echo_create(struct snd_card *card, /* constructor */ -static int __devinit snd_echo_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_echo_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2058,12 +2059,11 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, DE_INIT(("Echoaudio driver starting...\n")); i = 0; - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; - snd_card_set_dev(card, &pci->dev); - chip = NULL; /* Tells snd_echo_create to allocate chip */ if ((err = snd_echo_create(card, pci, &chip)) < 0) { snd_card_free(card); @@ -2082,7 +2082,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, chip->dsp_registers_phys, chip->irq); if ((err = snd_echo_new_pcm(chip)) < 0) { - snd_printk(KERN_ERR "new pcm error %d\n", err); + dev_err(chip->card->dev, "new pcm error %d\n", err); snd_card_free(card); return err; } @@ -2090,7 +2090,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, #ifdef ECHOCARD_HAS_MIDI if (chip->has_midi) { /* Some Mia's do not have midi */ if ((err = snd_echo_midi_create(card, chip)) < 0) { - snd_printk(KERN_ERR "new midi error %d\n", err); + dev_err(chip->card->dev, "new midi error %d\n", err); snd_card_free(card); return err; } @@ -2189,14 +2189,14 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, err = snd_card_register(card); if (err < 0) goto ctl_error; - snd_printk(KERN_INFO "Card registered: %s\n", card->longname); + dev_info(card->dev, "Card registered: %s\n", card->longname); pci_set_drvdata(pci, chip); dev++; return 0; ctl_error: - snd_printk(KERN_ERR "new control error %d\n", err); + dev_err(card->dev, "new control error %d\n", err); snd_card_free(card); return err; } @@ -2291,8 +2291,8 @@ static int snd_echo_resume(struct device *dev) if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { + dev_err(chip->card->dev, "cannot grab irq\n"); snd_echo_free(chip); - snd_printk(KERN_ERR "cannot grab irq\n"); return -EBUSY; } chip->irq = pci->irq; @@ -2316,14 +2316,13 @@ static SIMPLE_DEV_PM_OPS(snd_echo_pm, snd_echo_suspend, snd_echo_resume); #endif /* CONFIG_PM_SLEEP */ -static void __devexit snd_echo_remove(struct pci_dev *pci) +static void snd_echo_remove(struct pci_dev *pci) { struct echoaudio *chip; chip = pci_get_drvdata(pci); if (chip) snd_card_free(chip->card); - pci_set_drvdata(pci, NULL); } @@ -2337,7 +2336,7 @@ static struct pci_driver echo_driver = { .name = KBUILD_MODNAME, .id_table = snd_echo_ids, .probe = snd_echo_probe, - .remove = __devexit_p(snd_echo_remove), + .remove = snd_echo_remove, .driver = { .pm = SND_ECHO_PM_OPS, }, diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index e158369f5fa..b86b88da81c 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h @@ -475,8 +475,8 @@ static int enable_midi_input(struct echoaudio *chip, char enable); static void snd_echo_midi_output_trigger( struct snd_rawmidi_substream *substream, int up); static int midi_service_irq(struct echoaudio *chip); -static int __devinit snd_echo_midi_create(struct snd_card *card, - struct echoaudio *chip); +static int snd_echo_midi_create(struct snd_card *card, + struct echoaudio *chip); #endif diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index d8c670c9d62..5a6a217b82e 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c @@ -53,7 +53,7 @@ static int wait_handshake(struct echoaudio *chip) udelay(1); } - snd_printk(KERN_ERR "wait_handshake(): Timeout waiting for DSP\n"); + dev_err(chip->card->dev, "wait_handshake(): Timeout waiting for DSP\n"); return -EBUSY; } @@ -149,7 +149,8 @@ static int read_sn(struct echoaudio *chip) for (i = 0; i < 5; i++) { if (read_dsp(chip, &sn[i])) { - snd_printk(KERN_ERR "Failed to read serial number\n"); + dev_err(chip->card->dev, + "Failed to read serial number\n"); return -EIO; } } @@ -184,7 +185,7 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) err = get_firmware(&fw, chip, asic); if (err < 0) { - snd_printk(KERN_WARNING "Firmware not found !\n"); + dev_warn(chip->card->dev, "Firmware not found !\n"); return err; } @@ -247,7 +248,7 @@ static int install_resident_loader(struct echoaudio *chip) i = get_firmware(&fw, chip, FW_361_LOADER); if (i < 0) { - snd_printk(KERN_WARNING "Firmware not found !\n"); + dev_warn(chip->card->dev, "Firmware not found !\n"); return i; } diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c index a953d142cb4..7f4dfae0323 100644 --- a/sound/pci/echoaudio/midi.c +++ b/sound/pci/echoaudio/midi.c @@ -221,7 +221,8 @@ static void snd_echo_midi_output_write(unsigned long data) DE_MID(("Try to send %d bytes...\n", bytes)); sent = write_midi(chip, buf, bytes); if (sent < 0) { - snd_printk(KERN_ERR "write_midi() error %d\n", sent); + dev_err(chip->card->dev, + "write_midi() error %d\n", sent); /* retry later */ sent = 9000; chip->midi_full = 1; @@ -307,8 +308,8 @@ static struct snd_rawmidi_ops snd_echo_midi_output = { /* <--snd_echo_probe() */ -static int __devinit snd_echo_midi_create(struct snd_card *card, - struct echoaudio *chip) +static int snd_echo_midi_create(struct snd_card *card, + struct echoaudio *chip) { int err; diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index b7c1875ba90..ad9d9f8b48e 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c @@ -99,8 +99,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { MODULE_DEVICE_TABLE(pci, snd_emu10k1_ids); -static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_emu10k1_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -117,7 +117,8 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; if (max_buffer_size[dev] < 32) @@ -169,7 +170,8 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_EMU10K1_SYNTH, sizeof(struct snd_emu10k1_synth_arg), &wave) < 0 || wave == NULL) { - snd_printk(KERN_WARNING "can't initialize Emu10k1 wavetable synth\n"); + dev_warn(emu->card->dev, + "can't initialize Emu10k1 wavetable synth\n"); } else { struct snd_emu10k1_synth_arg *arg; arg = SNDRV_SEQ_DEVICE_ARGPTR(wave); @@ -199,10 +201,9 @@ static int __devinit snd_card_emu10k1_probe(struct pci_dev *pci, return err; } -static void __devexit snd_card_emu10k1_remove(struct pci_dev *pci) +static void snd_card_emu10k1_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -215,6 +216,8 @@ static int snd_emu10k1_suspend(struct device *dev) snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + emu->suspend = 1; + snd_pcm_suspend_all(emu->pcm); snd_pcm_suspend_all(emu->pcm_mic); snd_pcm_suspend_all(emu->pcm_efx); @@ -245,8 +248,7 @@ static int snd_emu10k1_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "emu10k1: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -260,6 +262,8 @@ static int snd_emu10k1_resume(struct device *dev) if (emu->card_capabilities->ca0151_chip) snd_p16v_resume(emu); + emu->suspend = 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } @@ -274,7 +278,7 @@ static struct pci_driver emu10k1_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, - .remove = __devexit_p(snd_card_emu10k1_remove), + .remove = snd_card_emu10k1_remove, .driver = { .pm = SND_EMU10K1_PM_OPS, }, diff --git a/sound/pci/emu10k1/emu10k1_callback.c b/sound/pci/emu10k1/emu10k1_callback.c index cae36597aa7..3f3ef38d9b6 100644 --- a/sound/pci/emu10k1/emu10k1_callback.c +++ b/sound/pci/emu10k1/emu10k1_callback.c @@ -105,7 +105,7 @@ snd_emu10k1_synth_get_voice(struct snd_emu10k1 *hw) vp = &emu->voices[best[i].voice]; if ((ch = vp->ch) < 0) { /* - printk(KERN_WARNING + dev_warn(emu->card->dev, "synth_get_voice: ch < 0 (%d) ??", i); */ continue; @@ -339,7 +339,7 @@ start_voice(struct snd_emux_voice *vp) return -EINVAL; emem->map_locked++; if (snd_emu10k1_memblk_map(hw, emem) < 0) { - /* printk(KERN_ERR "emu: cannot map!\n"); */ + /* dev_err(hw->card->devK, "emu: cannot map!\n"); */ return -ENOMEM; } mapped_offset = snd_emu10k1_memblk_offset(emem) >> 1; diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index c21adb6ef1d..22926978802 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c @@ -217,7 +217,7 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) } if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ /* Hacks for Alice3 to work independent of haP16V driver */ - snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); + dev_info(emu->card->dev, "Audigy2 value: Special config.\n"); /* Setup SRCMulti_I2S SamplingRate */ tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); tmp &= 0xfffff1ff; @@ -657,22 +657,17 @@ static int snd_emu10k1_cardbus_init(struct snd_emu10k1 *emu) return 0; } -static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filename) +static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, + const struct firmware *fw_entry) { - int err; int n, i; int reg; int value; unsigned int write_post; unsigned long flags; - const struct firmware *fw_entry; - err = request_firmware(&fw_entry, filename, &emu->pci->dev); - if (err != 0) { - snd_printk(KERN_ERR "firmware: %s not found. Err = %d\n", filename, err); - return err; - } - snd_printk(KERN_INFO "firmware size = 0x%zx\n", fw_entry->size); + if (!fw_entry) + return -EIO; /* The FPGA is a Xilinx Spartan IIE XC2S50E */ /* GPIO7 -> FPGA PGMN @@ -705,7 +700,6 @@ static int snd_emu1010_load_firmware(struct snd_emu10k1 *emu, const char *filena write_post = inl(emu->port + A_IOCFG); spin_unlock_irqrestore(&emu->emu_lock, flags); - release_firmware(fw_entry); return 0; } @@ -720,45 +714,68 @@ static int emu1010_firmware_thread(void *data) msleep_interruptible(1000); if (kthread_should_stop()) break; +#ifdef CONFIG_PM_SLEEP + if (emu->suspend) + continue; +#endif snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, &tmp); /* IRQ Status */ snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); /* OPTIONS: Which cards are attached to the EMU */ if (reg & EMU_HANA_OPTION_DOCK_OFFLINE) { /* Audio Dock attached */ /* Return to Audio Dock programming mode */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware\n"); + dev_info(emu->card->dev, + "emu1010: Loading Audio Dock Firmware\n"); snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, EMU_HANA_FPGA_CONFIG_AUDIODOCK); - if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010) { - err = snd_emu1010_load_firmware(emu, DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1010B) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) - continue; - } else if (emu->card_capabilities->emu_model == - EMU_MODEL_EMU1616) { - err = snd_emu1010_load_firmware(emu, MICRO_DOCK_FILENAME); - if (err != 0) + + if (!emu->dock_fw) { + const char *filename = NULL; + switch (emu->card_capabilities->emu_model) { + case EMU_MODEL_EMU1010: + filename = DOCK_FILENAME; + break; + case EMU_MODEL_EMU1010B: + filename = MICRO_DOCK_FILENAME; + break; + case EMU_MODEL_EMU1616: + filename = MICRO_DOCK_FILENAME; + break; + } + if (filename) { + err = request_firmware(&emu->dock_fw, + filename, + &emu->pci->dev); + if (err) + continue; + } + } + + if (emu->dock_fw) { + err = snd_emu1010_load_firmware(emu, emu->dock_fw); + if (err) continue; } snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0); snd_emu1010_fpga_read(emu, EMU_HANA_IRQ_STATUS, ®); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", reg); + dev_info(emu->card->dev, + "emu1010: EMU_HANA+DOCK_IRQ_STATUS = 0x%x\n", + reg); /* ID, should read & 0x7f = 0x55 when FPGA programmed. */ snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printk(KERN_INFO "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); + dev_info(emu->card->dev, + "emu1010: EMU_HANA+DOCK_ID = 0x%x\n", reg); if ((reg & 0x1f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", reg); + dev_info(emu->card->dev, + "emu1010: Loading Audio Dock Firmware file failed, reg = 0x%x\n", + reg); continue; } - snd_printk(KERN_INFO "emu1010: Audio Dock Firmware loaded\n"); + dev_info(emu->card->dev, + "emu1010: Audio Dock Firmware loaded\n"); snd_emu1010_fpga_read(emu, EMU_DOCK_MAJOR_REV, &tmp); snd_emu1010_fpga_read(emu, EMU_DOCK_MINOR_REV, &tmp2); - snd_printk(KERN_INFO "Audio Dock ver: %u.%u\n", + dev_info(emu->card->dev, "Audio Dock ver: %u.%u\n", tmp, tmp2); /* Sync clocking between 1010 and Dock */ /* Allow DLL to settle */ @@ -767,7 +784,7 @@ static int emu1010_firmware_thread(void *data) snd_emu1010_fpga_write(emu, EMU_HANA_UNMUTE, EMU_UNMUTE); } } - snd_printk(KERN_INFO "emu1010: firmware thread stopping\n"); + dev_info(emu->card->dev, "emu1010: firmware thread stopping\n"); return 0; } @@ -807,9 +824,8 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) unsigned int i; u32 tmp, tmp2, reg; int err; - const char *filename = NULL; - snd_printk(KERN_INFO "emu1010: Special config.\n"); + dev_info(emu->card->dev, "emu1010: Special config.\n"); /* AC97 2.1, Any 16Meg of 4Gig address, Auto-Mute, EMU32 Slave, * Lock Sound Memory Cache, Lock Tank Memory Cache, * Mute all codecs. @@ -834,7 +850,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) /* ID, should read & 0x7f = 0x55. (Bit 7 is the IRQ bit) */ snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printdd("reg1 = 0x%x\n", reg); + dev_dbg(emu->card->dev, "reg1 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA netlist already present so clear it */ /* Return to programming mode */ @@ -842,37 +858,49 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_write(emu, EMU_HANA_FPGA_CONFIG, 0x02); } snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); - snd_printdd("reg2 = 0x%x\n", reg); + dev_dbg(emu->card->dev, "reg2 = 0x%x\n", reg); if ((reg & 0x3f) == 0x15) { /* FPGA failed to return to programming mode */ - snd_printk(KERN_INFO "emu1010: FPGA failed to return to programming mode\n"); + dev_info(emu->card->dev, + "emu1010: FPGA failed to return to programming mode\n"); return -ENODEV; } - snd_printk(KERN_INFO "emu1010: EMU_HANA_ID = 0x%x\n", reg); - switch (emu->card_capabilities->emu_model) { - case EMU_MODEL_EMU1010: - filename = HANA_FILENAME; - break; - case EMU_MODEL_EMU1010B: - filename = EMU1010B_FILENAME; - break; - case EMU_MODEL_EMU1616: - filename = EMU1010_NOTEBOOK_FILENAME; - break; - case EMU_MODEL_EMU0404: - filename = EMU0404_FILENAME; - break; - default: - filename = NULL; - return -ENODEV; - break; + dev_info(emu->card->dev, "emu1010: EMU_HANA_ID = 0x%x\n", reg); + + if (!emu->firmware) { + const char *filename; + switch (emu->card_capabilities->emu_model) { + case EMU_MODEL_EMU1010: + filename = HANA_FILENAME; + break; + case EMU_MODEL_EMU1010B: + filename = EMU1010B_FILENAME; + break; + case EMU_MODEL_EMU1616: + filename = EMU1010_NOTEBOOK_FILENAME; + break; + case EMU_MODEL_EMU0404: + filename = EMU0404_FILENAME; + break; + default: + return -ENODEV; + } + + err = request_firmware(&emu->firmware, filename, &emu->pci->dev); + if (err != 0) { + dev_info(emu->card->dev, + "emu1010: firmware: %s not found. Err = %d\n", + filename, err); + return err; + } + dev_info(emu->card->dev, + "emu1010: firmware file = %s, size = 0x%zx\n", + filename, emu->firmware->size); } - snd_printk(KERN_INFO "emu1010: filename %s testing\n", filename); - err = snd_emu1010_load_firmware(emu, filename); + + err = snd_emu1010_load_firmware(emu, emu->firmware); if (err != 0) { - snd_printk( - KERN_INFO "emu1010: Loading Firmware file %s failed\n", - filename); + dev_info(emu->card->dev, "emu1010: Loading Firmware failed\n"); return err; } @@ -880,21 +908,23 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_read(emu, EMU_HANA_ID, ®); if ((reg & 0x3f) != 0x15) { /* FPGA failed to be programmed */ - snd_printk(KERN_INFO "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", reg); + dev_info(emu->card->dev, + "emu1010: Loading Hana Firmware file failed, reg = 0x%x\n", + reg); return -ENODEV; } - snd_printk(KERN_INFO "emu1010: Hana Firmware loaded\n"); + dev_info(emu->card->dev, "emu1010: Hana Firmware loaded\n"); snd_emu1010_fpga_read(emu, EMU_HANA_MAJOR_REV, &tmp); snd_emu1010_fpga_read(emu, EMU_HANA_MINOR_REV, &tmp2); - snd_printk(KERN_INFO "emu1010: Hana version: %u.%u\n", tmp, tmp2); + dev_info(emu->card->dev, "emu1010: Hana version: %u.%u\n", tmp, tmp2); /* Enable 48Volt power to Audio Dock */ snd_emu1010_fpga_write(emu, EMU_HANA_DOCK_PWR, EMU_HANA_DOCK_PWR_ON); snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options = 0x%x\n", reg); + dev_info(emu->card->dev, "emu1010: Card options = 0x%x\n", reg); snd_emu1010_fpga_read(emu, EMU_HANA_OPTICAL_TYPE, &tmp); /* Optical -> ADAT I/O */ /* 0 : SPDIF @@ -933,7 +963,7 @@ static int snd_emu10k1_emu1010_init(struct snd_emu10k1 *emu) snd_emu1010_fpga_write(emu, EMU_HANA_IRQ_ENABLE, 0x00); snd_emu1010_fpga_read(emu, EMU_HANA_OPTION_CARDS, ®); - snd_printk(KERN_INFO "emu1010: Card options3 = 0x%x\n", reg); + dev_info(emu->card->dev, "emu1010: Card options3 = 0x%x\n", reg); /* Default WCLK set to 48kHz. */ snd_emu1010_fpga_write(emu, EMU_HANA_DEFCLOCK, 0x00); /* Word Clock source, Internal 48kHz x1 */ @@ -1259,6 +1289,10 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu) } if (emu->emu1010.firmware_thread) kthread_stop(emu->emu1010.firmware_thread); + if (emu->firmware) + release_firmware(emu->firmware); + if (emu->dock_fw) + release_firmware(emu->dock_fw); if (emu->irq >= 0) free_irq(emu->irq, emu); /* remove reserved page */ @@ -1738,7 +1772,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { { } /* terminator */ }; -int __devinit snd_emu10k1_create(struct snd_card *card, +int snd_emu10k1_create(struct snd_card *card, struct pci_dev *pci, unsigned short extin_mask, unsigned short extout_mask, @@ -1787,7 +1821,9 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &emu->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &emu->model); - snd_printdd("vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", pci->vendor, pci->device, emu->serial, emu->model); + dev_dbg(card->dev, + "vendor = 0x%x, device = 0x%x, subsystem_vendor_id = 0x%x, subsystem_id = 0x%x\n", + pci->vendor, pci->device, emu->serial, emu->model); for (c = emu_chip_details; c->vendor; c++) { if (c->vendor == pci->vendor && c->device == pci->device) { @@ -1806,21 +1842,21 @@ int __devinit snd_emu10k1_create(struct snd_card *card, } } if (c->vendor == 0) { - snd_printk(KERN_ERR "emu10k1: Card not recognised\n"); + dev_err(card->dev, "emu10k1: Card not recognised\n"); kfree(emu); pci_disable_device(pci); return -ENOENT; } emu->card_capabilities = c; if (c->subsystem && !subsystem) - snd_printdd("Sound card name = %s\n", c->name); + dev_dbg(card->dev, "Sound card name = %s\n", c->name); else if (subsystem) - snd_printdd("Sound card name = %s, " + dev_dbg(card->dev, "Sound card name = %s, " "vendor = 0x%x, device = 0x%x, subsystem = 0x%x. " "Forced to subsystem = 0x%x\n", c->name, pci->vendor, pci->device, emu->serial, c->subsystem); else - snd_printdd("Sound card name = %s, " + dev_dbg(card->dev, "Sound card name = %s, " "vendor = 0x%x, device = 0x%x, subsystem = 0x%x.\n", c->name, pci->vendor, pci->device, emu->serial); @@ -1848,7 +1884,9 @@ int __devinit snd_emu10k1_create(struct snd_card *card, emu->dma_mask = is_audigy ? AUDIGY_DMA_MASK : EMU10K1_DMA_MASK; if (pci_set_dma_mask(pci, emu->dma_mask) < 0 || pci_set_consistent_dma_mask(pci, emu->dma_mask) < 0) { - snd_printk(KERN_ERR "architecture does not support PCI busmaster DMA with mask 0x%lx\n", emu->dma_mask); + dev_err(card->dev, + "architecture does not support PCI busmaster DMA with mask 0x%lx\n", + emu->dma_mask); kfree(emu); pci_disable_device(pci); return -ENXIO; @@ -2000,7 +2038,6 @@ int __devinit snd_emu10k1_create(struct snd_card *card, snd_emu10k1_proc_init(emu); #endif - snd_card_set_dev(card, &pci->dev); *remu = emu; return 0; @@ -2025,7 +2062,7 @@ static unsigned char saved_regs_audigy[] = { 0xff /* end */ }; -static int __devinit alloc_pm_buffer(struct snd_emu10k1 *emu) +static int alloc_pm_buffer(struct snd_emu10k1 *emu) { int size; diff --git a/sound/pci/emu10k1/emu10k1_patch.c b/sound/pci/emu10k1/emu10k1_patch.c index e10f027bde0..0e069aeab86 100644 --- a/sound/pci/emu10k1/emu10k1_patch.c +++ b/sound/pci/emu10k1/emu10k1_patch.c @@ -50,7 +50,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, return -EINVAL; if (sp->v.size == 0) { - snd_printd("emu: rom font for sample %d\n", sp->v.sample); + dev_dbg(emu->card->dev, + "emu: rom font for sample %d\n", sp->v.sample); return 0; } @@ -92,7 +93,8 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, blocksize *= 2; sp->block = snd_emu10k1_synth_alloc(emu, blocksize); if (sp->block == NULL) { - snd_printd("emu10k1: synth malloc failed (size=%d)\n", blocksize); + dev_dbg(emu->card->dev, + "synth malloc failed (size=%d)\n", blocksize); /* not ENOMEM (for compatibility with OSS) */ return -ENOSPC; } @@ -123,7 +125,7 @@ snd_emu10k1_sample_new(struct snd_emux *rec, struct snd_sf_sample *sp, offset += size; data += size; -#if 0 /* not suppported yet */ +#if 0 /* not supported yet */ /* handle reverse (or bidirectional) loop */ if (sp->v.mode_flags & (SNDRV_SFNT_SAMPLE_BIDIR_LOOP|SNDRV_SFNT_SAMPLE_REVERSE_LOOP)) { /* copy loop in reverse */ diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 556fd6f456e..efe01752697 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -369,7 +369,8 @@ static void snd_emu10k1x_pcm_interrupt(struct emu10k1x *emu, struct emu10k1x_voi if (epcm->substream == NULL) return; #if 0 - snd_printk(KERN_INFO "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", + dev_info(emu->card->dev, + "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", epcm->substream->ops->pointer(epcm->substream), snd_pcm_lib_period_bytes(epcm->substream), snd_pcm_lib_buffer_bytes(epcm->substream)); @@ -487,7 +488,11 @@ static int snd_emu10k1x_pcm_trigger(struct snd_pcm_substream *substream, int channel = epcm->voice->number; int result = 0; -// snd_printk(KERN_INFO "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", (int)emu, cmd, (int)substream->ops->pointer(substream)); + /* + dev_dbg(emu->card->dev, + "trigger - emu10k1x = 0x%x, cmd = %i, pointer = %d\n", + (int)emu, cmd, (int)substream->ops->pointer(substream)); + */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -826,7 +831,7 @@ static irqreturn_t snd_emu10k1x_interrupt(int irq, void *dev_id) // acknowledge the interrupt if necessary outl(status, chip->port + IPR); - // snd_printk(KERN_INFO "interrupt %08x\n", status); + /* dev_dbg(chip->card->dev, "interrupt %08x\n", status); */ return IRQ_HANDLED; } @@ -842,7 +847,7 @@ static const struct snd_pcm_chmap_elem clfe_map[] = { { } }; -static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) +static int snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; const struct snd_pcm_chmap_elem *map = NULL; @@ -902,9 +907,9 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s return 0; } -static int __devinit snd_emu10k1x_create(struct snd_card *card, - struct pci_dev *pci, - struct emu10k1x **rchip) +static int snd_emu10k1x_create(struct snd_card *card, + struct pci_dev *pci, + struct emu10k1x **rchip) { struct emu10k1x *chip; int err; @@ -919,7 +924,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, return err; if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { - snd_printk(KERN_ERR "error to set 28bit mask DMA\n"); + dev_err(card->dev, "error to set 28bit mask DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -940,14 +945,15 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, chip->port = pci_resource_start(pci, 0); if ((chip->res_port = request_region(chip->port, 8, "EMU10K1X")) == NULL) { - snd_printk(KERN_ERR "emu10k1x: cannot allocate the port 0x%lx\n", chip->port); + dev_err(card->dev, "cannot allocate the port 0x%lx\n", + chip->port); snd_emu10k1x_free(chip); return -EBUSY; } if (request_irq(pci->irq, snd_emu10k1x_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "emu10k1x: cannot grab irq %d\n", pci->irq); + dev_err(card->dev, "cannot grab irq %d\n", pci->irq); snd_emu10k1x_free(chip); return -EBUSY; } @@ -964,7 +970,7 @@ static int __devinit snd_emu10k1x_create(struct snd_card *card, chip->revision = pci->revision; pci_read_config_dword(pci, PCI_SUBSYSTEM_VENDOR_ID, &chip->serial); pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &chip->model); - snd_printk(KERN_INFO "Model %04x Rev %08x Serial %08x\n", chip->model, + dev_info(card->dev, "Model %04x Rev %08x Serial %08x\n", chip->model, chip->revision, chip->serial); outl(0, chip->port + INTE); @@ -1066,7 +1072,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, } } -static int __devinit snd_emu10k1x_proc_init(struct emu10k1x * emu) +static int snd_emu10k1x_proc_init(struct emu10k1x *emu) { struct snd_info_entry *entry; @@ -1115,7 +1121,7 @@ static int snd_emu10k1x_shared_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_emu10k1x_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_emu10k1x_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog/Digital Output Jack", @@ -1194,7 +1200,7 @@ static struct snd_kcontrol_new snd_emu10k1x_spdif_control = .put = snd_emu10k1x_spdif_put }; -static int __devinit snd_emu10k1x_mixer(struct emu10k1x *emu) +static int snd_emu10k1x_mixer(struct emu10k1x *emu) { int err; struct snd_kcontrol *kctl; @@ -1248,7 +1254,9 @@ static void mpu401_clear_rx(struct emu10k1x *emu, struct emu10k1x_midi *mpu) mpu401_read_data(emu, mpu); #ifdef CONFIG_SND_DEBUG if (timeout <= 0) - snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu)); + dev_err(emu->card->dev, + "cmd: clear rx timeout (status = 0x%x)\n", + mpu401_read_stat(emu, mpu)); #endif } @@ -1322,7 +1330,8 @@ static int snd_emu10k1x_midi_cmd(struct emu10k1x * emu, } spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) { - snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", + dev_err(emu->card->dev, + "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", cmd, emu->port, mpu401_read_stat(emu, midi), mpu401_read_data(emu, midi)); @@ -1507,8 +1516,9 @@ static void snd_emu10k1x_midi_free(struct snd_rawmidi *rmidi) midi->rmidi = NULL; } -static int __devinit emu10k1x_midi_init(struct emu10k1x *emu, - struct emu10k1x_midi *midi, int device, char *name) +static int emu10k1x_midi_init(struct emu10k1x *emu, + struct emu10k1x_midi *midi, int device, + char *name) { struct snd_rawmidi *rmidi; int err; @@ -1531,7 +1541,7 @@ static int __devinit emu10k1x_midi_init(struct emu10k1x *emu, return 0; } -static int __devinit snd_emu10k1x_midi(struct emu10k1x *emu) +static int snd_emu10k1x_midi(struct emu10k1x *emu) { struct emu10k1x_midi *midi = &emu->midi; int err; @@ -1548,8 +1558,8 @@ static int __devinit snd_emu10k1x_midi(struct emu10k1x *emu) return 0; } -static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_emu10k1x_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1563,7 +1573,8 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -1607,8 +1618,6 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx irq %i", card->shortname, chip->port, chip->irq); - snd_card_set_dev(card, &pci->dev); - if ((err = snd_card_register(card)) < 0) { snd_card_free(card); return err; @@ -1619,10 +1628,9 @@ static int __devinit snd_emu10k1x_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) +static void snd_emu10k1x_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } // PCI IDs @@ -1637,7 +1645,7 @@ static struct pci_driver emu10k1x_driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, - .remove = __devexit_p(snd_emu10k1x_remove), + .remove = snd_emu10k1x_remove, }; module_pci_driver(emu10k1x_driver); diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index 52419959178..745f0627c63 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c @@ -1073,7 +1073,7 @@ static int snd_emu10k1_ipcm_peek(struct snd_emu10k1 *emu, #define SND_EMU10K1_PLAYBACK_CHANNELS 8 #define SND_EMU10K1_CAPTURE_CHANNELS 4 -static void __devinit +static void snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1094,7 +1094,7 @@ snd_emu10k1_init_mono_control(struct snd_emu10k1_fx8010_control_gpr *ctl, } } -static void __devinit +static void snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1116,7 +1116,7 @@ snd_emu10k1_init_stereo_control(struct snd_emu10k1_fx8010_control_gpr *ctl, } } -static void __devinit +static void snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1129,7 +1129,7 @@ snd_emu10k1_init_mono_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, ctl->translation = EMU10K1_GPR_TRANSLATION_ONOFF; } -static void __devinit +static void snd_emu10k1_init_stereo_onoff_control(struct snd_emu10k1_fx8010_control_gpr *ctl, const char *name, int gpr, int defval) { @@ -1168,7 +1168,7 @@ static int snd_emu10k1_audigy_dsp_convert_32_to_2x16( * initial DSP configuration for Audigy */ -static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) +static int _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, nctl; int bit_shifter16; @@ -1182,15 +1182,20 @@ static int __devinit _snd_emu10k1_audigy_init_efx(struct snd_emu10k1 *emu) u32 *gpr_map; mm_segment_t seg; - if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL || - (icode->gpr_map = (u_int32_t __user *) - kcalloc(512 + 256 + 256 + 2 * 1024, sizeof(u_int32_t), - GFP_KERNEL)) == NULL || - (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, - sizeof(*controls), GFP_KERNEL)) == NULL) { - err = -ENOMEM; - goto __err; - } + err = -ENOMEM; + icode = kzalloc(sizeof(*icode), GFP_KERNEL); + if (!icode) + return err; + + icode->gpr_map = (u_int32_t __user *) kcalloc(512 + 256 + 256 + 2 * 1024, + sizeof(u_int32_t), GFP_KERNEL); + if (!icode->gpr_map) + goto __err_gpr; + controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, + sizeof(*controls), GFP_KERNEL); + if (!controls) + goto __err_ctrls; + gpr_map = (u32 __force *)icode->gpr_map; icode->tram_data_map = icode->gpr_map + 512; @@ -1542,7 +1547,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* A_PUT_STEREO_OUTPUT(A_EXTOUT_FRONT_L, A_EXTOUT_FRONT_R, playback + SND_EMU10K1_PLAYBACK_CHANNELS); */ if (emu->card_capabilities->emu_model) { /* EMU1010 Outputs from PCM Front, Rear, Center, LFE, Side */ - snd_printk(KERN_INFO "EMU outputs on\n"); + dev_info(emu->card->dev, "EMU outputs on\n"); for (z = 0; z < 8; z++) { if (emu->card_capabilities->ca0108_chip) { A_OP(icode, &ptr, iACC3, A3_EMU32OUT(z), A_GPR(playback + SND_EMU10K1_PLAYBACK_CHANNELS + z), A_C_00000000, A_C_00000000); @@ -1566,7 +1571,9 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_SWITCH(icode, &ptr, tmp + 1, playback + SND_EMU10K1_PLAYBACK_CHANNELS + z, tmp + 1); if ((z==1) && (emu->card_capabilities->spdif_bug)) { /* Due to a SPDIF output bug on some Audigy cards, this code delays the Right channel by 1 sample */ - snd_printk(KERN_INFO "Installing spdif_bug patch: %s\n", emu->card_capabilities->name); + dev_info(emu->card->dev, + "Installing spdif_bug patch: %s\n", + emu->card_capabilities->name); A_OP(icode, &ptr, iACC3, A_EXTOUT(A_EXTOUT_FRONT_L + z), A_GPR(gpr - 3), A_C_00000000, A_C_00000000); A_OP(icode, &ptr, iACC3, A_GPR(gpr - 3), A_GPR(tmp + 0), A_GPR(tmp + 1), A_C_00000000); } else { @@ -1590,7 +1597,7 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) if (emu->card_capabilities->emu_model) { if (emu->card_capabilities->ca0108_chip) { - snd_printk(KERN_INFO "EMU2 inputs on\n"); + dev_info(emu->card->dev, "EMU2 inputs on\n"); for (z = 0; z < 0x10; z++) { snd_emu10k1_audigy_dsp_convert_32_to_2x16( icode, &ptr, tmp, bit_shifter16, @@ -1598,11 +1605,11 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) A_FXBUS2(z*2) ); } } else { - snd_printk(KERN_INFO "EMU inputs on\n"); + dev_info(emu->card->dev, "EMU inputs on\n"); /* Capture 16 (originally 8) channels of S32_LE sound */ /* - printk(KERN_DEBUG "emufx.c: gpr=0x%x, tmp=0x%x\n", + dev_dbg(emu->card->dev, "emufx.c: gpr=0x%x, tmp=0x%x\n", gpr, tmp); */ /* For the EMU1010: How to get 32bit values from the DSP. High 16bits into L, low 16bits into R. */ @@ -1741,12 +1748,12 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) emu->support_tlv = 0; /* clear again */ snd_leave_user(seg); - __err: +__err: kfree(controls); - if (icode != NULL) { - kfree((void __force *)icode->gpr_map); - kfree(icode); - } +__err_ctrls: + kfree((void __force *)icode->gpr_map); +__err_gpr: + kfree(icode); return err; } @@ -1757,14 +1764,14 @@ A_OP(icode, &ptr, iMAC0, A_GPR(var), A_GPR(var), A_GPR(vol), A_EXTIN(input)) /* when volume = max, then copy only to avoid volume modification */ /* with iMAC0 (negative values) */ -static void __devinit _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iMAC0, dst, C_00000000, src, vol); OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000001); OP(icode, ptr, iACC3, dst, src, C_00000000, C_00000000); } -static void __devinit _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); @@ -1772,7 +1779,7 @@ static void __devinit _volume_add(struct snd_emu10k1_fx8010_code *icode, u32 *pt OP(icode, ptr, iSKIP, C_00000000, C_7fffffff, C_7fffffff, C_00000001); OP(icode, ptr, iMAC0, dst, dst, src, vol); } -static void __devinit _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) +static void _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *ptr, u32 dst, u32 src, u32 vol) { OP(icode, ptr, iANDXOR, C_00000000, vol, C_ffffffff, C_7fffffff); OP(icode, ptr, iSKIP, GPR_COND, GPR_COND, CC_REG_NONZERO, C_00000002); @@ -1803,7 +1810,7 @@ static void __devinit _volume_out(struct snd_emu10k1_fx8010_code *icode, u32 *pt _SWITCH_NEG(icode, ptr, GPR(dst), GPR(src)) -static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) +static int _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) { int err, i, z, gpr, tmp, playback, capture; u32 ptr; @@ -1813,18 +1820,26 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) u32 *gpr_map; mm_segment_t seg; - if ((icode = kzalloc(sizeof(*icode), GFP_KERNEL)) == NULL) - return -ENOMEM; - if ((icode->gpr_map = (u_int32_t __user *) - kcalloc(256 + 160 + 160 + 2 * 512, sizeof(u_int32_t), - GFP_KERNEL)) == NULL || - (controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, - sizeof(struct snd_emu10k1_fx8010_control_gpr), - GFP_KERNEL)) == NULL || - (ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL)) == NULL) { - err = -ENOMEM; - goto __err; - } + err = -ENOMEM; + icode = kzalloc(sizeof(*icode), GFP_KERNEL); + if (!icode) + return err; + + icode->gpr_map = (u_int32_t __user *) kcalloc(256 + 160 + 160 + 2 * 512, + sizeof(u_int32_t), GFP_KERNEL); + if (!icode->gpr_map) + goto __err_gpr; + + controls = kcalloc(SND_EMU10K1_GPR_CONTROLS, + sizeof(struct snd_emu10k1_fx8010_control_gpr), + GFP_KERNEL); + if (!controls) + goto __err_ctrls; + + ipcm = kzalloc(sizeof(*ipcm), GFP_KERNEL); + if (!ipcm) + goto __err_ipcm; + gpr_map = (u32 __force *)icode->gpr_map; icode->tram_data_map = icode->gpr_map + 256; @@ -2363,17 +2378,18 @@ static int __devinit _snd_emu10k1_init_efx(struct snd_emu10k1 *emu) snd_leave_user(seg); if (err >= 0) err = snd_emu10k1_ipcm_poke(emu, ipcm); - __err: +__err: kfree(ipcm); +__err_ipcm: kfree(controls); - if (icode != NULL) { - kfree((void __force *)icode->gpr_map); - kfree(icode); - } +__err_ctrls: + kfree((void __force *)icode->gpr_map); +__err_gpr: + kfree(icode); return err; } -int __devinit snd_emu10k1_init_efx(struct snd_emu10k1 *emu) +int snd_emu10k1_init_efx(struct snd_emu10k1 *emu) { spin_lock_init(&emu->fx8010.irq_lock); INIT_LIST_HEAD(&emu->fx8010.gpr_ctl); @@ -2626,7 +2642,8 @@ static int snd_emu10k1_fx8010_release(struct snd_hwdep * hw, struct file *file) return 0; } -int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct snd_hwdep ** rhwdep) +int snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, + struct snd_hwdep **rhwdep) { struct snd_hwdep *hw; int err; @@ -2647,7 +2664,7 @@ int __devinit snd_emu10k1_fx8010_new(struct snd_emu10k1 *emu, int device, struct } #ifdef CONFIG_PM_SLEEP -int __devinit snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu) +int snd_emu10k1_efx_alloc_pm_buffer(struct snd_emu10k1 *emu) { int len; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9d890a5aec5..c5ae2a24d8a 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -510,7 +510,7 @@ static int snd_emu1010_input_source_put(struct snd_kcontrol *kcontrol, .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] = { EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), @@ -539,7 +539,7 @@ static struct snd_kcontrol_new snd_emu1010_output_enum_ctls[] __devinitdata = { /* 1616(m) cardbus */ -static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] = { EMU1010_SOURCE_OUTPUT("Dock DAC1 Left Playback Enum", 0), EMU1010_SOURCE_OUTPUT("Dock DAC1 Right Playback Enum", 1), EMU1010_SOURCE_OUTPUT("Dock DAC2 Left Playback Enum", 2), @@ -571,7 +571,7 @@ static struct snd_kcontrol_new snd_emu1616_output_enum_ctls[] __devinitdata = { .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_input_enum_ctls[] = { EMU1010_SOURCE_INPUT("DSP 0 Capture Enum", 0), EMU1010_SOURCE_INPUT("DSP 1 Capture Enum", 1), EMU1010_SOURCE_INPUT("DSP 2 Capture Enum", 2), @@ -639,7 +639,7 @@ static int snd_emu1010_adc_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_adc_pads[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_adc_pads[] = { EMU1010_ADC_PADS("ADC1 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD1), EMU1010_ADC_PADS("ADC2 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD2), EMU1010_ADC_PADS("ADC3 14dB PAD Audio Dock Capture Switch", EMU_HANA_DOCK_ADC_PAD3), @@ -687,7 +687,7 @@ static int snd_emu1010_dac_pads_put(struct snd_kcontrol *kcontrol, struct snd_ct .private_value = chid \ } -static struct snd_kcontrol_new snd_emu1010_dac_pads[] __devinitdata = { +static struct snd_kcontrol_new snd_emu1010_dac_pads[] = { EMU1010_DAC_PADS("DAC1 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD1), EMU1010_DAC_PADS("DAC2 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD2), EMU1010_DAC_PADS("DAC3 Audio Dock 14dB PAD Playback Switch", EMU_HANA_DOCK_DAC_PAD3), @@ -989,7 +989,7 @@ static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { +static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = { I2C_VOLUME("Mic Capture Volume", 0), I2C_VOLUME("Line Capture Volume", 0) }; @@ -1621,7 +1621,7 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_emu10k1_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "SB Live Analog/Digital Output Jack", @@ -1630,7 +1630,7 @@ static struct snd_kcontrol_new snd_emu10k1_shared_spdif __devinitdata = .put = snd_emu10k1_shared_spdif_put }; -static struct snd_kcontrol_new snd_audigy_shared_spdif __devinitdata = +static struct snd_kcontrol_new snd_audigy_shared_spdif = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Audigy Analog/Digital Output Jack", @@ -1668,7 +1668,7 @@ static int snd_audigy_capture_boost_put(struct snd_kcontrol *kcontrol, return snd_ac97_update(emu->ac97, AC97_REC_GAIN, val); } -static struct snd_kcontrol_new snd_audigy_capture_boost __devinitdata = +static struct snd_kcontrol_new snd_audigy_capture_boost = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Capture Boost", @@ -1716,8 +1716,8 @@ static int rename_ctl(struct snd_card *card, const char *src, const char *dst) return -ENOENT; } -int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, - int pcm_device, int multi_device) +int snd_emu10k1_mixer(struct snd_emu10k1 *emu, + int pcm_device, int multi_device) { int err, pcm; struct snd_kcontrol *kctl; @@ -1853,8 +1853,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, if ((err = snd_ac97_mixer(pbus, &ac97, &emu->ac97)) < 0) { if (emu->card_capabilities->ac97_chip == 1) return err; - snd_printd(KERN_INFO "emu10k1: AC97 is optional on this board\n"); - snd_printd(KERN_INFO" Proceeding without ac97 mixers...\n"); + dev_info(emu->card->dev, + "AC97 is optional on this board\n"); + dev_info(emu->card->dev, + "Proceeding without ac97 mixers...\n"); snd_device_free(emu->card, pbus); goto no_ac97; /* FIXME: get rid of ugly gotos.. */ } diff --git a/sound/pci/emu10k1/emumpu401.c b/sound/pci/emu10k1/emumpu401.c index bab564824ef..fdf2b0ada48 100644 --- a/sound/pci/emu10k1/emumpu401.c +++ b/sound/pci/emu10k1/emumpu401.c @@ -64,7 +64,9 @@ static void mpu401_clear_rx(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *mp mpu401_read_data(emu, mpu); #ifdef CONFIG_SND_DEBUG if (timeout <= 0) - snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", mpu401_read_stat(emu, mpu)); + dev_err(emu->card->dev, + "cmd: clear rx timeout (status = 0x%x)\n", + mpu401_read_stat(emu, mpu)); #endif } @@ -141,7 +143,8 @@ static int snd_emu10k1_midi_cmd(struct snd_emu10k1 * emu, struct snd_emu10k1_mid } spin_unlock_irqrestore(&midi->input_lock, flags); if (!ok) { - snd_printk(KERN_ERR "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", + dev_err(emu->card->dev, + "midi_cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)!!!\n", cmd, emu->port, mpu401_read_stat(emu, midi), mpu401_read_data(emu, midi)); @@ -326,7 +329,7 @@ static void snd_emu10k1_midi_free(struct snd_rawmidi *rmidi) midi->rmidi = NULL; } -static int __devinit emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name) +static int emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10k1_midi *midi, int device, char *name) { struct snd_rawmidi *rmidi; int err; @@ -349,7 +352,7 @@ static int __devinit emu10k1_midi_init(struct snd_emu10k1 *emu, struct snd_emu10 return 0; } -int __devinit snd_emu10k1_midi(struct snd_emu10k1 *emu) +int snd_emu10k1_midi(struct snd_emu10k1 *emu) { struct snd_emu10k1_midi *midi = &emu->midi; int err; @@ -366,7 +369,7 @@ int __devinit snd_emu10k1_midi(struct snd_emu10k1 *emu) return 0; } -int __devinit snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) +int snd_emu10k1_audigy_midi(struct snd_emu10k1 *emu) { struct snd_emu10k1_midi *midi; int err; diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 0e6664fa6cd..f82481bd254 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c @@ -44,7 +44,8 @@ static void snd_emu10k1_pcm_interrupt(struct snd_emu10k1 *emu, if (epcm->substream == NULL) return; #if 0 - printk(KERN_DEBUG "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", + dev_dbg(emu->card->dev, + "IRQ: position = 0x%x, period = 0x%x, size = 0x%x\n", epcm->substream->runtime->hw->pointer(emu, epcm->substream), snd_pcm_lib_period_bytes(epcm->substream), snd_pcm_lib_buffer_bytes(epcm->substream)); @@ -147,7 +148,7 @@ static int snd_emu10k1_pcm_channel_alloc(struct snd_emu10k1_pcm * epcm, int voic &epcm->extra); if (err < 0) { /* - printk(KERN_DEBUG "pcm_channel_alloc: " + dev_dbg(emu->card->dev, "pcm_channel_alloc: " "failed extra: voices=%d, frame=%d\n", voices, frame); */ @@ -761,7 +762,8 @@ static int snd_emu10k1_playback_trigger(struct snd_pcm_substream *substream, int result = 0; /* - printk(KERN_DEBUG "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", + dev_dbg(emu->card->dev, + "trigger - emu10k1 = 0x%x, cmd = %i, pointer = %i\n", (int)emu, cmd, substream->ops->pointer(substream)) */ spin_lock(&emu->reg_lock); @@ -815,7 +817,7 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, outl(epcm->capture_ipr, emu->port + IPR); snd_emu10k1_intr_enable(emu, epcm->capture_inte); /* - printk(KERN_DEBUG "adccr = 0x%x, adcbs = 0x%x\n", + dev_dbg(emu->card->dev, "adccr = 0x%x, adcbs = 0x%x\n", epcm->adccr, epcm->adcbs); */ switch (epcm->type) { @@ -826,7 +828,10 @@ static int snd_emu10k1_capture_trigger(struct snd_pcm_substream *substream, if (emu->audigy) { snd_emu10k1_ptr_write(emu, A_FXWC1, 0, epcm->capture_cr_val); snd_emu10k1_ptr_write(emu, A_FXWC2, 0, epcm->capture_cr_val2); - snd_printdd("cr_val=0x%x, cr_val2=0x%x\n", epcm->capture_cr_val, epcm->capture_cr_val2); + dev_dbg(emu->card->dev, + "cr_val=0x%x, cr_val2=0x%x\n", + epcm->capture_cr_val, + epcm->capture_cr_val2); } else snd_emu10k1_ptr_write(emu, FXWC, 0, epcm->capture_cr_val); break; @@ -889,7 +894,7 @@ static snd_pcm_uframes_t snd_emu10k1_playback_pointer(struct snd_pcm_substream * } #endif /* - printk(KERN_DEBUG + dev_dbg(emu->card->dev, "ptr = 0x%lx, buffer_size = 0x%lx, period_size = 0x%lx\n", (long)ptr, (long)runtime->buffer_size, (long)runtime->period_size); @@ -1127,7 +1132,7 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) struct snd_emu10k1_pcm *epcm; struct snd_emu10k1_pcm_mixer *mix; struct snd_pcm_runtime *runtime = substream->runtime; - int i, err; + int i, err, sample_rate; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); if (epcm == NULL) @@ -1146,7 +1151,11 @@ static int snd_emu10k1_playback_open(struct snd_pcm_substream *substream) kfree(epcm); return err; } - err = snd_pcm_hw_rule_noresample(runtime, 48000); + if (emu->card_capabilities->emu_model && emu->emu1010.internal_clock == 0) + sample_rate = 44100; + else + sample_rate = 48000; + err = snd_pcm_hw_rule_noresample(runtime, sample_rate); if (err < 0) { kfree(epcm); return err; @@ -1391,7 +1400,7 @@ static struct snd_pcm_ops snd_emu10k1_efx_playback_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int __devinit snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1426,7 +1435,8 @@ int __devinit snd_emu10k1_pcm(struct snd_emu10k1 * emu, int device, struct snd_p return 0; } -int __devinit snd_emu10k1_pcm_multi(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_multi(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; @@ -1469,7 +1479,8 @@ static struct snd_pcm_ops snd_emu10k1_capture_mic_ops = { .pointer = snd_emu10k1_capture_pointer, }; -int __devinit snd_emu10k1_pcm_mic(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_mic(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1588,7 +1599,8 @@ static void snd_emu10k1_fx8010_playback_tram_poke1(unsigned short *dst_left, unsigned int tram_shift) { /* - printk(KERN_DEBUG "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, " + dev_dbg(emu->card->dev, + "tram_poke1: dst_left = 0x%p, dst_right = 0x%p, " "src = 0x%p, count = 0x%x\n", dst_left, dst_right, src, count); */ @@ -1669,7 +1681,7 @@ static int snd_emu10k1_fx8010_playback_prepare(struct snd_pcm_substream *substre unsigned int i; /* - printk(KERN_DEBUG "prepare: etram_pages = 0x%p, dma_area = 0x%x, " + dev_dbg(emu->card->dev, "prepare: etram_pages = 0x%p, dma_area = 0x%x, " "buffer_size = 0x%x (0x%x)\n", emu->fx8010.etram_pages, runtime->dma_area, runtime->buffer_size, runtime->buffer_size << 2); @@ -1810,7 +1822,8 @@ static struct snd_pcm_ops snd_emu10k1_fx8010_playback_ops = { .ack = snd_emu10k1_fx8010_playback_transfer, }; -int __devinit snd_emu10k1_pcm_efx(struct snd_emu10k1 * emu, int device, struct snd_pcm ** rpcm) +int snd_emu10k1_pcm_efx(struct snd_emu10k1 *emu, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_kcontrol *kctl; diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bc38dd4d071..2ca9f2e9313 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -577,7 +577,7 @@ static struct snd_info_entry_ops snd_emu10k1_proc_ops_fx8010 = { .read = snd_emu10k1_fx8010_read, }; -int __devinit snd_emu10k1_proc_init(struct snd_emu10k1 * emu) +int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) { struct snd_info_entry *entry; #ifdef CONFIG_SND_DEBUG diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index e4fba49fee4..706b4f0c680 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -71,11 +71,8 @@ void snd_emu10k1_ptr_write(struct snd_emu10k1 *emu, unsigned int reg, unsigned i unsigned long flags; unsigned int mask; - if (!emu) { - snd_printk(KERN_ERR "ptr_write: emu is null!\n"); - dump_stack(); + if (snd_BUG_ON(!emu)) return; - } mask = emu->audigy ? A_PTR_ADDRESS_MASK : PTR_ADDRESS_MASK; regptr = ((reg << 16) & mask) | (chn & PTR_CHANNELNUM_MASK); @@ -199,7 +196,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, int err = 0; if ((reg > 0x7f) || (value > 0x1ff)) { - snd_printk(KERN_ERR "i2c_write: invalid values.\n"); + dev_err(emu->card->dev, "i2c_write: invalid values.\n"); return -EINVAL; } @@ -227,7 +224,7 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, break; if (timeout > 1000) { - snd_printk(KERN_WARNING + dev_warn(emu->card->dev, "emu10k1:I2C:timeout status=0x%x\n", status); break; @@ -239,8 +236,8 @@ int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, } if (retry == 10) { - snd_printk(KERN_ERR "Writing to ADC failed!\n"); - snd_printk(KERN_ERR "status=0x%x, reg=%d, value=%d\n", + dev_err(emu->card->dev, "Writing to ADC failed!\n"); + dev_err(emu->card->dev, "status=0x%x, reg=%d, value=%d\n", status, reg, value); /* dump_stack(); */ err = -EINVAL; diff --git a/sound/pci/emu10k1/irq.c b/sound/pci/emu10k1/irq.c index 30bfed6f833..3c5c5e3dc2d 100644 --- a/sound/pci/emu10k1/irq.c +++ b/sound/pci/emu10k1/irq.c @@ -41,11 +41,12 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) orig_status = status; handled = 1; if ((status & 0xffffffff) == 0xffffffff) { - snd_printk(KERN_INFO "snd-emu10k1: Suspected sound card removal\n"); + dev_info(emu->card->dev, + "Suspected sound card removal\n"); break; } if (status & IPR_PCIERROR) { - snd_printk(KERN_ERR "interrupt: PCI error\n"); + dev_err(emu->card->dev, "interrupt: PCI error\n"); snd_emu10k1_intr_disable(emu, INTE_PCIERRORENABLE); status &= ~IPR_PCIERROR; } @@ -157,19 +158,22 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) struct snd_emu10k1_voice *pvoice = &(emu->p16v_voices[0]); struct snd_emu10k1_voice *cvoice = &(emu->p16v_capture_voice); - //printk(KERN_INFO "status2=0x%x\n", status2); + /* dev_dbg(emu->card->dev, "status2=0x%x\n", status2); */ orig_status2 = status2; if(status2 & mask) { if(pvoice->use) { snd_pcm_period_elapsed(pvoice->epcm->substream); } else { - snd_printk(KERN_ERR "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", status2, mask, pvoice, pvoice->use); + dev_err(emu->card->dev, + "p16v: status: 0x%08x, mask=0x%08x, pvoice=%p, use=%d\n", + status2, mask, pvoice, + pvoice->use); } } if(status2 & 0x110000) { - //printk(KERN_INFO "capture int found\n"); + /* dev_info(emu->card->dev, "capture int found\n"); */ if(cvoice->use) { - //printk(KERN_INFO "capture period_elapsed\n"); + /* dev_info(emu->card->dev, "capture period_elapsed\n"); */ snd_pcm_period_elapsed(cvoice->epcm->substream); } } @@ -180,7 +184,8 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) if (status) { unsigned int bits; - snd_printk(KERN_ERR "emu10k1: unhandled interrupt: 0x%08x\n", status); + dev_err(emu->card->dev, + "unhandled interrupt: 0x%08x\n", status); //make sure any interrupts we don't handle are disabled: bits = INTE_FXDSPENABLE | INTE_PCIERRORENABLE | @@ -202,7 +207,7 @@ irqreturn_t snd_emu10k1_interrupt(int irq, void *dev_id) outl(orig_status, emu->port + IPR); /* ack all */ } if (timeout == 1000) - snd_printk(KERN_INFO "emu10k1 irq routine failure\n"); + dev_info(emu->card->dev, "emu10k1 irq routine failure\n"); return IRQ_RETVAL(handled); } diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index ae709c1ab3a..c68e6dd2fa6 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c @@ -236,11 +236,13 @@ __found_pages: static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) { if (addr & ~emu->dma_mask) { - snd_printk(KERN_ERR "max memory size is 0x%lx (addr = 0x%lx)!!\n", emu->dma_mask, (unsigned long)addr); + dev_err(emu->card->dev, + "max memory size is 0x%lx (addr = 0x%lx)!!\n", + emu->dma_mask, (unsigned long)addr); return 0; } if (addr & (EMUPAGESIZE-1)) { - snd_printk(KERN_ERR "page is not aligned\n"); + dev_err(emu->card->dev, "page is not aligned\n"); return 0; } return 1; @@ -331,7 +333,8 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst else addr = snd_pcm_sgbuf_get_addr(substream, ofs); if (! is_valid_page(emu, addr)) { - printk(KERN_ERR "emu: failure page = %d\n", idx); + dev_err(emu->card->dev, + "emu: failure page = %d\n", idx); mutex_unlock(&hdr->block_mutex); return NULL; } @@ -507,7 +510,8 @@ static inline void *offset_ptr(struct snd_emu10k1 *emu, int page, int offset) return NULL; ptr = emu->page_ptr_table[page]; if (! ptr) { - printk(KERN_ERR "emu10k1: access to NULL ptr: page = %d\n", page); + dev_err(emu->card->dev, + "access to NULL ptr: page = %d\n", page); return NULL; } ptr += offset & (PAGE_SIZE - 1); diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c index 88cec6b7dd4..a4fe7f0c945 100644 --- a/sound/pci/emu10k1/p16v.c +++ b/sound/pci/emu10k1/p16v.c @@ -168,7 +168,7 @@ static void snd_p16v_pcm_free_substream(struct snd_pcm_runtime *runtime) struct snd_emu10k1_pcm *epcm = runtime->private_data; if (epcm) { - /* snd_printk(KERN_DEBUG "epcm free: %p\n", epcm); */ + /* dev_dbg(emu->card->dev, "epcm free: %p\n", epcm); */ kfree(epcm); } } @@ -183,14 +183,14 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea int err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */ + /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ if (epcm == NULL) return -ENOMEM; epcm->emu = emu; epcm->substream = substream; /* - snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n", + dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ runtime->private_data = epcm; @@ -203,10 +203,10 @@ static int snd_p16v_pcm_open_playback_channel(struct snd_pcm_substream *substrea channel->use=1; #if 0 /* debug */ - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); - printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n", + dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", channel_id, chip, channel); #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ @@ -231,14 +231,14 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream int err; epcm = kzalloc(sizeof(*epcm), GFP_KERNEL); - /* snd_printk(KERN_DEBUG "epcm kcalloc: %p\n", epcm); */ + /* dev_dbg(emu->card->dev, "epcm kcalloc: %p\n", epcm); */ if (epcm == NULL) return -ENOMEM; epcm->emu = emu; epcm->substream = substream; /* - snd_printk(KERN_DEBUG "epcm device=%d, channel_id=%d\n", + dev_dbg(emu->card->dev, "epcm device=%d, channel_id=%d\n", substream->pcm->device, channel_id); */ runtime->private_data = epcm; @@ -251,10 +251,10 @@ static int snd_p16v_pcm_open_capture_channel(struct snd_pcm_substream *substream channel->use=1; #if 0 /* debug */ - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "p16v: open channel_id=%d, channel=%p, use=0x%x\n", channel_id, channel, channel->use); - printk(KERN_DEBUG "open:channel_id=%d, chip=%p, channel=%p\n", + dev_dbg(emu->card->dev, "open:channel_id=%d, chip=%p, channel=%p\n", channel_id, chip, channel); #endif /* debug */ /* channel->interrupt = snd_p16v_pcm_channel_interrupt; */ @@ -349,15 +349,18 @@ static int snd_p16v_pcm_prepare_playback(struct snd_pcm_substream *substream) u32 tmp; #if 0 /* debug */ - snd_printk(KERN_DEBUG "prepare:channel_number=%d, rate=%d, " + dev_dbg(emu->card->dev, + "prepare:channel_number=%d, rate=%d, " "format=0x%x, channels=%d, buffer_size=%ld, " "period_size=%ld, periods=%u, frames_to_bytes=%d\n", channel, runtime->rate, runtime->format, runtime->channels, runtime->buffer_size, runtime->period_size, runtime->periods, frames_to_bytes(runtime, 1)); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, table_base=%p\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, table_base=%p\n", runtime->dma_addr, runtime->dma_area, table_base); - snd_printk(KERN_DEBUG "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", + dev_dbg(emu->card->dev, + "dma_addr=%x, dma_area=%p, dma_bytes(size)=%x\n", emu->p16v_buffer.addr, emu->p16v_buffer.area, emu->p16v_buffer.bytes); #endif /* debug */ @@ -405,7 +408,7 @@ static int snd_p16v_pcm_prepare_capture(struct snd_pcm_substream *substream) u32 tmp; /* - printk(KERN_DEBUG "prepare capture:channel_number=%d, rate=%d, " + dev_dbg(emu->card->dev, "prepare capture:channel_number=%d, rate=%d, " "format=0x%x, channels=%d, buffer_size=%ld, period_size=%ld, " "frames_to_bytes=%d\n", channel, runtime->rate, runtime->format, runtime->channels, @@ -491,13 +494,13 @@ static int snd_p16v_pcm_trigger_playback(struct snd_pcm_substream *substream, runtime = s->runtime; epcm = runtime->private_data; channel = substream->pcm->device-emu->p16v_device_offset; - /* snd_printk(KERN_DEBUG "p16v channel=%d\n", channel); */ + /* dev_dbg(emu->card->dev, "p16v channel=%d\n", channel); */ epcm->running = running; basic |= (0x1<<channel); inte |= (INTE2_PLAYBACK_CH_0_LOOP<<channel); snd_pcm_trigger_done(s, substream); } - /* snd_printk(KERN_DEBUG "basic=0x%x, inte=0x%x\n", basic, inte); */ + /* dev_dbg(emu->card->dev, "basic=0x%x, inte=0x%x\n", basic, inte); */ switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -588,10 +591,10 @@ snd_p16v_pcm_pointer_capture(struct snd_pcm_substream *substream) ptr=ptr2; if (ptr >= runtime->buffer_size) { ptr -= runtime->buffer_size; - printk(KERN_WARNING "buffer capture limited!\n"); + dev_warn(emu->card->dev, "buffer capture limited!\n"); } /* - printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " + dev_dbg(emu->card->dev, "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", ptr1, ptr2, ptr, (int)runtime->buffer_size, (int)runtime->period_size, (int)runtime->frame_bits, @@ -630,21 +633,21 @@ int snd_p16v_free(struct snd_emu10k1 *chip) if (chip->p16v_buffer.area) { snd_dma_free_pages(&chip->p16v_buffer); /* - snd_printk(KERN_DEBUG "period lables free: %p\n", + dev_dbg(chip->card->dev, "period lables free: %p\n", &chip->p16v_buffer); */ } return 0; } -int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) +int snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; struct snd_pcm_substream *substream; int err; int capture=1; - /* snd_printk(KERN_DEBUG "snd_p16v_pcm called. device=%d\n", device); */ + /* dev_dbg(emu->card->dev, "snd_p16v_pcm called. device=%d\n", device); */ emu->p16v_device_offset = device; if (rpcm) *rpcm = NULL; @@ -672,7 +675,7 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm * ((65536 - 64) * 8), ((65536 - 64) * 8))) < 0) return err; /* - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "preallocate playback substream: err=%d\n", err); */ } @@ -686,7 +689,7 @@ int __devinit snd_p16v_pcm(struct snd_emu10k1 *emu, int device, struct snd_pcm * 65536 - 64, 65536 - 64)) < 0) return err; /* - snd_printk(KERN_DEBUG + dev_dbg(emu->card->dev, "preallocate capture substream: err=%d\n", err); */ } @@ -854,7 +857,7 @@ static const DECLARE_TLV_DB_SCALE(snd_p16v_db_scale1, -5175, 25, 1); .private_value = ((xreg) | ((xhl) << 8)) \ } -static struct snd_kcontrol_new p16v_mixer_controls[] __devinitdata = { +static struct snd_kcontrol_new p16v_mixer_controls[] = { P16V_VOL("HD Analog Front Playback Volume", PLAYBACK_VOLUME_MIXER9, 0), P16V_VOL("HD Analog Rear Playback Volume", PLAYBACK_VOLUME_MIXER10, 1), P16V_VOL("HD Analog Center/LFE Playback Volume", PLAYBACK_VOLUME_MIXER9, 1), @@ -880,7 +883,7 @@ static struct snd_kcontrol_new p16v_mixer_controls[] __devinitdata = { }; -int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu) +int snd_p16v_mixer(struct snd_emu10k1 *emu) { int i, err; struct snd_card *card = emu->card; @@ -897,7 +900,7 @@ int __devinit snd_p16v_mixer(struct snd_emu10k1 *emu) #define NUM_CHS 1 /* up to 4, but only first channel is used */ -int __devinit snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) +int snd_p16v_alloc_pm_buffer(struct snd_emu10k1 *emu) { emu->p16v_saved = vmalloc(NUM_CHS * 4 * 0x80); if (! emu->p16v_saved) diff --git a/sound/pci/emu10k1/timer.c b/sound/pci/emu10k1/timer.c index 72321e946cc..b69a7f8a216 100644 --- a/sound/pci/emu10k1/timer.c +++ b/sound/pci/emu10k1/timer.c @@ -75,7 +75,7 @@ static struct snd_timer_hardware snd_emu10k1_timer_hw = { .precise_resolution = snd_emu10k1_timer_precise_resolution, }; -int __devinit snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) +int snd_emu10k1_timer(struct snd_emu10k1 *emu, int device) { struct snd_timer *timer = NULL; struct snd_timer_id tid; diff --git a/sound/pci/emu10k1/voice.c b/sound/pci/emu10k1/voice.c index 101e7cb79cb..f16fd5cfb7c 100644 --- a/sound/pci/emu10k1/voice.c +++ b/sound/pci/emu10k1/voice.c @@ -55,7 +55,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, first_voice = last_voice = 0; for (i = emu->next_free_voice, j = 0; j < NUM_G ; i += number, j += number) { /* - printk(KERN_DEBUG "i %d j %d next free %d!\n", + dev_dbg(emu->card->dev, "i %d j %d next free %d!\n", i, j, emu->next_free_voice); */ i %= NUM_G; @@ -75,7 +75,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, } } if (!skip) { - /* printk(KERN_DEBUG "allocated voice %d\n", i); */ + /* dev_dbg(emu->card->dev, "allocated voice %d\n", i); */ first_voice = i; last_voice = (i + number) % NUM_G; emu->next_free_voice = last_voice; @@ -89,7 +89,7 @@ static int voice_alloc(struct snd_emu10k1 *emu, int type, int number, for (i = 0; i < number; i++) { voice = &emu->voices[(first_voice + i) % NUM_G]; /* - printk(kERN_DEBUG "voice alloc - %i, %i of %i\n", + dev_dbg(emu->card->dev, "voice alloc - %i, %i of %i\n", voice->number, idx-first_voice+1, number); */ voice->use = 1; diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 5674cc31653..29cd339ffc3 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c @@ -525,7 +525,7 @@ static unsigned int snd_es1371_wait_src_ready(struct ensoniq * ensoniq) return r; cond_resched(); } - snd_printk(KERN_ERR "wait src ready timeout 0x%lx [0x%x]\n", + dev_err(ensoniq->card->dev, "wait src ready timeout 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_SMPRATE), r); return 0; } @@ -587,7 +587,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531, unsigned long end_time = jiffies + HZ / 10; #if 0 - printk(KERN_DEBUG + dev_dbg(ensoniq->card->dev, "CODEC WRITE: reg = 0x%x, val = 0x%x (0x%x), creg = 0x%x\n", reg, val, ES_1370_CODEC_WRITE(reg, val), ES_REG(ensoniq, 1370_CODEC)); #endif @@ -598,7 +598,7 @@ static void snd_es1370_codec_write(struct snd_ak4531 *ak4531, } schedule_timeout_uninterruptible(1); } while (time_after(end_time, jiffies)); - snd_printk(KERN_ERR "codec write timeout, status = 0x%x\n", + dev_err(ensoniq->card->dev, "codec write timeout, status = 0x%x\n", inl(ES_REG(ensoniq, STATUS))); } @@ -649,7 +649,7 @@ static void snd_es1371_codec_write(struct snd_ac97 *ac97, } } mutex_unlock(&ensoniq->src_mutex); - snd_printk(KERN_ERR "codec write timeout at 0x%lx [0x%x]\n", + dev_err(ensoniq->card->dev, "codec write timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); } @@ -706,8 +706,8 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, } mutex_unlock(&ensoniq->src_mutex); if (++fail > 10) { - snd_printk(KERN_ERR "codec read timeout (final) " - "at 0x%lx, reg = 0x%x [0x%x]\n", + dev_err(ensoniq->card->dev, + "codec read timeout (final) at 0x%lx, reg = 0x%x [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), reg, inl(ES_REG(ensoniq, 1371_CODEC))); return 0; @@ -716,7 +716,7 @@ static unsigned short snd_es1371_codec_read(struct snd_ac97 *ac97, } } mutex_unlock(&ensoniq->src_mutex); - snd_printk(KERN_ERR "es1371: codec read timeout at 0x%lx [0x%x]\n", + dev_err(ensoniq->card->dev, "codec read timeout at 0x%lx [0x%x]\n", ES_REG(ensoniq, 1371_CODEC), inl(ES_REG(ensoniq, 1371_CODEC))); return 0; } @@ -1268,8 +1268,8 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device, - struct snd_pcm ** rpcm) +static int snd_ensoniq_pcm(struct ensoniq *ensoniq, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1310,8 +1310,8 @@ static int __devinit snd_ensoniq_pcm(struct ensoniq * ensoniq, int device, return 0; } -static int __devinit snd_ensoniq_pcm2(struct ensoniq * ensoniq, int device, - struct snd_pcm ** rpcm) +static int snd_ensoniq_pcm2(struct ensoniq *ensoniq, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1484,7 +1484,7 @@ static int snd_es1371_spdif_put(struct snd_kcontrol *kcontrol, /* spdif controls */ -static struct snd_kcontrol_new snd_es1371_mixer_spdif[] __devinitdata = { +static struct snd_kcontrol_new snd_es1371_mixer_spdif[] = { ES1371_SPDIF(SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH)), { .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1546,7 +1546,7 @@ static int snd_es1373_rear_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ens1373_rear __devinitdata = +static struct snd_kcontrol_new snd_ens1373_rear = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 2ch->4ch Copy Switch", @@ -1591,7 +1591,7 @@ static int snd_es1373_line_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new snd_ens1373_line __devinitdata = +static struct snd_kcontrol_new snd_ens1373_line = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Line In->Rear Out Switch", @@ -1625,7 +1625,7 @@ static int es1371_quirk_lookup(struct ensoniq *ensoniq, return 0; } -static struct es1371_quirk es1371_spdif_present[] __devinitdata = { +static struct es1371_quirk es1371_spdif_present[] = { { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_C }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_D }, { .vid = PCI_VENDOR_ID_ENSONIQ, .did = PCI_DEVICE_ID_ENSONIQ_CT5880, .rev = CT5880REV_CT5880_E }, @@ -1634,14 +1634,14 @@ static struct es1371_quirk es1371_spdif_present[] __devinitdata = { { .vid = PCI_ANY_ID, .did = PCI_ANY_ID } }; -static struct snd_pci_quirk ens1373_line_quirk[] __devinitdata = { +static struct snd_pci_quirk ens1373_line_quirk[] = { SND_PCI_QUIRK_ID(0x1274, 0x2000), /* GA-7DXR */ SND_PCI_QUIRK_ID(0x1458, 0xa000), /* GA-8IEXP */ { } /* end */ }; -static int __devinit snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, - int has_spdif, int has_line) +static int snd_ensoniq_1371_mixer(struct ensoniq *ensoniq, + int has_spdif, int has_line) { struct snd_card *card = ensoniq->card; struct snd_ac97_bus *pbus; @@ -1749,7 +1749,7 @@ static int snd_ensoniq_control_put(struct snd_kcontrol *kcontrol, * ENS1370 mixer */ -static struct snd_kcontrol_new snd_es1370_controls[2] __devinitdata = { +static struct snd_kcontrol_new snd_es1370_controls[2] = { ENSONIQ_CONTROL("PCM 0 Output also on Line-In Jack", ES_1370_XCTL0), ENSONIQ_CONTROL("Mic +5V bias", ES_1370_XCTL1) }; @@ -1762,7 +1762,7 @@ static void snd_ensoniq_mixer_free_ak4531(struct snd_ak4531 *ak4531) ensoniq->u.es1370.ak4531 = NULL; } -static int __devinit snd_ensoniq_1370_mixer(struct ensoniq * ensoniq) +static int snd_ensoniq_1370_mixer(struct ensoniq *ensoniq) { struct snd_card *card = ensoniq->card; struct snd_ak4531 ak4531; @@ -1796,7 +1796,7 @@ static int __devinit snd_ensoniq_1370_mixer(struct ensoniq * ensoniq) #ifdef SUPPORT_JOYSTICK #ifdef CHIP1371 -static int __devinit snd_ensoniq_get_joystick_port(int dev) +static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev) { switch (joystick_port[dev]) { case 0: /* disabled */ @@ -1808,23 +1808,24 @@ static int __devinit snd_ensoniq_get_joystick_port(int dev) return joystick_port[dev]; default: - printk(KERN_ERR "ens1371: invalid joystick port %#x", joystick_port[dev]); + dev_err(ensoniq->card->dev, + "invalid joystick port %#x", joystick_port[dev]); return 0; } } #else -static inline int snd_ensoniq_get_joystick_port(int dev) +static int snd_ensoniq_get_joystick_port(struct ensoniq *ensoniq, int dev) { return joystick[dev] ? 0x200 : 0; } #endif -static int __devinit snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev) +static int snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int dev) { struct gameport *gp; int io_port; - io_port = snd_ensoniq_get_joystick_port(dev); + io_port = snd_ensoniq_get_joystick_port(ensoniq, dev); switch (io_port) { case 0: @@ -1835,14 +1836,16 @@ static int __devinit snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int de if (request_region(io_port, 8, "ens137x: gameport")) break; if (io_port > 0x218) { - printk(KERN_WARNING "ens137x: no gameport ports available\n"); + dev_warn(ensoniq->card->dev, + "no gameport ports available\n"); return -EBUSY; } break; default: if (!request_region(io_port, 8, "ens137x: gameport")) { - printk(KERN_WARNING "ens137x: gameport io port 0x%#x in use\n", + dev_warn(ensoniq->card->dev, + "gameport io port %#x in use\n", io_port); return -EBUSY; } @@ -1851,7 +1854,8 @@ static int __devinit snd_ensoniq_create_gameport(struct ensoniq *ensoniq, int de ensoniq->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "ens137x: cannot allocate memory for gameport\n"); + dev_err(ensoniq->card->dev, + "cannot allocate memory for gameport\n"); release_region(io_port, 8); return -ENOMEM; } @@ -1913,7 +1917,7 @@ static void snd_ensoniq_proc_read(struct snd_info_entry *entry, #endif } -static void __devinit snd_ensoniq_proc_init(struct ensoniq * ensoniq) +static void snd_ensoniq_proc_init(struct ensoniq *ensoniq) { struct snd_info_entry *entry; @@ -1939,7 +1943,7 @@ static int snd_ensoniq_free(struct ensoniq *ensoniq) #endif if (ensoniq->irq >= 0) synchronize_irq(ensoniq->irq); - pci_set_power_state(ensoniq->pci, 3); + pci_set_power_state(ensoniq->pci, PCI_D3hot); __hw_end: #ifdef CHIP1370 if (ensoniq->dma_bug.area) @@ -1960,7 +1964,7 @@ static int snd_ensoniq_dev_free(struct snd_device *device) } #ifdef CHIP1371 -static struct snd_pci_quirk es1371_amplifier_hack[] __devinitdata = { +static struct snd_pci_quirk es1371_amplifier_hack[] = { SND_PCI_QUIRK_ID(0x107b, 0x2150), /* Gateway Solo 2150 */ SND_PCI_QUIRK_ID(0x13bd, 0x100c), /* EV1938 on Mebius PC-MJ100V */ SND_PCI_QUIRK_ID(0x1102, 0x5938), /* Targa Xtender300 */ @@ -2082,8 +2086,7 @@ static int snd_ensoniq_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR DRIVER_NAME ": pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2106,9 +2109,9 @@ static SIMPLE_DEV_PM_OPS(snd_ensoniq_pm, snd_ensoniq_suspend, snd_ensoniq_resume #define SND_ENSONIQ_PM_OPS NULL #endif /* CONFIG_PM_SLEEP */ -static int __devinit snd_ensoniq_create(struct snd_card *card, - struct pci_dev *pci, - struct ensoniq ** rensoniq) +static int snd_ensoniq_create(struct snd_card *card, + struct pci_dev *pci, + struct ensoniq **rensoniq) { struct ensoniq *ensoniq; int err; @@ -2137,7 +2140,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, ensoniq->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_audiopci_interrupt, IRQF_SHARED, KBUILD_MODNAME, ensoniq)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_ensoniq_free(ensoniq); return -EBUSY; } @@ -2145,7 +2148,7 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, #ifdef CHIP1370 if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), 16, &ensoniq->dma_bug) < 0) { - snd_printk(KERN_ERR "unable to allocate space for phantom area - dma_bug\n"); + dev_err(card->dev, "unable to allocate space for phantom area - dma_bug\n"); snd_ensoniq_free(ensoniq); return -EBUSY; } @@ -2180,8 +2183,6 @@ static int __devinit snd_ensoniq_create(struct snd_card *card, snd_ensoniq_proc_init(ensoniq); - snd_card_set_dev(card, &pci->dev); - *rensoniq = ensoniq; return 0; } @@ -2361,8 +2362,8 @@ static struct snd_rawmidi_ops snd_ensoniq_midi_input = .trigger = snd_ensoniq_midi_input_trigger, }; -static int __devinit snd_ensoniq_midi(struct ensoniq * ensoniq, int device, - struct snd_rawmidi **rrawmidi) +static int snd_ensoniq_midi(struct ensoniq *ensoniq, int device, + struct snd_rawmidi **rrawmidi) { struct snd_rawmidi *rmidi; int err; @@ -2422,8 +2423,8 @@ static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } -static int __devinit snd_audiopci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_audiopci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2437,7 +2438,8 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2494,17 +2496,16 @@ static int __devinit snd_audiopci_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_audiopci_remove(struct pci_dev *pci) +static void snd_audiopci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ens137x_driver = { .name = KBUILD_MODNAME, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, - .remove = __devexit_p(snd_audiopci_remove), + .remove = snd_audiopci_remove, .driver = { .pm = SND_ENSONIQ_PM_OPS, }, diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 394c5d41353..34d95bf916b 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -254,7 +254,6 @@ MODULE_DEVICE_TABLE(pci, snd_es1938_ids); #define WRITE_LOOP_TIMEOUT 0x10000 #define GET_LOOP_TIMEOUT 0x01000 -#undef REG_DEBUG /* ----------------------------------------------------------------- * Write to a mixer register * -----------------------------------------------------------------*/ @@ -265,9 +264,7 @@ static void snd_es1938_mixer_write(struct es1938 *chip, unsigned char reg, unsig outb(reg, SLSB_REG(chip, MIXERADDR)); outb(val, SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x set to %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Mixer reg %02x set to %02x\n", reg, val); } /* ----------------------------------------------------------------- @@ -281,9 +278,7 @@ static int snd_es1938_mixer_read(struct es1938 *chip, unsigned char reg) outb(reg, SLSB_REG(chip, MIXERADDR)); data = inb(SLSB_REG(chip, MIXERDATA)); spin_unlock_irqrestore(&chip->mixer_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x now is %02x\n", reg, data); -#endif + dev_dbg(chip->card->dev, "Mixer reg %02x now is %02x\n", reg, data); return data; } @@ -302,10 +297,9 @@ static int snd_es1938_mixer_bits(struct es1938 *chip, unsigned char reg, if (val != oval) { new = (old & ~mask) | (val & mask); outb(new, SLSB_REG(chip, MIXERDATA)); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Mixer reg %02x was %02x, set to %02x\n", + dev_dbg(chip->card->dev, + "Mixer reg %02x was %02x, set to %02x\n", reg, old, new); -#endif } spin_unlock_irqrestore(&chip->mixer_lock, flags); return oval; @@ -324,7 +318,8 @@ static void snd_es1938_write_cmd(struct es1938 *chip, unsigned char cmd) return; } } - printk(KERN_ERR "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); + dev_err(chip->card->dev, + "snd_es1938_write_cmd timeout (0x02%x/0x02%x)\n", cmd, v); } /* ----------------------------------------------------------------- @@ -337,7 +332,7 @@ static int snd_es1938_get_byte(struct es1938 *chip) for (i = GET_LOOP_TIMEOUT; i; i--) if ((v = inb(SLSB_REG(chip, STATUS))) & 0x80) return inb(SLSB_REG(chip, READDATA)); - snd_printk(KERN_ERR "get_byte timeout: status 0x02%x\n", v); + dev_err(chip->card->dev, "get_byte timeout: status 0x02%x\n", v); return -ENODEV; } @@ -351,9 +346,7 @@ static void snd_es1938_write(struct es1938 *chip, unsigned char reg, unsigned ch snd_es1938_write_cmd(chip, reg); snd_es1938_write_cmd(chip, val); spin_unlock_irqrestore(&chip->reg_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x set to %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Reg %02x set to %02x\n", reg, val); } /* ----------------------------------------------------------------- @@ -368,9 +361,7 @@ static unsigned char snd_es1938_read(struct es1938 *chip, unsigned char reg) snd_es1938_write_cmd(chip, reg); val = snd_es1938_get_byte(chip); spin_unlock_irqrestore(&chip->reg_lock, flags); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x now is %02x\n", reg, val); -#endif + dev_dbg(chip->card->dev, "Reg %02x now is %02x\n", reg, val); return val; } @@ -391,10 +382,8 @@ static int snd_es1938_bits(struct es1938 *chip, unsigned char reg, unsigned char snd_es1938_write_cmd(chip, reg); new = (old & ~mask) | (val & mask); snd_es1938_write_cmd(chip, new); -#ifdef REG_DEBUG - snd_printk(KERN_DEBUG "Reg %02x was %02x, set to %02x\n", + dev_dbg(chip->card->dev, "Reg %02x was %02x, set to %02x\n", reg, old, new); -#endif } spin_unlock_irqrestore(&chip->reg_lock, flags); return oval; @@ -416,7 +405,7 @@ static void snd_es1938_reset(struct es1938 *chip) goto __next; } } - snd_printk(KERN_ERR "ESS Solo-1 reset failed\n"); + dev_err(chip->card->dev, "ESS Solo-1 reset failed\n"); __next: snd_es1938_write_cmd(chip, ESS_CMD_ENABLEEXT); @@ -1027,7 +1016,7 @@ static struct snd_pcm_ops snd_es1938_capture_ops = { .copy = snd_es1938_capture_copy, }; -static int __devinit snd_es1938_new_pcm(struct es1938 *chip, int device) +static int snd_es1938_new_pcm(struct es1938 *chip, int device) { struct snd_pcm *pcm; int err; @@ -1504,16 +1493,15 @@ static int es1938_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "es1938: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR "es1938: unable to grab IRQ %d, " - "disabling device\n", pci->irq); + dev_err(dev, "unable to grab IRQ %d, disabling device\n", + pci->irq); snd_card_disconnect(card); return -EIO; } @@ -1539,13 +1527,14 @@ static SIMPLE_DEV_PM_OPS(es1938_pm, es1938_suspend, es1938_resume); #endif /* CONFIG_PM_SLEEP */ #ifdef SUPPORT_JOYSTICK -static int __devinit snd_es1938_create_gameport(struct es1938 *chip) +static int snd_es1938_create_gameport(struct es1938 *chip) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "es1938: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -1594,9 +1583,9 @@ static int snd_es1938_dev_free(struct snd_device *device) return snd_es1938_free(chip); } -static int __devinit snd_es1938_create(struct snd_card *card, - struct pci_dev * pci, - struct es1938 ** rchip) +static int snd_es1938_create(struct snd_card *card, + struct pci_dev *pci, + struct es1938 **rchip) { struct es1938 *chip; int err; @@ -1612,7 +1601,8 @@ static int __devinit snd_es1938_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) { - snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1639,15 +1629,14 @@ static int __devinit snd_es1938_create(struct snd_card *card, chip->game_port = pci_resource_start(pci, 4); if (request_irq(pci->irq, snd_es1938_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_es1938_free(chip); return -EBUSY; } chip->irq = pci->irq; -#ifdef ES1938_DDEBUG - snd_printk(KERN_DEBUG "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", + dev_dbg(card->dev, + "create: io: 0x%lx, sb: 0x%lx, vc: 0x%lx, mpu: 0x%lx, game: 0x%lx\n", chip->io_port, chip->sb_port, chip->vc_port, chip->mpu_port, chip->game_port); -#endif chip->ddma_port = chip->vc_port + 0x00; /* fix from Thomas Sailer */ @@ -1658,8 +1647,6 @@ static int __devinit snd_es1938_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } @@ -1675,21 +1662,22 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) status = inb(SLIO_REG(chip, IRQCONTROL)); #if 0 - printk(KERN_DEBUG "Es1938debug - interrupt status: =0x%x\n", status); + dev_dbg(chip->card->dev, + "Es1938debug - interrupt status: =0x%x\n", status); #endif /* AUDIO 1 */ if (status & 0x10) { #if 0 - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 1 interrupt\n"); - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 1 DMAC DMA count: %u\n", inw(SLDM_REG(chip, DMACOUNT))); - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 1 DMAC DMA base: %u\n", inl(SLDM_REG(chip, DMAADDR))); - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 1 DMAC DMA status: 0x%x\n", inl(SLDM_REG(chip, DMASTATUS))); #endif @@ -1705,12 +1693,12 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) /* AUDIO 2 */ if (status & 0x20) { #if 0 - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 2 interrupt\n"); - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 2 DMAC DMA count: %u\n", inw(SLIO_REG(chip, AUDIO2DMACOUNT))); - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "Es1938debug - AUDIO channel 2 DMAC DMA base: %u\n", inl(SLIO_REG(chip, AUDIO2DMAADDR))); @@ -1754,7 +1742,7 @@ static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id) #define ES1938_DMA_SIZE 64 -static int __devinit snd_es1938_mixer(struct es1938 *chip) +static int snd_es1938_mixer(struct es1938 *chip) { struct snd_card *card; unsigned int idx; @@ -1792,8 +1780,8 @@ static int __devinit snd_es1938_mixer(struct es1938 *chip) } -static int __devinit snd_es1938_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_es1938_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1808,7 +1796,8 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; for (idx = 0; idx < 5; idx++) { @@ -1843,7 +1832,7 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, SLSB_REG(chip, FMLOWADDR), SLSB_REG(chip, FMHIGHADDR), OPL3_HW_OPL3, 1, &opl3) < 0) { - printk(KERN_ERR "es1938: OPL3 not detected at 0x%lx\n", + dev_err(card->dev, "OPL3 not detected at 0x%lx\n", SLSB_REG(chip, FMLOWADDR)); } else { if ((err = snd_opl3_timer_new(opl3, 0, 1)) < 0) { @@ -1859,7 +1848,7 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, chip->mpu_port, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi) < 0) { - printk(KERN_ERR "es1938: unable to initialize MPU-401\n"); + dev_err(card->dev, "unable to initialize MPU-401\n"); } else { // this line is vital for MIDI interrupt handling on ess-solo1 // andreas@flying-snail.de @@ -1878,17 +1867,16 @@ static int __devinit snd_es1938_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_es1938_remove(struct pci_dev *pci) +static void snd_es1938_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver es1938_driver = { .name = KBUILD_MODNAME, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, - .remove = __devexit_p(snd_es1938_remove), + .remove = snd_es1938_remove, .driver = { .pm = ES1938_PM_OPS, }, diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index 5d0e568fdea..5bb1cf60330 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c @@ -113,7 +113,7 @@ #include <sound/initval.h> #ifdef CONFIG_SND_ES1968_RADIO -#include <sound/tea575x-tuner.h> +#include <media/tea575x.h> #endif #define CARD_NAME "ESS Maestro1/2" @@ -564,6 +564,7 @@ struct es1968 { #ifdef CONFIG_SND_ES1968_RADIO struct v4l2_device v4l2_dev; struct snd_tea575x tea; + unsigned int tea575x_tuner; #endif }; @@ -631,7 +632,7 @@ static int snd_es1968_ac97_wait(struct es1968 *chip) return 0; cond_resched(); } - snd_printd("es1968: ac97 timeout\n"); + dev_dbg(chip->card->dev, "ac97 timeout\n"); return 1; /* timeout */ } @@ -643,7 +644,7 @@ static int snd_es1968_ac97_wait_poll(struct es1968 *chip) if (!(inb(chip->io_port + ESM_AC97_INDEX) & 1)) return 0; } - snd_printd("es1968: ac97 timeout\n"); + dev_dbg(chip->card->dev, "ac97 timeout\n"); return 1; /* timeout */ } @@ -686,7 +687,7 @@ static void apu_index_set(struct es1968 *chip, u16 index) for (i = 0; i < 1000; i++) if (__maestro_read(chip, IDR1_CRAM_POINTER) == index) return; - snd_printd("es1968: APU register select failed. (Timeout)\n"); + dev_dbg(chip->card->dev, "APU register select failed. (Timeout)\n"); } /* no spinlock */ @@ -698,7 +699,7 @@ static void apu_data_set(struct es1968 *chip, u16 data) return; __maestro_write(chip, IDR0_DATA_PORT, data); } - snd_printd("es1968: APU register set probably failed (Timeout)!\n"); + dev_dbg(chip->card->dev, "APU register set probably failed (Timeout)!\n"); } /* no spinlock */ @@ -1421,7 +1422,7 @@ static void snd_es1968_free_dmabuf(struct es1968 *chip) if (! chip->dma.area) return; - snd_dma_reserve_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci)); + snd_dma_free_pages(&chip->dma); while ((p = chip->buf_list.next) != &chip->buf_list) { struct esm_memory *chunk = list_entry(p, struct esm_memory, list); list_del(p); @@ -1429,7 +1430,7 @@ static void snd_es1968_free_dmabuf(struct es1968 *chip) } } -static int __devinit +static int snd_es1968_init_dmabuf(struct es1968 *chip) { int err; @@ -1437,20 +1438,19 @@ snd_es1968_init_dmabuf(struct es1968 *chip) chip->dma.dev.type = SNDRV_DMA_TYPE_DEV; chip->dma.dev.dev = snd_dma_pci_data(chip->pci); - if (! snd_dma_get_reserved_buf(&chip->dma, snd_dma_pci_buf_id(chip->pci))) { - err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - chip->total_bufsize, &chip->dma); - if (err < 0 || ! chip->dma.area) { - snd_printk(KERN_ERR "es1968: can't allocate dma pages for size %d\n", - chip->total_bufsize); - return -ENOMEM; - } - if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { - snd_dma_free_pages(&chip->dma); - snd_printk(KERN_ERR "es1968: DMA buffer beyond 256MB.\n"); - return -ENOMEM; - } + err = snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, + snd_dma_pci_data(chip->pci), + chip->total_bufsize, &chip->dma); + if (err < 0 || ! chip->dma.area) { + dev_err(chip->card->dev, + "can't allocate dma pages for size %d\n", + chip->total_bufsize); + return -ENOMEM; + } + if ((chip->dma.addr + chip->dma.bytes - 1) & ~((1 << 28) - 1)) { + snd_dma_free_pages(&chip->dma); + dev_err(chip->card->dev, "DMA buffer beyond 256MB.\n"); + return -ENOMEM; } INIT_LIST_HEAD(&chip->buf_list); @@ -1490,7 +1490,8 @@ static int snd_es1968_hw_params(struct snd_pcm_substream *substream, } chan->memory = snd_es1968_new_memory(chip, size); if (chan->memory == NULL) { - // snd_printd("cannot allocate dma buffer: size = %d\n", size); + dev_dbg(chip->card->dev, + "cannot allocate dma buffer: size = %d\n", size); return -ENOMEM; } snd_pcm_set_runtime_buffer(substream, &chan->memory->buf); @@ -1704,7 +1705,7 @@ static struct snd_pcm_ops snd_es1968_capture_ops = { */ #define CLOCK_MEASURE_BUFSIZE 16768 /* enough large for a single shot */ -static void __devinit es1968_measure_clock(struct es1968 *chip) +static void es1968_measure_clock(struct es1968 *chip) { int i, apu; unsigned int pa, offset, t; @@ -1716,11 +1717,13 @@ static void __devinit es1968_measure_clock(struct es1968 *chip) /* search 2 APUs (although one apu is enough) */ if ((apu = snd_es1968_alloc_apu_pair(chip, ESM_APU_PCM_PLAY)) < 0) { - snd_printk(KERN_ERR "Hmm, cannot find empty APU pair!?\n"); + dev_err(chip->card->dev, "Hmm, cannot find empty APU pair!?\n"); return; } if ((memory = snd_es1968_new_memory(chip, CLOCK_MEASURE_BUFSIZE)) == NULL) { - snd_printk(KERN_ERR "cannot allocate dma buffer - using default clock %d\n", chip->clock); + dev_warn(chip->card->dev, + "cannot allocate dma buffer - using default clock %d\n", + chip->clock); snd_es1968_free_apu_pair(chip, apu); return; } @@ -1781,7 +1784,7 @@ static void __devinit es1968_measure_clock(struct es1968 *chip) else t += stop_time.tv_usec - start_time.tv_usec; if (t == 0) { - snd_printk(KERN_ERR "?? calculation error..\n"); + dev_err(chip->card->dev, "?? calculation error..\n"); } else { offset *= 1000; offset = (offset / t) * 1000 + ((offset % t) * 1000) / t; @@ -1789,7 +1792,7 @@ static void __devinit es1968_measure_clock(struct es1968 *chip) if (offset >= 40000 && offset <= 50000) chip->clock = (chip->clock * offset) / 48000; } - printk(KERN_INFO "es1968: clocking to %d\n", chip->clock); + dev_info(chip->card->dev, "clocking to %d\n", chip->clock); } snd_es1968_free_memory(chip, memory); snd_es1968_free_apu_pair(chip, apu); @@ -1806,7 +1809,7 @@ static void snd_es1968_pcm_free(struct snd_pcm *pcm) esm->pcm = NULL; } -static int __devinit +static int snd_es1968_pcm(struct es1968 *chip, int device) { struct snd_pcm *pcm; @@ -2016,7 +2019,7 @@ static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id) * Mixer stuff */ -static int __devinit +static int snd_es1968_mixer(struct es1968 *chip) { struct snd_ac97_bus *pbus; @@ -2109,7 +2112,7 @@ static void snd_es1968_ac97_reset(struct es1968 *chip) outw(inw(ioaddr + 0x3c) & 0xfffc, ioaddr + 0x3c); #if 0 /* the loop here needs to be much better if we want it.. */ - snd_printk(KERN_INFO "trying software reset\n"); + dev_info(chip->card->dev, "trying software reset\n"); /* try and do a software reset */ outb(0x80 | 0x7c, ioaddr + 0x30); for (w = 0;; w++) { @@ -2291,7 +2294,7 @@ static void snd_es1968_chip_init(struct es1968 *chip) outb(0x88, iobase+0x1f); /* it appears some maestros (dell 7500) only work if these are set, - regardless of wether we use the assp or not. */ + regardless of whether we use the assp or not. */ outb(0, iobase + ASSP_CONTROL_B); outb(3, iobase + ASSP_CONTROL_A); /* M: Reserved bits... */ @@ -2417,8 +2420,7 @@ static int es1968_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "es1968: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2465,7 +2467,7 @@ static SIMPLE_DEV_PM_OPS(es1968_pm, es1968_suspend, es1968_resume); #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 -static int __devinit snd_es1968_create_gameport(struct es1968 *chip, int dev) +static int snd_es1968_create_gameport(struct es1968 *chip, int dev) { struct gameport *gp; struct resource *r; @@ -2480,7 +2482,8 @@ static int __devinit snd_es1968_create_gameport(struct es1968 *chip, int dev) chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "es1968: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } @@ -2516,7 +2519,7 @@ static inline void snd_es1968_free_gameport(struct es1968 *chip) { } #endif #ifdef CONFIG_SND_ES1968_INPUT -static int __devinit snd_es1968_input_register(struct es1968 *chip) +static int snd_es1968_input_register(struct es1968 *chip) { struct input_dev *input_dev; int err; @@ -2557,33 +2560,48 @@ static int __devinit snd_es1968_input_register(struct es1968 *chip) bits 1=unmask write to given bit */ #define IO_DIR 8 /* direction register offset from GPIO_DATA bits 0/1=read/write direction */ -/* mask bits for GPIO lines */ -#define STR_DATA 0x0040 /* GPIO6 */ -#define STR_CLK 0x0080 /* GPIO7 */ -#define STR_WREN 0x0100 /* GPIO8 */ -#define STR_MOST 0x0200 /* GPIO9 */ + +/* GPIO to TEA575x maps */ +struct snd_es1968_tea575x_gpio { + u8 data, clk, wren, most; + char *name; +}; + +static struct snd_es1968_tea575x_gpio snd_es1968_tea575x_gpios[] = { + { .data = 6, .clk = 7, .wren = 8, .most = 9, .name = "SF64-PCE2" }, + { .data = 7, .clk = 8, .wren = 6, .most = 10, .name = "M56VAP" }, +}; + +#define get_tea575x_gpio(chip) \ + (&snd_es1968_tea575x_gpios[(chip)->tea575x_tuner]) + static void snd_es1968_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct es1968 *chip = tea->private_data; - unsigned long io = chip->io_port + GPIO_DATA; + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); u16 val = 0; - val |= (pins & TEA575X_DATA) ? STR_DATA : 0; - val |= (pins & TEA575X_CLK) ? STR_CLK : 0; - val |= (pins & TEA575X_WREN) ? STR_WREN : 0; + val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0; + val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0; + val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0; - outw(val, io); + outw(val, chip->io_port + GPIO_DATA); } static u8 snd_es1968_tea575x_get_pins(struct snd_tea575x *tea) { struct es1968 *chip = tea->private_data; - unsigned long io = chip->io_port + GPIO_DATA; - u16 val = inw(io); + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); + u16 val = inw(chip->io_port + GPIO_DATA); + u8 ret = 0; - return (val & STR_DATA) ? TEA575X_DATA : 0 | - (val & STR_MOST) ? TEA575X_MOST : 0; + if (val & (1 << gpio.data)) + ret |= TEA575X_DATA; + if (val & (1 << gpio.most)) + ret |= TEA575X_MOST; + + return ret; } static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool output) @@ -2591,13 +2609,18 @@ static void snd_es1968_tea575x_set_direction(struct snd_tea575x *tea, bool outpu struct es1968 *chip = tea->private_data; unsigned long io = chip->io_port + GPIO_DATA; u16 odir = inw(io + IO_DIR); + struct snd_es1968_tea575x_gpio gpio = *get_tea575x_gpio(chip); if (output) { - outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); - outw(odir | STR_DATA | STR_CLK | STR_WREN, io + IO_DIR); + outw(~((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren)), + io + IO_MASK); + outw(odir | (1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren), + io + IO_DIR); } else { - outw(~(STR_CLK | STR_WREN | STR_DATA | STR_MOST), io + IO_MASK); - outw((odir & ~(STR_DATA | STR_MOST)) | STR_CLK | STR_WREN, io + IO_DIR); + outw(~((1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) | (1 << gpio.most)), + io + IO_MASK); + outw((odir & ~((1 << gpio.data) | (1 << gpio.most))) + | (1 << gpio.clk) | (1 << gpio.wren), io + IO_DIR); } } @@ -2648,28 +2671,30 @@ struct ess_device_list { unsigned short vendor; /* subsystem vendor id */ }; -static struct ess_device_list pm_whitelist[] __devinitdata = { +static struct ess_device_list pm_whitelist[] = { { TYPE_MAESTRO2E, 0x0e11 }, /* Compaq Armada */ { TYPE_MAESTRO2E, 0x1028 }, { TYPE_MAESTRO2E, 0x103c }, { TYPE_MAESTRO2E, 0x1179 }, { TYPE_MAESTRO2E, 0x14c0 }, /* HP omnibook 4150 */ { TYPE_MAESTRO2E, 0x1558 }, + { TYPE_MAESTRO2E, 0x125d }, /* a PCI card, e.g. Terratec DMX */ + { TYPE_MAESTRO2, 0x125d }, /* a PCI card, e.g. SF64-PCE2 */ }; -static struct ess_device_list mpu_blacklist[] __devinitdata = { +static struct ess_device_list mpu_blacklist[] = { { TYPE_MAESTRO2, 0x125d }, }; -static int __devinit snd_es1968_create(struct snd_card *card, - struct pci_dev *pci, - int total_bufsize, - int play_streams, - int capt_streams, - int chip_type, - int do_pm, - int radio_nr, - struct es1968 **chip_ret) +static int snd_es1968_create(struct snd_card *card, + struct pci_dev *pci, + int total_bufsize, + int play_streams, + int capt_streams, + int chip_type, + int do_pm, + int radio_nr, + struct es1968 **chip_ret) { static struct snd_device_ops ops = { .dev_free = snd_es1968_dev_free, @@ -2685,7 +2710,8 @@ static int __devinit snd_es1968_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { - snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2719,7 +2745,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, chip->io_port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_es1968_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_es1968_free(chip); return -EBUSY; } @@ -2749,7 +2775,7 @@ static int __devinit snd_es1968_create(struct snd_card *card, } if (do_pm > 1) { /* not matched; disabling pm */ - printk(KERN_INFO "es1968: not attempting power management.\n"); + dev_info(card->dev, "not attempting power management.\n"); do_pm = 0; } } @@ -2762,9 +2788,10 @@ static int __devinit snd_es1968_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - #ifdef CONFIG_SND_ES1968_RADIO + /* don't play with GPIOs on laptops */ + if (chip->pci->subsystem_vendor != 0x125d) + goto no_radio; err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); if (err < 0) { snd_es1968_free(chip); @@ -2774,10 +2801,18 @@ static int __devinit snd_es1968_create(struct snd_card *card, chip->tea.private_data = chip; chip->tea.radio_nr = radio_nr; chip->tea.ops = &snd_es1968_tea_ops; - strlcpy(chip->tea.card, "SF64-PCE2", sizeof(chip->tea.card)); sprintf(chip->tea.bus_info, "PCI:%s", pci_name(pci)); - if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) - printk(KERN_INFO "es1968: detected TEA575x radio\n"); + for (i = 0; i < ARRAY_SIZE(snd_es1968_tea575x_gpios); i++) { + chip->tea575x_tuner = i; + if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) { + dev_info(card->dev, "detected TEA575x radio type %s\n", + get_tea575x_gpio(chip)->name); + strlcpy(chip->tea.card, get_tea575x_gpio(chip)->name, + sizeof(chip->tea.card)); + break; + } + } +no_radio: #endif *chip_ret = chip; @@ -2788,8 +2823,8 @@ static int __devinit snd_es1968_create(struct snd_card *card, /* */ -static int __devinit snd_es1968_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_es1968_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2804,7 +2839,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2868,7 +2904,7 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi)) < 0) { - printk(KERN_WARNING "es1968: skipping MPU-401 MIDI support..\n"); + dev_warn(card->dev, "skipping MPU-401 MIDI support..\n"); } } @@ -2877,8 +2913,8 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, #ifdef CONFIG_SND_ES1968_INPUT err = snd_es1968_input_register(chip); if (err) - snd_printk(KERN_WARNING "Input device registration " - "failed with error %i", err); + dev_warn(card->dev, + "Input device registration failed with error %i", err); #endif snd_es1968_start_irq(chip); @@ -2899,17 +2935,16 @@ static int __devinit snd_es1968_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_es1968_remove(struct pci_dev *pci) +static void snd_es1968_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver es1968_driver = { .name = KBUILD_MODNAME, .id_table = snd_es1968_ids, .probe = snd_es1968_probe, - .remove = __devexit_p(snd_es1968_remove), + .remove = snd_es1968_remove, .driver = { .pm = ES1968_PM_OPS, }, diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index cc2e91d1553..529f5f4f4c9 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/init.h> #include <linux/interrupt.h> +#include <linux/io.h> #include <linux/pci.h> #include <linux/slab.h> #include <linux/module.h> @@ -34,10 +35,8 @@ #include <sound/opl3.h> #include <sound/initval.h> -#include <asm/io.h> - #ifdef CONFIG_SND_FM801_TEA575X_BOOL -#include <sound/tea575x-tuner.h> +#include <media/tea575x.h> #endif MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); @@ -80,7 +79,10 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers"); * Direct registers */ -#define FM801_REG(chip, reg) (chip->port + FM801_##reg) +#define fm801_writew(chip,reg,value) outw((value), chip->port + FM801_##reg) +#define fm801_readw(chip,reg) inw(chip->port + FM801_##reg) + +#define fm801_writel(chip,reg,value) outl((value), chip->port + FM801_##reg) #define FM801_PCM_VOL 0x00 /* PCM Output Volume */ #define FM801_FM_VOL 0x02 /* FM Output Volume */ @@ -156,21 +158,27 @@ MODULE_PARM_DESC(radio_nr, "Radio device numbers"); #define FM801_GPIO_GS3 (1<<15) #define FM801_GPIO_GS(x) (1<<(12+(x))) -/* - +/** + * struct fm801 - describes FM801 chip + * @port: I/O port number + * @multichannel: multichannel support + * @secondary: secondary codec + * @secondary_addr: address of the secondary codec + * @tea575x_tuner: tuner access method & flags + * @ply_ctrl: playback control + * @cap_ctrl: capture control */ - struct fm801 { int irq; - unsigned long port; /* I/O port number */ - unsigned int multichannel: 1, /* multichannel support */ - secondary: 1; /* secondary codec */ - unsigned char secondary_addr; /* address of the secondary codec */ - unsigned int tea575x_tuner; /* tuner access method & flags */ + unsigned long port; + unsigned int multichannel: 1, + secondary: 1; + unsigned char secondary_addr; + unsigned int tea575x_tuner; - unsigned short ply_ctrl; /* playback control */ - unsigned short cap_ctrl; /* capture control */ + unsigned short ply_ctrl; + unsigned short cap_ctrl; unsigned long ply_buffer; unsigned int ply_buf; @@ -222,6 +230,30 @@ MODULE_DEVICE_TABLE(pci, snd_fm801_ids); * common I/O routines */ +static bool fm801_ac97_is_ready(struct fm801 *chip, unsigned int iterations) +{ + unsigned int idx; + + for (idx = 0; idx < iterations; idx++) { + if (!(fm801_readw(chip, AC97_CMD) & FM801_AC97_BUSY)) + return true; + udelay(10); + } + return false; +} + +static bool fm801_ac97_is_valid(struct fm801 *chip, unsigned int iterations) +{ + unsigned int idx; + + for (idx = 0; idx < iterations; idx++) { + if (fm801_readw(chip, AC97_CMD) & FM801_AC97_VALID) + return true; + udelay(10); + } + return false; +} + static int snd_fm801_update_bits(struct fm801 *chip, unsigned short reg, unsigned short mask, unsigned short value) { @@ -244,73 +276,54 @@ static void snd_fm801_codec_write(struct snd_ac97 *ac97, unsigned short val) { struct fm801 *chip = ac97->private_data; - int idx; /* * Wait until the codec interface is not ready.. */ - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok1; - udelay(10); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); + return; } - snd_printk(KERN_ERR "AC'97 interface is busy (1)\n"); - return; - ok1: /* write data and address */ - outw(val, FM801_REG(chip, AC97_DATA)); - outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT), FM801_REG(chip, AC97_CMD)); + fm801_writew(chip, AC97_DATA, val); + fm801_writew(chip, AC97_CMD, reg | (ac97->addr << FM801_AC97_ADDR_SHIFT)); /* * Wait until the write command is not completed.. - */ - for (idx = 0; idx < 1000; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - return; - udelay(10); - } - snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num); + */ + if (!fm801_ac97_is_ready(chip, 1000)) + dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", + ac97->num); } static unsigned short snd_fm801_codec_read(struct snd_ac97 *ac97, unsigned short reg) { struct fm801 *chip = ac97->private_data; - int idx; /* * Wait until the codec interface is not ready.. */ - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok1; - udelay(10); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface is busy (1)\n"); + return 0; } - snd_printk(KERN_ERR "AC'97 interface is busy (1)\n"); - return 0; - ok1: /* read command */ - outw(reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ, - FM801_REG(chip, AC97_CMD)); - for (idx = 0; idx < 100; idx++) { - if (!(inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_BUSY)) - goto ok2; - udelay(10); + fm801_writew(chip, AC97_CMD, + reg | (ac97->addr << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ); + if (!fm801_ac97_is_ready(chip, 100)) { + dev_err(chip->card->dev, "AC'97 interface #%d is busy (2)\n", + ac97->num); + return 0; } - snd_printk(KERN_ERR "AC'97 interface #%d is busy (2)\n", ac97->num); - return 0; - ok2: - for (idx = 0; idx < 1000; idx++) { - if (inw(FM801_REG(chip, AC97_CMD)) & FM801_AC97_VALID) - goto ok3; - udelay(10); + if (!fm801_ac97_is_valid(chip, 1000)) { + dev_err(chip->card->dev, + "AC'97 interface #%d is not valid (2)\n", ac97->num); + return 0; } - snd_printk(KERN_ERR "AC'97 interface #%d is not valid (2)\n", ac97->num); - return 0; - ok3: - return inw(FM801_REG(chip, AC97_DATA)); + return fm801_readw(chip, AC97_DATA); } static unsigned int rates[] = { @@ -384,7 +397,7 @@ static int snd_fm801_playback_trigger(struct snd_pcm_substream *substream, snd_BUG(); return -EINVAL; } - outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL)); + fm801_writew(chip, PLY_CTRL, chip->ply_ctrl); spin_unlock(&chip->reg_lock); return 0; } @@ -419,7 +432,7 @@ static int snd_fm801_capture_trigger(struct snd_pcm_substream *substream, snd_BUG(); return -EINVAL; } - outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); + fm801_writew(chip, CAP_CTRL, chip->cap_ctrl); spin_unlock(&chip->reg_lock); return 0; } @@ -457,12 +470,13 @@ static int snd_fm801_playback_prepare(struct snd_pcm_substream *substream) } chip->ply_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->ply_buf = 0; - outw(chip->ply_ctrl, FM801_REG(chip, PLY_CTRL)); - outw(chip->ply_count - 1, FM801_REG(chip, PLY_COUNT)); + fm801_writew(chip, PLY_CTRL, chip->ply_ctrl); + fm801_writew(chip, PLY_COUNT, chip->ply_count - 1); chip->ply_buffer = runtime->dma_addr; chip->ply_pos = 0; - outl(chip->ply_buffer, FM801_REG(chip, PLY_BUF1)); - outl(chip->ply_buffer + (chip->ply_count % chip->ply_size), FM801_REG(chip, PLY_BUF2)); + fm801_writel(chip, PLY_BUF1, chip->ply_buffer); + fm801_writel(chip, PLY_BUF2, + chip->ply_buffer + (chip->ply_count % chip->ply_size)); spin_unlock_irq(&chip->reg_lock); return 0; } @@ -483,12 +497,13 @@ static int snd_fm801_capture_prepare(struct snd_pcm_substream *substream) chip->cap_ctrl |= FM801_STEREO; chip->cap_ctrl |= snd_fm801_rate_bits(runtime->rate) << FM801_RATE_SHIFT; chip->cap_buf = 0; - outw(chip->cap_ctrl, FM801_REG(chip, CAP_CTRL)); - outw(chip->cap_count - 1, FM801_REG(chip, CAP_COUNT)); + fm801_writew(chip, CAP_CTRL, chip->cap_ctrl); + fm801_writew(chip, CAP_COUNT, chip->cap_count - 1); chip->cap_buffer = runtime->dma_addr; chip->cap_pos = 0; - outl(chip->cap_buffer, FM801_REG(chip, CAP_BUF1)); - outl(chip->cap_buffer + (chip->cap_count % chip->cap_size), FM801_REG(chip, CAP_BUF2)); + fm801_writel(chip, CAP_BUF1, chip->cap_buffer); + fm801_writel(chip, CAP_BUF2, + chip->cap_buffer + (chip->cap_count % chip->cap_size)); spin_unlock_irq(&chip->reg_lock); return 0; } @@ -501,8 +516,8 @@ static snd_pcm_uframes_t snd_fm801_playback_pointer(struct snd_pcm_substream *su if (!(chip->ply_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); - ptr = chip->ply_pos + (chip->ply_count - 1) - inw(FM801_REG(chip, PLY_COUNT)); - if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_PLAYBACK) { + ptr = chip->ply_pos + (chip->ply_count - 1) - fm801_readw(chip, PLY_COUNT); + if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_PLAYBACK) { ptr += chip->ply_count; ptr %= chip->ply_size; } @@ -518,8 +533,8 @@ static snd_pcm_uframes_t snd_fm801_capture_pointer(struct snd_pcm_substream *sub if (!(chip->cap_ctrl & FM801_START)) return 0; spin_lock(&chip->reg_lock); - ptr = chip->cap_pos + (chip->cap_count - 1) - inw(FM801_REG(chip, CAP_COUNT)); - if (inw(FM801_REG(chip, IRQ_STATUS)) & FM801_IRQ_CAPTURE) { + ptr = chip->cap_pos + (chip->cap_count - 1) - fm801_readw(chip, CAP_COUNT); + if (fm801_readw(chip, IRQ_STATUS) & FM801_IRQ_CAPTURE) { ptr += chip->cap_count; ptr %= chip->cap_size; } @@ -533,12 +548,12 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) unsigned short status; unsigned int tmp; - status = inw(FM801_REG(chip, IRQ_STATUS)); + status = fm801_readw(chip, IRQ_STATUS); status &= FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU|FM801_IRQ_VOLUME; if (! status) return IRQ_NONE; /* ack first */ - outw(status, FM801_REG(chip, IRQ_STATUS)); + fm801_writew(chip, IRQ_STATUS, status); if (chip->pcm && (status & FM801_IRQ_PLAYBACK) && chip->playback_substream) { spin_lock(&chip->reg_lock); chip->ply_buf++; @@ -546,10 +561,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) chip->ply_pos %= chip->ply_size; tmp = chip->ply_pos + chip->ply_count; tmp %= chip->ply_size; - outl(chip->ply_buffer + tmp, - (chip->ply_buf & 1) ? - FM801_REG(chip, PLY_BUF1) : - FM801_REG(chip, PLY_BUF2)); + if (chip->ply_buf & 1) + fm801_writel(chip, PLY_BUF1, chip->ply_buffer + tmp); + else + fm801_writel(chip, PLY_BUF2, chip->ply_buffer + tmp); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->playback_substream); } @@ -560,10 +575,10 @@ static irqreturn_t snd_fm801_interrupt(int irq, void *dev_id) chip->cap_pos %= chip->cap_size; tmp = chip->cap_pos + chip->cap_count; tmp %= chip->cap_size; - outl(chip->cap_buffer + tmp, - (chip->cap_buf & 1) ? - FM801_REG(chip, CAP_BUF1) : - FM801_REG(chip, CAP_BUF2)); + if (chip->cap_buf & 1) + fm801_writel(chip, CAP_BUF1, chip->cap_buffer + tmp); + else + fm801_writel(chip, CAP_BUF2, chip->cap_buffer + tmp); spin_unlock(&chip->reg_lock); snd_pcm_period_elapsed(chip->capture_substream); } @@ -689,7 +704,7 @@ static struct snd_pcm_ops snd_fm801_capture_ops = { .pointer = snd_fm801_capture_pointer, }; -static int __devinit snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm ** rpcm) +static int snd_fm801_pcm(struct fm801 *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -747,7 +762,7 @@ static struct snd_fm801_tea575x_gpio snd_fm801_tea575x_gpios[] = { static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); reg &= ~(FM801_GPIO_GP(gpio.data) | @@ -759,23 +774,28 @@ static void snd_fm801_tea575x_set_pins(struct snd_tea575x *tea, u8 pins) /* WRITE_ENABLE is inverted */ reg |= (pins & TEA575X_WREN) ? 0 : FM801_GPIO_GP(gpio.wren); - outw(reg, FM801_REG(chip, GPIO_CTRL)); + fm801_writew(chip, GPIO_CTRL, reg); } static u8 snd_fm801_tea575x_get_pins(struct snd_tea575x *tea) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); - - return (reg & FM801_GPIO_GP(gpio.data)) ? TEA575X_DATA : 0 | - (reg & FM801_GPIO_GP(gpio.most)) ? TEA575X_MOST : 0; + u8 ret; + + ret = 0; + if (reg & FM801_GPIO_GP(gpio.data)) + ret |= TEA575X_DATA; + if (reg & FM801_GPIO_GP(gpio.most)) + ret |= TEA575X_MOST; + return ret; } static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output) { struct fm801 *chip = tea->private_data; - unsigned short reg = inw(FM801_REG(chip, GPIO_CTRL)); + unsigned short reg = fm801_readw(chip, GPIO_CTRL); struct snd_fm801_tea575x_gpio gpio = *get_tea575x_gpio(chip); /* use GPIO lines and set write enable bit */ @@ -806,7 +826,7 @@ static void snd_fm801_tea575x_set_direction(struct snd_tea575x *tea, bool output FM801_GPIO_GP(gpio.clk)); } - outw(reg, FM801_REG(chip, GPIO_CTRL)); + fm801_writew(chip, GPIO_CTRL, reg); } static struct snd_tea575x_ops snd_fm801_tea_ops = { @@ -957,7 +977,7 @@ static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol, struct fm801 *chip = snd_kcontrol_chip(kcontrol); unsigned short val; - val = inw(FM801_REG(chip, REC_SRC)) & 7; + val = fm801_readw(chip, REC_SRC) & 7; if (val > 4) val = 4; ucontrol->value.enumerated.item[0] = val; @@ -979,7 +999,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_dsp, -3450, 150, 0); #define FM801_CONTROLS ARRAY_SIZE(snd_fm801_controls) -static struct snd_kcontrol_new snd_fm801_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_fm801_controls[] = { FM801_DOUBLE_TLV("Wave Playback Volume", FM801_PCM_VOL, 0, 8, 31, 1, db_scale_dsp), FM801_SINGLE("Wave Playback Switch", FM801_PCM_VOL, 15, 1, 1), @@ -1000,7 +1020,7 @@ FM801_SINGLE("FM Playback Switch", FM801_FM_VOL, 15, 1, 1), #define FM801_CONTROLS_MULTI ARRAY_SIZE(snd_fm801_controls_multi) -static struct snd_kcontrol_new snd_fm801_controls_multi[] __devinitdata = { +static struct snd_kcontrol_new snd_fm801_controls_multi[] = { FM801_SINGLE("AC97 2ch->4ch Copy Switch", FM801_CODEC_CTRL, 7, 1, 0), FM801_SINGLE("AC97 18-bit Switch", FM801_CODEC_CTRL, 10, 1, 0), FM801_SINGLE(SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), FM801_I2S_MODE, 8, 1, 0), @@ -1025,7 +1045,7 @@ static void snd_fm801_mixer_free_ac97(struct snd_ac97 *ac97) } } -static int __devinit snd_fm801_mixer(struct fm801 *chip) +static int snd_fm801_mixer(struct fm801 *chip) { struct snd_ac97_template ac97; unsigned int i; @@ -1068,12 +1088,12 @@ static int wait_for_codec(struct fm801 *chip, unsigned int codec_id, { unsigned long timeout = jiffies + waits; - outw(FM801_AC97_READ | (codec_id << FM801_AC97_ADDR_SHIFT) | reg, - FM801_REG(chip, AC97_CMD)); + fm801_writew(chip, AC97_CMD, + reg | (codec_id << FM801_AC97_ADDR_SHIFT) | FM801_AC97_READ); udelay(5); do { - if ((inw(FM801_REG(chip, AC97_CMD)) & (FM801_AC97_VALID|FM801_AC97_BUSY)) - == FM801_AC97_VALID) + if ((fm801_readw(chip, AC97_CMD) & + (FM801_AC97_VALID | FM801_AC97_BUSY)) == FM801_AC97_VALID) return 0; schedule_timeout_uninterruptible(1); } while (time_after(timeout, jiffies)); @@ -1088,15 +1108,15 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) goto __ac97_ok; /* codec cold reset + AC'97 warm reset */ - outw((1<<5) | (1<<6), FM801_REG(chip, CODEC_CTRL)); - inw(FM801_REG(chip, CODEC_CTRL)); /* flush posting data */ + fm801_writew(chip, CODEC_CTRL, (1 << 5) | (1 << 6)); + fm801_readw(chip, CODEC_CTRL); /* flush posting data */ udelay(100); - outw(0, FM801_REG(chip, CODEC_CTRL)); + fm801_writew(chip, CODEC_CTRL, 0); if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) if (!resume) { - snd_printk(KERN_INFO "Primary AC'97 codec not found, " - "assume SF64-PCR (tuner-only)\n"); + dev_info(chip->card->dev, + "Primary AC'97 codec not found, assume SF64-PCR (tuner-only)\n"); chip->tea575x_tuner = 3 | TUNER_ONLY; goto __ac97_ok; } @@ -1112,7 +1132,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) for (i = 3; i > 0; i--) { if (!wait_for_codec(chip, i, AC97_VENDOR_ID1, msecs_to_jiffies(50))) { - cmdw = inw(FM801_REG(chip, AC97_DATA)); + cmdw = fm801_readw(chip, AC97_DATA); if (cmdw != 0xffff && cmdw != 0) { chip->secondary = 1; chip->secondary_addr = i; @@ -1130,23 +1150,24 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) __ac97_ok: /* init volume */ - outw(0x0808, FM801_REG(chip, PCM_VOL)); - outw(0x9f1f, FM801_REG(chip, FM_VOL)); - outw(0x8808, FM801_REG(chip, I2S_VOL)); + fm801_writew(chip, PCM_VOL, 0x0808); + fm801_writew(chip, FM_VOL, 0x9f1f); + fm801_writew(chip, I2S_VOL, 0x8808); /* I2S control - I2S mode */ - outw(0x0003, FM801_REG(chip, I2S_MODE)); + fm801_writew(chip, I2S_MODE, 0x0003); /* interrupt setup */ - cmdw = inw(FM801_REG(chip, IRQ_MASK)); + cmdw = fm801_readw(chip, IRQ_MASK); if (chip->irq < 0) cmdw |= 0x00c3; /* mask everything, no PCM nor MPU */ else cmdw &= ~0x0083; /* unmask MPU, PLAYBACK & CAPTURE */ - outw(cmdw, FM801_REG(chip, IRQ_MASK)); + fm801_writew(chip, IRQ_MASK, cmdw); /* interrupt clear */ - outw(FM801_IRQ_PLAYBACK|FM801_IRQ_CAPTURE|FM801_IRQ_MPU, FM801_REG(chip, IRQ_STATUS)); + fm801_writew(chip, IRQ_STATUS, + FM801_IRQ_PLAYBACK | FM801_IRQ_CAPTURE | FM801_IRQ_MPU); return 0; } @@ -1160,9 +1181,9 @@ static int snd_fm801_free(struct fm801 *chip) goto __end_hw; /* interrupt setup - mask everything */ - cmdw = inw(FM801_REG(chip, IRQ_MASK)); + cmdw = fm801_readw(chip, IRQ_MASK); cmdw |= 0x00c3; - outw(cmdw, FM801_REG(chip, IRQ_MASK)); + fm801_writew(chip, IRQ_MASK, cmdw); __end_hw: #ifdef CONFIG_SND_FM801_TEA575X_BOOL @@ -1186,11 +1207,11 @@ static int snd_fm801_dev_free(struct snd_device *device) return snd_fm801_free(chip); } -static int __devinit snd_fm801_create(struct snd_card *card, - struct pci_dev * pci, - int tea575x_tuner, - int radio_nr, - struct fm801 ** rchip) +static int snd_fm801_create(struct snd_card *card, + struct pci_dev *pci, + int tea575x_tuner, + int radio_nr, + struct fm801 **rchip) { struct fm801 *chip; int err; @@ -1220,7 +1241,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", chip->irq); snd_fm801_free(chip); return -EBUSY; } @@ -1246,8 +1267,6 @@ static int __devinit snd_fm801_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - #ifdef CONFIG_SND_FM801_TEA575X_BOOL err = v4l2_device_register(&pci->dev, &chip->v4l2_dev); if (err < 0) { @@ -1262,7 +1281,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && (tea575x_tuner & TUNER_TYPE_MASK) < 4) { if (snd_tea575x_init(&chip->tea, THIS_MODULE)) { - snd_printk(KERN_ERR "TEA575x radio not found\n"); + dev_err(card->dev, "TEA575x radio not found\n"); snd_fm801_free(chip); return -ENODEV; } @@ -1271,13 +1290,14 @@ static int __devinit snd_fm801_create(struct snd_card *card, for (tea575x_tuner = 1; tea575x_tuner <= 3; tea575x_tuner++) { chip->tea575x_tuner = tea575x_tuner; if (!snd_tea575x_init(&chip->tea, THIS_MODULE)) { - snd_printk(KERN_INFO "detected TEA575x radio type %s\n", + dev_info(card->dev, + "detected TEA575x radio type %s\n", get_tea575x_gpio(chip)->name); break; } } if (tea575x_tuner == 4) { - snd_printk(KERN_ERR "TEA575x radio not found\n"); + dev_err(card->dev, "TEA575x radio not found\n"); chip->tea575x_tuner = TUNER_DISABLED; } } @@ -1291,8 +1311,8 @@ static int __devinit snd_fm801_create(struct snd_card *card, return 0; } -static int __devinit snd_card_fm801_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_fm801_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1307,7 +1327,8 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; if ((err = snd_fm801_create(card, pci, tea575x_tuner[dev], radio_nr[dev], &chip)) < 0) { @@ -1334,15 +1355,15 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return err; } if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_FM801, - FM801_REG(chip, MPU401_DATA), + chip->port + FM801_MPU401_DATA, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi)) < 0) { snd_card_free(card); return err; } - if ((err = snd_opl3_create(card, FM801_REG(chip, OPL3_BANK0), - FM801_REG(chip, OPL3_BANK1), + if ((err = snd_opl3_create(card, chip->port + FM801_OPL3_BANK0, + chip->port + FM801_OPL3_BANK1, OPL3_HW_OPL3_FM801, 1, &opl3)) < 0) { snd_card_free(card); return err; @@ -1362,10 +1383,9 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_fm801_remove(struct pci_dev *pci) +static void snd_card_fm801_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP @@ -1407,8 +1427,7 @@ static int snd_fm801_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "fm801: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1434,7 +1453,7 @@ static struct pci_driver fm801_driver = { .name = KBUILD_MODNAME, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, - .remove = __devexit_p(snd_card_fm801_remove), + .remove = snd_card_fm801_remove, .driver = { .pm = SND_FM801_PM_OPS, }, diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 7105c3de1bc..ebf4c2fb99d 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -1,8 +1,15 @@ -menuconfig SND_HDA_INTEL - tristate "Intel HD Audio" +menu "HD-Audio" + +config SND_HDA + tristate select SND_PCM select SND_VMASTER select SND_KCTL_JACK + +config SND_HDA_INTEL + tristate "HD Audio PCI" + depends on SND_PCI + select SND_HDA help Say Y here to include support for Intel "High Definition Audio" (Azalia) and its compatible devices. @@ -13,7 +20,25 @@ menuconfig SND_HDA_INTEL To compile this driver as a module, choose M here: the module will be called snd-hda-intel. -if SND_HDA_INTEL +config SND_HDA_TEGRA + tristate "NVIDIA Tegra HD Audio" + depends on ARCH_TEGRA + select SND_HDA + help + Say Y here to support the HDA controller present in NVIDIA + Tegra SoCs + + This options enables support for the HD Audio controller + present in some NVIDIA Tegra SoCs, used to communicate audio + to the HDMI output. + + To compile this driver as a module, choose M here: the module + will be called snd-hda-tegra. + +if SND_HDA + +config SND_HDA_DSP_LOADER + bool config SND_HDA_PREALLOC_SIZE int "Pre-allocated buffer size for HD-audio driver" @@ -37,8 +62,7 @@ config SND_HDA_HWDEP with codecs for debugging purposes. config SND_HDA_RECONFIG - bool "Allow dynamic codec reconfiguration (EXPERIMENTAL)" - depends on SND_HDA_HWDEP && EXPERIMENTAL + bool "Allow dynamic codec reconfiguration" help Say Y here to enable the HD-audio codec re-configuration feature. This adds the sysfs interfaces to allow user to clear the whole @@ -47,7 +71,7 @@ config SND_HDA_RECONFIG config SND_HDA_INPUT_BEEP bool "Support digital beep via input layer" - depends on INPUT=y || INPUT=SND_HDA_INTEL + depends on INPUT=y || INPUT=SND_HDA help Say Y here to build a digital beep interface for HD-audio driver. This interface is used to generate digital beeps. @@ -72,9 +96,7 @@ config SND_HDA_INPUT_JACK config SND_HDA_PATCH_LOADER bool "Support initialization patch loading for HD-audio" - depends on EXPERIMENTAL select FW_LOADER - select SND_HDA_HWDEP select SND_HDA_RECONFIG help Say Y here to allow the HD-audio driver to load a pseudo @@ -82,152 +104,140 @@ config SND_HDA_PATCH_LOADER start up. The "patch" file can be specified via patch module option, such as patch=hda-init. - This option turns on hwdep and reconfig features automatically. - config SND_HDA_CODEC_REALTEK - bool "Build Realtek HD-audio codec support" - default y + tristate "Build Realtek HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include Realtek HD-audio codec support in + Say Y or M here to include Realtek HD-audio codec support in snd-hda-intel driver, such as ALC880. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-realtek. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_REALTEK=m config SND_HDA_CODEC_ANALOG - bool "Build Analog Device HD-audio codec support" - default y + tristate "Build Analog Device HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include Analog Device HD-audio codec support in + Say Y or M here to include Analog Device HD-audio codec support in snd-hda-intel driver, such as AD1986A. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-analog. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_ANALOG=m config SND_HDA_CODEC_SIGMATEL - bool "Build IDT/Sigmatel HD-audio codec support" - default y + tristate "Build IDT/Sigmatel HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include IDT (Sigmatel) HD-audio codec support in + Say Y or M here to include IDT (Sigmatel) HD-audio codec support in snd-hda-intel driver, such as STAC9200. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-idt. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_SIGMATEL=m config SND_HDA_CODEC_VIA - bool "Build VIA HD-audio codec support" - default y + tristate "Build VIA HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include VIA HD-audio codec support in + Say Y or M here to include VIA HD-audio codec support in snd-hda-intel driver, such as VT1708. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-via. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_VIA=m config SND_HDA_CODEC_HDMI - bool "Build HDMI/DisplayPort HD-audio codec support" - select SND_DYNAMIC_MINORS - default y + tristate "Build HDMI/DisplayPort HD-audio codec support" help - Say Y here to include HDMI and DisplayPort HD-audio codec + Say Y or M here to include HDMI and DisplayPort HD-audio codec support in snd-hda-intel driver. This includes all AMD/ATI, Intel and Nvidia HDMI/DisplayPort codecs. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-hdmi. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m -config SND_HDA_CODEC_CIRRUS - bool "Build Cirrus Logic codec support" - depends on SND_HDA_INTEL +config SND_HDA_I915 + bool default y + depends on DRM_I915 + +config SND_HDA_CODEC_CIRRUS + tristate "Build Cirrus Logic codec support" + select SND_HDA_GENERIC help - Say Y here to include Cirrus Logic codec support in + Say Y or M here to include Cirrus Logic codec support in snd-hda-intel driver, such as CS4206. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-cirrus. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CIRRUS=m config SND_HDA_CODEC_CONEXANT - bool "Build Conexant HD-audio codec support" - default y + tristate "Build Conexant HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include Conexant HD-audio codec support in + Say Y or M here to include Conexant HD-audio codec support in snd-hda-intel driver, such as CX20549. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-conexant. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CONEXANT=m config SND_HDA_CODEC_CA0110 - bool "Build Creative CA0110-IBG codec support" - depends on SND_HDA_INTEL - default y + tristate "Build Creative CA0110-IBG codec support" + select SND_HDA_GENERIC help - Say Y here to include Creative CA0110-IBG codec support in + Say Y or M here to include Creative CA0110-IBG codec support in snd-hda-intel driver, found on some Creative X-Fi cards. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0110. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CA0110=m config SND_HDA_CODEC_CA0132 - bool "Build Creative CA0132 codec support" - depends on SND_HDA_INTEL - default y + tristate "Build Creative CA0132 codec support" help - Say Y here to include Creative CA0132 codec support in + Say Y or M here to include Creative CA0132 codec support in snd-hda-intel driver. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-ca0132. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CA0132=m + +config SND_HDA_CODEC_CA0132_DSP + bool "Support new DSP code for CA0132 codec" + depends on SND_HDA_CODEC_CA0132 + select SND_HDA_DSP_LOADER + select FW_LOADER + help + Say Y here to enable the DSP for Creative CA0132 for extended + features like equalizer or echo cancellation. + + Note that this option requires the external firmware file + (ctefx.bin). config SND_HDA_CODEC_CMEDIA - bool "Build C-Media HD-audio codec support" - default y + tristate "Build C-Media HD-audio codec support" + select SND_HDA_GENERIC help - Say Y here to include C-Media HD-audio codec support in + Say Y or M here to include C-Media HD-audio codec support in snd-hda-intel driver, such as CMI9880. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-cmedia. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_CMEDIA=m config SND_HDA_CODEC_SI3054 - bool "Build Silicon Labs 3054 HD-modem codec support" - default y + tristate "Build Silicon Labs 3054 HD-modem codec support" help - Say Y here to include Silicon Labs 3054 HD-modem codec + Say Y or M here to include Silicon Labs 3054 HD-modem codec (and compatibles) support in snd-hda-intel driver. - When the HD-audio driver is built as a module, the codec - support code is also built as another module, - snd-hda-codec-si3054. - This module is automatically loaded at probing. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_CODEC_SI3054=m config SND_HDA_GENERIC - bool "Enable generic HD-audio codec parser" - default y + tristate "Enable generic HD-audio codec parser" help - Say Y here to enable the generic HD-audio codec parser + Say Y or M here to enable the generic HD-audio codec parser in snd-hda-intel driver. +comment "Set to Y if you want auto-loading the codec driver" + depends on SND_HDA=y && SND_HDA_GENERIC=m + config SND_HDA_POWER_SAVE_DEFAULT int "Default time-out for HD-audio power-save mode" depends on PM @@ -237,3 +247,5 @@ config SND_HDA_POWER_SAVE_DEFAULT power-save mode. 0 means to disable the power-save mode. endif + +endmenu diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index bd4149f1aaf..194f30935e7 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -1,14 +1,19 @@ snd-hda-intel-objs := hda_intel.o +snd-hda-controller-objs := hda_controller.o +snd-hda-tegra-objs := hda_tegra.o +# for haswell power well +snd-hda-intel-$(CONFIG_SND_HDA_I915) += hda_i915.o -snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o -snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o +snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o hda_sysfs.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o # for trace-points CFLAGS_hda_codec.o := -I$(src) +CFLAGS_hda_controller.o := -I$(src) +snd-hda-codec-generic-objs := hda_generic.o snd-hda-codec-realtek-objs := patch_realtek.o snd-hda-codec-cmedia-objs := patch_cmedia.o snd-hda-codec-analog-objs := patch_analog.o @@ -22,44 +27,25 @@ snd-hda-codec-via-objs := patch_via.o snd-hda-codec-hdmi-objs := patch_hdmi.o hda_eld.o # common driver -obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o +obj-$(CONFIG_SND_HDA) := snd-hda-codec.o +obj-$(CONFIG_SND_HDA) += snd-hda-controller.o -# codec drivers (note: CONFIG_SND_HDA_CODEC_XXX are booleans) -ifdef CONFIG_SND_HDA_CODEC_REALTEK -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-realtek.o -endif -ifdef CONFIG_SND_HDA_CODEC_CMEDIA -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cmedia.o -endif -ifdef CONFIG_SND_HDA_CODEC_ANALOG -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-analog.o -endif -ifdef CONFIG_SND_HDA_CODEC_SIGMATEL -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-idt.o -endif -ifdef CONFIG_SND_HDA_CODEC_SI3054 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-si3054.o -endif -ifdef CONFIG_SND_HDA_CODEC_CIRRUS -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-cirrus.o -endif -ifdef CONFIG_SND_HDA_CODEC_CA0110 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o -endif -ifdef CONFIG_SND_HDA_CODEC_CA0132 -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0132.o -endif -ifdef CONFIG_SND_HDA_CODEC_CONEXANT -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o -endif -ifdef CONFIG_SND_HDA_CODEC_VIA -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-via.o -endif -ifdef CONFIG_SND_HDA_CODEC_HDMI -obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-hdmi.o -endif +# codec drivers +obj-$(CONFIG_SND_HDA_GENERIC) += snd-hda-codec-generic.o +obj-$(CONFIG_SND_HDA_CODEC_REALTEK) += snd-hda-codec-realtek.o +obj-$(CONFIG_SND_HDA_CODEC_CMEDIA) += snd-hda-codec-cmedia.o +obj-$(CONFIG_SND_HDA_CODEC_ANALOG) += snd-hda-codec-analog.o +obj-$(CONFIG_SND_HDA_CODEC_SIGMATEL) += snd-hda-codec-idt.o +obj-$(CONFIG_SND_HDA_CODEC_SI3054) += snd-hda-codec-si3054.o +obj-$(CONFIG_SND_HDA_CODEC_CIRRUS) += snd-hda-codec-cirrus.o +obj-$(CONFIG_SND_HDA_CODEC_CA0110) += snd-hda-codec-ca0110.o +obj-$(CONFIG_SND_HDA_CODEC_CA0132) += snd-hda-codec-ca0132.o +obj-$(CONFIG_SND_HDA_CODEC_CONEXANT) += snd-hda-codec-conexant.o +obj-$(CONFIG_SND_HDA_CODEC_VIA) += snd-hda-codec-via.o +obj-$(CONFIG_SND_HDA_CODEC_HDMI) += snd-hda-codec-hdmi.o # this must be the last entry after codec drivers; # otherwise the codec patches won't be hooked before the PCI probe # when built in kernel obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-intel.o +obj-$(CONFIG_SND_HDA_TEGRA) += snd-hda-tegra.o diff --git a/sound/pci/hda/ca0132_regs.h b/sound/pci/hda/ca0132_regs.h new file mode 100644 index 00000000000..07e760937d3 --- /dev/null +++ b/sound/pci/hda/ca0132_regs.h @@ -0,0 +1,409 @@ +/* + * HD audio interface patch for Creative CA0132 chip. + * CA0132 registers defines. + * + * Copyright (c) 2011, Creative Technology Ltd. + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __CA0132_REGS_H +#define __CA0312_REGS_H + +#define DSP_CHIP_OFFSET 0x100000 +#define DSP_DBGCNTL_MODULE_OFFSET 0xE30 +#define DSP_DBGCNTL_INST_OFFSET \ + (DSP_CHIP_OFFSET + DSP_DBGCNTL_MODULE_OFFSET) + +#define DSP_DBGCNTL_EXEC_LOBIT 0x0 +#define DSP_DBGCNTL_EXEC_HIBIT 0x3 +#define DSP_DBGCNTL_EXEC_MASK 0xF + +#define DSP_DBGCNTL_SS_LOBIT 0x4 +#define DSP_DBGCNTL_SS_HIBIT 0x7 +#define DSP_DBGCNTL_SS_MASK 0xF0 + +#define DSP_DBGCNTL_STATE_LOBIT 0xA +#define DSP_DBGCNTL_STATE_HIBIT 0xD +#define DSP_DBGCNTL_STATE_MASK 0x3C00 + +#define XRAM_CHIP_OFFSET 0x0 +#define XRAM_XRAM_CHANNEL_COUNT 0xE000 +#define XRAM_XRAM_MODULE_OFFSET 0x0 +#define XRAM_XRAM_CHAN_INCR 4 +#define XRAM_XRAM_INST_OFFSET(_chan) \ + (XRAM_CHIP_OFFSET + XRAM_XRAM_MODULE_OFFSET + \ + (_chan * XRAM_XRAM_CHAN_INCR)) + +#define YRAM_CHIP_OFFSET 0x40000 +#define YRAM_YRAM_CHANNEL_COUNT 0x8000 +#define YRAM_YRAM_MODULE_OFFSET 0x0 +#define YRAM_YRAM_CHAN_INCR 4 +#define YRAM_YRAM_INST_OFFSET(_chan) \ + (YRAM_CHIP_OFFSET + YRAM_YRAM_MODULE_OFFSET + \ + (_chan * YRAM_YRAM_CHAN_INCR)) + +#define UC_CHIP_OFFSET 0x80000 +#define UC_UC_CHANNEL_COUNT 0x10000 +#define UC_UC_MODULE_OFFSET 0x0 +#define UC_UC_CHAN_INCR 4 +#define UC_UC_INST_OFFSET(_chan) \ + (UC_CHIP_OFFSET + UC_UC_MODULE_OFFSET + \ + (_chan * UC_UC_CHAN_INCR)) + +#define AXRAM_CHIP_OFFSET 0x3C000 +#define AXRAM_AXRAM_CHANNEL_COUNT 0x1000 +#define AXRAM_AXRAM_MODULE_OFFSET 0x0 +#define AXRAM_AXRAM_CHAN_INCR 4 +#define AXRAM_AXRAM_INST_OFFSET(_chan) \ + (AXRAM_CHIP_OFFSET + AXRAM_AXRAM_MODULE_OFFSET + \ + (_chan * AXRAM_AXRAM_CHAN_INCR)) + +#define AYRAM_CHIP_OFFSET 0x78000 +#define AYRAM_AYRAM_CHANNEL_COUNT 0x1000 +#define AYRAM_AYRAM_MODULE_OFFSET 0x0 +#define AYRAM_AYRAM_CHAN_INCR 4 +#define AYRAM_AYRAM_INST_OFFSET(_chan) \ + (AYRAM_CHIP_OFFSET + AYRAM_AYRAM_MODULE_OFFSET + \ + (_chan * AYRAM_AYRAM_CHAN_INCR)) + +#define DSPDMAC_CHIP_OFFSET 0x110000 +#define DSPDMAC_DMA_CFG_CHANNEL_COUNT 12 +#define DSPDMAC_DMACFG_MODULE_OFFSET 0xF00 +#define DSPDMAC_DMACFG_CHAN_INCR 0x10 +#define DSPDMAC_DMACFG_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_DMACFG_MODULE_OFFSET + \ + (_chan * DSPDMAC_DMACFG_CHAN_INCR)) + +#define DSPDMAC_DMACFG_DBADR_LOBIT 0x0 +#define DSPDMAC_DMACFG_DBADR_HIBIT 0x10 +#define DSPDMAC_DMACFG_DBADR_MASK 0x1FFFF +#define DSPDMAC_DMACFG_LP_LOBIT 0x11 +#define DSPDMAC_DMACFG_LP_HIBIT 0x11 +#define DSPDMAC_DMACFG_LP_MASK 0x20000 + +#define DSPDMAC_DMACFG_AINCR_LOBIT 0x12 +#define DSPDMAC_DMACFG_AINCR_HIBIT 0x12 +#define DSPDMAC_DMACFG_AINCR_MASK 0x40000 + +#define DSPDMAC_DMACFG_DWR_LOBIT 0x13 +#define DSPDMAC_DMACFG_DWR_HIBIT 0x13 +#define DSPDMAC_DMACFG_DWR_MASK 0x80000 + +#define DSPDMAC_DMACFG_AJUMP_LOBIT 0x14 +#define DSPDMAC_DMACFG_AJUMP_HIBIT 0x17 +#define DSPDMAC_DMACFG_AJUMP_MASK 0xF00000 + +#define DSPDMAC_DMACFG_AMODE_LOBIT 0x18 +#define DSPDMAC_DMACFG_AMODE_HIBIT 0x19 +#define DSPDMAC_DMACFG_AMODE_MASK 0x3000000 + +#define DSPDMAC_DMACFG_LK_LOBIT 0x1A +#define DSPDMAC_DMACFG_LK_HIBIT 0x1A +#define DSPDMAC_DMACFG_LK_MASK 0x4000000 + +#define DSPDMAC_DMACFG_AICS_LOBIT 0x1B +#define DSPDMAC_DMACFG_AICS_HIBIT 0x1F +#define DSPDMAC_DMACFG_AICS_MASK 0xF8000000 + +#define DSPDMAC_DMACFG_LP_SINGLE 0 +#define DSPDMAC_DMACFG_LP_LOOPING 1 + +#define DSPDMAC_DMACFG_AINCR_XANDY 0 +#define DSPDMAC_DMACFG_AINCR_XORY 1 + +#define DSPDMAC_DMACFG_DWR_DMA_RD 0 +#define DSPDMAC_DMACFG_DWR_DMA_WR 1 + +#define DSPDMAC_DMACFG_AMODE_LINEAR 0 +#define DSPDMAC_DMACFG_AMODE_RSV1 1 +#define DSPDMAC_DMACFG_AMODE_WINTLV 2 +#define DSPDMAC_DMACFG_AMODE_GINTLV 3 + +#define DSPDMAC_DSP_ADR_OFS_CHANNEL_COUNT 12 +#define DSPDMAC_DSPADROFS_MODULE_OFFSET 0xF04 +#define DSPDMAC_DSPADROFS_CHAN_INCR 0x10 +#define DSPDMAC_DSPADROFS_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADROFS_MODULE_OFFSET + \ + (_chan * DSPDMAC_DSPADROFS_CHAN_INCR)) + +#define DSPDMAC_DSPADROFS_COFS_LOBIT 0x0 +#define DSPDMAC_DSPADROFS_COFS_HIBIT 0xF +#define DSPDMAC_DSPADROFS_COFS_MASK 0xFFFF + +#define DSPDMAC_DSPADROFS_BOFS_LOBIT 0x10 +#define DSPDMAC_DSPADROFS_BOFS_HIBIT 0x1F +#define DSPDMAC_DSPADROFS_BOFS_MASK 0xFFFF0000 + +#define DSPDMAC_DSP_ADR_WOFS_CHANNEL_COUNT 12 +#define DSPDMAC_DSPADRWOFS_MODULE_OFFSET 0xF04 +#define DSPDMAC_DSPADRWOFS_CHAN_INCR 0x10 + +#define DSPDMAC_DSPADRWOFS_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRWOFS_MODULE_OFFSET + \ + (_chan * DSPDMAC_DSPADRWOFS_CHAN_INCR)) + +#define DSPDMAC_DSPADRWOFS_WCOFS_LOBIT 0x0 +#define DSPDMAC_DSPADRWOFS_WCOFS_HIBIT 0xA +#define DSPDMAC_DSPADRWOFS_WCOFS_MASK 0x7FF + +#define DSPDMAC_DSPADRWOFS_WCBFR_LOBIT 0xB +#define DSPDMAC_DSPADRWOFS_WCBFR_HIBIT 0xF +#define DSPDMAC_DSPADRWOFS_WCBFR_MASK 0xF800 + +#define DSPDMAC_DSPADRWOFS_WBOFS_LOBIT 0x10 +#define DSPDMAC_DSPADRWOFS_WBOFS_HIBIT 0x1A +#define DSPDMAC_DSPADRWOFS_WBOFS_MASK 0x7FF0000 + +#define DSPDMAC_DSPADRWOFS_WBBFR_LOBIT 0x1B +#define DSPDMAC_DSPADRWOFS_WBBFR_HIBIT 0x1F +#define DSPDMAC_DSPADRWOFS_WBBFR_MASK 0xF8000000 + +#define DSPDMAC_DSP_ADR_GOFS_CHANNEL_COUNT 12 +#define DSPDMAC_DSPADRGOFS_MODULE_OFFSET 0xF04 +#define DSPDMAC_DSPADRGOFS_CHAN_INCR 0x10 +#define DSPDMAC_DSPADRGOFS_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_DSPADRGOFS_MODULE_OFFSET + \ + (_chan * DSPDMAC_DSPADRGOFS_CHAN_INCR)) + +#define DSPDMAC_DSPADRGOFS_GCOFS_LOBIT 0x0 +#define DSPDMAC_DSPADRGOFS_GCOFS_HIBIT 0x9 +#define DSPDMAC_DSPADRGOFS_GCOFS_MASK 0x3FF + +#define DSPDMAC_DSPADRGOFS_GCS_LOBIT 0xA +#define DSPDMAC_DSPADRGOFS_GCS_HIBIT 0xC +#define DSPDMAC_DSPADRGOFS_GCS_MASK 0x1C00 + +#define DSPDMAC_DSPADRGOFS_GCBFR_LOBIT 0xD +#define DSPDMAC_DSPADRGOFS_GCBFR_HIBIT 0xF +#define DSPDMAC_DSPADRGOFS_GCBFR_MASK 0xE000 + +#define DSPDMAC_DSPADRGOFS_GBOFS_LOBIT 0x10 +#define DSPDMAC_DSPADRGOFS_GBOFS_HIBIT 0x19 +#define DSPDMAC_DSPADRGOFS_GBOFS_MASK 0x3FF0000 + +#define DSPDMAC_DSPADRGOFS_GBS_LOBIT 0x1A +#define DSPDMAC_DSPADRGOFS_GBS_HIBIT 0x1C +#define DSPDMAC_DSPADRGOFS_GBS_MASK 0x1C000000 + +#define DSPDMAC_DSPADRGOFS_GBBFR_LOBIT 0x1D +#define DSPDMAC_DSPADRGOFS_GBBFR_HIBIT 0x1F +#define DSPDMAC_DSPADRGOFS_GBBFR_MASK 0xE0000000 + +#define DSPDMAC_XFR_CNT_CHANNEL_COUNT 12 +#define DSPDMAC_XFRCNT_MODULE_OFFSET 0xF08 +#define DSPDMAC_XFRCNT_CHAN_INCR 0x10 + +#define DSPDMAC_XFRCNT_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_XFRCNT_MODULE_OFFSET + \ + (_chan * DSPDMAC_XFRCNT_CHAN_INCR)) + +#define DSPDMAC_XFRCNT_CCNT_LOBIT 0x0 +#define DSPDMAC_XFRCNT_CCNT_HIBIT 0xF +#define DSPDMAC_XFRCNT_CCNT_MASK 0xFFFF + +#define DSPDMAC_XFRCNT_BCNT_LOBIT 0x10 +#define DSPDMAC_XFRCNT_BCNT_HIBIT 0x1F +#define DSPDMAC_XFRCNT_BCNT_MASK 0xFFFF0000 + +#define DSPDMAC_IRQ_CNT_CHANNEL_COUNT 12 +#define DSPDMAC_IRQCNT_MODULE_OFFSET 0xF0C +#define DSPDMAC_IRQCNT_CHAN_INCR 0x10 +#define DSPDMAC_IRQCNT_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_IRQCNT_MODULE_OFFSET + \ + (_chan * DSPDMAC_IRQCNT_CHAN_INCR)) + +#define DSPDMAC_IRQCNT_CICNT_LOBIT 0x0 +#define DSPDMAC_IRQCNT_CICNT_HIBIT 0xF +#define DSPDMAC_IRQCNT_CICNT_MASK 0xFFFF + +#define DSPDMAC_IRQCNT_BICNT_LOBIT 0x10 +#define DSPDMAC_IRQCNT_BICNT_HIBIT 0x1F +#define DSPDMAC_IRQCNT_BICNT_MASK 0xFFFF0000 + +#define DSPDMAC_AUD_CHSEL_CHANNEL_COUNT 12 +#define DSPDMAC_AUDCHSEL_MODULE_OFFSET 0xFC0 +#define DSPDMAC_AUDCHSEL_CHAN_INCR 0x4 +#define DSPDMAC_AUDCHSEL_INST_OFFSET(_chan) \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_AUDCHSEL_MODULE_OFFSET + \ + (_chan * DSPDMAC_AUDCHSEL_CHAN_INCR)) + +#define DSPDMAC_AUDCHSEL_ACS_LOBIT 0x0 +#define DSPDMAC_AUDCHSEL_ACS_HIBIT 0x1F +#define DSPDMAC_AUDCHSEL_ACS_MASK 0xFFFFFFFF + +#define DSPDMAC_CHNLSTART_MODULE_OFFSET 0xFF0 +#define DSPDMAC_CHNLSTART_INST_OFFSET \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTART_MODULE_OFFSET) + +#define DSPDMAC_CHNLSTART_EN_LOBIT 0x0 +#define DSPDMAC_CHNLSTART_EN_HIBIT 0xB +#define DSPDMAC_CHNLSTART_EN_MASK 0xFFF + +#define DSPDMAC_CHNLSTART_VAI1_LOBIT 0xC +#define DSPDMAC_CHNLSTART_VAI1_HIBIT 0xF +#define DSPDMAC_CHNLSTART_VAI1_MASK 0xF000 + +#define DSPDMAC_CHNLSTART_DIS_LOBIT 0x10 +#define DSPDMAC_CHNLSTART_DIS_HIBIT 0x1B +#define DSPDMAC_CHNLSTART_DIS_MASK 0xFFF0000 + +#define DSPDMAC_CHNLSTART_VAI2_LOBIT 0x1C +#define DSPDMAC_CHNLSTART_VAI2_HIBIT 0x1F +#define DSPDMAC_CHNLSTART_VAI2_MASK 0xF0000000 + +#define DSPDMAC_CHNLSTATUS_MODULE_OFFSET 0xFF4 +#define DSPDMAC_CHNLSTATUS_INST_OFFSET \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLSTATUS_MODULE_OFFSET) + +#define DSPDMAC_CHNLSTATUS_ISC_LOBIT 0x0 +#define DSPDMAC_CHNLSTATUS_ISC_HIBIT 0xB +#define DSPDMAC_CHNLSTATUS_ISC_MASK 0xFFF + +#define DSPDMAC_CHNLSTATUS_AOO_LOBIT 0xC +#define DSPDMAC_CHNLSTATUS_AOO_HIBIT 0xC +#define DSPDMAC_CHNLSTATUS_AOO_MASK 0x1000 + +#define DSPDMAC_CHNLSTATUS_AOU_LOBIT 0xD +#define DSPDMAC_CHNLSTATUS_AOU_HIBIT 0xD +#define DSPDMAC_CHNLSTATUS_AOU_MASK 0x2000 + +#define DSPDMAC_CHNLSTATUS_AIO_LOBIT 0xE +#define DSPDMAC_CHNLSTATUS_AIO_HIBIT 0xE +#define DSPDMAC_CHNLSTATUS_AIO_MASK 0x4000 + +#define DSPDMAC_CHNLSTATUS_AIU_LOBIT 0xF +#define DSPDMAC_CHNLSTATUS_AIU_HIBIT 0xF +#define DSPDMAC_CHNLSTATUS_AIU_MASK 0x8000 + +#define DSPDMAC_CHNLSTATUS_IEN_LOBIT 0x10 +#define DSPDMAC_CHNLSTATUS_IEN_HIBIT 0x1B +#define DSPDMAC_CHNLSTATUS_IEN_MASK 0xFFF0000 + +#define DSPDMAC_CHNLSTATUS_VAI0_LOBIT 0x1C +#define DSPDMAC_CHNLSTATUS_VAI0_HIBIT 0x1F +#define DSPDMAC_CHNLSTATUS_VAI0_MASK 0xF0000000 + +#define DSPDMAC_CHNLPROP_MODULE_OFFSET 0xFF8 +#define DSPDMAC_CHNLPROP_INST_OFFSET \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_CHNLPROP_MODULE_OFFSET) + +#define DSPDMAC_CHNLPROP_DCON_LOBIT 0x0 +#define DSPDMAC_CHNLPROP_DCON_HIBIT 0xB +#define DSPDMAC_CHNLPROP_DCON_MASK 0xFFF + +#define DSPDMAC_CHNLPROP_FFS_LOBIT 0xC +#define DSPDMAC_CHNLPROP_FFS_HIBIT 0xC +#define DSPDMAC_CHNLPROP_FFS_MASK 0x1000 + +#define DSPDMAC_CHNLPROP_NAJ_LOBIT 0xD +#define DSPDMAC_CHNLPROP_NAJ_HIBIT 0xD +#define DSPDMAC_CHNLPROP_NAJ_MASK 0x2000 + +#define DSPDMAC_CHNLPROP_ENH_LOBIT 0xE +#define DSPDMAC_CHNLPROP_ENH_HIBIT 0xE +#define DSPDMAC_CHNLPROP_ENH_MASK 0x4000 + +#define DSPDMAC_CHNLPROP_MSPCE_LOBIT 0x10 +#define DSPDMAC_CHNLPROP_MSPCE_HIBIT 0x1B +#define DSPDMAC_CHNLPROP_MSPCE_MASK 0xFFF0000 + +#define DSPDMAC_CHNLPROP_AC_LOBIT 0x1C +#define DSPDMAC_CHNLPROP_AC_HIBIT 0x1F +#define DSPDMAC_CHNLPROP_AC_MASK 0xF0000000 + +#define DSPDMAC_ACTIVE_MODULE_OFFSET 0xFFC +#define DSPDMAC_ACTIVE_INST_OFFSET \ + (DSPDMAC_CHIP_OFFSET + DSPDMAC_ACTIVE_MODULE_OFFSET) + +#define DSPDMAC_ACTIVE_AAR_LOBIT 0x0 +#define DSPDMAC_ACTIVE_AAR_HIBIT 0xB +#define DSPDMAC_ACTIVE_AAR_MASK 0xFFF + +#define DSPDMAC_ACTIVE_WFR_LOBIT 0xC +#define DSPDMAC_ACTIVE_WFR_HIBIT 0x17 +#define DSPDMAC_ACTIVE_WFR_MASK 0xFFF000 + +#define DSP_AUX_MEM_BASE 0xE000 +#define INVALID_CHIP_ADDRESS (~0U) + +#define X_SIZE (XRAM_XRAM_CHANNEL_COUNT * XRAM_XRAM_CHAN_INCR) +#define Y_SIZE (YRAM_YRAM_CHANNEL_COUNT * YRAM_YRAM_CHAN_INCR) +#define AX_SIZE (AXRAM_AXRAM_CHANNEL_COUNT * AXRAM_AXRAM_CHAN_INCR) +#define AY_SIZE (AYRAM_AYRAM_CHANNEL_COUNT * AYRAM_AYRAM_CHAN_INCR) +#define UC_SIZE (UC_UC_CHANNEL_COUNT * UC_UC_CHAN_INCR) + +#define XEXT_SIZE (X_SIZE + AX_SIZE) +#define YEXT_SIZE (Y_SIZE + AY_SIZE) + +#define U64K 0x10000UL + +#define X_END (XRAM_CHIP_OFFSET + X_SIZE) +#define X_EXT (XRAM_CHIP_OFFSET + XEXT_SIZE) +#define AX_END (XRAM_CHIP_OFFSET + U64K*4) + +#define Y_END (YRAM_CHIP_OFFSET + Y_SIZE) +#define Y_EXT (YRAM_CHIP_OFFSET + YEXT_SIZE) +#define AY_END (YRAM_CHIP_OFFSET + U64K*4) + +#define UC_END (UC_CHIP_OFFSET + UC_SIZE) + +#define X_RANGE_MAIN(a, s) \ + (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_END)) +#define X_RANGE_AUX(a, s) \ + (((a) >= X_END) && ((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END)) +#define X_RANGE_EXT(a, s) \ + (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < X_EXT)) +#define X_RANGE_ALL(a, s) \ + (((a)+((s)-1)*XRAM_XRAM_CHAN_INCR < AX_END)) + +#define Y_RANGE_MAIN(a, s) \ + (((a) >= YRAM_CHIP_OFFSET) && \ + ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_END)) +#define Y_RANGE_AUX(a, s) \ + (((a) >= Y_END) && \ + ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END)) +#define Y_RANGE_EXT(a, s) \ + (((a) >= YRAM_CHIP_OFFSET) && \ + ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < Y_EXT)) +#define Y_RANGE_ALL(a, s) \ + (((a) >= YRAM_CHIP_OFFSET) && \ + ((a)+((s)-1)*YRAM_YRAM_CHAN_INCR < AY_END)) + +#define UC_RANGE(a, s) \ + (((a) >= UC_CHIP_OFFSET) && \ + ((a)+((s)-1)*UC_UC_CHAN_INCR < UC_END)) + +#define X_OFF(a) \ + (((a) - XRAM_CHIP_OFFSET) / XRAM_XRAM_CHAN_INCR) +#define AX_OFF(a) \ + (((a) % (AXRAM_AXRAM_CHANNEL_COUNT * \ + AXRAM_AXRAM_CHAN_INCR)) / AXRAM_AXRAM_CHAN_INCR) + +#define Y_OFF(a) \ + (((a) - YRAM_CHIP_OFFSET) / YRAM_YRAM_CHAN_INCR) +#define AY_OFF(a) \ + (((a) % (AYRAM_AYRAM_CHANNEL_COUNT * \ + AYRAM_AYRAM_CHAN_INCR)) / AYRAM_AYRAM_CHAN_INCR) + +#define UC_OFF(a) (((a) - UC_CHIP_OFFSET) / UC_UC_CHAN_INCR) + +#define X_EXT_MAIN_SIZE(a) (XRAM_XRAM_CHANNEL_COUNT - X_OFF(a)) +#define X_EXT_AUX_SIZE(a, s) ((s) - X_EXT_MAIN_SIZE(a)) + +#define Y_EXT_MAIN_SIZE(a) (YRAM_YRAM_CHANNEL_COUNT - Y_OFF(a)) +#define Y_EXT_AUX_SIZE(a, s) ((s) - Y_EXT_MAIN_SIZE(a)) + +#endif diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index 4ec6dc88b7f..dabe41975a9 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c @@ -11,6 +11,7 @@ #include <linux/slab.h> #include <linux/export.h> +#include <linux/sort.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" @@ -30,29 +31,30 @@ static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) return 0; } +/* a pair of input pin and its sequence */ +struct auto_out_pin { + hda_nid_t pin; + short seq; +}; + +static int compare_seq(const void *ap, const void *bp) +{ + const struct auto_out_pin *a = ap; + const struct auto_out_pin *b = bp; + return (int)(a->seq - b->seq); +} /* * Sort an associated group of pins according to their sequence numbers. + * then store it to a pin array. */ -static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, +static void sort_pins_by_sequence(hda_nid_t *pins, struct auto_out_pin *list, int num_pins) { - int i, j; - short seq; - hda_nid_t nid; - - for (i = 0; i < num_pins; i++) { - for (j = i + 1; j < num_pins; j++) { - if (sequences[i] > sequences[j]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = pins[i]; - pins[i] = pins[j]; - pins[j] = nid; - } - } - } + int i; + sort(list, num_pins, sizeof(list[0]), compare_seq, NULL); + for (i = 0; i < num_pins; i++) + pins[i] = list[i].pin; } @@ -67,21 +69,11 @@ static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, } } -/* sort inputs in the order of AUTO_PIN_* type */ -static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +static int compare_input_type(const void *ap, const void *bp) { - int i, j; - - for (i = 0; i < cfg->num_inputs; i++) { - for (j = i + 1; j < cfg->num_inputs; j++) { - if (cfg->inputs[i].type > cfg->inputs[j].type) { - struct auto_pin_cfg_item tmp; - tmp = cfg->inputs[i]; - cfg->inputs[i] = cfg->inputs[j]; - cfg->inputs[j] = tmp; - } - } - } + const struct auto_pin_cfg_item *a = ap; + const struct auto_pin_cfg_item *b = bp; + return (int)(a->type - b->type); } /* Reorder the surround channels @@ -105,6 +97,54 @@ static void reorder_outputs(unsigned int nums, hda_nid_t *pins) } } +/* check whether the given pin has a proper pin I/O capability bit */ +static bool check_pincap_validity(struct hda_codec *codec, hda_nid_t pin, + unsigned int dev) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + + /* some old hardware don't return the proper pincaps */ + if (!pincap) + return true; + + switch (dev) { + case AC_JACK_LINE_OUT: + case AC_JACK_SPEAKER: + case AC_JACK_HP_OUT: + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + return !!(pincap & AC_PINCAP_OUT); + default: + return !!(pincap & AC_PINCAP_IN); + } +} + +static bool can_be_headset_mic(struct hda_codec *codec, + struct auto_pin_cfg_item *item, + int seq_number) +{ + int attr; + unsigned int def_conf; + if (item->type != AUTO_PIN_MIC) + return false; + + if (item->is_headset_mic || item->is_headphone_mic) + return false; /* Already assigned */ + + def_conf = snd_hda_codec_get_pincfg(codec, item->pin); + attr = snd_hda_get_input_pin_attr(def_conf); + if (attr <= INPUT_PIN_ATTR_DOCK) + return false; + + if (seq_number >= 0) { + int seq = get_defcfg_sequence(def_conf); + if (seq != seq_number) + return false; + } + + return true; +} + /* * Parse all pin widgets and store the useful pin nids to cfg * @@ -129,16 +169,19 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, { hda_nid_t nid, end_nid; short seq, assoc_line_out; - short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; - short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; - short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + struct auto_out_pin line_out[ARRAY_SIZE(cfg->line_out_pins)]; + struct auto_out_pin speaker_out[ARRAY_SIZE(cfg->speaker_pins)]; + struct auto_out_pin hp_out[ARRAY_SIZE(cfg->hp_pins)]; int i; + if (!snd_hda_get_int_hint(codec, "parser_flags", &i)) + cond_flags = i; + memset(cfg, 0, sizeof(*cfg)); - memset(sequences_line_out, 0, sizeof(sequences_line_out)); - memset(sequences_speaker, 0, sizeof(sequences_speaker)); - memset(sequences_hp, 0, sizeof(sequences_hp)); + memset(line_out, 0, sizeof(line_out)); + memset(speaker_out, 0, sizeof(speaker_out)); + memset(hp_out, 0, sizeof(hp_out)); assoc_line_out = 0; end_nid = codec->start_nid + codec->num_nodes; @@ -164,10 +207,14 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, /* workaround for buggy BIOS setups */ if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) + if (conn == AC_JACK_PORT_FIXED || + conn == AC_JACK_PORT_BOTH) dev = AC_JACK_SPEAKER; } + if (!check_pincap_validity(codec, nid, dev)) + continue; + switch (dev) { case AC_JACK_LINE_OUT: seq = get_defcfg_sequence(def_conf); @@ -180,30 +227,46 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, continue; if (!assoc_line_out) assoc_line_out = assoc; - else if (assoc_line_out != assoc) + else if (assoc_line_out != assoc) { + codec_info(codec, + "ignore pin 0x%x with mismatching assoc# 0x%x vs 0x%x\n", + nid, assoc, assoc_line_out); continue; - if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) + } + if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) { + codec_info(codec, + "ignore pin 0x%x, too many assigned pins\n", + nid); continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences_line_out[cfg->line_outs] = seq; + } + line_out[cfg->line_outs].pin = nid; + line_out[cfg->line_outs].seq = seq; cfg->line_outs++; break; case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); - if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) + if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) { + codec_info(codec, + "ignore pin 0x%x, too many assigned pins\n", + nid); continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + } + speaker_out[cfg->speaker_outs].pin = nid; + speaker_out[cfg->speaker_outs].seq = (assoc << 4) | seq; cfg->speaker_outs++; break; case AC_JACK_HP_OUT: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); - if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) + if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) { + codec_info(codec, + "ignore pin 0x%x, too many assigned pins\n", + nid); continue; - cfg->hp_pins[cfg->hp_outs] = nid; - sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; + } + hp_out[cfg->hp_outs].pin = nid; + hp_out[cfg->hp_outs].seq = (assoc << 4) | seq; cfg->hp_outs++; break; case AC_JACK_MIC_IN: @@ -220,8 +283,12 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, break; case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: - if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) + if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) { + codec_info(codec, + "ignore pin 0x%x, too many assigned pins\n", + nid); continue; + } cfg->dig_out_pins[cfg->dig_outs] = nid; cfg->dig_out_type[cfg->dig_outs] = (loc == AC_JACK_LOC_HDMI) ? @@ -239,6 +306,38 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, } } + /* Find a pin that could be a headset or headphone mic */ + if (cond_flags & HDA_PINCFG_HEADSET_MIC || cond_flags & HDA_PINCFG_HEADPHONE_MIC) { + bool hsmic = !!(cond_flags & HDA_PINCFG_HEADSET_MIC); + bool hpmic = !!(cond_flags & HDA_PINCFG_HEADPHONE_MIC); + for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) + if (hsmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xc)) { + cfg->inputs[i].is_headset_mic = 1; + hsmic = false; + } else if (hpmic && can_be_headset_mic(codec, &cfg->inputs[i], 0xd)) { + cfg->inputs[i].is_headphone_mic = 1; + hpmic = false; + } + + /* If we didn't find our sequence number mark, fall back to any sequence number */ + for (i = 0; (hsmic || hpmic) && (i < cfg->num_inputs); i++) { + if (!can_be_headset_mic(codec, &cfg->inputs[i], -1)) + continue; + if (hsmic) { + cfg->inputs[i].is_headset_mic = 1; + hsmic = false; + } else if (hpmic) { + cfg->inputs[i].is_headphone_mic = 1; + hpmic = false; + } + } + + if (hsmic) + codec_dbg(codec, "Told to look for a headset mic, but didn't find any.\n"); + if (hpmic) + codec_dbg(codec, "Told to look for a headphone mic, but didn't find any.\n"); + } + /* FIX-UP: * If no line-out is defined but multiple HPs are found, * some of them might be the real line-outs. @@ -248,34 +347,28 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, int i = 0; while (i < cfg->hp_outs) { /* The real HPs should have the sequence 0x0f */ - if ((sequences_hp[i] & 0x0f) == 0x0f) { + if ((hp_out[i].seq & 0x0f) == 0x0f) { i++; continue; } /* Move it to the line-out table */ - cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; - sequences_line_out[cfg->line_outs] = sequences_hp[i]; - cfg->line_outs++; + line_out[cfg->line_outs++] = hp_out[i]; cfg->hp_outs--; - memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, - sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i, sequences_hp + i + 1, - sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); + memmove(hp_out + i, hp_out + i + 1, + sizeof(hp_out[0]) * (cfg->hp_outs - i)); } - memset(cfg->hp_pins + cfg->hp_outs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + memset(hp_out + cfg->hp_outs, 0, + sizeof(hp_out[0]) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); if (!cfg->hp_outs) cfg->line_out_type = AUTO_PIN_HP_OUT; } /* sort by sequence */ - sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, - cfg->line_outs); - sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, + sort_pins_by_sequence(cfg->line_out_pins, line_out, cfg->line_outs); + sort_pins_by_sequence(cfg->speaker_pins, speaker_out, cfg->speaker_outs); - sort_pins_by_sequence(cfg->hp_pins, sequences_hp, - cfg->hp_outs); + sort_pins_by_sequence(cfg->hp_pins, hp_out, cfg->hp_outs); /* * FIX-UP: if no line-outs are detected, try to use speaker or HP pin @@ -304,42 +397,44 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, reorder_outputs(cfg->hp_outs, cfg->hp_pins); reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); - sort_autocfg_input_pins(cfg); + /* sort inputs in the order of AUTO_PIN_* type */ + sort(cfg->inputs, cfg->num_inputs, sizeof(cfg->inputs[0]), + compare_input_type, NULL); /* * debug prints of the parsed results */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", + codec_info(codec, "autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], cfg->line_out_pins[2], cfg->line_out_pins[3], cfg->line_out_pins[4], cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? "speaker" : "line")); - snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + codec_info(codec, " speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->speaker_outs, cfg->speaker_pins[0], cfg->speaker_pins[1], cfg->speaker_pins[2], cfg->speaker_pins[3], cfg->speaker_pins[4]); - snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + codec_info(codec, " hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", cfg->hp_outs, cfg->hp_pins[0], cfg->hp_pins[1], cfg->hp_pins[2], cfg->hp_pins[3], cfg->hp_pins[4]); - snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); + codec_info(codec, " mono: mono_out=0x%x\n", cfg->mono_out_pin); if (cfg->dig_outs) - snd_printd(" dig-out=0x%x/0x%x\n", + codec_info(codec, " dig-out=0x%x/0x%x\n", cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs:\n"); + codec_info(codec, " inputs:\n"); for (i = 0; i < cfg->num_inputs; i++) { - snd_printd(" %s=0x%x\n", + codec_info(codec, " %s=0x%x\n", hda_get_autocfg_input_label(codec, cfg, i), cfg->inputs[i].pin); } if (cfg->dig_in_pin) - snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); + codec_info(codec, " dig-in=0x%x\n", cfg->dig_in_pin); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); +EXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg); int snd_hda_get_input_pin_attr(unsigned int def_conf) { @@ -360,7 +455,7 @@ int snd_hda_get_input_pin_attr(unsigned int def_conf) return INPUT_PIN_ATTR_FRONT; return INPUT_PIN_ATTR_NORMAL; } -EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); +EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr); /** * hda_get_input_pin_label - Give a label for the given input pin @@ -371,11 +466,12 @@ EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); */ static const char *hda_get_input_pin_label(struct hda_codec *codec, + const struct auto_pin_cfg_item *item, hda_nid_t pin, bool check_location) { unsigned int def_conf; static const char * const mic_names[] = { - "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", + "Internal Mic", "Dock Mic", "Mic", "Rear Mic", "Front Mic" }; int attr; @@ -383,6 +479,10 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec, switch (get_defcfg_device(def_conf)) { case AC_JACK_MIC_IN: + if (item && item->is_headset_mic) + return "Headset Mic"; + if (item && item->is_headphone_mic) + return "Headphone Mic"; if (!check_location) return "Mic"; attr = snd_hda_get_input_pin_attr(def_conf); @@ -406,6 +506,8 @@ static const char *hda_get_input_pin_label(struct hda_codec *codec, return "SPDIF In"; case AC_JACK_DIG_OTHER_IN: return "Digital In"; + case AC_JACK_HP_OUT: + return "Headphone Mic"; default: return "Misc"; } @@ -461,10 +563,11 @@ const char *hda_get_autocfg_input_label(struct hda_codec *codec, has_multiple_pins = 1; if (has_multiple_pins && type == AUTO_PIN_MIC) has_multiple_pins &= check_mic_location_need(codec, cfg, input); - return hda_get_input_pin_label(codec, cfg->inputs[input].pin, + return hda_get_input_pin_label(codec, &cfg->inputs[input], + cfg->inputs[input].pin, has_multiple_pins); } -EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); +EXPORT_SYMBOL_GPL(hda_get_autocfg_input_label); /* return the position of NID in the list, or -1 if not found */ static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) @@ -555,7 +658,7 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, /* don't add channel suffix for Headphone controls */ int idx = get_hp_label_index(codec, nid, cfg->hp_pins, cfg->hp_outs); - if (idx >= 0) + if (idx >= 0 && indexp) *indexp = idx; sfx = ""; } @@ -564,6 +667,9 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, return 1; } +#define is_hdmi_cfg(conf) \ + (get_defcfg_location(conf) == AC_JACK_LOC_HDMI) + /** * snd_hda_get_pin_label - Get a label for the given I/O pin * @@ -584,6 +690,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); const char *name = NULL; int i; + bool hdmi; if (indexp) *indexp = 0; @@ -602,16 +709,18 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, label, maxlen, indexp); case AC_JACK_SPDIF_OUT: case AC_JACK_DIG_OTHER_OUT: - if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) - name = "HDMI"; - else - name = "SPDIF"; - if (cfg && indexp) { - i = find_idx_in_nid_list(nid, cfg->dig_out_pins, - cfg->dig_outs); - if (i >= 0) - *indexp = i; - } + hdmi = is_hdmi_cfg(def_conf); + name = hdmi ? "HDMI" : "SPDIF"; + if (cfg && indexp) + for (i = 0; i < cfg->dig_outs; i++) { + hda_nid_t pin = cfg->dig_out_pins[i]; + unsigned int c; + if (pin == nid) + break; + c = snd_hda_codec_get_pincfg(codec, pin); + if (hdmi == is_hdmi_cfg(c)) + (*indexp)++; + } break; default: if (cfg) { @@ -624,7 +733,7 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, } } if (!name) - name = hda_get_input_pin_label(codec, nid, true); + name = hda_get_input_pin_label(codec, NULL, nid, true); break; } if (!name) @@ -632,30 +741,29 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, strlcpy(label, name, maxlen); return 1; } -EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); +EXPORT_SYMBOL_GPL(snd_hda_get_pin_label); -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list) +int snd_hda_add_verbs(struct hda_codec *codec, + const struct hda_verb *list) { const struct hda_verb **v; - v = snd_array_new(&spec->verbs); + v = snd_array_new(&codec->verbs); if (!v) return -ENOMEM; *v = list; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs); +EXPORT_SYMBOL_GPL(snd_hda_add_verbs); -void snd_hda_gen_apply_verbs(struct hda_codec *codec) +void snd_hda_apply_verbs(struct hda_codec *codec) { - struct hda_gen_spec *spec = codec->spec; int i; - for (i = 0; i < spec->verbs.used; i++) { - struct hda_verb **v = snd_array_elem(&spec->verbs, i); + for (i = 0; i < codec->verbs.used; i++) { + struct hda_verb **v = snd_array_elem(&codec->verbs, i); snd_hda_sequence_write(codec, *v); } } -EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs); +EXPORT_SYMBOL_GPL(snd_hda_apply_verbs); void snd_hda_apply_pincfgs(struct hda_codec *codec, const struct hda_pintbl *cfg) @@ -663,86 +771,136 @@ void snd_hda_apply_pincfgs(struct hda_codec *codec, for (; cfg->nid; cfg++) snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); } -EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs); +EXPORT_SYMBOL_GPL(snd_hda_apply_pincfgs); -void snd_hda_apply_fixup(struct hda_codec *codec, int action) +static void set_pin_targets(struct hda_codec *codec, + const struct hda_pintbl *cfg) { - struct hda_gen_spec *spec = codec->spec; - int id = spec->fixup_id; -#ifdef CONFIG_SND_DEBUG_VERBOSE - const char *modelname = spec->fixup_name; -#endif - int depth = 0; + for (; cfg->nid; cfg++) + snd_hda_set_pin_ctl_cache(codec, cfg->nid, cfg->val); +} - if (!spec->fixup_list) - return; +static void apply_fixup(struct hda_codec *codec, int id, int action, int depth) +{ + const char *modelname = codec->fixup_name; while (id >= 0) { - const struct hda_fixup *fix = spec->fixup_list + id; + const struct hda_fixup *fix = codec->fixup_list + id; + + if (fix->chained_before) + apply_fixup(codec, fix->chain_id, action, depth + 1); switch (fix->type) { case HDA_FIXUP_PINS: if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins) break; - snd_printdd(KERN_INFO SFX - "%s: Apply pincfg for %s\n", + codec_dbg(codec, "%s: Apply pincfg for %s\n", codec->chip_name, modelname); snd_hda_apply_pincfgs(codec, fix->v.pins); break; case HDA_FIXUP_VERBS: if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs) break; - snd_printdd(KERN_INFO SFX - "%s: Apply fix-verbs for %s\n", + codec_dbg(codec, "%s: Apply fix-verbs for %s\n", codec->chip_name, modelname); - snd_hda_gen_add_verbs(codec->spec, fix->v.verbs); + snd_hda_add_verbs(codec, fix->v.verbs); break; case HDA_FIXUP_FUNC: if (!fix->v.func) break; - snd_printdd(KERN_INFO SFX - "%s: Apply fix-func for %s\n", + codec_dbg(codec, "%s: Apply fix-func for %s\n", codec->chip_name, modelname); fix->v.func(codec, fix, action); break; + case HDA_FIXUP_PINCTLS: + if (action != HDA_FIXUP_ACT_PROBE || !fix->v.pins) + break; + codec_dbg(codec, "%s: Apply pinctl for %s\n", + codec->chip_name, modelname); + set_pin_targets(codec, fix->v.pins); + break; default: - snd_printk(KERN_ERR SFX - "%s: Invalid fixup type %d\n", + codec_err(codec, "%s: Invalid fixup type %d\n", codec->chip_name, fix->type); break; } - if (!fix->chained) + if (!fix->chained || fix->chained_before) break; if (++depth > 10) break; id = fix->chain_id; } } -EXPORT_SYMBOL_HDA(snd_hda_apply_fixup); + +void snd_hda_apply_fixup(struct hda_codec *codec, int action) +{ + if (codec->fixup_list) + apply_fixup(codec, codec->fixup_id, action, 0); +} +EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); + +static bool pin_config_match(struct hda_codec *codec, + const struct hda_pintbl *pins) +{ + for (; pins->nid; pins++) { + u32 def_conf = snd_hda_codec_get_pincfg(codec, pins->nid); + if (pins->val != def_conf) + return false; + } + return true; +} + +void snd_hda_pick_pin_fixup(struct hda_codec *codec, + const struct snd_hda_pin_quirk *pin_quirk, + const struct hda_fixup *fixlist) +{ + const struct snd_hda_pin_quirk *pq; + + if (codec->fixup_forced) + return; + + for (pq = pin_quirk; pq->subvendor; pq++) { + if ((codec->subsystem_id & 0xffff0000) != (pq->subvendor << 16)) + continue; + if (codec->vendor_id != pq->codec) + continue; + if (pin_config_match(codec, pq->pins)) { + codec->fixup_id = pq->value; +#ifdef CONFIG_SND_DEBUG_VERBOSE + codec->fixup_name = pq->name; +#endif + codec->fixup_list = fixlist; + return; + } + } +} +EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup); void snd_hda_pick_fixup(struct hda_codec *codec, const struct hda_model_fixup *models, const struct snd_pci_quirk *quirk, const struct hda_fixup *fixlist) { - struct hda_gen_spec *spec = codec->spec; const struct snd_pci_quirk *q; int id = -1; const char *name = NULL; /* when model=nofixup is given, don't pick up any fixups */ if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { - spec->fixup_list = NULL; - spec->fixup_id = -1; + codec->fixup_list = NULL; + codec->fixup_id = -1; + codec->fixup_forced = 1; return; } if (codec->modelname && models) { while (models->name) { if (!strcmp(codec->modelname, models->name)) { - id = models->id; - name = models->name; - break; + codec->fixup_id = models->id; + codec->fixup_name = models->name; + codec->fixup_list = fixlist; + codec->fixup_forced = 1; + return; } models++; } @@ -757,7 +915,7 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } if (id < 0 && quirk) { - for (q = quirk; q->subvendor; q++) { + for (q = quirk; q->subvendor || q->subdevice; q++) { unsigned int vendorid = q->subdevice | (q->subvendor << 16); unsigned int mask = 0xffff0000 | q->subdevice_mask; @@ -771,10 +929,11 @@ void snd_hda_pick_fixup(struct hda_codec *codec, } } - spec->fixup_id = id; + codec->fixup_forced = 0; + codec->fixup_id = id; if (id >= 0) { - spec->fixup_list = fixlist; - spec->fixup_name = name; + codec->fixup_list = fixlist; + codec->fixup_name = name; } } -EXPORT_SYMBOL_HDA(snd_hda_pick_fixup); +EXPORT_SYMBOL_GPL(snd_hda_pick_fixup); diff --git a/sound/pci/hda/hda_auto_parser.h b/sound/pci/hda/hda_auto_parser.h index 632ad0ad300..e941f604f5e 100644 --- a/sound/pci/hda/hda_auto_parser.h +++ b/sound/pci/hda/hda_auto_parser.h @@ -36,6 +36,8 @@ enum { struct auto_pin_cfg_item { hda_nid_t pin; int type; + unsigned int is_headset_mic:1; + unsigned int is_headphone_mic:1; /* Mic-only in headphone jack */ }; struct auto_pin_cfg; @@ -51,8 +53,9 @@ enum { INPUT_PIN_ATTR_INT, /* internal mic/line-in */ INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ - INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ + INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ + INPUT_PIN_ATTR_LAST = INPUT_PIN_ATTR_FRONT, }; int snd_hda_get_input_pin_attr(unsigned int def_conf); @@ -77,8 +80,10 @@ struct auto_pin_cfg { }; /* bit-flags for snd_hda_parse_pin_def_config() behavior */ -#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ -#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ +#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ +#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ +#define HDA_PINCFG_HEADSET_MIC (1 << 2) /* Try to find headset mic; mark seq number as 0xc to trigger */ +#define HDA_PINCFG_HEADPHONE_MIC (1 << 3) /* Try to find headphone mic; mark seq number as 0xd to trigger */ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, struct auto_pin_cfg *cfg, @@ -89,82 +94,25 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec, #define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) -/* - */ - -struct hda_gen_spec { - /* fix-up list */ - int fixup_id; - const struct hda_fixup *fixup_list; - const char *fixup_name; - - /* additional init verbs */ - struct snd_array verbs; -}; - - -/* - * Fix-up pin default configurations and add default verbs - */ - -struct hda_pintbl { - hda_nid_t nid; - u32 val; -}; - -struct hda_model_fixup { - const int id; - const char *name; -}; - -struct hda_fixup { - int type; - bool chained; - int chain_id; - union { - const struct hda_pintbl *pins; - const struct hda_verb *verbs; - void (*func)(struct hda_codec *codec, - const struct hda_fixup *fix, - int action); - } v; -}; - -/* fixup types */ -enum { - HDA_FIXUP_INVALID, - HDA_FIXUP_PINS, - HDA_FIXUP_VERBS, - HDA_FIXUP_FUNC, -}; - -/* fixup action definitions */ -enum { - HDA_FIXUP_ACT_PRE_PROBE, - HDA_FIXUP_ACT_PROBE, - HDA_FIXUP_ACT_INIT, - HDA_FIXUP_ACT_BUILD, -}; - -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list); -void snd_hda_gen_apply_verbs(struct hda_codec *codec); -void snd_hda_apply_pincfgs(struct hda_codec *codec, - const struct hda_pintbl *cfg); -void snd_hda_apply_fixup(struct hda_codec *codec, int action); -void snd_hda_pick_fixup(struct hda_codec *codec, - const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, - const struct hda_fixup *fixlist); - -static inline void snd_hda_gen_init(struct hda_gen_spec *spec) +static inline int auto_cfg_hp_outs(const struct auto_pin_cfg *cfg) { - snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8); + return (cfg->line_out_type == AUTO_PIN_HP_OUT) ? + cfg->line_outs : cfg->hp_outs; } - -static inline void snd_hda_gen_free(struct hda_gen_spec *spec) +static inline const hda_nid_t *auto_cfg_hp_pins(const struct auto_pin_cfg *cfg) +{ + return (cfg->line_out_type == AUTO_PIN_HP_OUT) ? + cfg->line_out_pins : cfg->hp_pins; +} +static inline int auto_cfg_speaker_outs(const struct auto_pin_cfg *cfg) +{ + return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ? + cfg->line_outs : cfg->speaker_outs; +} +static inline const hda_nid_t *auto_cfg_speaker_pins(const struct auto_pin_cfg *cfg) { - snd_array_free(&spec->verbs); + return (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) ? + cfg->line_out_pins : cfg->speaker_pins; } #endif /* __SOUND_HDA_AUTO_PARSER_H */ diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 0849aac449f..8c6c50afc0b 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -20,7 +20,6 @@ */ #include <linux/input.h> -#include <linux/pci.h> #include <linux/slab.h> #include <linux/workqueue.h> #include <linux/export.h> @@ -39,13 +38,23 @@ static void snd_hda_generate_beep(struct work_struct *work) struct hda_beep *beep = container_of(work, struct hda_beep, beep_work); struct hda_codec *codec = beep->codec; + int tone; if (!beep->enabled) return; + tone = beep->tone; + if (tone && !beep->playing) { + snd_hda_power_up(codec); + beep->playing = 1; + } /* generate tone */ snd_hda_codec_write(codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, beep->tone); + AC_VERB_SET_BEEP_CONTROL, tone); + if (!tone && beep->playing) { + beep->playing = 0; + snd_hda_power_down(codec); + } } /* (non-standard) Linear beep tone calculation for IDT/STAC codecs @@ -100,6 +109,7 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, case SND_BELL: if (hz) hz = 1000; + /* fallthru */ case SND_TONE: if (beep->linear_tone) beep->tone = beep_linear_tone(beep, hz); @@ -115,27 +125,36 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, return 0; } +static void turn_off_beep(struct hda_beep *beep) +{ + cancel_work_sync(&beep->beep_work); + if (beep->playing) { + /* turn off beep */ + snd_hda_codec_write(beep->codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, 0); + beep->playing = 0; + snd_hda_power_down(beep->codec); + } +} + static void snd_hda_do_detach(struct hda_beep *beep) { - input_unregister_device(beep->dev); + if (beep->registered) + input_unregister_device(beep->dev); + else + input_free_device(beep->dev); beep->dev = NULL; - cancel_work_sync(&beep->beep_work); - /* turn off beep for sure */ - snd_hda_codec_write(beep->codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, 0); + turn_off_beep(beep); } static int snd_hda_do_attach(struct hda_beep *beep) { struct input_dev *input_dev; struct hda_codec *codec = beep->codec; - int err; input_dev = input_allocate_device(); - if (!input_dev) { - printk(KERN_INFO "hda_beep: unable to allocate input device\n"); + if (!input_dev) return -ENOMEM; - } /* setup digital beep device */ input_dev->name = "HDA Digital PCBeep"; @@ -149,15 +168,9 @@ static int snd_hda_do_attach(struct hda_beep *beep) input_dev->evbit[0] = BIT_MASK(EV_SND); input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE); input_dev->event = snd_hda_beep_event; - input_dev->dev.parent = &codec->bus->pci->dev; + input_dev->dev.parent = &codec->dev; input_set_drvdata(input_dev, beep); - err = input_register_device(input_dev); - if (err < 0) { - input_free_device(input_dev); - printk(KERN_INFO "hda_beep: unable to register input device\n"); - return err; - } beep->dev = input_dev; return 0; } @@ -170,17 +183,13 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) enable = !!enable; if (beep->enabled != enable) { beep->enabled = enable; - if (!enable) { - cancel_work_sync(&beep->beep_work); - /* turn off beep */ - snd_hda_codec_write(beep->codec, beep->nid, 0, - AC_VERB_SET_BEEP_CONTROL, 0); - } + if (!enable) + turn_off_beep(beep); return 1; } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device); +EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device); int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { @@ -198,7 +207,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) snprintf(beep->phys, sizeof(beep->phys), "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); /* enable linear scale */ - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_2, 0x01); beep->nid = nid; @@ -217,7 +226,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) return 0; } -EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); +EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device); void snd_hda_detach_beep_device(struct hda_codec *codec) { @@ -229,7 +238,28 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) kfree(beep); } } -EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); +EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device); + +int snd_hda_register_beep_device(struct hda_codec *codec) +{ + struct hda_beep *beep = codec->beep; + int err; + + if (!beep || !beep->dev) + return 0; + + err = input_register_device(beep->dev); + if (err < 0) { + codec_err(codec, "hda_beep: unable to register input device\n"); + input_free_device(beep->dev); + codec->beep = NULL; + kfree(beep); + return err; + } + beep->registered = true; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_register_beep_device); static bool ctl_has_mute(struct snd_kcontrol *kcontrol) { @@ -251,7 +281,7 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol, } return snd_hda_mixer_amp_switch_get(kcontrol, ucontrol); } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get_beep); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep); int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -274,4 +304,4 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, return 0; return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put_beep); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 4dc6933bc65..a63b5e07733 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -34,8 +34,10 @@ struct hda_beep { char phys[32]; int tone; hda_nid_t nid; + unsigned int registered:1; unsigned int enabled:1; unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ + unsigned int playing:1; struct work_struct beep_work; /* scheduled task for beep event */ struct mutex mutex; }; @@ -44,6 +46,7 @@ struct hda_beep { int snd_hda_enable_beep_device(struct hda_codec *codec, int enable); int snd_hda_attach_beep_device(struct hda_codec *codec, int nid); void snd_hda_detach_beep_device(struct hda_codec *codec); +int snd_hda_register_beep_device(struct hda_codec *codec); #else static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) { @@ -52,5 +55,9 @@ static inline int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) static inline void snd_hda_detach_beep_device(struct hda_codec *codec) { } +static inline int snd_hda_register_beep_device(struct hda_codec *codec) +{ + return 0; +} #endif #endif diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 70d4848b5cd..4c20277a683 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -23,9 +23,9 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/mutex.h> #include <linux/module.h> +#include <linux/async.h> #include <sound/core.h> #include "hda_codec.h" #include <sound/asoundef.h> @@ -67,6 +67,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { { 0x17e8, "Chrontel" }, { 0x1854, "LG" }, { 0x1aec, "Wolfson Microelectronics" }, + { 0x1af4, "QEMU" }, { 0x434d, "C-Media" }, { 0x8086, "Intel" }, { 0x8384, "SigmaTel" }, @@ -83,7 +84,7 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_codec_preset); +EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset); int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) { @@ -92,21 +93,31 @@ int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset) mutex_unlock(&preset_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); +EXPORT_SYMBOL_GPL(snd_hda_delete_codec_preset); #ifdef CONFIG_PM +#define codec_in_pm(codec) ((codec)->in_pm) static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); #define hda_codec_is_power_on(codec) ((codec)->power_on) -static inline void hda_call_pm_notify(struct hda_bus *bus, bool power_up) + +static void hda_call_pm_notify(struct hda_codec *codec, bool power_up) { + struct hda_bus *bus = codec->bus; + + if ((power_up && codec->pm_up_notified) || + (!power_up && !codec->pm_up_notified)) + return; if (bus->ops.pm_notify) bus->ops.pm_notify(bus, power_up); + codec->pm_up_notified = power_up; } + #else +#define codec_in_pm(codec) 0 static inline void hda_keep_power_on(struct hda_codec *codec) {} #define hda_codec_is_power_on(codec) 1 -#define hda_call_pm_notify(bus, state) {} +#define hda_call_pm_notify(codec, state) {} #endif /** @@ -141,7 +152,7 @@ const char *snd_hda_get_jack_location(u32 cfg) } return "UNKNOWN"; } -EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); +EXPORT_SYMBOL_GPL(snd_hda_get_jack_location); /** * snd_hda_get_jack_connectivity - Give a connectivity string of the jack @@ -156,7 +167,7 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) return jack_locations[(cfg >> (AC_DEFCFG_LOCATION_SHIFT + 4)) & 3]; } -EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); +EXPORT_SYMBOL_GPL(snd_hda_get_jack_connectivity); /** * snd_hda_get_jack_type - Give a type string of the jack @@ -171,32 +182,31 @@ const char *snd_hda_get_jack_type(u32 cfg) "Line Out", "Speaker", "HP Out", "CD", "SPDIF Out", "Digital Out", "Modem Line", "Modem Hand", "Line In", "Aux", "Mic", "Telephony", - "SPDIF In", "Digitial In", "Reserved", "Other" + "SPDIF In", "Digital In", "Reserved", "Other" }; return jack_types[(cfg & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT]; } -EXPORT_SYMBOL_HDA(snd_hda_get_jack_type); +EXPORT_SYMBOL_GPL(snd_hda_get_jack_type); /* * Compose a 32bit command word to be sent to the HD-audio controller */ static inline unsigned int -make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, +make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm) { u32 val; - if ((codec->addr & ~0xf) || (direct & ~1) || (nid & ~0x7f) || + if ((codec->addr & ~0xf) || (nid & ~0x7f) || (verb & ~0xfff) || (parm & ~0xffff)) { - printk(KERN_ERR "hda-codec: out of range cmd %x:%x:%x:%x:%x\n", - codec->addr, direct, nid, verb, parm); + codec_err(codec, "hda-codec: out of range cmd %x:%x:%x:%x\n", + codec->addr, nid, verb, parm); return ~0; } val = (u32)codec->addr << 28; - val |= (u32)direct << 27; val |= (u32)nid << 20; val |= verb << 8; val |= parm; @@ -207,7 +217,7 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, * Send and receive a verb */ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, - unsigned int *res) + int flags, unsigned int *res) { struct hda_bus *bus = codec->bus; int err; @@ -220,25 +230,34 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, again: snd_hda_power_up(codec); mutex_lock(&bus->cmd_mutex); - trace_hda_send_cmd(codec, cmd); - err = bus->ops.command(bus, cmd); + if (flags & HDA_RW_NO_RESPONSE_FALLBACK) + bus->no_response_fallback = 1; + for (;;) { + trace_hda_send_cmd(codec, cmd); + err = bus->ops.command(bus, cmd); + if (err != -EAGAIN) + break; + /* process pending verbs */ + bus->ops.get_response(bus, codec->addr); + } if (!err && res) { *res = bus->ops.get_response(bus, codec->addr); trace_hda_get_response(codec, *res); } + bus->no_response_fallback = 0; mutex_unlock(&bus->cmd_mutex); snd_hda_power_down(codec); - if (res && *res == -1 && bus->rirb_error) { + if (!codec_in_pm(codec) && res && *res == -1 && bus->rirb_error) { if (bus->response_reset) { - snd_printd("hda_codec: resetting BUS due to " - "fatal communication error\n"); + codec_dbg(codec, + "resetting BUS due to fatal communication error\n"); trace_hda_bus_reset(bus); bus->ops.bus_reset(bus); } goto again; } /* clear reset-flag when the communication gets recovered */ - if (!err) + if (!err || codec_in_pm(codec)) bus->response_reset = 0; return err; } @@ -247,7 +266,7 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, * snd_hda_codec_read - send a command and get the response * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -256,22 +275,22 @@ static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, * Returns the obtained response value, or -1 for an error. */ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, - int direct, + int flags, unsigned int verb, unsigned int parm) { - unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); + unsigned cmd = make_codec_cmd(codec, nid, flags, verb, parm); unsigned int res; - if (codec_exec_verb(codec, cmd, &res)) + if (codec_exec_verb(codec, cmd, flags, &res)) return -1; return res; } -EXPORT_SYMBOL_HDA(snd_hda_codec_read); +EXPORT_SYMBOL_GPL(snd_hda_codec_read); /** * snd_hda_codec_write - send a single command without waiting for response * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -279,15 +298,15 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); * * Returns 0 if successful, or a negative error code. */ -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, - unsigned int verb, unsigned int parm) +int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, + unsigned int verb, unsigned int parm) { - unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); + unsigned int cmd = make_codec_cmd(codec, nid, flags, verb, parm); unsigned int res; - return codec_exec_verb(codec, cmd, + return codec_exec_verb(codec, cmd, flags, codec->bus->sync_write ? &res : NULL); } -EXPORT_SYMBOL_HDA(snd_hda_codec_write); +EXPORT_SYMBOL_GPL(snd_hda_codec_write); /** * snd_hda_sequence_write - sequence writes @@ -302,7 +321,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, const struct hda_verb *seq) for (; seq->nid; seq++) snd_hda_codec_write(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_HDA(snd_hda_sequence_write); +EXPORT_SYMBOL_GPL(snd_hda_sequence_write); /** * snd_hda_get_sub_nodes - get the range of sub nodes @@ -324,33 +343,117 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, *start_id = (parm >> 16) & 0x7fff; return (int)(parm & 0x7fff); } -EXPORT_SYMBOL_HDA(snd_hda_get_sub_nodes); +EXPORT_SYMBOL_GPL(snd_hda_get_sub_nodes); + +/* connection list element */ +struct hda_conn_list { + struct list_head list; + int len; + hda_nid_t nid; + hda_nid_t conns[0]; +}; /* look up the cached results */ -static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) +static struct hda_conn_list * +lookup_conn_list(struct hda_codec *codec, hda_nid_t nid) { - int i, len; - for (i = 0; i < array->used; ) { - hda_nid_t *p = snd_array_elem(array, i); - if (nid == *p) + struct hda_conn_list *p; + list_for_each_entry(p, &codec->conn_list, list) { + if (p->nid == nid) return p; - len = p[1]; - i += len + 2; } return NULL; } +static int add_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, + const hda_nid_t *list) +{ + struct hda_conn_list *p; + + p = kmalloc(sizeof(*p) + len * sizeof(hda_nid_t), GFP_KERNEL); + if (!p) + return -ENOMEM; + p->len = len; + p->nid = nid; + memcpy(p->conns, list, len * sizeof(hda_nid_t)); + list_add(&p->list, &codec->conn_list); + return 0; +} + +static void remove_conn_list(struct hda_codec *codec) +{ + while (!list_empty(&codec->conn_list)) { + struct hda_conn_list *p; + p = list_first_entry(&codec->conn_list, typeof(*p), list); + list_del(&p->list); + kfree(p); + } +} + /* read the connection and add to the cache */ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) { - hda_nid_t list[HDA_MAX_CONNECTIONS]; + hda_nid_t list[32]; + hda_nid_t *result = list; int len; len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list)); - if (len < 0) - return len; - return snd_hda_override_conn_list(codec, nid, len, list); + if (len == -ENOSPC) { + len = snd_hda_get_num_raw_conns(codec, nid); + result = kmalloc(sizeof(hda_nid_t) * len, GFP_KERNEL); + if (!result) + return -ENOMEM; + len = snd_hda_get_raw_connections(codec, nid, result, len); + } + if (len >= 0) + len = snd_hda_override_conn_list(codec, nid, len, result); + if (result != list) + kfree(result); + return len; +} + +/** + * snd_hda_get_conn_list - get connection list + * @codec: the HDA codec + * @nid: NID to parse + * @len: number of connection list entries + * @listp: the pointer to store NID list + * + * Parses the connection list of the given widget and stores the pointer + * to the list of NIDs. + * + * Returns the number of connections, or a negative error code. + * + * Note that the returned pointer isn't protected against the list + * modification. If snd_hda_override_conn_list() might be called + * concurrently, protect with a mutex appropriately. + */ +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp) +{ + bool added = false; + + for (;;) { + int err; + const struct hda_conn_list *p; + + /* if the connection-list is already cached, read it */ + p = lookup_conn_list(codec, nid); + if (p) { + if (listp) + *listp = p->conns; + return p->len; + } + if (snd_BUG_ON(added)) + return -EINVAL; + + err = read_and_add_raw_conns(codec, nid); + if (err < 0) + return err; + added = true; + } } +EXPORT_SYMBOL_GPL(snd_hda_get_conn_list); /** * snd_hda_get_connections - copy connection list @@ -367,41 +470,42 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns) { - struct snd_array *array = &codec->conn_lists; - int len; - hda_nid_t *p; - bool added = false; + const hda_nid_t *list; + int len = snd_hda_get_conn_list(codec, nid, &list); - again: - mutex_lock(&codec->hash_mutex); - len = -1; - /* if the connection-list is already cached, read it */ - p = lookup_conn_list(array, nid); - if (p) { - len = p[1]; - if (conn_list && len > max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", + if (len > 0 && conn_list) { + if (len > max_conns) { + codec_err(codec, "Too many connections %d for NID 0x%x\n", len, nid); - mutex_unlock(&codec->hash_mutex); return -EINVAL; } - if (conn_list && len) - memcpy(conn_list, p + 2, len * sizeof(hda_nid_t)); + memcpy(conn_list, list, len * sizeof(hda_nid_t)); } - mutex_unlock(&codec->hash_mutex); - if (len >= 0) - return len; - if (snd_BUG_ON(added)) - return -EINVAL; - len = read_and_add_raw_conns(codec, nid); - if (len < 0) - return len; - added = true; - goto again; + return len; +} +EXPORT_SYMBOL_GPL(snd_hda_get_connections); + +/* return CONNLIST_LEN parameter of the given widget */ +static unsigned int get_num_conns(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int parm; + + if (!(wcaps & AC_WCAP_CONN_LIST) && + get_wcaps_type(wcaps) != AC_WID_VOL_KNB) + return 0; + + parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); + if (parm == -1) + parm = 0; + return parm; +} + +int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_get_raw_connections(codec, nid, NULL, 0); } -EXPORT_SYMBOL_HDA(snd_hda_get_connections); /** * snd_hda_get_raw_connections - copy connection list without cache @@ -420,18 +524,13 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, unsigned int parm; int i, conn_len, conns; unsigned int shift, num_elems, mask; - unsigned int wcaps; hda_nid_t prev_nid; + int null_count = 0; - if (snd_BUG_ON(!conn_list || max_conns <= 0)) - return -EINVAL; - - wcaps = get_wcaps(codec, nid); - if (!(wcaps & AC_WCAP_CONN_LIST) && - get_wcaps_type(wcaps) != AC_WID_VOL_KNB) + parm = get_num_conns(codec, nid); + if (!parm) return 0; - parm = snd_hda_param_read(codec, nid, AC_PAR_CONNLIST_LEN); if (parm & AC_CLIST_LONG) { /* long form */ shift = 16; @@ -453,7 +552,8 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, AC_VERB_GET_CONNECT_LIST, 0); if (parm == -1 && codec->bus->rirb_error) return -EIO; - conn_list[0] = parm & mask; + if (conn_list) + conn_list[0] = parm & mask; return 1; } @@ -472,9 +572,9 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, } range_val = !!(parm & (1 << (shift-1))); /* ranges */ val = parm & mask; - if (val == 0) { - snd_printk(KERN_WARNING "hda_codec: " - "invalid CONNECT_LIST verb %x[%i]:%x\n", + if (val == 0 && null_count++) { /* no second chance */ + codec_dbg(codec, + "invalid CONNECT_LIST verb %x[%i]:%x\n", nid, i, parm); return 0; } @@ -482,43 +582,32 @@ int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, if (range_val) { /* ranges between the previous and this one */ if (!prev_nid || prev_nid >= val) { - snd_printk(KERN_WARNING "hda_codec: " + codec_warn(codec, "invalid dep_range_val %x:%x\n", prev_nid, val); continue; } for (n = prev_nid + 1; n <= val; n++) { - if (conns >= max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", - conns, nid); - return -EINVAL; + if (conn_list) { + if (conns >= max_conns) + return -ENOSPC; + conn_list[conns] = n; } - conn_list[conns++] = n; + conns++; } } else { - if (conns >= max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", - conns, nid); - return -EINVAL; + if (conn_list) { + if (conns >= max_conns) + return -ENOSPC; + conn_list[conns] = val; } - conn_list[conns++] = val; + conns++; } prev_nid = val; } return conns; } -static bool add_conn_list(struct snd_array *array, hda_nid_t nid) -{ - hda_nid_t *p = snd_array_new(array); - if (!p) - return false; - *p = nid; - return true; -} - /** * snd_hda_override_conn_list - add/modify the connection-list to cache * @codec: the HDA codec @@ -534,30 +623,17 @@ static bool add_conn_list(struct snd_array *array, hda_nid_t nid) int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, const hda_nid_t *list) { - struct snd_array *array = &codec->conn_lists; - hda_nid_t *p; - int i, old_used; + struct hda_conn_list *p; - mutex_lock(&codec->hash_mutex); - p = lookup_conn_list(array, nid); - if (p) - *p = -1; /* invalidate the old entry */ - - old_used = array->used; - if (!add_conn_list(array, nid) || !add_conn_list(array, len)) - goto error_add; - for (i = 0; i < len; i++) - if (!add_conn_list(array, list[i])) - goto error_add; - mutex_unlock(&codec->hash_mutex); - return 0; + p = lookup_conn_list(codec, nid); + if (p) { + list_del(&p->list); + kfree(p); + } - error_add: - array->used = old_used; - mutex_unlock(&codec->hash_mutex); - return -ENOMEM; + return add_conn_list(codec, nid, len, list); } -EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); +EXPORT_SYMBOL_GPL(snd_hda_override_conn_list); /** * snd_hda_get_conn_index - get the connection index of the given NID @@ -573,17 +649,17 @@ EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid, int recursive) { - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; + const hda_nid_t *conn; int i, nums; - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); + nums = snd_hda_get_conn_list(codec, mux, &conn); for (i = 0; i < nums; i++) if (conn[i] == nid) return i; if (!recursive) return -1; - if (recursive > 5) { - snd_printd("hda_codec: too deep connection for 0x%x\n", nid); + if (recursive > 10) { + codec_dbg(codec, "too deep connection for 0x%x\n", nid); return -1; } recursive++; @@ -596,7 +672,65 @@ int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, } return -1; } -EXPORT_SYMBOL_HDA(snd_hda_get_conn_index); +EXPORT_SYMBOL_GPL(snd_hda_get_conn_index); + + +/* return DEVLIST_LEN parameter of the given widget */ +static unsigned int get_num_devices(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int parm; + + if (!codec->dp_mst || !(wcaps & AC_WCAP_DIGITAL) || + get_wcaps_type(wcaps) != AC_WID_PIN) + return 0; + + parm = snd_hda_param_read(codec, nid, AC_PAR_DEVLIST_LEN); + if (parm == -1 && codec->bus->rirb_error) + parm = 0; + return parm & AC_DEV_LIST_LEN_MASK; +} + +/** + * snd_hda_get_devices - copy device list without cache + * @codec: the HDA codec + * @nid: NID of the pin to parse + * @dev_list: device list array + * @max_devices: max. number of devices to store + * + * Copy the device list. This info is dynamic and so not cached. + * Currently called only from hda_proc.c, so not exported. + */ +int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, + u8 *dev_list, int max_devices) +{ + unsigned int parm; + int i, dev_len, devices; + + parm = get_num_devices(codec, nid); + if (!parm) /* not multi-stream capable */ + return 0; + + dev_len = parm + 1; + dev_len = dev_len < max_devices ? dev_len : max_devices; + + devices = 0; + while (devices < dev_len) { + parm = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DEVICE_LIST, devices); + if (parm == -1 && codec->bus->rirb_error) + break; + + for (i = 0; i < 8; i++) { + dev_list[devices] = (u8)parm; + parm >>= 4; + devices++; + if (devices >= dev_len) + break; + } + } + return devices; +} /** * snd_hda_queue_unsol_event - add an unsolicited event to queue @@ -615,6 +749,9 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) struct hda_bus_unsolicited *unsol; unsigned int wp; + if (!bus || !bus->workq) + return 0; + trace_hda_unsol_event(bus, res, res_ex); unsol = bus->unsol; if (!unsol) @@ -631,7 +768,7 @@ int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex) return 0; } -EXPORT_SYMBOL_HDA(snd_hda_queue_unsol_event); +EXPORT_SYMBOL_GPL(snd_hda_queue_unsol_event); /* * process queued unsolicited events @@ -670,8 +807,7 @@ static int init_unsol_queue(struct hda_bus *bus) unsol = kzalloc(sizeof(*unsol), GFP_KERNEL); if (!unsol) { - snd_printk(KERN_ERR "hda_codec: " - "can't allocate unsolicited queue\n"); + dev_err(bus->card->dev, "can't allocate unsolicited queue\n"); return -ENOMEM; } INIT_WORK(&unsol->work, process_unsol_events); @@ -683,50 +819,36 @@ static int init_unsol_queue(struct hda_bus *bus) /* * destructor */ -static void snd_hda_codec_free(struct hda_codec *codec); - -static int snd_hda_bus_free(struct hda_bus *bus) +static void snd_hda_bus_free(struct hda_bus *bus) { - struct hda_codec *codec, *n; - if (!bus) - return 0; + return; + + WARN_ON(!list_empty(&bus->codec_list)); 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; } static int snd_hda_bus_dev_free(struct snd_device *device) { - struct hda_bus *bus = device->device_data; - bus->shutdown = 1; - return snd_hda_bus_free(bus); + snd_hda_bus_free(device->device_data); + return 0; } -#ifdef CONFIG_SND_HDA_HWDEP -static int snd_hda_bus_dev_register(struct snd_device *device) +static int snd_hda_bus_dev_disconnect(struct snd_device *device) { struct hda_bus *bus = device->device_data; - struct hda_codec *codec; - list_for_each_entry(codec, &bus->codec_list, list) { - snd_hda_hwdep_add_sysfs(codec); - snd_hda_hwdep_add_power_sysfs(codec); - } + bus->shutdown = 1; return 0; } -#else -#define snd_hda_bus_dev_register NULL -#endif /** * snd_hda_bus_new - create a HDA bus @@ -736,14 +858,14 @@ static int snd_hda_bus_dev_register(struct snd_device *device) * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, +int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, struct hda_bus **busp) { struct hda_bus *bus; int err; static struct snd_device_ops dev_ops = { - .dev_register = snd_hda_bus_dev_register, + .dev_disconnect = snd_hda_bus_dev_disconnect, .dev_free = snd_hda_bus_dev_free, }; @@ -757,7 +879,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, bus = kzalloc(sizeof(*bus), GFP_KERNEL); if (bus == NULL) { - snd_printk(KERN_ERR "can't allocate struct hda_bus\n"); + dev_err(card->dev, "can't allocate struct hda_bus\n"); return -ENOMEM; } @@ -776,7 +898,7 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, "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", + dev_err(card->dev, "cannot create workqueue %s\n", bus->workq_name); kfree(bus); return -ENOMEM; @@ -791,9 +913,9 @@ int /*__devinit*/ snd_hda_bus_new(struct snd_card *card, *busp = bus; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_bus_new); +EXPORT_SYMBOL_GPL(snd_hda_bus_new); -#ifdef CONFIG_SND_HDA_GENERIC +#if IS_ENABLED(CONFIG_SND_HDA_GENERIC) #define is_generic_config(codec) \ (codec->modelname && !strcmp(codec->modelname, "generic")) #else @@ -816,14 +938,11 @@ find_codec_preset(struct hda_codec *codec) const struct hda_codec_preset *preset; unsigned int mod_requested = 0; - if (is_generic_config(codec)) - return NULL; /* use the generic parser */ - again: mutex_lock(&preset_mutex); list_for_each_entry(tbl, &hda_preset_tables, list) { if (!try_module_get(tbl->owner)) { - snd_printk(KERN_ERR "hda_codec: cannot module_get\n"); + codec_err(codec, "cannot module_get\n"); continue; } for (preset = tbl->preset; preset->id; preset++) { @@ -906,7 +1025,7 @@ static int get_codec_name(struct hda_codec *codec) /* * look for an AFG and MFG nodes */ -static void /*__devinit*/ setup_fg_nodes(struct hda_codec *codec) +static void setup_fg_nodes(struct hda_codec *codec) { int i, total_nodes, function_id; hda_nid_t nid; @@ -991,19 +1110,6 @@ static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, return NULL; } -/* write a config value for the given NID */ -static void set_pincfg(struct hda_codec *codec, hda_nid_t nid, - unsigned int cfg) -{ - int i; - for (i = 0; i < 4; i++) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 + i, - cfg & 0xff); - cfg >>= 8; - } -} - /* set the current pin config value for the given NID. * the value is cached, and read via snd_hda_codec_get_pincfg() */ @@ -1011,12 +1117,16 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, hda_nid_t nid, unsigned int cfg) { struct hda_pincfg *pin; - unsigned int oldcfg; + /* the check below may be invalid when pins are added by a fixup + * dynamically (e.g. via snd_hda_codec_update_widgets()), so disabled + * for now + */ + /* if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) return -EINVAL; + */ - oldcfg = snd_hda_codec_get_pincfg(codec, nid); pin = look_up_pincfg(codec, list, nid); if (!pin) { pin = snd_array_new(list); @@ -1025,13 +1135,6 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, pin->nid = nid; } pin->cfg = cfg; - - /* change only when needed; e.g. if the pincfg is already present - * in user_pins[], don't write it - */ - cfg = snd_hda_codec_get_pincfg(codec, nid); - if (oldcfg != cfg) - set_pincfg(codec, nid, cfg); return 0; } @@ -1050,7 +1153,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, { return snd_hda_add_pincfg(codec, &codec->driver_pins, nid, cfg); } -EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); +EXPORT_SYMBOL_GPL(snd_hda_codec_set_pincfg); /** * snd_hda_codec_get_pincfg - Obtain a pin-default configuration @@ -1065,10 +1168,17 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) { struct hda_pincfg *pin; -#ifdef CONFIG_SND_HDA_HWDEP - pin = look_up_pincfg(codec, &codec->user_pins, nid); - if (pin) - return pin->cfg; +#ifdef CONFIG_SND_HDA_RECONFIG + { + unsigned int cfg = 0; + mutex_lock(&codec->user_mutex); + pin = look_up_pincfg(codec, &codec->user_pins, nid); + if (pin) + cfg = pin->cfg; + mutex_unlock(&codec->user_mutex); + if (cfg) + return cfg; + } #endif pin = look_up_pincfg(codec, &codec->driver_pins, nid); if (pin) @@ -1078,18 +1188,33 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) return pin->cfg; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_codec_get_pincfg); +EXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg); -/* restore all current pin configs */ -static void restore_pincfgs(struct hda_codec *codec) +/* remember the current pinctl target value */ +int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, + unsigned int val) { - int i; - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - set_pincfg(codec, pin->nid, - snd_hda_codec_get_pincfg(codec, pin->nid)); - } + struct hda_pincfg *pin; + + pin = look_up_pincfg(codec, &codec->init_pins, nid); + if (!pin) + return -EINVAL; + pin->target = val; + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target); + +/* return the current pinctl target value */ +int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_pincfg *pin; + + pin = look_up_pincfg(codec, &codec->init_pins, nid); + if (!pin) + return 0; + return pin->target; } +EXPORT_SYMBOL_GPL(snd_hda_codec_get_pin_target); /** * snd_hda_shutup_pins - Shut up all pins @@ -1114,7 +1239,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } codec->pins_shutup = 1; } -EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); +EXPORT_SYMBOL_GPL(snd_hda_shutup_pins); #ifdef CONFIG_PM /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ @@ -1135,21 +1260,32 @@ static void restore_shutup_pins(struct hda_codec *codec) } #endif +static void hda_jackpoll_work(struct work_struct *work) +{ + struct hda_codec *codec = + container_of(work, struct hda_codec, jackpoll_work.work); + + snd_hda_jack_set_dirty_all(codec); + snd_hda_jack_poll_all(codec); + + if (!codec->jackpoll_interval) + return; + + queue_delayed_work(codec->bus->workq, &codec->jackpoll_work, + codec->jackpoll_interval); +} + static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size); static void free_hda_cache(struct hda_cache_rec *cache); -/* restore the initial pin cfgs and release all pincfg lists */ -static void restore_init_pincfgs(struct hda_codec *codec) +/* release all pincfg lists */ +static void free_init_pincfgs(struct hda_codec *codec) { - /* first free driver_pins and user_pins, then call restore_pincfg - * so that only the values in init_pins are restored - */ snd_array_free(&codec->driver_pins); -#ifdef CONFIG_SND_HDA_HWDEP +#ifdef CONFIG_SND_HDA_RECONFIG snd_array_free(&codec->user_pins); #endif - restore_pincfgs(codec); snd_array_free(&codec->init_pins); } @@ -1184,14 +1320,29 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) } /* + * Dynamic symbol binding for the codec parsers + */ + +#define load_parser(codec, sym) \ + ((codec)->parser = (int (*)(struct hda_codec *))symbol_request(sym)) + +static void unload_parser(struct hda_codec *codec) +{ + if (codec->parser) + symbol_put_addr(codec->parser); + codec->parser = NULL; +} + +/* * codec destructor */ static void snd_hda_codec_free(struct hda_codec *codec) { if (!codec) return; + cancel_delayed_work_sync(&codec->jackpoll_work); snd_hda_jack_tbl_clear(codec); - restore_init_pincfgs(codec); + free_init_pincfgs(codec); #ifdef CONFIG_PM cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); @@ -1200,15 +1351,14 @@ static void snd_hda_codec_free(struct hda_codec *codec) snd_array_free(&codec->mixers); snd_array_free(&codec->nids); snd_array_free(&codec->cvt_setups); - snd_array_free(&codec->conn_lists); snd_array_free(&codec->spdif_out); + remove_conn_list(codec); codec->bus->caddr_tbl[codec->addr] = NULL; if (codec->patch_ops.free) codec->patch_ops.free(codec); -#ifdef CONFIG_PM - if (!codec->pm_down_notified) /* cancel leftover refcounts */ - hda_call_pm_notify(codec->bus, false); -#endif + hda_call_pm_notify(codec, false); /* cancel leftover refcounts */ + snd_hda_sysfs_clear(codec); + unload_parser(codec); module_put(codec->owner); free_hda_cache(&codec->amp_cache); free_hda_cache(&codec->cmd_cache); @@ -1216,7 +1366,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) kfree(codec->chip_name); kfree(codec->modelname); kfree(codec->wcaps); - kfree(codec); + codec->bus->num_codecs--; + put_device(&codec->dev); } static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, @@ -1225,6 +1376,38 @@ static bool snd_hda_codec_get_supported_ps(struct hda_codec *codec, static unsigned int hda_set_power_state(struct hda_codec *codec, unsigned int power_state); +static int snd_hda_codec_dev_register(struct snd_device *device) +{ + struct hda_codec *codec = device->device_data; + int err = device_add(&codec->dev); + + if (err < 0) + return err; + snd_hda_register_beep_device(codec); + return 0; +} + +static int snd_hda_codec_dev_disconnect(struct snd_device *device) +{ + struct hda_codec *codec = device->device_data; + + snd_hda_detach_beep_device(codec); + device_del(&codec->dev); + return 0; +} + +static int snd_hda_codec_dev_free(struct snd_device *device) +{ + snd_hda_codec_free(device->device_data); + return 0; +} + +/* just free the container */ +static void snd_hda_codec_dev_release(struct device *dev) +{ + kfree(container_of(dev, struct hda_codec, dev)); +} + /** * snd_hda_codec_new - create a HDA codec * @bus: the bus to assign @@ -1233,7 +1416,7 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, +int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp) { @@ -1241,6 +1424,11 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, char component[31]; hda_nid_t fg; int err; + static struct snd_device_ops dev_ops = { + .dev_register = snd_hda_codec_dev_register, + .dev_disconnect = snd_hda_codec_dev_disconnect, + .dev_free = snd_hda_codec_dev_free, + }; if (snd_BUG_ON(!bus)) return -EINVAL; @@ -1248,17 +1436,27 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, return -EINVAL; if (bus->caddr_tbl[codec_addr]) { - snd_printk(KERN_ERR "hda_codec: " - "address 0x%x is already occupied\n", codec_addr); + dev_err(bus->card->dev, + "address 0x%x is already occupied\n", + codec_addr); return -EBUSY; } codec = kzalloc(sizeof(*codec), GFP_KERNEL); if (codec == NULL) { - snd_printk(KERN_ERR "can't allocate struct hda_codec\n"); + dev_err(bus->card->dev, "can't allocate struct hda_codec\n"); return -ENOMEM; } + device_initialize(&codec->dev); + codec->dev.parent = &bus->card->card_dev; + codec->dev.class = sound_class; + codec->dev.release = snd_hda_codec_dev_release; + codec->dev.groups = snd_hda_dev_attr_groups; + dev_set_name(&codec->dev, "hdaudioC%dD%d", bus->card->number, + codec_addr); + dev_set_drvdata(&codec->dev, codec); /* for sysfs */ + codec->bus = bus; codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); @@ -1271,8 +1469,13 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); - snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); + snd_array_init(&codec->jacktbl, sizeof(struct hda_jack_tbl), 16); + snd_array_init(&codec->verbs, sizeof(struct hda_verb *), 8); + INIT_LIST_HEAD(&codec->conn_list); + + INIT_DELAYED_WORK(&codec->jackpoll_work, hda_jackpoll_work); + codec->depop_delay = -1; #ifdef CONFIG_PM spin_lock_init(&codec->power_lock); @@ -1282,18 +1485,21 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, * phase. */ hda_keep_power_on(codec); - hda_call_pm_notify(bus, true); #endif + snd_hda_sysfs_init(codec); + if (codec->bus->modelname) { codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); if (!codec->modelname) { - snd_hda_codec_free(codec); - return -ENODEV; + err = -ENODEV; + goto error; } } list_add_tail(&codec->list, &bus->codec_list); + bus->num_codecs++; + bus->caddr_tbl[codec_addr] = codec; codec->vendor_id = snd_hda_param_read(codec, AC_NODE_ROOT, @@ -1311,7 +1517,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, setup_fg_nodes(codec); if (!codec->afg && !codec->mfg) { - snd_printdd("hda_codec: no AFG or MFG node found\n"); + dev_err(bus->card->dev, "no AFG or MFG node found\n"); err = -ENODEV; goto error; } @@ -1319,7 +1525,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, fg = codec->afg ? codec->afg : codec->mfg; err = read_widget_caps(codec, fg); if (err < 0) { - snd_printk(KERN_ERR "hda_codec: cannot malloc\n"); + dev_err(bus->card->dev, "cannot malloc\n"); goto error; } err = read_pin_defaults(codec); @@ -1335,11 +1541,14 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, #ifdef CONFIG_PM codec->d3_stop_clk = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_CLKSTOP); - if (!codec->d3_stop_clk) - bus->power_keep_link_on = 1; #endif codec->epss = snd_hda_codec_get_supported_ps(codec, fg, AC_PWRST_EPSS); +#ifdef CONFIG_PM + if (!codec->d3_stop_clk || !codec->epss) + bus->power_keep_link_on = 1; +#endif + /* power-up all before initialization */ hda_set_power_state(codec, AC_PWRST_D0); @@ -1352,6 +1561,10 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, codec->subsystem_id, codec->revision_id); snd_component_add(codec->bus->card, component); + err = snd_device_new(bus->card, SNDRV_DEV_CODEC, codec, &dev_ops); + if (err < 0) + goto error; + if (codecp) *codecp = codec; return 0; @@ -1360,7 +1573,56 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_hda_codec_free(codec); return err; } -EXPORT_SYMBOL_HDA(snd_hda_codec_new); +EXPORT_SYMBOL_GPL(snd_hda_codec_new); + +int snd_hda_codec_update_widgets(struct hda_codec *codec) +{ + hda_nid_t fg; + int err; + + /* Assume the function group node does not change, + * only the widget nodes may change. + */ + kfree(codec->wcaps); + fg = codec->afg ? codec->afg : codec->mfg; + err = read_widget_caps(codec, fg); + if (err < 0) { + codec_err(codec, "cannot malloc\n"); + return err; + } + + snd_array_free(&codec->init_pins); + err = read_pin_defaults(codec); + + return err; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_update_widgets); + + +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) +/* if all audio out widgets are digital, let's assume the codec as a HDMI/DP */ +static bool is_likely_hdmi_codec(struct hda_codec *codec) +{ + hda_nid_t nid = codec->start_nid; + int i; + + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + switch (get_wcaps_type(wcaps)) { + case AC_WID_AUD_IN: + return false; /* HDMI parser supports only HDMI out */ + case AC_WID_AUD_OUT: + if (!(wcaps & AC_WCAP_DIGITAL)) + return false; + break; + } + } + return true; +} +#else +/* no HDMI codec parser support */ +#define is_likely_hdmi_codec(codec) false +#endif /* CONFIG_SND_HDA_CODEC_HDMI */ /** * snd_hda_codec_configure - (Re-)configure the HD-audio codec @@ -1373,6 +1635,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_new); */ int snd_hda_codec_configure(struct hda_codec *codec) { + int (*patch)(struct hda_codec *) = NULL; int err; codec->preset = find_codec_preset(codec); @@ -1382,31 +1645,50 @@ int snd_hda_codec_configure(struct hda_codec *codec) return err; } - if (is_generic_config(codec)) { - err = snd_hda_parse_generic_codec(codec); - goto patched; - } - if (codec->preset && codec->preset->patch) { - err = codec->preset->patch(codec); - goto patched; + if (!is_generic_config(codec) && codec->preset) + patch = codec->preset->patch; + if (!patch) { + unload_parser(codec); /* to be sure */ + if (is_likely_hdmi_codec(codec)) { +#if IS_MODULE(CONFIG_SND_HDA_CODEC_HDMI) + patch = load_parser(codec, snd_hda_parse_hdmi_codec); +#elif IS_BUILTIN(CONFIG_SND_HDA_CODEC_HDMI) + patch = snd_hda_parse_hdmi_codec; +#endif + } + if (!patch) { +#if IS_MODULE(CONFIG_SND_HDA_GENERIC) + patch = load_parser(codec, snd_hda_parse_generic_codec); +#elif IS_BUILTIN(CONFIG_SND_HDA_GENERIC) + patch = snd_hda_parse_generic_codec; +#endif + } + if (!patch) { + codec_err(codec, "No codec parser is available\n"); + return -ENODEV; + } } - /* call the default parser */ - err = snd_hda_parse_generic_codec(codec); - if (err < 0) - printk(KERN_ERR "hda-codec: No codec parser is available\n"); + err = patch(codec); + if (err < 0) { + unload_parser(codec); + return err; + } - patched: - if (!err && codec->patch_ops.unsol_event) + if (codec->patch_ops.unsol_event) { err = init_unsol_queue(codec->bus); + if (err < 0) + return err; + } + /* audio codec should override the mixer name */ - if (!err && (codec->afg || !*codec->bus->card->mixername)) + if (codec->afg || !*codec->bus->card->mixername) snprintf(codec->bus->card->mixername, sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); - return err; + return 0; } -EXPORT_SYMBOL_HDA(snd_hda_codec_configure); +EXPORT_SYMBOL_GPL(snd_hda_codec_configure); /* update the stream-id if changed */ static void update_pcm_stream_id(struct hda_codec *codec, @@ -1466,9 +1748,9 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, if (!nid) return; - snd_printdd("hda_codec_setup_stream: " - "NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", - nid, stream_tag, channel_id, format); + codec_dbg(codec, + "hda_codec_setup_stream: NID=0x%x, stream=0x%x, channel=%d, format=0x%x\n", + nid, stream_tag, channel_id, format); p = get_hda_cvt_setup(codec, nid); if (!p) return; @@ -1493,7 +1775,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, } } } -EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); +EXPORT_SYMBOL_GPL(snd_hda_codec_setup_stream); static void really_cleanup_stream(struct hda_codec *codec, struct hda_cvt_setup *q); @@ -1515,7 +1797,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, if (codec->no_sticky_stream) do_now = 1; - snd_printdd("hda_codec_cleanup_stream: NID=0x%x\n", nid); + codec_dbg(codec, "hda_codec_cleanup_stream: NID=0x%x\n", nid); p = get_hda_cvt_setup(codec, nid); if (p) { /* here we just clear the active flag when do_now isn't set; @@ -1528,7 +1810,7 @@ void __snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid, p->active = 0; } } -EXPORT_SYMBOL_HDA(__snd_hda_codec_cleanup_stream); +EXPORT_SYMBOL_GPL(__snd_hda_codec_cleanup_stream); static void really_cleanup_stream(struct hda_codec *codec, struct hda_cvt_setup *q) @@ -1586,7 +1868,7 @@ static void hda_cleanup_all_streams(struct hda_codec *codec) #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) /* initialize the hash table */ -static void /*__devinit*/ init_hda_cache(struct hda_cache_rec *cache, +static void init_hda_cache(struct hda_cache_rec *cache, unsigned int record_size) { memset(cache, 0, sizeof(*cache)); @@ -1629,6 +1911,7 @@ static struct hda_cache_head *get_alloc_hash(struct hda_cache_rec *cache, cur = snd_array_index(&cache->buf, info); info->key = key; info->val = 0; + info->dirty = 0; idx = key % (u16)ARRAY_SIZE(cache->hash); info->next = cache->hash[idx]; cache->hash[idx] = cur; @@ -1715,7 +1998,7 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) HDA_HASH_KEY(nid, direction, 0), read_amp_cap); } -EXPORT_SYMBOL_HDA(query_amp_caps); +EXPORT_SYMBOL_GPL(query_amp_caps); /** * snd_hda_override_amp_caps - Override the AMP capabilities @@ -1735,7 +2018,7 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, { return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps); } -EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); +EXPORT_SYMBOL_GPL(snd_hda_override_amp_caps); static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid, int dir) @@ -1759,7 +2042,7 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid), read_pin_cap); } -EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); +EXPORT_SYMBOL_GPL(snd_hda_query_pin_caps); /** * snd_hda_override_pin_caps - Override the pin capabilities @@ -1776,14 +2059,14 @@ int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, { return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps); } -EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); +EXPORT_SYMBOL_GPL(snd_hda_override_pin_caps); /* read or sync the hash value with the current value; * call within hash_mutex */ static struct hda_amp_info * update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int index) + int direction, int index, bool init_only) { struct hda_amp_info *info; unsigned int parm, val = 0; @@ -1809,14 +2092,15 @@ update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, } info->vol[ch] = val; info->head.val |= INFO_AMP_VOL(ch); - } + } else if (init_only) + return NULL; return info; } /* * write the current volume in info to the h/w */ -static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, +static void put_vol_mute(struct hda_codec *codec, unsigned int amp_caps, hda_nid_t nid, int ch, int direction, int index, int val) { @@ -1825,8 +2109,8 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, parm = ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT; parm |= direction == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT; parm |= index << AC_AMP_SET_INDEX_SHIFT; - if ((val & HDA_AMP_MUTE) && !(info->amp_caps & AC_AMPCAP_MUTE) && - (info->amp_caps & AC_AMPCAP_MIN_MUTE)) + if ((val & HDA_AMP_MUTE) && !(amp_caps & AC_AMPCAP_MUTE) && + (amp_caps & AC_AMPCAP_MIN_MUTE)) ; /* set the zero value as a fake mute */ else parm |= val; @@ -1850,38 +2134,28 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, unsigned int val = 0; mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, index); + info = update_amp_hash(codec, nid, ch, direction, index, false); if (info) val = info->vol[ch]; mutex_unlock(&codec->hash_mutex); return val; } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_read); -/** - * snd_hda_codec_amp_update - update the AMP value - * @codec: HD-audio codec - * @nid: NID to read the AMP value - * @ch: channel (left=0 or right=1) - * @direction: #HDA_INPUT or #HDA_OUTPUT - * @idx: the index value (only for input direction) - * @mask: bit mask to set - * @val: the bits value to set - * - * Update the AMP value with a bit mask. - * Returns 0 if the value is unchanged, 1 if changed. - */ -int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int idx, int mask, int val) +static int codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val, + bool init_only) { struct hda_amp_info *info; + unsigned int caps; + unsigned int cache_only; if (snd_BUG_ON(mask & ~0xff)) mask &= 0xff; val &= mask; mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, idx); + info = update_amp_hash(codec, nid, ch, direction, idx, init_only); if (!info) { mutex_unlock(&codec->hash_mutex); return 0; @@ -1892,11 +2166,33 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, return 0; } info->vol[ch] = val; + cache_only = info->head.dirty = codec->cached_write; + caps = info->amp_caps; mutex_unlock(&codec->hash_mutex); - put_vol_mute(codec, info, nid, ch, direction, idx, val); + if (!cache_only) + put_vol_mute(codec, caps, nid, ch, direction, idx, val); return 1; } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); + +/** + * snd_hda_codec_amp_update - update the AMP value + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @ch: channel (left=0 or right=1) + * @direction: #HDA_INPUT or #HDA_OUTPUT + * @idx: the index value (only for input direction) + * @mask: bit mask to set + * @val: the bits value to set + * + * Update the AMP value with a bit mask. + * Returns 0 if the value is unchanged, 1 if changed. + */ +int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val) +{ + return codec_amp_update(codec, nid, ch, direction, idx, mask, val, false); +} +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_update); /** * snd_hda_codec_amp_stereo - update the AMP stereo values @@ -1922,9 +2218,33 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, idx, mask, val); return ret; } -EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo); + +/* Works like snd_hda_codec_amp_update() but it writes the value only at + * the first access. If the amp was already initialized / updated beforehand, + * this does nothing. + */ +int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, + int dir, int idx, int mask, int val) +{ + return codec_amp_update(codec, nid, ch, dir, idx, mask, val, true); +} +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init); + +int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val) +{ + int ch, ret = 0; + + if (snd_BUG_ON(mask & ~0xff)) + mask &= 0xff; + for (ch = 0; ch < 2; ch++) + ret |= snd_hda_codec_amp_init(codec, nid, ch, dir, + idx, mask, val); + return ret; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init_stereo); -#ifdef CONFIG_PM /** * snd_hda_codec_resume_amp - Resume all AMP commands from the cache * @codec: HD-audio codec @@ -1933,28 +2253,40 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { - struct hda_amp_info *buffer = codec->amp_cache.buf.list; int i; - for (i = 0; i < codec->amp_cache.buf.used; i++, buffer++) { - u32 key = buffer->head.key; + mutex_lock(&codec->hash_mutex); + codec->cached_write = 0; + for (i = 0; i < codec->amp_cache.buf.used; i++) { + struct hda_amp_info *buffer; + u32 key; hda_nid_t nid; unsigned int idx, dir, ch; + struct hda_amp_info info; + + buffer = snd_array_elem(&codec->amp_cache.buf, i); + if (!buffer->head.dirty) + continue; + buffer->head.dirty = 0; + info = *buffer; + key = info.head.key; if (!key) continue; nid = key & 0xff; idx = (key >> 16) & 0xff; dir = (key >> 24) & 0xff; for (ch = 0; ch < 2; ch++) { - if (!(buffer->head.val & INFO_AMP_VOL(ch))) + if (!(info.head.val & INFO_AMP_VOL(ch))) continue; - put_vol_mute(codec, buffer, nid, ch, dir, idx, - buffer->vol[ch]); + mutex_unlock(&codec->hash_mutex); + put_vol_mute(codec, info.amp_caps, nid, ch, dir, idx, + info.vol[ch]); + mutex_lock(&codec->hash_mutex); } } + mutex_unlock(&codec->hash_mutex); } -EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); -#endif /* CONFIG_PM */ +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_amp); static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int ofs) @@ -1987,14 +2319,14 @@ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.min = 0; uinfo->value.integer.max = get_amp_max_value(codec, nid, dir, ofs); if (!uinfo->value.integer.max) { - printk(KERN_WARNING "hda_codec: " - "num_steps = 0 for NID=0x%x (ctl = %s)\n", nid, - kcontrol->id.name); + codec_warn(codec, + "num_steps = 0 for NID=0x%x (ctl = %s)\n", + nid, kcontrol->id.name); return -EINVAL; } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_info); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_info); static inline unsigned int @@ -2051,7 +2383,7 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, *valp = read_amp_value(codec, nid, 1, dir, idx, ofs); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get); /** * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume @@ -2081,7 +2413,7 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put); /** * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume @@ -2119,7 +2451,7 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -EFAULT; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_tlv); /** * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control @@ -2147,16 +2479,16 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, tlv[2] = -nums * step; tlv[3] = step; } -EXPORT_SYMBOL_HDA(snd_hda_set_vmaster_tlv); +EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); /* find a mixer control element with the given name */ static struct snd_kcontrol * -_snd_hda_find_mixer_ctl(struct hda_codec *codec, - const char *name, int idx) +find_mixer_ctl(struct hda_codec *codec, const char *name, int dev, int idx) { struct snd_ctl_elem_id id; memset(&id, 0, sizeof(id)); id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + id.device = dev; id.index = idx; if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) return NULL; @@ -2174,15 +2506,17 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name) { - return _snd_hda_find_mixer_ctl(codec, name, 0); + return find_mixer_ctl(codec, name, 0, 0); } -EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); +EXPORT_SYMBOL_GPL(snd_hda_find_mixer_ctl); -static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name) +static int find_empty_mixer_ctl_idx(struct hda_codec *codec, const char *name, + int start_idx) { - int idx; - for (idx = 0; idx < 16; idx++) { /* 16 ctlrs should be large enough */ - if (!_snd_hda_find_mixer_ctl(codec, name, idx)) + int i, idx; + /* 16 ctlrs should be large enough */ + for (i = 0, idx = start_idx; i < 16; i++, idx++) { + if (!find_mixer_ctl(codec, name, 0, idx)) return idx; } return -EBUSY; @@ -2234,7 +2568,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, item->flags = flags; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_ctl_add); +EXPORT_SYMBOL_GPL(snd_hda_ctl_add); /** * snd_hda_add_nid - Assign a NID to a control element @@ -2261,11 +2595,11 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, item->nid = nid; return 0; } - printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n", - kctl->id.name, kctl->id.index, index); + codec_err(codec, "no NID for mapping control %s:%d:%d\n", + kctl->id.name, kctl->id.index, index); return -EINVAL; } -EXPORT_SYMBOL_HDA(snd_hda_add_nid); +EXPORT_SYMBOL_GPL(snd_hda_add_nid); /** * snd_hda_ctls_clear - Clear all controls assigned to the given codec @@ -2316,7 +2650,7 @@ int snd_hda_lock_devices(struct hda_bus *bus) spin_unlock(&card->files_lock); return -EINVAL; } -EXPORT_SYMBOL_HDA(snd_hda_lock_devices); +EXPORT_SYMBOL_GPL(snd_hda_lock_devices); void snd_hda_unlock_devices(struct hda_bus *bus) { @@ -2327,7 +2661,7 @@ void snd_hda_unlock_devices(struct hda_bus *bus) card->shutdown = 0; spin_unlock(&card->files_lock); } -EXPORT_SYMBOL_HDA(snd_hda_unlock_devices); +EXPORT_SYMBOL_GPL(snd_hda_unlock_devices); /** * snd_hda_codec_reset - Clear all objects assigned to the codec @@ -2349,16 +2683,13 @@ int snd_hda_codec_reset(struct hda_codec *codec) return -EBUSY; /* OK, let it free */ - + cancel_delayed_work_sync(&codec->jackpoll_work); #ifdef CONFIG_PM cancel_delayed_work_sync(&codec->power_work); - codec->power_on = 0; - codec->power_transition = 0; - codec->power_jiffies = jiffies; flush_workqueue(bus->workq); #endif snd_hda_ctls_clear(codec); - /* relase PCMs */ + /* release PCMs */ for (i = 0; i < codec->num_pcms; i++) { if (codec->pcm_info[i].pcm) { snd_device_free(card, codec->pcm_info[i].pcm); @@ -2366,6 +2697,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) bus->pcm_dev_bits); } } + snd_hda_detach_beep_device(codec); if (codec->patch_ops.free) codec->patch_ops.free(codec); memset(&codec->patch_ops, 0, sizeof(codec->patch_ops)); @@ -2378,14 +2710,15 @@ int snd_hda_codec_reset(struct hda_codec *codec) init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); /* free only driver_pins so that init_pins + user_pins are restored */ snd_array_free(&codec->driver_pins); - restore_pincfgs(codec); snd_array_free(&codec->cvt_setups); snd_array_free(&codec->spdif_out); + snd_array_free(&codec->verbs); codec->num_pcms = 0; codec->pcm_info = NULL; codec->preset = NULL; codec->slave_dig_outs = NULL; codec->spdif_status_reset = 0; + unload_parser(codec); module_put(codec->owner); codec->owner = NULL; @@ -2407,8 +2740,7 @@ static int map_slaves(struct hda_codec *codec, const char * const *slaves, items = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) { struct snd_kcontrol *sctl = items[i].kctl; - if (!sctl || !sctl->id.name || - sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) + if (!sctl || sctl->id.iface != SNDRV_CTL_ELEM_IFACE_MIXER) continue; for (s = slaves; *s; s++) { char tmpname[sizeof(sctl->id.name)]; @@ -2435,7 +2767,7 @@ static int check_slave_present(void *data, struct snd_kcontrol *sctl) } /* guess the value corresponding to 0dB */ -static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) +static int get_kctl_0dB_offset(struct snd_kcontrol *kctl, int *step_to_check) { int _tlv[4]; const int *tlv = NULL; @@ -2450,8 +2782,19 @@ static int get_kctl_0dB_offset(struct snd_kcontrol *kctl) set_fs(fs); } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) tlv = kctl->tlv.p; - if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) - val = -tlv[2] / tlv[3]; + if (tlv && tlv[0] == SNDRV_CTL_TLVT_DB_SCALE) { + int step = tlv[3]; + step &= ~TLV_DB_SCALE_MUTE; + if (!step) + return -1; + if (*step_to_check && *step_to_check != step) { + snd_printk(KERN_ERR "hda_codec: Mismatching dB step for vmaster slave (%d!=%d)\n", +- *step_to_check, step); + return -1; + } + *step_to_check = step; + val = -tlv[2] / step; + } return val; } @@ -2472,7 +2815,7 @@ static int put_kctl_with_value(struct snd_kcontrol *kctl, int val) /* initialize the slave volume with 0dB */ static int init_slave_0dB(void *data, struct snd_kcontrol *slave) { - int offset = get_kctl_0dB_offset(slave); + int offset = get_kctl_0dB_offset(slave, data); if (offset > 0) put_kctl_with_value(slave, offset); return 0; @@ -2516,7 +2859,7 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, err = map_slaves(codec, slaves, suffix, check_slave_present, NULL); if (err != 1) { - snd_printdd("No slave found for %s\n", name); + codec_dbg(codec, "No slave found for %s\n", name); return 0; } kctl = snd_ctl_make_virtual_master(name, tlv); @@ -2533,15 +2876,17 @@ int __snd_hda_add_vmaster(struct hda_codec *codec, char *name, /* init with master mute & zero volume */ put_kctl_with_value(kctl, 0); - if (init_slave_vol) + if (init_slave_vol) { + int step = 0; map_slaves(codec, slaves, suffix, - tlv ? init_slave_0dB : init_slave_unmute, kctl); + tlv ? init_slave_0dB : init_slave_unmute, &step); + } if (ctl_ret) *ctl_ret = kctl; return 0; } -EXPORT_SYMBOL_HDA(__snd_hda_add_vmaster); +EXPORT_SYMBOL_GPL(__snd_hda_add_vmaster); /* * mute-LED control using vmaster @@ -2550,7 +2895,7 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { static const char * const texts[] = { - "Off", "On", "Follow Master" + "On", "Off", "Follow Master" }; unsigned int index; @@ -2618,7 +2963,7 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec, return -ENOMEM; return snd_hda_ctl_add(codec, 0, kctl); } -EXPORT_SYMBOL_HDA(snd_hda_add_vmaster_hook); +EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook); /* * Call the hook with the current value for synchronization @@ -2628,6 +2973,11 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) { if (!hook->hook || !hook->codec) return; + /* don't call vmaster hook in the destructor since it might have + * been already destroyed + */ + if (hook->codec->bus->shutdown) + return; switch (hook->mute_mode) { case HDA_VMUTE_FOLLOW_MASTER: snd_ctl_sync_vmaster_hook(hook->sw_kctl); @@ -2637,7 +2987,7 @@ void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook) break; } } -EXPORT_SYMBOL_HDA(snd_hda_sync_vmaster_hook); +EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook); /** @@ -2657,7 +3007,7 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, uinfo->value.integer.max = 1; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info); /** * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch @@ -2683,7 +3033,7 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, HDA_AMP_MUTE) ? 0 : 1; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get); /** * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch @@ -2717,7 +3067,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, snd_hda_power_down(codec); return change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); +EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put); /* * bound volume controls @@ -2749,7 +3099,7 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->control_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get); /** * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control @@ -2779,7 +3129,7 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put); /** * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control @@ -2802,7 +3152,7 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->control_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info); /** * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control @@ -2825,7 +3175,7 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->control_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get); /** * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control @@ -2854,7 +3204,7 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, mutex_unlock(&codec->control_mutex); return err < 0 ? err : change; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put); /** * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control @@ -2877,7 +3227,7 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, mutex_unlock(&codec->control_mutex); return err; } -EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_tlv); +EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_tlv); struct hda_ctl_ops snd_hda_bind_vol = { .info = snd_hda_mixer_amp_volume_info, @@ -2885,7 +3235,7 @@ struct hda_ctl_ops snd_hda_bind_vol = { .put = snd_hda_mixer_amp_volume_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_HDA(snd_hda_bind_vol); +EXPORT_SYMBOL_GPL(snd_hda_bind_vol); struct hda_ctl_ops snd_hda_bind_sw = { .info = snd_hda_mixer_amp_switch_info, @@ -2893,7 +3243,7 @@ struct hda_ctl_ops snd_hda_bind_sw = { .put = snd_hda_mixer_amp_switch_put, .tlv = snd_hda_mixer_amp_tlv }; -EXPORT_SYMBOL_HDA(snd_hda_bind_sw); +EXPORT_SYMBOL_GPL(snd_hda_bind_sw); /* * SPDIF out controls @@ -2985,7 +3335,7 @@ static unsigned int convert_to_spdif_status(unsigned short val) if (val & AC_DIG1_PROFESSIONAL) sbits |= IEC958_AES0_PROFESSIONAL; if (sbits & IEC958_AES0_PROFESSIONAL) { - if (sbits & AC_DIG1_EMPHASIS) + if (val & AC_DIG1_EMPHASIS) sbits |= IEC958_AES0_PRO_EMPHASIS_5015; } else { if (val & AC_DIG1_EMPHASIS) @@ -3133,31 +3483,54 @@ static struct snd_kcontrol_new dig_mixes[] = { }; /** - * snd_hda_create_spdif_out_ctls - create Output SPDIF-related controls + * snd_hda_create_dig_out_ctls - create Output SPDIF-related controls * @codec: the HDA codec - * @nid: audio out widget NID - * - * Creates controls related with the SPDIF output. - * Called from each patch supporting the SPDIF out. + * @associated_nid: NID that new ctls associated with + * @cvt_nid: converter NID + * @type: HDA_PCM_TYPE_* + * Creates controls related with the digital output. + * Called from each patch supporting the digital out. * * Returns 0 if successful, or a negative error code. */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid) +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, + int type) { int err; struct snd_kcontrol *kctl; struct snd_kcontrol_new *dig_mix; - int idx; + int idx = 0; + const int spdif_index = 16; struct hda_spdif_out *spdif; + struct hda_bus *bus = codec->bus; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch"); + if (bus->primary_dig_out_type == HDA_PCM_TYPE_HDMI && + type == HDA_PCM_TYPE_SPDIF) { + idx = spdif_index; + } else if (bus->primary_dig_out_type == HDA_PCM_TYPE_SPDIF && + type == HDA_PCM_TYPE_HDMI) { + /* suppose a single SPDIF device */ + for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { + kctl = find_mixer_ctl(codec, dig_mix->name, 0, 0); + if (!kctl) + break; + kctl->id.index = spdif_index; + } + bus->primary_dig_out_type = HDA_PCM_TYPE_HDMI; + } + if (!bus->primary_dig_out_type) + bus->primary_dig_out_type = type; + + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Playback Switch", idx); if (idx < 0) { - printk(KERN_ERR "hda_codec: too many IEC958 outputs\n"); + codec_err(codec, "too many IEC958 outputs\n"); return -EBUSY; } spdif = snd_array_new(&codec->spdif_out); + if (!spdif) + return -ENOMEM; for (dig_mix = dig_mixes; dig_mix->name; dig_mix++) { kctl = snd_ctl_new1(dig_mix, codec); if (!kctl) @@ -3174,7 +3547,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, spdif->status = convert_to_spdif_status(spdif->ctls); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); +EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls); /* get the hda_spdif_out entry from the given NID * call within spdif_mutex lock @@ -3191,7 +3564,7 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, } return NULL; } -EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); +EXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid); void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) { @@ -3202,7 +3575,7 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) spdif->nid = (u16)-1; mutex_unlock(&codec->spdif_mutex); } -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign); +EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign); void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) { @@ -3218,7 +3591,7 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) } mutex_unlock(&codec->spdif_mutex); } -EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_assign); +EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_assign); /* * SPDIF sharing with analog output @@ -3255,13 +3628,18 @@ static struct snd_kcontrol_new spdif_share_sw = { int snd_hda_create_spdif_share_sw(struct hda_codec *codec, struct hda_multi_out *mout) { + struct snd_kcontrol *kctl; + if (!mout->dig_out_nid) return 0; + + kctl = snd_ctl_new1(&spdif_share_sw, mout); + if (!kctl) + return -ENOMEM; /* ATTENTION: here mout is passed as private_data, instead of codec */ - return snd_hda_ctl_add(codec, mout->dig_out_nid, - snd_ctl_new1(&spdif_share_sw, mout)); + return snd_hda_ctl_add(codec, mout->dig_out_nid, kctl); } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_share_sw); /* * SPDIF input @@ -3349,9 +3727,9 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) struct snd_kcontrol_new *dig_mix; int idx; - idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch"); + idx = find_empty_mixer_ctl_idx(codec, "IEC958 Capture Switch", 0); if (idx < 0) { - printk(KERN_ERR "hda_codec: too many IEC958 inputs\n"); + codec_err(codec, "too many IEC958 inputs\n"); return -EBUSY; } for (dig_mix = dig_in_ctls; dig_mix->name; dig_mix++) { @@ -3369,14 +3747,13 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) AC_DIG1_ENABLE; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); +EXPORT_SYMBOL_GPL(snd_hda_create_spdif_in_ctls); -#ifdef CONFIG_PM /* * command cache */ -/* build a 32bit cache key with the widget id and the command parameter */ +/* build a 31bit cache key with the widget id and the command parameter */ #define build_cmd_cache_key(nid, verb) ((verb << 8) | nid) #define get_cmd_cache_nid(key) ((key) & 0xff) #define get_cmd_cache_cmd(key) (((key) >> 8) & 0xffff) @@ -3385,7 +3762,7 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); * snd_hda_codec_write_cache - send a single command with caching * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -3394,32 +3771,40 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); * Returns 0 if successful, or a negative error code. */ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm) + int flags, unsigned int verb, unsigned int parm) { - int err = snd_hda_codec_write(codec, nid, direct, verb, parm); + int err; struct hda_cache_head *c; u32 key; + unsigned int cache_only; + + cache_only = codec->cached_write; + if (!cache_only) { + err = snd_hda_codec_write(codec, nid, flags, verb, parm); + if (err < 0) + return err; + } - if (err < 0) - return err; /* parm may contain the verb stuff for get/set amp */ verb = verb | (parm >> 8); parm &= 0xff; key = build_cmd_cache_key(nid, verb); mutex_lock(&codec->bus->cmd_mutex); c = get_alloc_hash(&codec->cmd_cache, key); - if (c) + if (c) { c->val = parm; + c->dirty = cache_only; + } mutex_unlock(&codec->bus->cmd_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); +EXPORT_SYMBOL_GPL(snd_hda_codec_write_cache); /** * snd_hda_codec_update_cache - check cache and write the cmd only when needed * @codec: the HDA codec * @nid: NID to send the command - * @direct: direct flag + * @flags: optional bit flags * @verb: the verb to send * @parm: the parameter for the verb * @@ -3430,7 +3815,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); * Returns 0 if successful, or a negative error code. */ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm) + int flags, unsigned int verb, unsigned int parm) { struct hda_cache_head *c; u32 key; @@ -3446,9 +3831,9 @@ int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, return 0; } mutex_unlock(&codec->bus->cmd_mutex); - return snd_hda_codec_write_cache(codec, nid, direct, verb, parm); + return snd_hda_codec_write_cache(codec, nid, flags, verb, parm); } -EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); +EXPORT_SYMBOL_GPL(snd_hda_codec_update_cache); /** * snd_hda_codec_resume_cache - Resume the all commands from the cache @@ -3458,18 +3843,29 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_update_cache); */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { - struct hda_cache_head *buffer = codec->cmd_cache.buf.list; int i; - for (i = 0; i < codec->cmd_cache.buf.used; i++, buffer++) { - u32 key = buffer->key; + mutex_lock(&codec->hash_mutex); + codec->cached_write = 0; + for (i = 0; i < codec->cmd_cache.buf.used; i++) { + struct hda_cache_head *buffer; + u32 key; + + buffer = snd_array_elem(&codec->cmd_cache.buf, i); + key = buffer->key; if (!key) continue; + if (!buffer->dirty) + continue; + buffer->dirty = 0; + mutex_unlock(&codec->hash_mutex); snd_hda_codec_write(codec, get_cmd_cache_nid(key), 0, get_cmd_cache_cmd(key), buffer->val); + mutex_lock(&codec->hash_mutex); } + mutex_unlock(&codec->hash_mutex); } -EXPORT_SYMBOL_HDA(snd_hda_codec_resume_cache); +EXPORT_SYMBOL_GPL(snd_hda_codec_resume_cache); /** * snd_hda_sequence_write_cache - sequence writes with caching @@ -3487,36 +3883,40 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, snd_hda_codec_write_cache(codec, seq->nid, 0, seq->verb, seq->param); } -EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); -#endif /* CONFIG_PM */ +EXPORT_SYMBOL_GPL(snd_hda_sequence_write_cache); + +/** + * snd_hda_codec_flush_cache - Execute all pending (cached) amps / verbs + * @codec: HD-audio codec + */ +void snd_hda_codec_flush_cache(struct hda_codec *codec) +{ + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache); void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround) + unsigned int power_state) { hda_nid_t nid = codec->start_nid; int i; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); + unsigned int state = power_state; if (!(wcaps & AC_WCAP_POWER)) continue; - /* don't power down the widget if it controls eapd and - * EAPD_BTLENABLE is set. - */ - if (eapd_workaround && power_state == AC_PWRST_D3 && - get_wcaps_type(wcaps) == AC_WID_PIN && - (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { - int eapd = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_EAPD_BTLENABLE, 0); - if (eapd & 0x02) + if (codec->power_filter) { + state = codec->power_filter(codec, nid, power_state); + if (state != power_state && power_state == AC_PWRST_D3) continue; } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, - power_state); + state); } } -EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); +EXPORT_SYMBOL_GPL(snd_hda_codec_set_power_to_all); /* * supported power states check @@ -3560,6 +3960,25 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec, return state; } +/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */ +unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + if (nid == codec->afg || nid == codec->mfg) + return power_state; + if (power_state == AC_PWRST_D3 && + get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_PIN && + (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { + int eapd = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_EAPD_BTLENABLE, 0); + if (eapd & 0x02) + return AC_PWRST_D0; + } + return power_state; +} +EXPORT_SYMBOL_GPL(snd_hda_codec_eapd_power_filter); + /* * set power state of the codec, and return the power state */ @@ -3569,11 +3988,15 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, hda_nid_t fg = codec->afg ? codec->afg : codec->mfg; int count; unsigned int state; + int flags = 0; /* this delay seems necessary to avoid click noise at power-down */ if (power_state == AC_PWRST_D3) { - /* transition time less than 10ms for power down */ - msleep(codec->epss ? 10 : 100); + if (codec->depop_delay < 0) + msleep(codec->epss ? 10 : 100); + else if (codec->depop_delay > 0) + msleep(codec->depop_delay); + flags = HDA_RW_NO_RESPONSE_FALLBACK; } /* repeat power states setting at most 10 times*/ @@ -3582,11 +4005,14 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, codec->patch_ops.set_power_state(codec, fg, power_state); else { - snd_hda_codec_read(codec, fg, 0, - AC_VERB_SET_POWER_STATE, - power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state, - true); + state = power_state; + if (codec->power_filter) + state = codec->power_filter(codec, fg, state); + if (state == power_state || power_state != AC_PWRST_D3) + snd_hda_codec_read(codec, fg, flags, + AC_VERB_SET_POWER_STATE, + state); + snd_hda_codec_set_power_to_all(codec, fg, power_state); } state = hda_sync_power_state(codec, fg, power_state); if (!(state & AC_PWRST_ERROR)) @@ -3596,7 +4022,33 @@ static unsigned int hda_set_power_state(struct hda_codec *codec, return state; } -#ifdef CONFIG_SND_HDA_HWDEP +/* sync power states of all widgets; + * this is called at the end of codec parsing + */ +static void sync_power_up_states(struct hda_codec *codec) +{ + hda_nid_t nid = codec->start_nid; + int i; + + /* don't care if no filter is used */ + if (!codec->power_filter) + return; + + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int target; + if (!(wcaps & AC_WCAP_POWER)) + continue; + target = codec->power_filter(codec, nid, AC_PWRST_D0); + if (target == AC_PWRST_D0) + continue; + if (!snd_hda_check_power_state(codec, nid, target)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, target); + } +} + +#ifdef CONFIG_SND_HDA_RECONFIG /* execute additional init verbs */ static void hda_exec_init_verbs(struct hda_codec *codec) { @@ -3616,6 +4068,8 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) { unsigned int state; + codec->in_pm = 1; + if (codec->patch_ops.suspend) codec->patch_ops.suspend(codec); hda_cleanup_all_streams(codec); @@ -3630,20 +4084,40 @@ static unsigned int hda_call_codec_suspend(struct hda_codec *codec, bool in_wq) codec->power_transition = 0; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); + codec->in_pm = 0; return state; } +/* mark all entries of cmd and amp caches dirty */ +static void hda_mark_cmd_cache_dirty(struct hda_codec *codec) +{ + int i; + for (i = 0; i < codec->cmd_cache.buf.used; i++) { + struct hda_cache_head *cmd; + cmd = snd_array_elem(&codec->cmd_cache.buf, i); + cmd->dirty = 1; + } + for (i = 0; i < codec->amp_cache.buf.used; i++) { + struct hda_amp_info *amp; + amp = snd_array_elem(&codec->amp_cache.buf, i); + amp->head.dirty = 1; + } +} + /* * kick up codec; used both from PM and power-save */ static void hda_call_codec_resume(struct hda_codec *codec) { + codec->in_pm = 1; + + hda_mark_cmd_cache_dirty(codec); + /* set as if powered on for avoiding re-entering the resume * in the resume / power-save sequence */ hda_keep_power_on(codec); hda_set_power_state(codec, AC_PWRST_D0); - restore_pincfgs(codec); /* restore all current pin configs */ restore_shutup_pins(codec); hda_exec_init_verbs(codec); snd_hda_jack_set_dirty_all(codec); @@ -3655,7 +4129,13 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); } - snd_hda_jack_report_sync(codec); + + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else + snd_hda_jack_report_sync(codec); + + codec->in_pm = 0; snd_hda_power_down(codec); /* flag down before returning */ } #endif /* CONFIG_PM */ @@ -3669,26 +4149,27 @@ static void hda_call_codec_resume(struct hda_codec *codec) * * Returns 0 if successful, otherwise a negative error code. */ -int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) +int snd_hda_build_controls(struct hda_bus *bus) { struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) { - printk(KERN_ERR "hda_codec: cannot build controls " - "for #%d (error %d)\n", codec->addr, err); + codec_err(codec, + "cannot build controls for #%d (error %d)\n", + codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { - printk(KERN_ERR - "hda_codec: cannot revert codec\n"); + codec_err(codec, + "cannot revert codec\n"); return err; } } } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_build_controls); +EXPORT_SYMBOL_GPL(snd_hda_build_controls); /* * add standard channel maps if not specified @@ -3703,13 +4184,14 @@ static int add_std_chmaps(struct hda_codec *codec) struct hda_pcm_stream *hinfo = &codec->pcm_info[i].stream[str]; struct snd_pcm_chmap *chmap; + const struct snd_pcm_chmap_elem *elem; if (codec->pcm_info[i].own_chmap) continue; if (!pcm || !hinfo->substreams) continue; - err = snd_pcm_add_chmap_ctls(pcm, str, - snd_pcm_std_chmaps, + elem = hinfo->chmap ? hinfo->chmap : snd_pcm_std_chmaps; + err = snd_pcm_add_chmap_ctls(pcm, str, elem, hinfo->channels_max, 0, &chmap); if (err < 0) @@ -3720,6 +4202,19 @@ static int add_std_chmaps(struct hda_codec *codec) return 0; } +/* default channel maps for 2.1 speakers; + * since HD-audio supports only stereo, odd number channels are omitted + */ +const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, + SNDRV_CHMAP_LFE, SNDRV_CHMAP_LFE } }, + { } +}; +EXPORT_SYMBOL_GPL(snd_pcm_2_1_chmaps); + int snd_hda_codec_build_controls(struct hda_codec *codec) { int err = 0; @@ -3737,7 +4232,11 @@ int snd_hda_codec_build_controls(struct hda_codec *codec) if (err < 0) return err; - snd_hda_jack_report_sync(codec); /* call at the last init point */ + if (codec->jackpoll_interval) + hda_jackpoll_work(&codec->jackpoll_work.work); + else + snd_hda_jack_report_sync(codec); /* call at the last init point */ + sync_power_up_states(codec); return 0; } @@ -3834,7 +4333,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, break; default: snd_printdd("invalid format width %d\n", - snd_pcm_format_width(format)); + snd_pcm_format_width(format)); return 0; } @@ -3843,7 +4342,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, return val; } -EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); +EXPORT_SYMBOL_GPL(snd_hda_calc_stream_format); static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid, int dir) @@ -3910,10 +4409,10 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, rates |= rate_bits[i].alsa_bits; } if (rates == 0) { - snd_printk(KERN_ERR "hda_codec: rates == 0 " - "(nid=0x%x, val=0x%x, ovrd=%i)\n", - nid, val, - (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); + codec_err(codec, + "rates == 0 (nid=0x%x, val=0x%x, ovrd=%i)\n", + nid, val, + (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0); return -EIO; } *ratesp = rates; @@ -3973,12 +4472,11 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, bps = 8; } if (formats == 0) { - snd_printk(KERN_ERR "hda_codec: formats == 0 " - "(nid=0x%x, val=0x%x, ovrd=%i, " - "streams=0x%x)\n", - nid, val, - (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, - streams); + codec_err(codec, + "formats == 0 (nid=0x%x, val=0x%x, ovrd=%i, streams=0x%x)\n", + nid, val, + (wcaps & AC_WCAP_FORMAT_OVRD) ? 1 : 0, + streams); return -EIO; } if (formatsp) @@ -3989,7 +4487,7 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, return 0; } -EXPORT_SYMBOL_HDA(snd_hda_query_supported_pcm); +EXPORT_SYMBOL_GPL(snd_hda_query_supported_pcm); /** * snd_hda_is_supported_format - Check the validity of the format @@ -4056,7 +4554,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, return 1; } -EXPORT_SYMBOL_HDA(snd_hda_is_supported_format); +EXPORT_SYMBOL_GPL(snd_hda_is_supported_format); /* * PCM stuff @@ -4134,7 +4632,7 @@ int snd_hda_codec_prepare(struct hda_codec *codec, mutex_unlock(&codec->bus->prepare_mutex); return ret; } -EXPORT_SYMBOL_HDA(snd_hda_codec_prepare); +EXPORT_SYMBOL_GPL(snd_hda_codec_prepare); void snd_hda_codec_cleanup(struct hda_codec *codec, struct hda_pcm_stream *hinfo, @@ -4144,7 +4642,7 @@ void snd_hda_codec_cleanup(struct hda_codec *codec, hinfo->ops.cleanup(hinfo, codec, substream); mutex_unlock(&codec->bus->prepare_mutex); } -EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup); +EXPORT_SYMBOL_GPL(snd_hda_codec_cleanup); /* global */ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { @@ -4153,12 +4651,13 @@ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { /* * get the empty PCM device number to assign - * - * note the max device number is limited by HDA_MAX_PCMS, currently 10 */ -static int get_empty_pcm_device(struct hda_bus *bus, int type) +static int get_empty_pcm_device(struct hda_bus *bus, unsigned int type) { /* audio device indices; not linear to keep compatibility */ + /* assigned to static slots up to dev#10; if more needed, assign + * the later slot dynamically (when CONFIG_SND_DYNAMIC_MINORS=y) + */ static int audio_idx[HDA_PCM_NTYPES][5] = { [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, @@ -4168,22 +4667,33 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) int i; if (type >= HDA_PCM_NTYPES) { - snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); + dev_err(bus->card->dev, "Invalid PCM type %d\n", type); return -EINVAL; } - for (i = 0; audio_idx[type][i] >= 0 ; i++) + for (i = 0; audio_idx[type][i] >= 0; i++) { +#ifndef CONFIG_SND_DYNAMIC_MINORS + if (audio_idx[type][i] >= 8) + break; +#endif if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) return audio_idx[type][i]; + } +#ifdef CONFIG_SND_DYNAMIC_MINORS /* non-fixed slots starting from 10 */ for (i = 10; i < 32; i++) { if (!test_and_set_bit(i, bus->pcm_dev_bits)) return i; } +#endif - snd_printk(KERN_WARNING "Too many %s devices\n", + dev_warn(bus->card->dev, "Too many %s devices\n", snd_hda_pcm_type_name[type]); +#ifndef CONFIG_SND_DYNAMIC_MINORS + dev_warn(bus->card->dev, + "Consider building the kernel with CONFIG_SND_DYNAMIC_MINORS=y\n"); +#endif return -EAGAIN; } @@ -4220,12 +4730,13 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) return 0; err = codec->patch_ops.build_pcms(codec); if (err < 0) { - printk(KERN_ERR "hda_codec: cannot build PCMs" - "for #%d (error %d)\n", codec->addr, err); + codec_err(codec, + "cannot build PCMs for #%d (error %d)\n", + codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { - printk(KERN_ERR - "hda_codec: cannot revert codec\n"); + codec_err(codec, + "cannot revert codec\n"); return err; } } @@ -4244,9 +4755,9 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) cpcm->device = dev; err = snd_hda_attach_pcm(codec, cpcm); if (err < 0) { - printk(KERN_ERR "hda_codec: cannot attach " - "PCM stream %d for codec #%d\n", - dev, codec->addr); + codec_err(codec, + "cannot attach PCM stream %d for codec #%d\n", + dev, codec->addr); continue; /* no fatal error */ } } @@ -4291,7 +4802,7 @@ int snd_hda_build_pcms(struct hda_bus *bus) } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_build_pcms); +EXPORT_SYMBOL_GPL(snd_hda_build_pcms); /** * snd_hda_check_board_config - compare the current codec with the config table @@ -4315,8 +4826,8 @@ int snd_hda_check_board_config(struct hda_codec *codec, for (i = 0; i < num_configs; i++) { if (models[i] && !strcmp(codec->modelname, models[i])) { - snd_printd(KERN_INFO "hda_codec: model '%s' is " - "selected\n", models[i]); + codec_info(codec, "model '%s' is selected\n", + models[i]); return i; } } @@ -4338,16 +4849,15 @@ int snd_hda_check_board_config(struct hda_codec *codec, 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")); + codec_info(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_config); +EXPORT_SYMBOL_GPL(snd_hda_check_board_config); /** * snd_hda_check_board_codec_sid_config - compare the current codec @@ -4399,16 +4909,15 @@ int snd_hda_check_board_codec_sid_config(struct hda_codec *codec, 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")); + codec_info(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); +EXPORT_SYMBOL_GPL(snd_hda_check_board_codec_sid_config); /** * snd_hda_add_new_ctls - create controls from the array @@ -4449,7 +4958,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, addr = codec->addr; else if (!idx && !knew->index) { idx = find_empty_mixer_ctl_idx(codec, - knew->name); + knew->name, 0); if (idx <= 0) return err; } else @@ -4458,7 +4967,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); +EXPORT_SYMBOL_GPL(snd_hda_add_new_ctls); #ifdef CONFIG_PM static void hda_power_work(struct work_struct *work) @@ -4481,11 +4990,8 @@ static void hda_power_work(struct work_struct *work) spin_unlock(&codec->power_lock); state = hda_call_codec_suspend(codec, true); - codec->pm_down_notified = 0; - if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) { - codec->pm_down_notified = 1; - hda_call_pm_notify(bus, false); - } + if (!bus->power_keep_link_on && (state & AC_PWRST_CLK_STOP_OK)) + hda_call_pm_notify(codec, false); } static void hda_keep_power_on(struct hda_codec *codec) @@ -4495,6 +5001,7 @@ static void hda_keep_power_on(struct hda_codec *codec) codec->power_on = 1; codec->power_jiffies = jiffies; spin_unlock(&codec->power_lock); + hda_call_pm_notify(codec, true); } /* update the power on/off account with the current jiffies */ @@ -4514,8 +5021,6 @@ void snd_hda_update_power_acct(struct hda_codec *codec) /* call this with codec->power_lock held! */ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) { - struct hda_bus *bus = codec->bus; - /* Return if power_on or transitioning to power_on, unless currently * powering down. */ if ((codec->power_on || codec->power_transition > 0) && @@ -4542,11 +5047,6 @@ static void __snd_hda_power_up(struct hda_codec *codec, bool wait_power_down) codec->power_transition = 1; /* avoid reentrance */ spin_unlock(&codec->power_lock); - if (codec->pm_down_notified) { - codec->pm_down_notified = 0; - hda_call_pm_notify(bus, true); - } - hda_call_codec_resume(codec); spin_lock(&codec->power_lock); @@ -4589,7 +5089,7 @@ void snd_hda_power_save(struct hda_codec *codec, int delta, bool d3wait) __snd_hda_power_down(codec); spin_unlock(&codec->power_lock); } -EXPORT_SYMBOL_HDA(snd_hda_power_save); +EXPORT_SYMBOL_GPL(snd_hda_power_save); /** * snd_hda_check_amp_list_power - Check the amp list and update the power @@ -4639,7 +5139,7 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); +EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power); #endif /* @@ -4663,7 +5163,7 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, chmode[uinfo->value.enumerated.item].channels); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info); /** * snd_hda_ch_mode_get - Get callback helper for the channel mode enum @@ -4684,7 +5184,7 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get); /** * snd_hda_ch_mode_put - Put callback helper for the channel mode enum @@ -4708,7 +5208,7 @@ int snd_hda_ch_mode_put(struct hda_codec *codec, snd_hda_sequence_write_cache(codec, chmode[mode].sequence); return 1; } -EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); +EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put); /* * input MUX helper @@ -4733,7 +5233,7 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, strcpy(uinfo->value.enumerated.name, imux->items[index].label); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); +EXPORT_SYMBOL_GPL(snd_hda_input_mux_info); /** * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum @@ -4758,10 +5258,38 @@ int snd_hda_input_mux_put(struct hda_codec *codec, *cur_val = idx; return 1; } -EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); +EXPORT_SYMBOL_GPL(snd_hda_input_mux_put); /* + * process kcontrol info callback of a simple string enum array + * when @num_items is 0 or @texts is NULL, assume a boolean enum array + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_items, const char * const *texts) +{ + static const char * const texts_default[] = { + "Disabled", "Enabled" + }; + + if (!texts || !num_items) { + num_items = 2; + texts = texts_default; + } + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = num_items; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + texts[uinfo->value.enumerated.item]); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_enum_helper_info); + +/* * Multi-channel / digital-out PCM helper functions */ @@ -4769,10 +5297,20 @@ EXPORT_SYMBOL_HDA(snd_hda_input_mux_put); static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, unsigned int stream_tag, unsigned int format) { - struct hda_spdif_out *spdif = snd_hda_spdif_out_of_nid(codec, nid); - - /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + struct hda_spdif_out *spdif; + unsigned int curr_fmt; + bool reset; + + spdif = snd_hda_spdif_out_of_nid(codec, nid); + curr_fmt = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_STREAM_FORMAT, 0); + reset = codec->spdif_status_reset && + (spdif->ctls & AC_DIG1_ENABLE) && + curr_fmt != format; + + /* turn off SPDIF if needed; otherwise the IEC958 bits won't be + updated */ + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & ~AC_DIG1_ENABLE & 0xff, -1); @@ -4784,7 +5322,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, format); } /* turn on again (if needed) */ - if (codec->spdif_status_reset && (spdif->ctls & AC_DIG1_ENABLE)) + if (reset) set_dig_out_convert(codec, nid, spdif->ctls & 0xff, -1); } @@ -4815,7 +5353,7 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus) codec->patch_ops.reboot_notify(codec); } } -EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify); +EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify); /** * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode @@ -4831,7 +5369,7 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open); /** * snd_hda_multi_out_dig_prepare - prepare the digital out stream @@ -4847,7 +5385,7 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare); /** * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream @@ -4860,7 +5398,7 @@ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup); /** * snd_hda_multi_out_dig_close - release the digital out stream @@ -4873,7 +5411,7 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close); /** * snd_hda_multi_out_analog_open - open analog outputs @@ -4923,7 +5461,7 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, return snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open); /** * snd_hda_multi_out_analog_prepare - Preapre the analog outputs. @@ -4974,11 +5512,6 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, snd_hda_codec_setup_stream(codec, mout->hp_out_nid[i], stream_tag, 0, format); - for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) - if (!mout->no_share_stream && mout->extra_out_nid[i]) - snd_hda_codec_setup_stream(codec, - mout->extra_out_nid[i], - stream_tag, 0, format); /* surrounds */ for (i = 1; i < mout->num_dacs; i++) { @@ -4989,9 +5522,23 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, snd_hda_codec_setup_stream(codec, nids[i], stream_tag, 0, format); } + + /* extra surrounds */ + for (i = 0; i < ARRAY_SIZE(mout->extra_out_nid); i++) { + int ch = 0; + if (!mout->extra_out_nid[i]) + break; + if (chs >= (i + 1) * 2) + ch = i * 2; + else if (!mout->no_share_stream) + break; + snd_hda_codec_setup_stream(codec, mout->extra_out_nid[i], + stream_tag, ch, format); + } + return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare); /** * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out @@ -5022,7 +5569,7 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, mutex_unlock(&codec->spdif_mutex); return 0; } -EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); +EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup); /** * snd_hda_get_default_vref - Get the default (mic) VREF pin bits @@ -5049,25 +5596,64 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin) return AC_PINCTL_VREF_GRD; return AC_PINCTL_VREF_HIZ; } -EXPORT_SYMBOL_HDA(snd_hda_get_default_vref); +EXPORT_SYMBOL_GPL(snd_hda_get_default_vref); -int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, - unsigned int val, bool cached) +/* correct the pin ctl value for matching with the pin cap */ +unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, + hda_nid_t pin, unsigned int val) { - if (val) { - unsigned int cap = snd_hda_query_pin_caps(codec, pin); - if (cap && (val & AC_PINCTL_OUT_EN)) { - if (!(cap & AC_PINCAP_OUT)) - val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - else if ((val & AC_PINCTL_HP_EN) && - !(cap & AC_PINCAP_HP_DRV)) - val &= ~AC_PINCTL_HP_EN; - } - if (cap && (val & AC_PINCTL_IN_EN)) { - if (!(cap & AC_PINCAP_IN)) - val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); + static unsigned int cap_lists[][2] = { + { AC_PINCTL_VREF_100, AC_PINCAP_VREF_100 }, + { AC_PINCTL_VREF_80, AC_PINCAP_VREF_80 }, + { AC_PINCTL_VREF_50, AC_PINCAP_VREF_50 }, + { AC_PINCTL_VREF_GRD, AC_PINCAP_VREF_GRD }, + }; + unsigned int cap; + + if (!val) + return 0; + cap = snd_hda_query_pin_caps(codec, pin); + if (!cap) + return val; /* don't know what to do... */ + + if (val & AC_PINCTL_OUT_EN) { + if (!(cap & AC_PINCAP_OUT)) + val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + else if ((val & AC_PINCTL_HP_EN) && !(cap & AC_PINCAP_HP_DRV)) + val &= ~AC_PINCTL_HP_EN; + } + + if (val & AC_PINCTL_IN_EN) { + if (!(cap & AC_PINCAP_IN)) + val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); + else { + unsigned int vcap, vref; + int i; + vcap = (cap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + vref = val & AC_PINCTL_VREFEN; + for (i = 0; i < ARRAY_SIZE(cap_lists); i++) { + if (vref == cap_lists[i][0] && + !(vcap & cap_lists[i][1])) { + if (i == ARRAY_SIZE(cap_lists) - 1) + vref = AC_PINCTL_VREF_HIZ; + else + vref = cap_lists[i + 1][0]; + } + } + val &= ~AC_PINCTL_VREFEN; + val |= vref; } } + + return val; +} +EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl); + +int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, + unsigned int val, bool cached) +{ + val = snd_hda_correct_pin_ctl(codec, pin, val); + snd_hda_codec_set_pin_target(codec, pin, val); if (cached) return snd_hda_codec_update_cache(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); @@ -5075,7 +5661,7 @@ int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, return snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } -EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl); +EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl); /** * snd_hda_add_imux_item - Add an item to input_mux @@ -5109,7 +5695,7 @@ int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, imux->num_items++; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); +EXPORT_SYMBOL_GPL(snd_hda_add_imux_item); #ifdef CONFIG_PM @@ -5117,6 +5703,17 @@ EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); * power management */ + +static void hda_async_suspend(void *data, async_cookie_t cookie) +{ + hda_call_codec_suspend(data, false); +} + +static void hda_async_resume(void *data, async_cookie_t cookie) +{ + hda_call_codec_resume(data); +} + /** * snd_hda_suspend - suspend the codecs * @bus: the HDA bus @@ -5126,14 +5723,25 @@ EXPORT_SYMBOL_HDA(snd_hda_add_imux_item); int snd_hda_suspend(struct hda_bus *bus) { struct hda_codec *codec; + ASYNC_DOMAIN_EXCLUSIVE(domain); list_for_each_entry(codec, &bus->codec_list, list) { - if (hda_codec_is_power_on(codec)) - hda_call_codec_suspend(codec, false); + cancel_delayed_work_sync(&codec->jackpoll_work); + if (hda_codec_is_power_on(codec)) { + if (bus->num_codecs > 1) + async_schedule_domain(hda_async_suspend, codec, + &domain); + else + hda_call_codec_suspend(codec, false); + } } + + if (bus->num_codecs > 1) + async_synchronize_full_domain(&domain); + return 0; } -EXPORT_SYMBOL_HDA(snd_hda_suspend); +EXPORT_SYMBOL_GPL(snd_hda_suspend); /** * snd_hda_resume - resume the codecs @@ -5144,13 +5752,21 @@ EXPORT_SYMBOL_HDA(snd_hda_suspend); int snd_hda_resume(struct hda_bus *bus) { struct hda_codec *codec; + ASYNC_DOMAIN_EXCLUSIVE(domain); list_for_each_entry(codec, &bus->codec_list, list) { - hda_call_codec_resume(codec); + if (bus->num_codecs > 1) + async_schedule_domain(hda_async_resume, codec, &domain); + else + hda_call_codec_resume(codec); } + + if (bus->num_codecs > 1) + async_synchronize_full_domain(&domain); + return 0; } -EXPORT_SYMBOL_HDA(snd_hda_resume); +EXPORT_SYMBOL_GPL(snd_hda_resume); #endif /* CONFIG_PM */ /* @@ -5173,20 +5789,18 @@ void *snd_array_new(struct snd_array *array) if (array->used >= array->alloced) { int num = array->alloced + array->alloc_align; int size = (num + 1) * array->elem_size; - int oldsize = array->alloced * array->elem_size; void *nlist; if (snd_BUG_ON(num >= 4096)) return NULL; - nlist = krealloc(array->list, size, GFP_KERNEL); + nlist = krealloc(array->list, size, GFP_KERNEL | __GFP_ZERO); if (!nlist) return NULL; - memset(nlist + oldsize, 0, size - oldsize); array->list = nlist; array->alloced = num; } return snd_array_elem(array, array->used++); } -EXPORT_SYMBOL_HDA(snd_array_new); +EXPORT_SYMBOL_GPL(snd_array_new); /** * snd_array_free - free the given array elements @@ -5199,7 +5813,7 @@ void snd_array_free(struct snd_array *array) array->alloced = 0; array->list = NULL; } -EXPORT_SYMBOL_HDA(snd_array_free); +EXPORT_SYMBOL_GPL(snd_array_free); /** * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer @@ -5220,7 +5834,7 @@ void snd_print_pcm_bits(int pcm, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -EXPORT_SYMBOL_HDA(snd_print_pcm_bits); +EXPORT_SYMBOL_GPL(snd_print_pcm_bits); MODULE_DESCRIPTION("HDA codec core"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 507fe8a917b..5825aa17d8e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -25,537 +25,7 @@ #include <sound/control.h> #include <sound/pcm.h> #include <sound/hwdep.h> - -/* - * nodes - */ -#define AC_NODE_ROOT 0x00 - -/* - * function group types - */ -enum { - AC_GRP_AUDIO_FUNCTION = 0x01, - AC_GRP_MODEM_FUNCTION = 0x02, -}; - -/* - * widget types - */ -enum { - AC_WID_AUD_OUT, /* Audio Out */ - AC_WID_AUD_IN, /* Audio In */ - AC_WID_AUD_MIX, /* Audio Mixer */ - AC_WID_AUD_SEL, /* Audio Selector */ - AC_WID_PIN, /* Pin Complex */ - AC_WID_POWER, /* Power */ - AC_WID_VOL_KNB, /* Volume Knob */ - AC_WID_BEEP, /* Beep Generator */ - AC_WID_VENDOR = 0x0f /* Vendor specific */ -}; - -/* - * GET verbs - */ -#define AC_VERB_GET_STREAM_FORMAT 0x0a00 -#define AC_VERB_GET_AMP_GAIN_MUTE 0x0b00 -#define AC_VERB_GET_PROC_COEF 0x0c00 -#define AC_VERB_GET_COEF_INDEX 0x0d00 -#define AC_VERB_PARAMETERS 0x0f00 -#define AC_VERB_GET_CONNECT_SEL 0x0f01 -#define AC_VERB_GET_CONNECT_LIST 0x0f02 -#define AC_VERB_GET_PROC_STATE 0x0f03 -#define AC_VERB_GET_SDI_SELECT 0x0f04 -#define AC_VERB_GET_POWER_STATE 0x0f05 -#define AC_VERB_GET_CONV 0x0f06 -#define AC_VERB_GET_PIN_WIDGET_CONTROL 0x0f07 -#define AC_VERB_GET_UNSOLICITED_RESPONSE 0x0f08 -#define AC_VERB_GET_PIN_SENSE 0x0f09 -#define AC_VERB_GET_BEEP_CONTROL 0x0f0a -#define AC_VERB_GET_EAPD_BTLENABLE 0x0f0c -#define AC_VERB_GET_DIGI_CONVERT_1 0x0f0d -#define AC_VERB_GET_DIGI_CONVERT_2 0x0f0e /* unused */ -#define AC_VERB_GET_VOLUME_KNOB_CONTROL 0x0f0f -/* f10-f1a: GPIO */ -#define AC_VERB_GET_GPIO_DATA 0x0f15 -#define AC_VERB_GET_GPIO_MASK 0x0f16 -#define AC_VERB_GET_GPIO_DIRECTION 0x0f17 -#define AC_VERB_GET_GPIO_WAKE_MASK 0x0f18 -#define AC_VERB_GET_GPIO_UNSOLICITED_RSP_MASK 0x0f19 -#define AC_VERB_GET_GPIO_STICKY_MASK 0x0f1a -#define AC_VERB_GET_CONFIG_DEFAULT 0x0f1c -/* f20: AFG/MFG */ -#define AC_VERB_GET_SUBSYSTEM_ID 0x0f20 -#define AC_VERB_GET_CVT_CHAN_COUNT 0x0f2d -#define AC_VERB_GET_HDMI_DIP_SIZE 0x0f2e -#define AC_VERB_GET_HDMI_ELDD 0x0f2f -#define AC_VERB_GET_HDMI_DIP_INDEX 0x0f30 -#define AC_VERB_GET_HDMI_DIP_DATA 0x0f31 -#define AC_VERB_GET_HDMI_DIP_XMIT 0x0f32 -#define AC_VERB_GET_HDMI_CP_CTRL 0x0f33 -#define AC_VERB_GET_HDMI_CHAN_SLOT 0x0f34 - -/* - * SET verbs - */ -#define AC_VERB_SET_STREAM_FORMAT 0x200 -#define AC_VERB_SET_AMP_GAIN_MUTE 0x300 -#define AC_VERB_SET_PROC_COEF 0x400 -#define AC_VERB_SET_COEF_INDEX 0x500 -#define AC_VERB_SET_CONNECT_SEL 0x701 -#define AC_VERB_SET_PROC_STATE 0x703 -#define AC_VERB_SET_SDI_SELECT 0x704 -#define AC_VERB_SET_POWER_STATE 0x705 -#define AC_VERB_SET_CHANNEL_STREAMID 0x706 -#define AC_VERB_SET_PIN_WIDGET_CONTROL 0x707 -#define AC_VERB_SET_UNSOLICITED_ENABLE 0x708 -#define AC_VERB_SET_PIN_SENSE 0x709 -#define AC_VERB_SET_BEEP_CONTROL 0x70a -#define AC_VERB_SET_EAPD_BTLENABLE 0x70c -#define AC_VERB_SET_DIGI_CONVERT_1 0x70d -#define AC_VERB_SET_DIGI_CONVERT_2 0x70e -#define AC_VERB_SET_VOLUME_KNOB_CONTROL 0x70f -#define AC_VERB_SET_GPIO_DATA 0x715 -#define AC_VERB_SET_GPIO_MASK 0x716 -#define AC_VERB_SET_GPIO_DIRECTION 0x717 -#define AC_VERB_SET_GPIO_WAKE_MASK 0x718 -#define AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK 0x719 -#define AC_VERB_SET_GPIO_STICKY_MASK 0x71a -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_0 0x71c -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_1 0x71d -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_2 0x71e -#define AC_VERB_SET_CONFIG_DEFAULT_BYTES_3 0x71f -#define AC_VERB_SET_EAPD 0x788 -#define AC_VERB_SET_CODEC_RESET 0x7ff -#define AC_VERB_SET_CVT_CHAN_COUNT 0x72d -#define AC_VERB_SET_HDMI_DIP_INDEX 0x730 -#define AC_VERB_SET_HDMI_DIP_DATA 0x731 -#define AC_VERB_SET_HDMI_DIP_XMIT 0x732 -#define AC_VERB_SET_HDMI_CP_CTRL 0x733 -#define AC_VERB_SET_HDMI_CHAN_SLOT 0x734 - -/* - * Parameter IDs - */ -#define AC_PAR_VENDOR_ID 0x00 -#define AC_PAR_SUBSYSTEM_ID 0x01 -#define AC_PAR_REV_ID 0x02 -#define AC_PAR_NODE_COUNT 0x04 -#define AC_PAR_FUNCTION_TYPE 0x05 -#define AC_PAR_AUDIO_FG_CAP 0x08 -#define AC_PAR_AUDIO_WIDGET_CAP 0x09 -#define AC_PAR_PCM 0x0a -#define AC_PAR_STREAM 0x0b -#define AC_PAR_PIN_CAP 0x0c -#define AC_PAR_AMP_IN_CAP 0x0d -#define AC_PAR_CONNLIST_LEN 0x0e -#define AC_PAR_POWER_STATE 0x0f -#define AC_PAR_PROC_CAP 0x10 -#define AC_PAR_GPIO_CAP 0x11 -#define AC_PAR_AMP_OUT_CAP 0x12 -#define AC_PAR_VOL_KNB_CAP 0x13 -#define AC_PAR_HDMI_LPCM_CAP 0x20 - -/* - * AC_VERB_PARAMETERS results (32bit) - */ - -/* Function Group Type */ -#define AC_FGT_TYPE (0xff<<0) -#define AC_FGT_TYPE_SHIFT 0 -#define AC_FGT_UNSOL_CAP (1<<8) - -/* Audio Function Group Capabilities */ -#define AC_AFG_OUT_DELAY (0xf<<0) -#define AC_AFG_IN_DELAY (0xf<<8) -#define AC_AFG_BEEP_GEN (1<<16) - -/* Audio Widget Capabilities */ -#define AC_WCAP_STEREO (1<<0) /* stereo I/O */ -#define AC_WCAP_IN_AMP (1<<1) /* AMP-in present */ -#define AC_WCAP_OUT_AMP (1<<2) /* AMP-out present */ -#define AC_WCAP_AMP_OVRD (1<<3) /* AMP-parameter override */ -#define AC_WCAP_FORMAT_OVRD (1<<4) /* format override */ -#define AC_WCAP_STRIPE (1<<5) /* stripe */ -#define AC_WCAP_PROC_WID (1<<6) /* Proc Widget */ -#define AC_WCAP_UNSOL_CAP (1<<7) /* Unsol capable */ -#define AC_WCAP_CONN_LIST (1<<8) /* connection list */ -#define AC_WCAP_DIGITAL (1<<9) /* digital I/O */ -#define AC_WCAP_POWER (1<<10) /* power control */ -#define AC_WCAP_LR_SWAP (1<<11) /* L/R swap */ -#define AC_WCAP_CP_CAPS (1<<12) /* content protection */ -#define AC_WCAP_CHAN_CNT_EXT (7<<13) /* channel count ext */ -#define AC_WCAP_DELAY (0xf<<16) -#define AC_WCAP_DELAY_SHIFT 16 -#define AC_WCAP_TYPE (0xf<<20) -#define AC_WCAP_TYPE_SHIFT 20 - -/* supported PCM rates and bits */ -#define AC_SUPPCM_RATES (0xfff << 0) -#define AC_SUPPCM_BITS_8 (1<<16) -#define AC_SUPPCM_BITS_16 (1<<17) -#define AC_SUPPCM_BITS_20 (1<<18) -#define AC_SUPPCM_BITS_24 (1<<19) -#define AC_SUPPCM_BITS_32 (1<<20) - -/* supported PCM stream format */ -#define AC_SUPFMT_PCM (1<<0) -#define AC_SUPFMT_FLOAT32 (1<<1) -#define AC_SUPFMT_AC3 (1<<2) - -/* GP I/O count */ -#define AC_GPIO_IO_COUNT (0xff<<0) -#define AC_GPIO_O_COUNT (0xff<<8) -#define AC_GPIO_O_COUNT_SHIFT 8 -#define AC_GPIO_I_COUNT (0xff<<16) -#define AC_GPIO_I_COUNT_SHIFT 16 -#define AC_GPIO_UNSOLICITED (1<<30) -#define AC_GPIO_WAKE (1<<31) - -/* Converter stream, channel */ -#define AC_CONV_CHANNEL (0xf<<0) -#define AC_CONV_STREAM (0xf<<4) -#define AC_CONV_STREAM_SHIFT 4 - -/* Input converter SDI select */ -#define AC_SDI_SELECT (0xf<<0) - -/* stream format id */ -#define AC_FMT_CHAN_SHIFT 0 -#define AC_FMT_CHAN_MASK (0x0f << 0) -#define AC_FMT_BITS_SHIFT 4 -#define AC_FMT_BITS_MASK (7 << 4) -#define AC_FMT_BITS_8 (0 << 4) -#define AC_FMT_BITS_16 (1 << 4) -#define AC_FMT_BITS_20 (2 << 4) -#define AC_FMT_BITS_24 (3 << 4) -#define AC_FMT_BITS_32 (4 << 4) -#define AC_FMT_DIV_SHIFT 8 -#define AC_FMT_DIV_MASK (7 << 8) -#define AC_FMT_MULT_SHIFT 11 -#define AC_FMT_MULT_MASK (7 << 11) -#define AC_FMT_BASE_SHIFT 14 -#define AC_FMT_BASE_48K (0 << 14) -#define AC_FMT_BASE_44K (1 << 14) -#define AC_FMT_TYPE_SHIFT 15 -#define AC_FMT_TYPE_PCM (0 << 15) -#define AC_FMT_TYPE_NON_PCM (1 << 15) - -/* Unsolicited response control */ -#define AC_UNSOL_TAG (0x3f<<0) -#define AC_UNSOL_ENABLED (1<<7) -#define AC_USRSP_EN AC_UNSOL_ENABLED - -/* Unsolicited responses */ -#define AC_UNSOL_RES_TAG (0x3f<<26) -#define AC_UNSOL_RES_TAG_SHIFT 26 -#define AC_UNSOL_RES_SUBTAG (0x1f<<21) -#define AC_UNSOL_RES_SUBTAG_SHIFT 21 -#define AC_UNSOL_RES_ELDV (1<<1) /* ELD Data valid (for HDMI) */ -#define AC_UNSOL_RES_PD (1<<0) /* pinsense detect */ -#define AC_UNSOL_RES_CP_STATE (1<<1) /* content protection */ -#define AC_UNSOL_RES_CP_READY (1<<0) /* content protection */ - -/* Pin widget capabilies */ -#define AC_PINCAP_IMP_SENSE (1<<0) /* impedance sense capable */ -#define AC_PINCAP_TRIG_REQ (1<<1) /* trigger required */ -#define AC_PINCAP_PRES_DETECT (1<<2) /* presence detect capable */ -#define AC_PINCAP_HP_DRV (1<<3) /* headphone drive capable */ -#define AC_PINCAP_OUT (1<<4) /* output capable */ -#define AC_PINCAP_IN (1<<5) /* input capable */ -#define AC_PINCAP_BALANCE (1<<6) /* balanced I/O capable */ -/* Note: This LR_SWAP pincap is defined in the Realtek ALC883 specification, - * but is marked reserved in the Intel HDA specification. - */ -#define AC_PINCAP_LR_SWAP (1<<7) /* L/R swap */ -/* Note: The same bit as LR_SWAP is newly defined as HDMI capability - * in HD-audio specification - */ -#define AC_PINCAP_HDMI (1<<7) /* HDMI pin */ -#define AC_PINCAP_DP (1<<24) /* DisplayPort pin, can - * coexist with AC_PINCAP_HDMI - */ -#define AC_PINCAP_VREF (0x37<<8) -#define AC_PINCAP_VREF_SHIFT 8 -#define AC_PINCAP_EAPD (1<<16) /* EAPD capable */ -#define AC_PINCAP_HBR (1<<27) /* High Bit Rate */ -/* Vref status (used in pin cap) */ -#define AC_PINCAP_VREF_HIZ (1<<0) /* Hi-Z */ -#define AC_PINCAP_VREF_50 (1<<1) /* 50% */ -#define AC_PINCAP_VREF_GRD (1<<2) /* ground */ -#define AC_PINCAP_VREF_80 (1<<4) /* 80% */ -#define AC_PINCAP_VREF_100 (1<<5) /* 100% */ - -/* Amplifier capabilities */ -#define AC_AMPCAP_OFFSET (0x7f<<0) /* 0dB offset */ -#define AC_AMPCAP_OFFSET_SHIFT 0 -#define AC_AMPCAP_NUM_STEPS (0x7f<<8) /* number of steps */ -#define AC_AMPCAP_NUM_STEPS_SHIFT 8 -#define AC_AMPCAP_STEP_SIZE (0x7f<<16) /* step size 0-32dB - * in 0.25dB - */ -#define AC_AMPCAP_STEP_SIZE_SHIFT 16 -#define AC_AMPCAP_MUTE (1<<31) /* mute capable */ -#define AC_AMPCAP_MUTE_SHIFT 31 - -/* driver-specific amp-caps: using bits 24-30 */ -#define AC_AMPCAP_MIN_MUTE (1 << 30) /* min-volume = mute */ - -/* Connection list */ -#define AC_CLIST_LENGTH (0x7f<<0) -#define AC_CLIST_LONG (1<<7) - -/* Supported power status */ -#define AC_PWRST_D0SUP (1<<0) -#define AC_PWRST_D1SUP (1<<1) -#define AC_PWRST_D2SUP (1<<2) -#define AC_PWRST_D3SUP (1<<3) -#define AC_PWRST_D3COLDSUP (1<<4) -#define AC_PWRST_S3D3COLDSUP (1<<29) -#define AC_PWRST_CLKSTOP (1<<30) -#define AC_PWRST_EPSS (1U<<31) - -/* Power state values */ -#define AC_PWRST_SETTING (0xf<<0) -#define AC_PWRST_ACTUAL (0xf<<4) -#define AC_PWRST_ACTUAL_SHIFT 4 -#define AC_PWRST_D0 0x00 -#define AC_PWRST_D1 0x01 -#define AC_PWRST_D2 0x02 -#define AC_PWRST_D3 0x03 -#define AC_PWRST_ERROR (1<<8) -#define AC_PWRST_CLK_STOP_OK (1<<9) -#define AC_PWRST_SETTING_RESET (1<<10) - -/* Processing capabilies */ -#define AC_PCAP_BENIGN (1<<0) -#define AC_PCAP_NUM_COEF (0xff<<8) -#define AC_PCAP_NUM_COEF_SHIFT 8 - -/* Volume knobs capabilities */ -#define AC_KNBCAP_NUM_STEPS (0x7f<<0) -#define AC_KNBCAP_DELTA (1<<7) - -/* HDMI LPCM capabilities */ -#define AC_LPCMCAP_48K_CP_CHNS (0x0f<<0) /* max channels w/ CP-on */ -#define AC_LPCMCAP_48K_NO_CHNS (0x0f<<4) /* max channels w/o CP-on */ -#define AC_LPCMCAP_48K_20BIT (1<<8) /* 20b bitrate supported */ -#define AC_LPCMCAP_48K_24BIT (1<<9) /* 24b bitrate supported */ -#define AC_LPCMCAP_96K_CP_CHNS (0x0f<<10) /* max channels w/ CP-on */ -#define AC_LPCMCAP_96K_NO_CHNS (0x0f<<14) /* max channels w/o CP-on */ -#define AC_LPCMCAP_96K_20BIT (1<<18) /* 20b bitrate supported */ -#define AC_LPCMCAP_96K_24BIT (1<<19) /* 24b bitrate supported */ -#define AC_LPCMCAP_192K_CP_CHNS (0x0f<<20) /* max channels w/ CP-on */ -#define AC_LPCMCAP_192K_NO_CHNS (0x0f<<24) /* max channels w/o CP-on */ -#define AC_LPCMCAP_192K_20BIT (1<<28) /* 20b bitrate supported */ -#define AC_LPCMCAP_192K_24BIT (1<<29) /* 24b bitrate supported */ -#define AC_LPCMCAP_44K (1<<30) /* 44.1kHz support */ -#define AC_LPCMCAP_44K_MS (1<<31) /* 44.1kHz-multiplies support */ - -/* - * Control Parameters - */ - -/* Amp gain/mute */ -#define AC_AMP_MUTE (1<<7) -#define AC_AMP_GAIN (0x7f) -#define AC_AMP_GET_INDEX (0xf<<0) - -#define AC_AMP_GET_LEFT (1<<13) -#define AC_AMP_GET_RIGHT (0<<13) -#define AC_AMP_GET_OUTPUT (1<<15) -#define AC_AMP_GET_INPUT (0<<15) - -#define AC_AMP_SET_INDEX (0xf<<8) -#define AC_AMP_SET_INDEX_SHIFT 8 -#define AC_AMP_SET_RIGHT (1<<12) -#define AC_AMP_SET_LEFT (1<<13) -#define AC_AMP_SET_INPUT (1<<14) -#define AC_AMP_SET_OUTPUT (1<<15) - -/* DIGITAL1 bits */ -#define AC_DIG1_ENABLE (1<<0) -#define AC_DIG1_V (1<<1) -#define AC_DIG1_VCFG (1<<2) -#define AC_DIG1_EMPHASIS (1<<3) -#define AC_DIG1_COPYRIGHT (1<<4) -#define AC_DIG1_NONAUDIO (1<<5) -#define AC_DIG1_PROFESSIONAL (1<<6) -#define AC_DIG1_LEVEL (1<<7) - -/* DIGITAL2 bits */ -#define AC_DIG2_CC (0x7f<<0) - -/* DIGITAL3 bits */ -#define AC_DIG3_ICT (0xf<<0) -#define AC_DIG3_KAE (1<<7) - -/* Pin widget control - 8bit */ -#define AC_PINCTL_EPT (0x3<<0) -#define AC_PINCTL_EPT_NATIVE 0 -#define AC_PINCTL_EPT_HBR 3 -#define AC_PINCTL_VREFEN (0x7<<0) -#define AC_PINCTL_VREF_HIZ 0 /* Hi-Z */ -#define AC_PINCTL_VREF_50 1 /* 50% */ -#define AC_PINCTL_VREF_GRD 2 /* ground */ -#define AC_PINCTL_VREF_80 4 /* 80% */ -#define AC_PINCTL_VREF_100 5 /* 100% */ -#define AC_PINCTL_IN_EN (1<<5) -#define AC_PINCTL_OUT_EN (1<<6) -#define AC_PINCTL_HP_EN (1<<7) - -/* Pin sense - 32bit */ -#define AC_PINSENSE_IMPEDANCE_MASK (0x7fffffff) -#define AC_PINSENSE_PRESENCE (1<<31) -#define AC_PINSENSE_ELDV (1<<30) /* ELD valid (HDMI) */ - -/* EAPD/BTL enable - 32bit */ -#define AC_EAPDBTL_BALANCED (1<<0) -#define AC_EAPDBTL_EAPD (1<<1) -#define AC_EAPDBTL_LR_SWAP (1<<2) - -/* HDMI ELD data */ -#define AC_ELDD_ELD_VALID (1<<31) -#define AC_ELDD_ELD_DATA 0xff - -/* HDMI DIP size */ -#define AC_DIPSIZE_ELD_BUF (1<<3) /* ELD buf size of packet size */ -#define AC_DIPSIZE_PACK_IDX (0x07<<0) /* packet index */ - -/* HDMI DIP index */ -#define AC_DIPIDX_PACK_IDX (0x07<<5) /* packet idnex */ -#define AC_DIPIDX_BYTE_IDX (0x1f<<0) /* byte index */ - -/* HDMI DIP xmit (transmit) control */ -#define AC_DIPXMIT_MASK (0x3<<6) -#define AC_DIPXMIT_DISABLE (0x0<<6) /* disable xmit */ -#define AC_DIPXMIT_ONCE (0x2<<6) /* xmit once then disable */ -#define AC_DIPXMIT_BEST (0x3<<6) /* best effort */ - -/* HDMI content protection (CP) control */ -#define AC_CPCTRL_CES (1<<9) /* current encryption state */ -#define AC_CPCTRL_READY (1<<8) /* ready bit */ -#define AC_CPCTRL_SUBTAG (0x1f<<3) /* subtag for unsol-resp */ -#define AC_CPCTRL_STATE (3<<0) /* current CP request state */ - -/* Converter channel <-> HDMI slot mapping */ -#define AC_CVTMAP_HDMI_SLOT (0xf<<0) /* HDMI slot number */ -#define AC_CVTMAP_CHAN (0xf<<4) /* converter channel number */ - -/* configuration default - 32bit */ -#define AC_DEFCFG_SEQUENCE (0xf<<0) -#define AC_DEFCFG_DEF_ASSOC (0xf<<4) -#define AC_DEFCFG_ASSOC_SHIFT 4 -#define AC_DEFCFG_MISC (0xf<<8) -#define AC_DEFCFG_MISC_SHIFT 8 -#define AC_DEFCFG_MISC_NO_PRESENCE (1<<0) -#define AC_DEFCFG_COLOR (0xf<<12) -#define AC_DEFCFG_COLOR_SHIFT 12 -#define AC_DEFCFG_CONN_TYPE (0xf<<16) -#define AC_DEFCFG_CONN_TYPE_SHIFT 16 -#define AC_DEFCFG_DEVICE (0xf<<20) -#define AC_DEFCFG_DEVICE_SHIFT 20 -#define AC_DEFCFG_LOCATION (0x3f<<24) -#define AC_DEFCFG_LOCATION_SHIFT 24 -#define AC_DEFCFG_PORT_CONN (0x3<<30) -#define AC_DEFCFG_PORT_CONN_SHIFT 30 - -/* device device types (0x0-0xf) */ -enum { - AC_JACK_LINE_OUT, - AC_JACK_SPEAKER, - AC_JACK_HP_OUT, - AC_JACK_CD, - AC_JACK_SPDIF_OUT, - AC_JACK_DIG_OTHER_OUT, - AC_JACK_MODEM_LINE_SIDE, - AC_JACK_MODEM_HAND_SIDE, - AC_JACK_LINE_IN, - AC_JACK_AUX, - AC_JACK_MIC_IN, - AC_JACK_TELEPHONY, - AC_JACK_SPDIF_IN, - AC_JACK_DIG_OTHER_IN, - AC_JACK_OTHER = 0xf, -}; - -/* jack connection types (0x0-0xf) */ -enum { - AC_JACK_CONN_UNKNOWN, - AC_JACK_CONN_1_8, - AC_JACK_CONN_1_4, - AC_JACK_CONN_ATAPI, - AC_JACK_CONN_RCA, - AC_JACK_CONN_OPTICAL, - AC_JACK_CONN_OTHER_DIGITAL, - AC_JACK_CONN_OTHER_ANALOG, - AC_JACK_CONN_DIN, - AC_JACK_CONN_XLR, - AC_JACK_CONN_RJ11, - AC_JACK_CONN_COMB, - AC_JACK_CONN_OTHER = 0xf, -}; - -/* jack colors (0x0-0xf) */ -enum { - AC_JACK_COLOR_UNKNOWN, - AC_JACK_COLOR_BLACK, - AC_JACK_COLOR_GREY, - AC_JACK_COLOR_BLUE, - AC_JACK_COLOR_GREEN, - AC_JACK_COLOR_RED, - AC_JACK_COLOR_ORANGE, - AC_JACK_COLOR_YELLOW, - AC_JACK_COLOR_PURPLE, - AC_JACK_COLOR_PINK, - AC_JACK_COLOR_WHITE = 0xe, - AC_JACK_COLOR_OTHER, -}; - -/* Jack location (0x0-0x3f) */ -/* common case */ -enum { - AC_JACK_LOC_NONE, - AC_JACK_LOC_REAR, - AC_JACK_LOC_FRONT, - AC_JACK_LOC_LEFT, - AC_JACK_LOC_RIGHT, - AC_JACK_LOC_TOP, - AC_JACK_LOC_BOTTOM, -}; -/* bits 4-5 */ -enum { - AC_JACK_LOC_EXTERNAL = 0x00, - AC_JACK_LOC_INTERNAL = 0x10, - AC_JACK_LOC_SEPARATE = 0x20, - AC_JACK_LOC_OTHER = 0x30, -}; -enum { - /* external on primary chasis */ - AC_JACK_LOC_REAR_PANEL = 0x07, - AC_JACK_LOC_DRIVE_BAY, - /* internal */ - AC_JACK_LOC_RISER = 0x17, - AC_JACK_LOC_HDMI, - AC_JACK_LOC_ATAPI, - /* others */ - AC_JACK_LOC_MOBILE_IN = 0x37, - AC_JACK_LOC_MOBILE_OUT, -}; - -/* Port connectivity (0-3) */ -enum { - AC_JACK_PORT_COMPLEX, - AC_JACK_PORT_NONE, - AC_JACK_PORT_FIXED, - AC_JACK_PORT_BOTH, -}; - -/* max. connections to a widget */ -#define HDA_MAX_CONNECTIONS 32 - -/* max. codec address */ -#define HDA_MAX_CODEC_ADDRESS 0x0f +#include <sound/hda_verbs.h> /* * generic arrays @@ -618,6 +88,17 @@ struct hda_bus_ops { /* notify power-up/down from codec to controller */ void (*pm_notify)(struct hda_bus *bus, bool power_up); #endif +#ifdef CONFIG_SND_HDA_DSP_LOADER + /* prepare DSP transfer */ + int (*load_dsp_prepare)(struct hda_bus *bus, unsigned int format, + unsigned int byte_size, + struct snd_dma_buffer *bufp); + /* start/stop DSP transfer */ + void (*load_dsp_trigger)(struct hda_bus *bus, bool start); + /* clean up DSP transfer */ + void (*load_dsp_cleanup)(struct hda_bus *bus, + struct snd_dma_buffer *dmab); +#endif }; /* template to pass to the bus constructor */ @@ -647,6 +128,7 @@ struct hda_bus { /* codec linked list */ struct list_head codec_list; + unsigned int num_codecs; /* link caddr -> codec */ struct hda_codec *caddr_tbl[HDA_MAX_CODEC_ADDRESS + 1]; @@ -671,6 +153,9 @@ struct hda_bus { unsigned int response_reset:1; /* controller was reset */ unsigned int in_reset:1; /* during reset operation */ unsigned int power_keep_link_on:1; /* don't power off HDA link */ + unsigned int no_response_fallback:1; /* don't fallback at RIRB error */ + + int primary_dig_out_type; /* primary digital out PCM type */ }; /* @@ -719,9 +204,10 @@ struct hda_codec_ops { /* record for amp information cache */ struct hda_cache_head { - u32 key; /* hash key */ + u32 key:31; /* hash key */ + u32 dirty:1; u16 val; /* assigned value */ - u16 next; /* next link; -1 = terminal */ + u16 next; }; struct hda_amp_info { @@ -746,6 +232,9 @@ struct hda_pcm_ops { struct snd_pcm_substream *substream); int (*cleanup)(struct hda_pcm_stream *info, struct hda_codec *codec, struct snd_pcm_substream *substream); + unsigned int (*get_delay)(struct hda_pcm_stream *info, + struct hda_codec *codec, + struct snd_pcm_substream *substream); }; /* PCM information for each substream */ @@ -757,6 +246,7 @@ struct hda_pcm_stream { u32 rates; /* supported rates */ u64 formats; /* supported formats (SNDRV_PCM_FMTBIT_) */ unsigned int maxbps; /* supported max. bit per sample */ + const struct snd_pcm_chmap_elem *chmap; /* chmap to override */ struct hda_pcm_ops ops; }; @@ -781,6 +271,7 @@ struct hda_pcm { /* codec information */ struct hda_codec { + struct device dev; struct hda_bus *bus; unsigned int addr; /* codec addr*/ struct list_head list; /* list point */ @@ -800,6 +291,7 @@ struct hda_codec { /* detected preset */ const struct hda_codec_preset *preset; struct module *owner; + int (*parser)(struct hda_codec *codec); const char *vendor_name; /* codec vendor name */ const char *chip_name; /* codec chip name */ const char *modelname; /* model name for preset */ @@ -829,7 +321,7 @@ struct hda_codec { struct hda_cache_rec amp_cache; /* cache for amp access */ struct hda_cache_rec cmd_cache; /* cache for other commands */ - struct snd_array conn_lists; /* connection-list array */ + struct list_head conn_list; /* linked-list of connection-list */ struct mutex spdif_mutex; struct mutex control_mutex; @@ -841,13 +333,17 @@ struct hda_codec { struct snd_array driver_pins; /* pin configs set by codec parser */ struct snd_array cvt_setups; /* audio convert setups */ -#ifdef CONFIG_SND_HDA_HWDEP - struct snd_hwdep *hwdep; /* assigned hwdep device */ + struct mutex user_mutex; +#ifdef CONFIG_SND_HDA_RECONFIG struct snd_array init_verbs; /* additional init verbs */ struct snd_array hints; /* additional hints */ struct snd_array user_pins; /* default pin configs to override */ #endif +#ifdef CONFIG_SND_HDA_HWDEP + struct snd_hwdep *hwdep; /* assigned hwdep device */ +#endif + /* misc flags */ unsigned int spdif_status_reset :1; /* needs to toggle SPDIF for each * status change @@ -863,12 +359,18 @@ struct hda_codec { unsigned int pins_shutup:1; /* pins are shut up */ unsigned int no_trigger_sense:1; /* don't trigger at pin-sensing */ unsigned int no_jack_detect:1; /* Machine has no jack-detection */ + unsigned int inv_eapd:1; /* broken h/w: inverted EAPD control */ + unsigned int inv_jack_detect:1; /* broken h/w: inverted detection bit */ unsigned int pcm_format_first:1; /* PCM format must be set first */ unsigned int epss:1; /* supporting EPSS? */ + unsigned int cached_write:1; /* write only to caches */ + unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */ + unsigned int dump_coef:1; /* dump processing coefs in codec proc file */ #ifdef CONFIG_PM unsigned int power_on :1; /* current (global) power-state */ unsigned int d3_stop_clk:1; /* support D3 operation without BCLK */ - unsigned int pm_down_notified:1; /* PM notified to controller */ + unsigned int pm_up_notified:1; /* PM notified to controller */ + unsigned int in_pm:1; /* suspend/resume being performed */ int power_transition; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ @@ -878,17 +380,34 @@ struct hda_codec { spinlock_t power_lock; #endif + /* filter the requested power state per nid */ + unsigned int (*power_filter)(struct hda_codec *codec, hda_nid_t nid, + unsigned int power_state); + /* codec-specific additional proc output */ void (*proc_widget_hook)(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid); /* jack detection */ struct snd_array jacktbl; + unsigned long jackpoll_interval; /* In jiffies. Zero means no poll, rely on unsol events */ + struct delayed_work jackpoll_work; #ifdef CONFIG_SND_HDA_INPUT_JACK /* jack detection */ struct snd_array jacks; #endif + + int depop_delay; /* depop delay in ms, -1 for default delay time */ + + /* fix-up list */ + int fixup_id; + unsigned int fixup_forced:1; /* fixup explicitly set by user */ + const struct hda_fixup *fixup_list; + const char *fixup_name; + + /* additional init verbs */ + struct snd_array verbs; }; /* direction */ @@ -896,6 +415,8 @@ enum { HDA_INPUT, HDA_OUTPUT }; +/* snd_hda_codec_read/write optional flags */ +#define HDA_RW_NO_RESPONSE_FALLBACK (1 << 0) /* * constructors @@ -905,14 +426,15 @@ int snd_hda_bus_new(struct snd_card *card, const struct hda_bus_template *temp, int snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, struct hda_codec **codecp); int snd_hda_codec_configure(struct hda_codec *codec); +int snd_hda_codec_update_widgets(struct hda_codec *codec); /* * low level functions */ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, - int direct, + int flags, unsigned int verb, unsigned int parm); -int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, +int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int flags, unsigned int verb, unsigned int parm); #define snd_hda_param_read(codec, nid, param) \ snd_hda_codec_read(codec, nid, 0, AC_VERB_PARAMETERS, param) @@ -925,12 +447,17 @@ snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_get_connections(codec, nid, NULL, 0); } +int snd_hda_get_num_raw_conns(struct hda_codec *codec, hda_nid_t nid); int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp); int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, const hda_nid_t *list); int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, hda_nid_t nid, int recursive); +int snd_hda_get_devices(struct hda_codec *codec, hda_nid_t nid, + u8 *dev_list, int max_devices); int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, u32 *ratesp, u64 *formatsp, unsigned int *bpsp); @@ -947,25 +474,21 @@ void snd_hda_sequence_write(struct hda_codec *codec, int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ -#ifdef CONFIG_PM int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm); + int flags, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, const struct hda_verb *seq); int snd_hda_codec_update_cache(struct hda_codec *codec, hda_nid_t nid, - int direct, unsigned int verb, unsigned int parm); + int flags, unsigned int verb, unsigned int parm); void snd_hda_codec_resume_cache(struct hda_codec *codec); -#else -#define snd_hda_codec_write_cache snd_hda_codec_write -#define snd_hda_codec_update_cache snd_hda_codec_write -#define snd_hda_sequence_write_cache snd_hda_sequence_write -#endif +/* both for cmd & amp caches */ +void snd_hda_codec_flush_cache(struct hda_codec *codec); /* the struct for codec->pin_configs */ struct hda_pincfg { hda_nid_t nid; - unsigned char ctrl; /* current pin control value */ - unsigned char pad; /* reserved */ + unsigned char ctrl; /* original pin control value */ + unsigned char target; /* target pin control value */ unsigned int cfg; /* default configuration */ }; @@ -1023,14 +546,15 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, unsigned int format); +extern const struct snd_pcm_chmap_elem snd_pcm_2_1_chmaps[]; + /* * Misc */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); void snd_hda_bus_reboot_notify(struct hda_bus *bus); void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround); + unsigned int power_state); int snd_hda_lock_devices(struct hda_bus *bus); void snd_hda_unlock_devices(struct hda_bus *bus); @@ -1129,19 +653,40 @@ static inline void snd_hda_power_sync(struct hda_codec *codec) int snd_hda_load_patch(struct hda_bus *bus, size_t size, const void *buf); #endif -/* - * Codec modularization - */ - -/* Export symbols only for communication with codec drivers; - * When built in kernel, all HD-audio drivers are supposed to be statically - * linked to the kernel. Thus, the symbols don't have to (or shouldn't) be - * exported unless it's built as a module. - */ -#ifdef MODULE -#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) +#ifdef CONFIG_SND_HDA_DSP_LOADER +static inline int +snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, + unsigned int size, + struct snd_dma_buffer *bufp) +{ + return codec->bus->ops.load_dsp_prepare(codec->bus, format, size, bufp); +} +static inline void +snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) +{ + return codec->bus->ops.load_dsp_trigger(codec->bus, start); +} +static inline void +snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, + struct snd_dma_buffer *dmab) +{ + return codec->bus->ops.load_dsp_cleanup(codec->bus, dmab); +} #else -#define EXPORT_SYMBOL_HDA(sym) +static inline int +snd_hda_codec_load_dsp_prepare(struct hda_codec *codec, unsigned int format, + unsigned int size, + struct snd_dma_buffer *bufp) +{ + return -ENOSYS; +} +static inline void +snd_hda_codec_load_dsp_trigger(struct hda_codec *codec, bool start) {} +static inline void +snd_hda_codec_load_dsp_cleanup(struct hda_codec *codec, + struct snd_dma_buffer *dmab) {} #endif +#define EXPORT_SYMBOL_HDA(sym) EXPORT_SYMBOL_GPL(sym) + #endif /* __SOUND_HDA_CODEC_H */ diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c new file mode 100644 index 00000000000..6df04d91c93 --- /dev/null +++ b/sound/pci/hda/hda_controller.c @@ -0,0 +1,2035 @@ +/* + * + * Implementation of primary alsa driver code base for Intel HD Audio. + * + * Copyright(c) 2004 Intel Corporation. All rights reserved. + * + * Copyright (c) 2004 Takashi Iwai <tiwai@suse.de> + * PeiSen Hou <pshou@realtek.com.tw> + * + * 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 Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * + */ + +#include <linux/clocksource.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/pm_runtime.h> +#include <linux/slab.h> +#include <sound/core.h> +#include <sound/initval.h> +#include "hda_priv.h" +#include "hda_controller.h" + +#define CREATE_TRACE_POINTS +#include "hda_intel_trace.h" + +/* DSP lock helpers */ +#ifdef CONFIG_SND_HDA_DSP_LOADER +#define dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex) +#define dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex) +#define dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex) +#define dsp_is_locked(dev) ((dev)->locked) +#else +#define dsp_lock_init(dev) do {} while (0) +#define dsp_lock(dev) do {} while (0) +#define dsp_unlock(dev) do {} while (0) +#define dsp_is_locked(dev) 0 +#endif + +/* + * AZX stream operations. + */ + +/* start a stream */ +static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) +{ + /* + * Before stream start, initialize parameter + */ + azx_dev->insufficient = 1; + + /* enable SIE */ + azx_writel(chip, INTCTL, + azx_readl(chip, INTCTL) | (1 << azx_dev->index)); + /* set DMA start and interrupt mask */ + azx_sd_writeb(chip, azx_dev, SD_CTL, + azx_sd_readb(chip, azx_dev, SD_CTL) | + SD_CTL_DMA_START | SD_INT_MASK); +} + +/* stop DMA */ +static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) +{ + azx_sd_writeb(chip, azx_dev, SD_CTL, + azx_sd_readb(chip, azx_dev, SD_CTL) & + ~(SD_CTL_DMA_START | SD_INT_MASK)); + azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ +} + +/* stop a stream */ +void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) +{ + azx_stream_clear(chip, azx_dev); + /* disable SIE */ + azx_writel(chip, INTCTL, + azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); +} +EXPORT_SYMBOL_GPL(azx_stream_stop); + +/* reset stream */ +static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) +{ + unsigned char val; + int timeout; + + azx_stream_clear(chip, azx_dev); + + azx_sd_writeb(chip, azx_dev, SD_CTL, + azx_sd_readb(chip, azx_dev, SD_CTL) | + SD_CTL_STREAM_RESET); + udelay(3); + timeout = 300; + while (!((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & + SD_CTL_STREAM_RESET) && --timeout) + ; + val &= ~SD_CTL_STREAM_RESET; + azx_sd_writeb(chip, azx_dev, SD_CTL, val); + udelay(3); + + timeout = 300; + /* waiting for hardware to report that the stream is out of reset */ + while (((val = azx_sd_readb(chip, azx_dev, SD_CTL)) & + SD_CTL_STREAM_RESET) && --timeout) + ; + + /* reset first position - may not be synced with hw at this time */ + *azx_dev->posbuf = 0; +} + +/* + * set up the SD for streaming + */ +static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) +{ + unsigned int val; + /* make sure the run bit is zero for SD */ + azx_stream_clear(chip, azx_dev); + /* program the stream_tag */ + val = azx_sd_readl(chip, azx_dev, SD_CTL); + val = (val & ~SD_CTL_STREAM_TAG_MASK) | + (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT); + if (!azx_snoop(chip)) + val |= SD_CTL_TRAFFIC_PRIO; + azx_sd_writel(chip, azx_dev, SD_CTL, val); + + /* program the length of samples in cyclic buffer */ + azx_sd_writel(chip, azx_dev, SD_CBL, azx_dev->bufsize); + + /* program the stream format */ + /* this value needs to be the same as the one programmed */ + azx_sd_writew(chip, azx_dev, SD_FORMAT, azx_dev->format_val); + + /* program the stream LVI (last valid index) of the BDL */ + azx_sd_writew(chip, azx_dev, SD_LVI, azx_dev->frags - 1); + + /* program the BDL address */ + /* lower BDL address */ + azx_sd_writel(chip, azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); + /* upper BDL address */ + azx_sd_writel(chip, azx_dev, SD_BDLPU, + upper_32_bits(azx_dev->bdl.addr)); + + /* enable the position buffer */ + if (chip->position_fix[0] != POS_FIX_LPIB || + chip->position_fix[1] != POS_FIX_LPIB) { + if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) + azx_writel(chip, DPLBASE, + (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); + } + + /* set the interrupt enable bits in the descriptor control register */ + azx_sd_writel(chip, azx_dev, SD_CTL, + azx_sd_readl(chip, azx_dev, SD_CTL) | SD_INT_MASK); + + return 0; +} + +/* assign a stream for the PCM */ +static inline struct azx_dev * +azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) +{ + int dev, i, nums; + struct azx_dev *res = NULL; + /* make a non-zero unique key for the substream */ + int key = (substream->pcm->device << 16) | (substream->number << 2) | + (substream->stream + 1); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + dev = chip->playback_index_offset; + nums = chip->playback_streams; + } else { + dev = chip->capture_index_offset; + nums = chip->capture_streams; + } + for (i = 0; i < nums; i++, dev++) { + struct azx_dev *azx_dev = &chip->azx_dev[dev]; + dsp_lock(azx_dev); + if (!azx_dev->opened && !dsp_is_locked(azx_dev)) { + if (azx_dev->assigned_key == key) { + azx_dev->opened = 1; + azx_dev->assigned_key = key; + dsp_unlock(azx_dev); + return azx_dev; + } + if (!res || + (chip->driver_caps & AZX_DCAPS_REVERSE_ASSIGN)) + res = azx_dev; + } + dsp_unlock(azx_dev); + } + if (res) { + dsp_lock(res); + res->opened = 1; + res->assigned_key = key; + dsp_unlock(res); + } + return res; +} + +/* release the assigned stream */ +static inline void azx_release_device(struct azx_dev *azx_dev) +{ + azx_dev->opened = 0; +} + +static cycle_t azx_cc_read(const struct cyclecounter *cc) +{ + struct azx_dev *azx_dev = container_of(cc, struct azx_dev, azx_cc); + struct snd_pcm_substream *substream = azx_dev->substream; + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + + return azx_readl(chip, WALLCLK); +} + +static void azx_timecounter_init(struct snd_pcm_substream *substream, + bool force, cycle_t last) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + struct timecounter *tc = &azx_dev->azx_tc; + struct cyclecounter *cc = &azx_dev->azx_cc; + u64 nsec; + + cc->read = azx_cc_read; + cc->mask = CLOCKSOURCE_MASK(32); + + /* + * Converting from 24 MHz to ns means applying a 125/3 factor. + * To avoid any saturation issues in intermediate operations, + * the 125 factor is applied first. The division is applied + * last after reading the timecounter value. + * Applying the 1/3 factor as part of the multiplication + * requires at least 20 bits for a decent precision, however + * overflows occur after about 4 hours or less, not a option. + */ + + cc->mult = 125; /* saturation after 195 years */ + cc->shift = 0; + + nsec = 0; /* audio time is elapsed time since trigger */ + timecounter_init(tc, cc, nsec); + if (force) + /* + * force timecounter to use predefined value, + * used for synchronized starts + */ + tc->cycle_last = last; +} + +static u64 azx_adjust_codec_delay(struct snd_pcm_substream *substream, + u64 nsec) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + u64 codec_frames, codec_nsecs; + + if (!hinfo->ops.get_delay) + return nsec; + + codec_frames = hinfo->ops.get_delay(hinfo, apcm->codec, substream); + codec_nsecs = div_u64(codec_frames * 1000000000LL, + substream->runtime->rate); + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + return nsec + codec_nsecs; + + return (nsec > codec_nsecs) ? nsec - codec_nsecs : 0; +} + +/* + * set up a BDL entry + */ +static int setup_bdle(struct azx *chip, + struct snd_dma_buffer *dmab, + struct azx_dev *azx_dev, u32 **bdlp, + int ofs, int size, int with_ioc) +{ + u32 *bdl = *bdlp; + + while (size > 0) { + dma_addr_t addr; + int chunk; + + if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) + return -EINVAL; + + addr = snd_sgbuf_get_addr(dmab, ofs); + /* program the address field of the BDL entry */ + bdl[0] = cpu_to_le32((u32)addr); + bdl[1] = cpu_to_le32(upper_32_bits(addr)); + /* program the size field of the BDL entry */ + chunk = snd_sgbuf_get_chunk_size(dmab, ofs, size); + /* one BDLE cannot cross 4K boundary on CTHDA chips */ + if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { + u32 remain = 0x1000 - (ofs & 0xfff); + if (chunk > remain) + chunk = remain; + } + bdl[2] = cpu_to_le32(chunk); + /* program the IOC to enable interrupt + * only when the whole fragment is processed + */ + size -= chunk; + bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); + bdl += 4; + azx_dev->frags++; + ofs += chunk; + } + *bdlp = bdl; + return ofs; +} + +/* + * set up BDL entries + */ +static int azx_setup_periods(struct azx *chip, + struct snd_pcm_substream *substream, + struct azx_dev *azx_dev) +{ + u32 *bdl; + int i, ofs, periods, period_bytes; + int pos_adj = 0; + + /* reset BDL address */ + azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); + azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); + + period_bytes = azx_dev->period_bytes; + periods = azx_dev->bufsize / period_bytes; + + /* program the initial BDL entries */ + bdl = (u32 *)azx_dev->bdl.area; + ofs = 0; + azx_dev->frags = 0; + + if (chip->bdl_pos_adj) + pos_adj = chip->bdl_pos_adj[chip->dev_index]; + if (!azx_dev->no_period_wakeup && pos_adj > 0) { + struct snd_pcm_runtime *runtime = substream->runtime; + int pos_align = pos_adj; + pos_adj = (pos_adj * runtime->rate + 47999) / 48000; + if (!pos_adj) + pos_adj = pos_align; + else + pos_adj = ((pos_adj + pos_align - 1) / pos_align) * + pos_align; + pos_adj = frames_to_bytes(runtime, pos_adj); + if (pos_adj >= period_bytes) { + dev_warn(chip->card->dev,"Too big adjustment %d\n", + pos_adj); + pos_adj = 0; + } else { + ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), + azx_dev, + &bdl, ofs, pos_adj, true); + if (ofs < 0) + goto error; + } + } else + pos_adj = 0; + + for (i = 0; i < periods; i++) { + if (i == periods - 1 && pos_adj) + ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), + azx_dev, &bdl, ofs, + period_bytes - pos_adj, 0); + else + ofs = setup_bdle(chip, snd_pcm_get_dma_buf(substream), + azx_dev, &bdl, ofs, + period_bytes, + !azx_dev->no_period_wakeup); + if (ofs < 0) + goto error; + } + return 0; + + error: + dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n", + azx_dev->bufsize, period_bytes); + return -EINVAL; +} + +/* + * PCM ops + */ + +static int azx_pcm_close(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); + unsigned long flags; + + mutex_lock(&chip->open_mutex); + spin_lock_irqsave(&chip->reg_lock, flags); + azx_dev->substream = NULL; + azx_dev->running = 0; + spin_unlock_irqrestore(&chip->reg_lock, flags); + azx_release_device(azx_dev); + hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); + mutex_unlock(&chip->open_mutex); + return 0; +} + +static int azx_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + int ret; + + dsp_lock(get_azx_dev(substream)); + if (dsp_is_locked(get_azx_dev(substream))) { + ret = -EBUSY; + goto unlock; + } + + ret = chip->ops->substream_alloc_pages(chip, substream, + params_buffer_bytes(hw_params)); +unlock: + dsp_unlock(get_azx_dev(substream)); + return ret; +} + +static int azx_pcm_hw_free(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx_dev *azx_dev = get_azx_dev(substream); + struct azx *chip = apcm->chip; + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + int err; + + /* reset BDL address */ + dsp_lock(azx_dev); + if (!dsp_is_locked(azx_dev)) { + azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); + azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); + azx_sd_writel(chip, azx_dev, SD_CTL, 0); + azx_dev->bufsize = 0; + azx_dev->period_bytes = 0; + azx_dev->format_val = 0; + } + + snd_hda_codec_cleanup(apcm->codec, hinfo, substream); + + err = chip->ops->substream_free_pages(chip, substream); + azx_dev->prepared = 0; + dsp_unlock(azx_dev); + return err; +} + +static int azx_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned int bufsize, period_bytes, format_val, stream_tag; + int err; + struct hda_spdif_out *spdif = + snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); + unsigned short ctls = spdif ? spdif->ctls : 0; + + dsp_lock(azx_dev); + if (dsp_is_locked(azx_dev)) { + err = -EBUSY; + goto unlock; + } + + azx_stream_reset(chip, azx_dev); + format_val = snd_hda_calc_stream_format(runtime->rate, + runtime->channels, + runtime->format, + hinfo->maxbps, + ctls); + if (!format_val) { + dev_err(chip->card->dev, + "invalid format_val, rate=%d, ch=%d, format=%d\n", + runtime->rate, runtime->channels, runtime->format); + err = -EINVAL; + goto unlock; + } + + bufsize = snd_pcm_lib_buffer_bytes(substream); + period_bytes = snd_pcm_lib_period_bytes(substream); + + dev_dbg(chip->card->dev, "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", + bufsize, format_val); + + if (bufsize != azx_dev->bufsize || + period_bytes != azx_dev->period_bytes || + format_val != azx_dev->format_val || + runtime->no_period_wakeup != azx_dev->no_period_wakeup) { + azx_dev->bufsize = bufsize; + azx_dev->period_bytes = period_bytes; + azx_dev->format_val = format_val; + azx_dev->no_period_wakeup = runtime->no_period_wakeup; + err = azx_setup_periods(chip, substream, azx_dev); + if (err < 0) + goto unlock; + } + + /* when LPIB delay correction gives a small negative value, + * we ignore it; currently set the threshold statically to + * 64 frames + */ + if (runtime->period_size > 64) + azx_dev->delay_negative_threshold = -frames_to_bytes(runtime, 64); + else + azx_dev->delay_negative_threshold = 0; + + /* wallclk has 24Mhz clock source */ + azx_dev->period_wallclk = (((runtime->period_size * 24000) / + runtime->rate) * 1000); + azx_setup_controller(chip, azx_dev); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + azx_dev->fifo_size = + azx_sd_readw(chip, azx_dev, SD_FIFOSIZE) + 1; + else + azx_dev->fifo_size = 0; + + stream_tag = azx_dev->stream_tag; + /* CA-IBG chips need the playback stream starting from 1 */ + if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && + stream_tag > chip->capture_streams) + stream_tag -= chip->capture_streams; + err = snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, + azx_dev->format_val, substream); + + unlock: + if (!err) + azx_dev->prepared = 1; + dsp_unlock(azx_dev); + return err; +} + +static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev; + struct snd_pcm_substream *s; + int rstart = 0, start, nsync = 0, sbits = 0; + int nwait, timeout; + + azx_dev = get_azx_dev(substream); + trace_azx_pcm_trigger(chip, azx_dev, cmd); + + if (dsp_is_locked(azx_dev) || !azx_dev->prepared) + return -EPIPE; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + rstart = 1; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + case SNDRV_PCM_TRIGGER_RESUME: + start = 1; + break; + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + case SNDRV_PCM_TRIGGER_SUSPEND: + case SNDRV_PCM_TRIGGER_STOP: + start = 0; + break; + default: + return -EINVAL; + } + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); + sbits |= 1 << azx_dev->index; + nsync++; + snd_pcm_trigger_done(s, substream); + } + + spin_lock(&chip->reg_lock); + + /* first, set SYNC bits of corresponding streams */ + if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) + azx_writel(chip, OLD_SSYNC, + azx_readl(chip, OLD_SSYNC) | sbits); + else + azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); + if (start) { + azx_dev->start_wallclk = azx_readl(chip, WALLCLK); + if (!rstart) + azx_dev->start_wallclk -= + azx_dev->period_wallclk; + azx_stream_start(chip, azx_dev); + } else { + azx_stream_stop(chip, azx_dev); + } + azx_dev->running = start; + } + spin_unlock(&chip->reg_lock); + if (start) { + /* wait until all FIFOs get ready */ + for (timeout = 5000; timeout; timeout--) { + nwait = 0; + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); + if (!(azx_sd_readb(chip, azx_dev, SD_STS) & + SD_STS_FIFO_READY)) + nwait++; + } + if (!nwait) + break; + cpu_relax(); + } + } else { + /* wait until all RUN bits are cleared */ + for (timeout = 5000; timeout; timeout--) { + nwait = 0; + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_dev = get_azx_dev(s); + if (azx_sd_readb(chip, azx_dev, SD_CTL) & + SD_CTL_DMA_START) + nwait++; + } + if (!nwait) + break; + cpu_relax(); + } + } + spin_lock(&chip->reg_lock); + /* reset SYNC bits */ + if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) + azx_writel(chip, OLD_SSYNC, + azx_readl(chip, OLD_SSYNC) & ~sbits); + else + azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); + if (start) { + azx_timecounter_init(substream, 0, 0); + if (nsync > 1) { + cycle_t cycle_last; + + /* same start cycle for master and group */ + azx_dev = get_azx_dev(substream); + cycle_last = azx_dev->azx_tc.cycle_last; + + snd_pcm_group_for_each_entry(s, substream) { + if (s->pcm->card != substream->pcm->card) + continue; + azx_timecounter_init(s, 1, cycle_last); + } + } + } + spin_unlock(&chip->reg_lock); + return 0; +} + +/* get the current DMA position with correction on VIA chips */ +static unsigned int azx_via_get_position(struct azx *chip, + struct azx_dev *azx_dev) +{ + unsigned int link_pos, mini_pos, bound_pos; + unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; + unsigned int fifo_size; + + link_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + /* Playback, no problem using link position */ + return link_pos; + } + + /* Capture */ + /* For new chipset, + * use mod to get the DMA position just like old chipset + */ + mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); + mod_dma_pos %= azx_dev->period_bytes; + + /* azx_dev->fifo_size can't get FIFO size of in stream. + * Get from base address + offset. + */ + fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); + + if (azx_dev->insufficient) { + /* Link position never gather than FIFO size */ + if (link_pos <= fifo_size) + return 0; + + azx_dev->insufficient = 0; + } + + if (link_pos <= fifo_size) + mini_pos = azx_dev->bufsize + link_pos - fifo_size; + else + mini_pos = link_pos - fifo_size; + + /* Find nearest previous boudary */ + mod_mini_pos = mini_pos % azx_dev->period_bytes; + mod_link_pos = link_pos % azx_dev->period_bytes; + if (mod_link_pos >= fifo_size) + bound_pos = link_pos - mod_link_pos; + else if (mod_dma_pos >= mod_mini_pos) + bound_pos = mini_pos - mod_mini_pos; + else { + bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; + if (bound_pos >= azx_dev->bufsize) + bound_pos = 0; + } + + /* Calculate real DMA position we want */ + return bound_pos + mod_dma_pos; +} + +unsigned int azx_get_position(struct azx *chip, + struct azx_dev *azx_dev, + bool with_check) +{ + struct snd_pcm_substream *substream = azx_dev->substream; + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + unsigned int pos; + int stream = substream->stream; + struct hda_pcm_stream *hinfo = apcm->hinfo[stream]; + int delay = 0; + + switch (chip->position_fix[stream]) { + case POS_FIX_LPIB: + /* read LPIB */ + pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + break; + case POS_FIX_VIACOMBO: + pos = azx_via_get_position(chip, azx_dev); + break; + default: + /* use the position buffer */ + pos = le32_to_cpu(*azx_dev->posbuf); + if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { + if (!pos || pos == (u32)-1) { + dev_info(chip->card->dev, + "Invalid position buffer, using LPIB read method instead.\n"); + chip->position_fix[stream] = POS_FIX_LPIB; + pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + } else + chip->position_fix[stream] = POS_FIX_POSBUF; + } + break; + } + + if (pos >= azx_dev->bufsize) + pos = 0; + + /* calculate runtime delay from LPIB */ + if (substream->runtime && + chip->position_fix[stream] == POS_FIX_POSBUF && + (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { + unsigned int lpib_pos = azx_sd_readl(chip, azx_dev, SD_LPIB); + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + delay = pos - lpib_pos; + else + delay = lpib_pos - pos; + if (delay < 0) { + if (delay >= azx_dev->delay_negative_threshold) + delay = 0; + else + delay += azx_dev->bufsize; + } + if (delay >= azx_dev->period_bytes) { + dev_info(chip->card->dev, + "Unstable LPIB (%d >= %d); disabling LPIB delay counting\n", + delay, azx_dev->period_bytes); + delay = 0; + chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; + } + delay = bytes_to_frames(substream->runtime, delay); + } + + if (substream->runtime) { + if (hinfo->ops.get_delay) + delay += hinfo->ops.get_delay(hinfo, apcm->codec, + substream); + substream->runtime->delay = delay; + } + + trace_azx_get_position(chip, azx_dev, pos, delay); + return pos; +} +EXPORT_SYMBOL_GPL(azx_get_position); + +static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev = get_azx_dev(substream); + return bytes_to_frames(substream->runtime, + azx_get_position(chip, azx_dev, false)); +} + +static int azx_get_wallclock_tstamp(struct snd_pcm_substream *substream, + struct timespec *ts) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + u64 nsec; + + nsec = timecounter_read(&azx_dev->azx_tc); + nsec = div_u64(nsec, 3); /* can be optimized */ + nsec = azx_adjust_codec_delay(substream, nsec); + + *ts = ns_to_timespec(nsec); + + return 0; +} + +static struct snd_pcm_hardware azx_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_BLOCK_TRANSFER | + SNDRV_PCM_INFO_MMAP_VALID | + /* No full-resume yet implemented */ + /* SNDRV_PCM_INFO_RESUME |*/ + SNDRV_PCM_INFO_PAUSE | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_HAS_WALL_CLOCK | + SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rates = SNDRV_PCM_RATE_48000, + .rate_min = 48000, + .rate_max = 48000, + .channels_min = 2, + .channels_max = 2, + .buffer_bytes_max = AZX_MAX_BUF_SIZE, + .period_bytes_min = 128, + .period_bytes_max = AZX_MAX_BUF_SIZE / 2, + .periods_min = 2, + .periods_max = AZX_MAX_FRAG, + .fifo_size = 0, +}; + +static int azx_pcm_open(struct snd_pcm_substream *substream) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; + struct azx *chip = apcm->chip; + struct azx_dev *azx_dev; + struct snd_pcm_runtime *runtime = substream->runtime; + unsigned long flags; + int err; + int buff_step; + + mutex_lock(&chip->open_mutex); + azx_dev = azx_assign_device(chip, substream); + if (azx_dev == NULL) { + mutex_unlock(&chip->open_mutex); + return -EBUSY; + } + runtime->hw = azx_pcm_hw; + runtime->hw.channels_min = hinfo->channels_min; + runtime->hw.channels_max = hinfo->channels_max; + runtime->hw.formats = hinfo->formats; + runtime->hw.rates = hinfo->rates; + snd_pcm_limit_hw_rates(runtime); + snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); + + /* avoid wrap-around with wall-clock */ + snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_TIME, + 20, + 178000000); + + if (chip->align_buffer_size) + /* constrain buffer sizes to be multiple of 128 + bytes. This is more efficient in terms of memory + access but isn't required by the HDA spec and + prevents users from specifying exact period/buffer + sizes. For example for 44.1kHz, a period size set + to 20ms will be rounded to 19.59ms. */ + buff_step = 128; + else + /* Don't enforce steps on buffer sizes, still need to + be multiple of 4 bytes (HDA spec). Tested on Intel + HDA controllers, may not work on all devices where + option needs to be disabled */ + buff_step = 4; + + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, + buff_step); + snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, + buff_step); + snd_hda_power_up_d3wait(apcm->codec); + err = hinfo->ops.open(hinfo, apcm->codec, substream); + if (err < 0) { + azx_release_device(azx_dev); + snd_hda_power_down(apcm->codec); + mutex_unlock(&chip->open_mutex); + return err; + } + snd_pcm_limit_hw_rates(runtime); + /* sanity check */ + if (snd_BUG_ON(!runtime->hw.channels_min) || + snd_BUG_ON(!runtime->hw.channels_max) || + snd_BUG_ON(!runtime->hw.formats) || + snd_BUG_ON(!runtime->hw.rates)) { + azx_release_device(azx_dev); + hinfo->ops.close(hinfo, apcm->codec, substream); + snd_hda_power_down(apcm->codec); + mutex_unlock(&chip->open_mutex); + return -EINVAL; + } + + /* disable WALLCLOCK timestamps for capture streams + until we figure out how to handle digital inputs */ + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) + runtime->hw.info &= ~SNDRV_PCM_INFO_HAS_WALL_CLOCK; + + spin_lock_irqsave(&chip->reg_lock, flags); + azx_dev->substream = substream; + azx_dev->running = 0; + spin_unlock_irqrestore(&chip->reg_lock, flags); + + runtime->private_data = azx_dev; + snd_pcm_set_sync(substream); + mutex_unlock(&chip->open_mutex); + return 0; +} + +static int azx_pcm_mmap(struct snd_pcm_substream *substream, + struct vm_area_struct *area) +{ + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + if (chip->ops->pcm_mmap_prepare) + chip->ops->pcm_mmap_prepare(substream, area); + return snd_pcm_lib_default_mmap(substream, area); +} + +static struct snd_pcm_ops azx_pcm_ops = { + .open = azx_pcm_open, + .close = azx_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = azx_pcm_hw_params, + .hw_free = azx_pcm_hw_free, + .prepare = azx_pcm_prepare, + .trigger = azx_pcm_trigger, + .pointer = azx_pcm_pointer, + .wall_clock = azx_get_wallclock_tstamp, + .mmap = azx_pcm_mmap, + .page = snd_pcm_sgbuf_ops_page, +}; + +static void azx_pcm_free(struct snd_pcm *pcm) +{ + struct azx_pcm *apcm = pcm->private_data; + if (apcm) { + list_del(&apcm->list); + kfree(apcm); + } +} + +#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) + +static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, + struct hda_pcm *cpcm) +{ + struct azx *chip = bus->private_data; + struct snd_pcm *pcm; + struct azx_pcm *apcm; + int pcm_dev = cpcm->device; + unsigned int size; + int s, err; + + list_for_each_entry(apcm, &chip->pcm_list, list) { + if (apcm->pcm->device == pcm_dev) { + dev_err(chip->card->dev, "PCM %d already exists\n", + pcm_dev); + return -EBUSY; + } + } + err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, + cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, + cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, + &pcm); + if (err < 0) + return err; + strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); + apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); + if (apcm == NULL) + return -ENOMEM; + apcm->chip = chip; + apcm->pcm = pcm; + apcm->codec = codec; + pcm->private_data = apcm; + pcm->private_free = azx_pcm_free; + if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) + pcm->dev_class = SNDRV_PCM_CLASS_MODEM; + list_add_tail(&apcm->list, &chip->pcm_list); + cpcm->pcm = pcm; + for (s = 0; s < 2; s++) { + apcm->hinfo[s] = &cpcm->stream[s]; + if (cpcm->stream[s].substreams) + snd_pcm_set_ops(pcm, s, &azx_pcm_ops); + } + /* buffer pre-allocation */ + size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; + if (size > MAX_PREALLOC_SIZE) + size = MAX_PREALLOC_SIZE; + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, + chip->card->dev, + size, MAX_PREALLOC_SIZE); + /* link to codec */ + pcm->dev = &codec->dev; + return 0; +} + +/* + * CORB / RIRB interface + */ +static int azx_alloc_cmd_io(struct azx *chip) +{ + int err; + + /* single page (at least 4096 bytes) must suffice for both ringbuffes */ + err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, + PAGE_SIZE, &chip->rb); + if (err < 0) + dev_err(chip->card->dev, "cannot allocate CORB/RIRB\n"); + return err; +} +EXPORT_SYMBOL_GPL(azx_alloc_cmd_io); + +static void azx_init_cmd_io(struct azx *chip) +{ + int timeout; + + spin_lock_irq(&chip->reg_lock); + /* CORB set up */ + chip->corb.addr = chip->rb.addr; + chip->corb.buf = (u32 *)chip->rb.area; + azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); + azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); + + /* set the corb size to 256 entries (ULI requires explicitly) */ + azx_writeb(chip, CORBSIZE, 0x02); + /* set the corb write pointer to 0 */ + azx_writew(chip, CORBWP, 0); + + /* reset the corb hw read pointer */ + azx_writew(chip, CORBRP, ICH6_CORBRP_RST); + if (!(chip->driver_caps & AZX_DCAPS_CORBRP_SELF_CLEAR)) { + for (timeout = 1000; timeout > 0; timeout--) { + if ((azx_readw(chip, CORBRP) & ICH6_CORBRP_RST) == ICH6_CORBRP_RST) + break; + udelay(1); + } + if (timeout <= 0) + dev_err(chip->card->dev, "CORB reset timeout#1, CORBRP = %d\n", + azx_readw(chip, CORBRP)); + + azx_writew(chip, CORBRP, 0); + for (timeout = 1000; timeout > 0; timeout--) { + if (azx_readw(chip, CORBRP) == 0) + break; + udelay(1); + } + if (timeout <= 0) + dev_err(chip->card->dev, "CORB reset timeout#2, CORBRP = %d\n", + azx_readw(chip, CORBRP)); + } + + /* enable corb dma */ + azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); + + /* RIRB set up */ + chip->rirb.addr = chip->rb.addr + 2048; + chip->rirb.buf = (u32 *)(chip->rb.area + 2048); + chip->rirb.wp = chip->rirb.rp = 0; + memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); + azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); + azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); + + /* set the rirb size to 256 entries (ULI requires explicitly) */ + azx_writeb(chip, RIRBSIZE, 0x02); + /* reset the rirb hw write pointer */ + azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); + /* set N=1, get RIRB response interrupt for new entry */ + if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) + azx_writew(chip, RINTCNT, 0xc0); + else + azx_writew(chip, RINTCNT, 1); + /* enable rirb dma and response irq */ + azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); + spin_unlock_irq(&chip->reg_lock); +} +EXPORT_SYMBOL_GPL(azx_init_cmd_io); + +static void azx_free_cmd_io(struct azx *chip) +{ + spin_lock_irq(&chip->reg_lock); + /* disable ringbuffer DMAs */ + azx_writeb(chip, RIRBCTL, 0); + azx_writeb(chip, CORBCTL, 0); + spin_unlock_irq(&chip->reg_lock); +} +EXPORT_SYMBOL_GPL(azx_free_cmd_io); + +static unsigned int azx_command_addr(u32 cmd) +{ + unsigned int addr = cmd >> 28; + + if (addr >= AZX_MAX_CODECS) { + snd_BUG(); + addr = 0; + } + + return addr; +} + +/* send a command */ +static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) +{ + struct azx *chip = bus->private_data; + unsigned int addr = azx_command_addr(val); + unsigned int wp, rp; + + spin_lock_irq(&chip->reg_lock); + + /* add command to corb */ + wp = azx_readw(chip, CORBWP); + if (wp == 0xffff) { + /* something wrong, controller likely turned to D3 */ + spin_unlock_irq(&chip->reg_lock); + return -EIO; + } + wp++; + wp %= ICH6_MAX_CORB_ENTRIES; + + rp = azx_readw(chip, CORBRP); + if (wp == rp) { + /* oops, it's full */ + spin_unlock_irq(&chip->reg_lock); + return -EAGAIN; + } + + chip->rirb.cmds[addr]++; + chip->corb.buf[wp] = cpu_to_le32(val); + azx_writew(chip, CORBWP, wp); + + spin_unlock_irq(&chip->reg_lock); + + return 0; +} + +#define ICH6_RIRB_EX_UNSOL_EV (1<<4) + +/* retrieve RIRB entry - called from interrupt handler */ +static void azx_update_rirb(struct azx *chip) +{ + unsigned int rp, wp; + unsigned int addr; + u32 res, res_ex; + + wp = azx_readw(chip, RIRBWP); + if (wp == 0xffff) { + /* something wrong, controller likely turned to D3 */ + return; + } + + if (wp == chip->rirb.wp) + return; + chip->rirb.wp = wp; + + while (chip->rirb.rp != wp) { + chip->rirb.rp++; + chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; + + rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ + res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); + res = le32_to_cpu(chip->rirb.buf[rp]); + addr = res_ex & 0xf; + if ((addr >= AZX_MAX_CODECS) || !(chip->codec_mask & (1 << addr))) { + dev_err(chip->card->dev, "spurious response %#x:%#x, rp = %d, wp = %d", + res, res_ex, + chip->rirb.rp, wp); + snd_BUG(); + } + else if (res_ex & ICH6_RIRB_EX_UNSOL_EV) + snd_hda_queue_unsol_event(chip->bus, res, res_ex); + else if (chip->rirb.cmds[addr]) { + chip->rirb.res[addr] = res; + smp_wmb(); + chip->rirb.cmds[addr]--; + } else if (printk_ratelimit()) { + dev_err(chip->card->dev, "spurious response %#x:%#x, last cmd=%#08x\n", + res, res_ex, + chip->last_cmd[addr]); + } + } +} + +/* receive a response */ +static unsigned int azx_rirb_get_response(struct hda_bus *bus, + unsigned int addr) +{ + struct azx *chip = bus->private_data; + unsigned long timeout; + unsigned long loopcounter; + int do_poll = 0; + + again: + timeout = jiffies + msecs_to_jiffies(1000); + + for (loopcounter = 0;; loopcounter++) { + if (chip->polling_mode || do_poll) { + spin_lock_irq(&chip->reg_lock); + azx_update_rirb(chip); + spin_unlock_irq(&chip->reg_lock); + } + if (!chip->rirb.cmds[addr]) { + smp_rmb(); + bus->rirb_error = 0; + + if (!do_poll) + chip->poll_count = 0; + return chip->rirb.res[addr]; /* the last value */ + } + if (time_after(jiffies, timeout)) + break; + if (bus->needs_damn_long_delay || loopcounter > 3000) + msleep(2); /* temporary workaround */ + else { + udelay(10); + cond_resched(); + } + } + + if (!bus->no_response_fallback) + return -1; + + if (!chip->polling_mode && chip->poll_count < 2) { + dev_dbg(chip->card->dev, + "azx_get_response timeout, polling the codec once: last cmd=0x%08x\n", + chip->last_cmd[addr]); + do_poll = 1; + chip->poll_count++; + goto again; + } + + + if (!chip->polling_mode) { + dev_warn(chip->card->dev, + "azx_get_response timeout, switching to polling mode: last cmd=0x%08x\n", + chip->last_cmd[addr]); + chip->polling_mode = 1; + goto again; + } + + if (chip->msi) { + dev_warn(chip->card->dev, + "No response from codec, disabling MSI: last cmd=0x%08x\n", + chip->last_cmd[addr]); + if (chip->ops->disable_msi_reset_irq(chip) && + chip->ops->disable_msi_reset_irq(chip) < 0) { + bus->rirb_error = 1; + return -1; + } + goto again; + } + + if (chip->probing) { + /* If this critical timeout happens during the codec probing + * phase, this is likely an access to a non-existing codec + * slot. Better to return an error and reset the system. + */ + return -1; + } + + /* a fatal communication error; need either to reset or to fallback + * to the single_cmd mode + */ + bus->rirb_error = 1; + if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { + bus->response_reset = 1; + return -1; /* give a chance to retry */ + } + + dev_err(chip->card->dev, + "azx_get_response timeout, switching to single_cmd mode: last cmd=0x%08x\n", + chip->last_cmd[addr]); + chip->single_cmd = 1; + bus->response_reset = 0; + /* release CORB/RIRB */ + azx_free_cmd_io(chip); + /* disable unsolicited responses */ + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); + return -1; +} + +/* + * Use the single immediate command instead of CORB/RIRB for simplicity + * + * Note: according to Intel, this is not preferred use. The command was + * intended for the BIOS only, and may get confused with unsolicited + * responses. So, we shouldn't use it for normal operation from the + * driver. + * I left the codes, however, for debugging/testing purposes. + */ + +/* receive a response */ +static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) +{ + int timeout = 50; + + while (timeout--) { + /* check IRV busy bit */ + if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { + /* reuse rirb.res as the response return value */ + chip->rirb.res[addr] = azx_readl(chip, IR); + return 0; + } + udelay(1); + } + if (printk_ratelimit()) + dev_dbg(chip->card->dev, "get_response timeout: IRS=0x%x\n", + azx_readw(chip, IRS)); + chip->rirb.res[addr] = -1; + return -EIO; +} + +/* send a command */ +static int azx_single_send_cmd(struct hda_bus *bus, u32 val) +{ + struct azx *chip = bus->private_data; + unsigned int addr = azx_command_addr(val); + int timeout = 50; + + bus->rirb_error = 0; + while (timeout--) { + /* check ICB busy bit */ + if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { + /* Clear IRV valid bit */ + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_VALID); + azx_writel(chip, IC, val); + azx_writew(chip, IRS, azx_readw(chip, IRS) | + ICH6_IRS_BUSY); + return azx_single_wait_for_response(chip, addr); + } + udelay(1); + } + if (printk_ratelimit()) + dev_dbg(chip->card->dev, + "send_cmd timeout: IRS=0x%x, val=0x%x\n", + azx_readw(chip, IRS), val); + return -EIO; +} + +/* receive a response */ +static unsigned int azx_single_get_response(struct hda_bus *bus, + unsigned int addr) +{ + struct azx *chip = bus->private_data; + return chip->rirb.res[addr]; +} + +/* + * The below are the main callbacks from hda_codec. + * + * They are just the skeleton to call sub-callbacks according to the + * current setting of chip->single_cmd. + */ + +/* send a command */ +static int azx_send_cmd(struct hda_bus *bus, unsigned int val) +{ + struct azx *chip = bus->private_data; + + if (chip->disabled) + return 0; + chip->last_cmd[azx_command_addr(val)] = val; + if (chip->single_cmd) + return azx_single_send_cmd(bus, val); + else + return azx_corb_send_cmd(bus, val); +} +EXPORT_SYMBOL_GPL(azx_send_cmd); + +/* get a response */ +static unsigned int azx_get_response(struct hda_bus *bus, + unsigned int addr) +{ + struct azx *chip = bus->private_data; + if (chip->disabled) + return 0; + if (chip->single_cmd) + return azx_single_get_response(bus, addr); + else + return azx_rirb_get_response(bus, addr); +} +EXPORT_SYMBOL_GPL(azx_get_response); + +#ifdef CONFIG_SND_HDA_DSP_LOADER +/* + * DSP loading code (e.g. for CA0132) + */ + +/* use the first stream for loading DSP */ +static struct azx_dev * +azx_get_dsp_loader_dev(struct azx *chip) +{ + return &chip->azx_dev[chip->playback_index_offset]; +} + +static int azx_load_dsp_prepare(struct hda_bus *bus, unsigned int format, + unsigned int byte_size, + struct snd_dma_buffer *bufp) +{ + u32 *bdl; + struct azx *chip = bus->private_data; + struct azx_dev *azx_dev; + int err; + + azx_dev = azx_get_dsp_loader_dev(chip); + + dsp_lock(azx_dev); + spin_lock_irq(&chip->reg_lock); + if (azx_dev->running || azx_dev->locked) { + spin_unlock_irq(&chip->reg_lock); + err = -EBUSY; + goto unlock; + } + azx_dev->prepared = 0; + chip->saved_azx_dev = *azx_dev; + azx_dev->locked = 1; + spin_unlock_irq(&chip->reg_lock); + + err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV_SG, + byte_size, bufp); + if (err < 0) + goto err_alloc; + + azx_dev->bufsize = byte_size; + azx_dev->period_bytes = byte_size; + azx_dev->format_val = format; + + azx_stream_reset(chip, azx_dev); + + /* reset BDL address */ + azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); + azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); + + azx_dev->frags = 0; + bdl = (u32 *)azx_dev->bdl.area; + err = setup_bdle(chip, bufp, azx_dev, &bdl, 0, byte_size, 0); + if (err < 0) + goto error; + + azx_setup_controller(chip, azx_dev); + dsp_unlock(azx_dev); + return azx_dev->stream_tag; + + error: + chip->ops->dma_free_pages(chip, bufp); + err_alloc: + spin_lock_irq(&chip->reg_lock); + if (azx_dev->opened) + *azx_dev = chip->saved_azx_dev; + azx_dev->locked = 0; + spin_unlock_irq(&chip->reg_lock); + unlock: + dsp_unlock(azx_dev); + return err; +} + +static void azx_load_dsp_trigger(struct hda_bus *bus, bool start) +{ + struct azx *chip = bus->private_data; + struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); + + if (start) + azx_stream_start(chip, azx_dev); + else + azx_stream_stop(chip, azx_dev); + azx_dev->running = start; +} + +static void azx_load_dsp_cleanup(struct hda_bus *bus, + struct snd_dma_buffer *dmab) +{ + struct azx *chip = bus->private_data; + struct azx_dev *azx_dev = azx_get_dsp_loader_dev(chip); + + if (!dmab->area || !azx_dev->locked) + return; + + dsp_lock(azx_dev); + /* reset BDL address */ + azx_sd_writel(chip, azx_dev, SD_BDLPL, 0); + azx_sd_writel(chip, azx_dev, SD_BDLPU, 0); + azx_sd_writel(chip, azx_dev, SD_CTL, 0); + azx_dev->bufsize = 0; + azx_dev->period_bytes = 0; + azx_dev->format_val = 0; + + chip->ops->dma_free_pages(chip, dmab); + dmab->area = NULL; + + spin_lock_irq(&chip->reg_lock); + if (azx_dev->opened) + *azx_dev = chip->saved_azx_dev; + azx_dev->locked = 0; + spin_unlock_irq(&chip->reg_lock); + dsp_unlock(azx_dev); +} +#endif /* CONFIG_SND_HDA_DSP_LOADER */ + +int azx_alloc_stream_pages(struct azx *chip) +{ + int i, err; + struct snd_card *card = chip->card; + + for (i = 0; i < chip->num_streams; i++) { + dsp_lock_init(&chip->azx_dev[i]); + /* allocate memory for the BDL for each stream */ + err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, + BDL_SIZE, + &chip->azx_dev[i].bdl); + if (err < 0) { + dev_err(card->dev, "cannot allocate BDL\n"); + return -ENOMEM; + } + } + /* allocate memory for the position buffer */ + err = chip->ops->dma_alloc_pages(chip, SNDRV_DMA_TYPE_DEV, + chip->num_streams * 8, &chip->posbuf); + if (err < 0) { + dev_err(card->dev, "cannot allocate posbuf\n"); + return -ENOMEM; + } + + /* allocate CORB/RIRB */ + err = azx_alloc_cmd_io(chip); + if (err < 0) + return err; + return 0; +} +EXPORT_SYMBOL_GPL(azx_alloc_stream_pages); + +void azx_free_stream_pages(struct azx *chip) +{ + int i; + if (chip->azx_dev) { + for (i = 0; i < chip->num_streams; i++) + if (chip->azx_dev[i].bdl.area) + chip->ops->dma_free_pages( + chip, &chip->azx_dev[i].bdl); + } + if (chip->rb.area) + chip->ops->dma_free_pages(chip, &chip->rb); + if (chip->posbuf.area) + chip->ops->dma_free_pages(chip, &chip->posbuf); +} +EXPORT_SYMBOL_GPL(azx_free_stream_pages); + +/* + * Lowlevel interface + */ + +/* enter link reset */ +void azx_enter_link_reset(struct azx *chip) +{ + unsigned long timeout; + + /* reset controller */ + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); + + timeout = jiffies + msecs_to_jiffies(100); + while ((azx_readb(chip, GCTL) & ICH6_GCTL_RESET) && + time_before(jiffies, timeout)) + usleep_range(500, 1000); +} +EXPORT_SYMBOL_GPL(azx_enter_link_reset); + +/* exit link reset */ +static void azx_exit_link_reset(struct azx *chip) +{ + unsigned long timeout; + + azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); + + timeout = jiffies + msecs_to_jiffies(100); + while (!azx_readb(chip, GCTL) && + time_before(jiffies, timeout)) + usleep_range(500, 1000); +} + +/* reset codec link */ +static int azx_reset(struct azx *chip, bool full_reset) +{ + if (!full_reset) + goto __skip; + + /* clear STATESTS */ + azx_writew(chip, STATESTS, STATESTS_INT_MASK); + + /* reset controller */ + azx_enter_link_reset(chip); + + /* delay for >= 100us for codec PLL to settle per spec + * Rev 0.9 section 5.5.1 + */ + usleep_range(500, 1000); + + /* Bring controller out of reset */ + azx_exit_link_reset(chip); + + /* Brent Chartrand said to wait >= 540us for codecs to initialize */ + usleep_range(1000, 1200); + + __skip: + /* check to see if controller is ready */ + if (!azx_readb(chip, GCTL)) { + dev_dbg(chip->card->dev, "azx_reset: controller not ready!\n"); + return -EBUSY; + } + + /* Accept unsolicited responses */ + if (!chip->single_cmd) + azx_writel(chip, GCTL, azx_readl(chip, GCTL) | + ICH6_GCTL_UNSOL); + + /* detect codecs */ + if (!chip->codec_mask) { + chip->codec_mask = azx_readw(chip, STATESTS); + dev_dbg(chip->card->dev, "codec_mask = 0x%x\n", + chip->codec_mask); + } + + return 0; +} + +/* enable interrupts */ +static void azx_int_enable(struct azx *chip) +{ + /* enable controller CIE and GIE */ + azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | + ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); +} + +/* disable interrupts */ +static void azx_int_disable(struct azx *chip) +{ + int i; + + /* disable interrupts in stream descriptor */ + for (i = 0; i < chip->num_streams; i++) { + struct azx_dev *azx_dev = &chip->azx_dev[i]; + azx_sd_writeb(chip, azx_dev, SD_CTL, + azx_sd_readb(chip, azx_dev, SD_CTL) & + ~SD_INT_MASK); + } + + /* disable SIE for all streams */ + azx_writeb(chip, INTCTL, 0); + + /* disable controller CIE and GIE */ + azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & + ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); +} + +/* clear interrupts */ +static void azx_int_clear(struct azx *chip) +{ + int i; + + /* clear stream status */ + for (i = 0; i < chip->num_streams; i++) { + struct azx_dev *azx_dev = &chip->azx_dev[i]; + azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); + } + + /* clear STATESTS */ + azx_writew(chip, STATESTS, STATESTS_INT_MASK); + + /* clear rirb status */ + azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); + + /* clear int status */ + azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); +} + +/* + * reset and start the controller registers + */ +void azx_init_chip(struct azx *chip, bool full_reset) +{ + if (chip->initialized) + return; + + /* reset controller */ + azx_reset(chip, full_reset); + + /* initialize interrupts */ + azx_int_clear(chip); + azx_int_enable(chip); + + /* initialize the codec command I/O */ + if (!chip->single_cmd) + azx_init_cmd_io(chip); + + /* program the position buffer */ + azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); + azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); + + chip->initialized = 1; +} +EXPORT_SYMBOL_GPL(azx_init_chip); + +void azx_stop_chip(struct azx *chip) +{ + if (!chip->initialized) + return; + + /* disable interrupts */ + azx_int_disable(chip); + azx_int_clear(chip); + + /* disable CORB/RIRB */ + azx_free_cmd_io(chip); + + /* disable position buffer */ + azx_writel(chip, DPLBASE, 0); + azx_writel(chip, DPUBASE, 0); + + chip->initialized = 0; +} +EXPORT_SYMBOL_GPL(azx_stop_chip); + +/* + * interrupt handler + */ +irqreturn_t azx_interrupt(int irq, void *dev_id) +{ + struct azx *chip = dev_id; + struct azx_dev *azx_dev; + u32 status; + u8 sd_status; + int i; + +#ifdef CONFIG_PM_RUNTIME + if (chip->driver_caps & AZX_DCAPS_PM_RUNTIME) + if (!pm_runtime_active(chip->card->dev)) + return IRQ_NONE; +#endif + + spin_lock(&chip->reg_lock); + + if (chip->disabled) { + spin_unlock(&chip->reg_lock); + return IRQ_NONE; + } + + status = azx_readl(chip, INTSTS); + if (status == 0 || status == 0xffffffff) { + spin_unlock(&chip->reg_lock); + return IRQ_NONE; + } + + for (i = 0; i < chip->num_streams; i++) { + azx_dev = &chip->azx_dev[i]; + if (status & azx_dev->sd_int_sta_mask) { + sd_status = azx_sd_readb(chip, azx_dev, SD_STS); + azx_sd_writeb(chip, azx_dev, SD_STS, SD_INT_MASK); + if (!azx_dev->substream || !azx_dev->running || + !(sd_status & SD_INT_COMPLETE)) + continue; + /* check whether this IRQ is really acceptable */ + if (!chip->ops->position_check || + chip->ops->position_check(chip, azx_dev)) { + spin_unlock(&chip->reg_lock); + snd_pcm_period_elapsed(azx_dev->substream); + spin_lock(&chip->reg_lock); + } + } + } + + /* clear rirb int */ + status = azx_readb(chip, RIRBSTS); + if (status & RIRB_INT_MASK) { + if (status & RIRB_INT_RESPONSE) { + if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) + udelay(80); + azx_update_rirb(chip); + } + azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); + } + + spin_unlock(&chip->reg_lock); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(azx_interrupt); + +/* + * Codec initerface + */ + +/* + * Probe the given codec address + */ +static int probe_codec(struct azx *chip, int addr) +{ + unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | + (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; + unsigned int res; + + mutex_lock(&chip->bus->cmd_mutex); + chip->probing = 1; + azx_send_cmd(chip->bus, cmd); + res = azx_get_response(chip->bus, addr); + chip->probing = 0; + mutex_unlock(&chip->bus->cmd_mutex); + if (res == -1) + return -EIO; + dev_dbg(chip->card->dev, "codec #%d probed OK\n", addr); + return 0; +} + +static void azx_bus_reset(struct hda_bus *bus) +{ + struct azx *chip = bus->private_data; + + bus->in_reset = 1; + azx_stop_chip(chip); + azx_init_chip(chip, true); +#ifdef CONFIG_PM + if (chip->initialized) { + struct azx_pcm *p; + list_for_each_entry(p, &chip->pcm_list, list) + snd_pcm_suspend_all(p->pcm); + snd_hda_suspend(chip->bus); + snd_hda_resume(chip->bus); + } +#endif + bus->in_reset = 0; +} + +#ifdef CONFIG_PM +/* power-up/down the controller */ +static void azx_power_notify(struct hda_bus *bus, bool power_up) +{ + struct azx *chip = bus->private_data; + + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return; + + if (power_up) + pm_runtime_get_sync(chip->card->dev); + else + pm_runtime_put_sync(chip->card->dev); +} +#endif + +static int get_jackpoll_interval(struct azx *chip) +{ + int i; + unsigned int j; + + if (!chip->jackpoll_ms) + return 0; + + i = chip->jackpoll_ms[chip->dev_index]; + if (i == 0) + return 0; + if (i < 50 || i > 60000) + j = 0; + else + j = msecs_to_jiffies(i); + if (j == 0) + dev_warn(chip->card->dev, + "jackpoll_ms value out of range: %d\n", i); + return j; +} + +/* Codec initialization */ +int azx_codec_create(struct azx *chip, const char *model, + unsigned int max_slots, + int *power_save_to) +{ + struct hda_bus_template bus_temp; + int c, codecs, err; + + memset(&bus_temp, 0, sizeof(bus_temp)); + bus_temp.private_data = chip; + bus_temp.modelname = model; + bus_temp.pci = chip->pci; + bus_temp.ops.command = azx_send_cmd; + bus_temp.ops.get_response = azx_get_response; + bus_temp.ops.attach_pcm = azx_attach_pcm_stream; + bus_temp.ops.bus_reset = azx_bus_reset; +#ifdef CONFIG_PM + bus_temp.power_save = power_save_to; + bus_temp.ops.pm_notify = azx_power_notify; +#endif +#ifdef CONFIG_SND_HDA_DSP_LOADER + bus_temp.ops.load_dsp_prepare = azx_load_dsp_prepare; + bus_temp.ops.load_dsp_trigger = azx_load_dsp_trigger; + bus_temp.ops.load_dsp_cleanup = azx_load_dsp_cleanup; +#endif + + err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); + if (err < 0) + return err; + + if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { + dev_dbg(chip->card->dev, "Enable delay in RIRB handling\n"); + chip->bus->needs_damn_long_delay = 1; + } + + codecs = 0; + if (!max_slots) + max_slots = AZX_DEFAULT_CODECS; + + /* First try to probe all given codec slots */ + for (c = 0; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + if (probe_codec(chip, c) < 0) { + /* Some BIOSen give you wrong codec addresses + * that don't exist + */ + dev_warn(chip->card->dev, + "Codec #%d probe error; disabling it...\n", c); + chip->codec_mask &= ~(1 << c); + /* More badly, accessing to a non-existing + * codec often screws up the controller chip, + * and disturbs the further communications. + * Thus if an error occurs during probing, + * better to reset the controller chip to + * get back to the sanity state. + */ + azx_stop_chip(chip); + azx_init_chip(chip, true); + } + } + } + + /* AMD chipsets often cause the communication stalls upon certain + * sequence like the pin-detection. It seems that forcing the synced + * access works around the stall. Grrr... + */ + if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { + dev_dbg(chip->card->dev, "Enable sync_write for stable communication\n"); + chip->bus->sync_write = 1; + chip->bus->allow_bus_reset = 1; + } + + /* Then create codec instances */ + for (c = 0; c < max_slots; c++) { + if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { + struct hda_codec *codec; + err = snd_hda_codec_new(chip->bus, c, &codec); + if (err < 0) + continue; + codec->jackpoll_interval = get_jackpoll_interval(chip); + codec->beep_mode = chip->beep_mode; + codecs++; + } + } + if (!codecs) { + dev_err(chip->card->dev, "no codecs initialized\n"); + return -ENXIO; + } + return 0; +} +EXPORT_SYMBOL_GPL(azx_codec_create); + +/* configure each codec instance */ +int azx_codec_configure(struct azx *chip) +{ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) { + snd_hda_codec_configure(codec); + } + return 0; +} +EXPORT_SYMBOL_GPL(azx_codec_configure); + +/* mixer creation - all stuff is implemented in hda module */ +int azx_mixer_create(struct azx *chip) +{ + return snd_hda_build_controls(chip->bus); +} +EXPORT_SYMBOL_GPL(azx_mixer_create); + + +/* initialize SD streams */ +int azx_init_stream(struct azx *chip) +{ + int i; + + /* initialize each stream (aka device) + * assign the starting bdl address to each stream (device) + * and initialize + */ + for (i = 0; i < chip->num_streams; i++) { + struct azx_dev *azx_dev = &chip->azx_dev[i]; + azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); + /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ + azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); + /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ + azx_dev->sd_int_sta_mask = 1 << i; + /* stream tag: must be non-zero and unique */ + azx_dev->index = i; + azx_dev->stream_tag = i + 1; + } + + return 0; +} +EXPORT_SYMBOL_GPL(azx_init_stream); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Common HDA driver funcitons"); diff --git a/sound/pci/hda/hda_controller.h b/sound/pci/hda/hda_controller.h new file mode 100644 index 00000000000..baf0e77330a --- /dev/null +++ b/sound/pci/hda/hda_controller.h @@ -0,0 +1,53 @@ +/* + * Common functionality for the alsa driver code base for HD Audio. + * + * 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 Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __SOUND_HDA_CONTROLLER_H +#define __SOUND_HDA_CONTROLLER_H + +#include <sound/core.h> +#include <sound/initval.h> +#include "hda_codec.h" +#include "hda_priv.h" + +/* PCM setup */ +static inline struct azx_dev *get_azx_dev(struct snd_pcm_substream *substream) +{ + return substream->runtime->private_data; +} +unsigned int azx_get_position(struct azx *chip, + struct azx_dev *azx_dev, + bool with_check); + +/* Stream control. */ +void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev); + +/* Allocation functions. */ +int azx_alloc_stream_pages(struct azx *chip); +void azx_free_stream_pages(struct azx *chip); + +/* Low level azx interface */ +void azx_init_chip(struct azx *chip, bool full_reset); +void azx_stop_chip(struct azx *chip); +void azx_enter_link_reset(struct azx *chip); +irqreturn_t azx_interrupt(int irq, void *dev_id); + +/* Codec interface */ +int azx_codec_create(struct azx *chip, const char *model, + unsigned int max_slots, + int *power_save_to); +int azx_codec_configure(struct azx *chip); +int azx_mixer_create(struct azx *chip); +int azx_init_stream(struct azx *chip); + +#endif /* __SOUND_HDA_CONTROLLER_H */ diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 4c054f4486b..46690a7f48f 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -2,6 +2,7 @@ * Generic routines and proc interface for ELD(EDID Like Data) information * * Copyright(c) 2008 Intel Corporation. + * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi> * * Authors: * Wu Fengguang <wfg@linux.intel.com> @@ -152,7 +153,7 @@ static unsigned int hdmi_get_eld_data(struct hda_codec *codec, hda_nid_t nid, val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_ELDD, byte_index); #ifdef BE_PARANOID - printk(KERN_INFO "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); + codec_info(codec, "HDMI: ELD data byte %d: 0x%x\n", byte_index, val); #endif return val; } @@ -246,8 +247,8 @@ static void hdmi_update_short_audio_desc(struct cea_sad *a, /* * Be careful, ELD buf could be totally rubbish! */ -static int hdmi_update_eld(struct hdmi_eld *e, - const unsigned char *buf, int size) +int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, + const unsigned char *buf, int size) { int mnl; int i; @@ -260,7 +261,6 @@ static int hdmi_update_eld(struct hdmi_eld *e, goto out_fail; } - e->eld_size = size; e->baseline_len = GRAB_BITS(buf, 2, 0, 8); mnl = GRAB_BITS(buf, 4, 0, 5); e->cea_edid_ver = GRAB_BITS(buf, 4, 5, 3); @@ -305,7 +305,6 @@ static int hdmi_update_eld(struct hdmi_eld *e, if (!e->spk_alloc) e->spk_alloc = 0xffff; - e->eld_valid = true; return 0; out_fail: @@ -318,33 +317,30 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) AC_DIPSIZE_ELD_BUF); } -int snd_hdmi_get_eld(struct hdmi_eld *eld, - struct hda_codec *codec, hda_nid_t nid) +int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size) { int i; - int ret; + int ret = 0; int size; - unsigned char *buf; /* * ELD size is initialized to zero in caller function. If no errors and - * ELD is valid, actual eld_size is assigned in hdmi_update_eld() + * ELD is valid, actual eld_size is assigned. */ size = snd_hdmi_get_eld_size(codec, nid); if (size == 0) { /* wfg: workaround for ASUS P5E-VM HDMI board */ - snd_printd(KERN_INFO "HDMI: ELD buf size is 0, force 128\n"); + codec_info(codec, "HDMI: ELD buf size is 0, force 128\n"); size = 128; } if (size < ELD_FIXED_BYTES || size > ELD_MAX_SIZE) { - snd_printd(KERN_INFO "HDMI: invalid ELD buf size %d\n", size); + codec_info(codec, "HDMI: invalid ELD buf size %d\n", size); return -ERANGE; } /* set ELD buffer */ - buf = eld->eld_buffer; - for (i = 0; i < size; i++) { unsigned int val = hdmi_get_eld_data(codec, nid, i); /* @@ -352,8 +348,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, * Just abort. The caller will repoll after a while. */ if (!(val & AC_ELDD_ELD_VALID)) { - snd_printd(KERN_INFO - "HDMI: invalid ELD data byte %d\n", i); + codec_info(codec, "HDMI: invalid ELD data byte %d\n", i); ret = -EINVAL; goto error; } @@ -365,15 +360,14 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, * correctly writes ELD content before setting ELD_valid bit. */ if (!val && !i) { - snd_printdd(KERN_INFO "HDMI: 0 ELD data\n"); + codec_dbg(codec, "HDMI: 0 ELD data\n"); ret = -EINVAL; goto error; } buf[i] = val; } - ret = hdmi_update_eld(eld, buf, size); - + *eld_size = size; error: return ret; } @@ -438,7 +432,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) buf[j] = '\0'; /* necessary when j == 0 */ } -void snd_hdmi_show_eld(struct hdmi_eld *e) +void snd_hdmi_show_eld(struct parsed_hdmi_eld *e) { int i; @@ -484,13 +478,13 @@ static void hdmi_print_sad_info(int i, struct cea_sad *a, snd_iprintf(buffer, "sad%d_profile\t\t%d\n", i, a->profile); } -static void hdmi_print_eld_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +void snd_hdmi_print_eld_info(struct hdmi_eld *eld, + struct snd_info_buffer *buffer) { - struct hdmi_eld *e = entry->private_data; + struct parsed_hdmi_eld *e = &eld->info; char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; int i; - static char *eld_versoin_names[32] = { + static char *eld_version_names[32] = { "reserved", "reserved", "CEA-861D or below", @@ -505,15 +499,15 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, [4 ... 7] = "reserved" }; - snd_iprintf(buffer, "monitor_present\t\t%d\n", e->monitor_present); - snd_iprintf(buffer, "eld_valid\t\t%d\n", e->eld_valid); - if (!e->eld_valid) + snd_iprintf(buffer, "monitor_present\t\t%d\n", eld->monitor_present); + snd_iprintf(buffer, "eld_valid\t\t%d\n", eld->eld_valid); + if (!eld->eld_valid) return; snd_iprintf(buffer, "monitor_name\t\t%s\n", e->monitor_name); snd_iprintf(buffer, "connection_type\t\t%s\n", eld_connection_type_names[e->conn_type]); snd_iprintf(buffer, "eld_version\t\t[0x%x] %s\n", e->eld_ver, - eld_versoin_names[e->eld_ver]); + eld_version_names[e->eld_ver]); snd_iprintf(buffer, "edid_version\t\t[0x%x] %s\n", e->cea_edid_ver, cea_edid_version_names[e->cea_edid_ver]); snd_iprintf(buffer, "manufacture_id\t\t0x%x\n", e->manufacture_id); @@ -532,10 +526,10 @@ static void hdmi_print_eld_info(struct snd_info_entry *entry, hdmi_print_sad_info(i, e->sad + i, buffer); } -static void hdmi_write_eld_info(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) +void snd_hdmi_write_eld_info(struct hdmi_eld *eld, + struct snd_info_buffer *buffer) { - struct hdmi_eld *e = entry->private_data; + struct parsed_hdmi_eld *e = &eld->info; char line[64]; char name[64]; char *sname; @@ -551,9 +545,9 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, * eld_version edid_version */ if (!strcmp(name, "monitor_present")) - e->monitor_present = val; + eld->monitor_present = val; else if (!strcmp(name, "eld_valid")) - e->eld_valid = val; + eld->eld_valid = val; else if (!strcmp(name, "connection_type")) e->conn_type = val; else if (!strcmp(name, "port_id")) @@ -594,40 +588,10 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, } } } - - -int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, - int index) -{ - char name[32]; - struct snd_info_entry *entry; - int err; - - snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); - err = snd_card_proc_new(codec->bus->card, name, &entry); - if (err < 0) - return err; - - snd_info_set_text_ops(entry, eld, hdmi_print_eld_info); - entry->c.text.write = hdmi_write_eld_info; - entry->mode |= S_IWUSR; - eld->proc_entry = entry; - - return 0; -} - -void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) -{ - if (!codec->bus->shutdown && eld->proc_entry) { - snd_device_free(codec->bus->card, eld->proc_entry); - eld->proc_entry = NULL; - } -} - #endif /* CONFIG_PROC_FS */ /* update PCM info based on ELD */ -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, +void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo) { u32 rates; @@ -644,8 +608,8 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, formats = SNDRV_PCM_FMTBIT_S16_LE; maxbps = 16; channels_max = 2; - for (i = 0; i < eld->sad_count; i++) { - struct cea_sad *a = &eld->sad[i]; + for (i = 0; i < e->sad_count; i++) { + struct cea_sad *a = &e->sad[i]; rates |= a->rates; if (a->channels > channels_max) channels_max = a->channels; @@ -669,3 +633,174 @@ void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, hinfo->maxbps = min(hinfo->maxbps, maxbps); hinfo->channels_max = min(hinfo->channels_max, channels_max); } + + +/* ATI/AMD specific stuff (ELD emulation) */ + +#define ATI_VERB_SET_AUDIO_DESCRIPTOR 0x776 +#define ATI_VERB_SET_SINK_INFO_INDEX 0x780 +#define ATI_VERB_GET_SPEAKER_ALLOCATION 0xf70 +#define ATI_VERB_GET_AUDIO_DESCRIPTOR 0xf76 +#define ATI_VERB_GET_AUDIO_VIDEO_DELAY 0xf7b +#define ATI_VERB_GET_SINK_INFO_INDEX 0xf80 +#define ATI_VERB_GET_SINK_INFO_DATA 0xf81 + +#define ATI_SPKALLOC_SPKALLOC 0x007f +#define ATI_SPKALLOC_TYPE_HDMI 0x0100 +#define ATI_SPKALLOC_TYPE_DISPLAYPORT 0x0200 + +/* first three bytes are just standard SAD */ +#define ATI_AUDIODESC_CHANNELS 0x00000007 +#define ATI_AUDIODESC_RATES 0x0000ff00 +#define ATI_AUDIODESC_LPCM_STEREO_RATES 0xff000000 + +/* in standard HDMI VSDB format */ +#define ATI_DELAY_VIDEO_LATENCY 0x000000ff +#define ATI_DELAY_AUDIO_LATENCY 0x0000ff00 + +enum ati_sink_info_idx { + ATI_INFO_IDX_MANUFACTURER_ID = 0, + ATI_INFO_IDX_PRODUCT_ID = 1, + ATI_INFO_IDX_SINK_DESC_LEN = 2, + ATI_INFO_IDX_PORT_ID_LOW = 3, + ATI_INFO_IDX_PORT_ID_HIGH = 4, + ATI_INFO_IDX_SINK_DESC_FIRST = 5, + ATI_INFO_IDX_SINK_DESC_LAST = 22, /* max len 18 bytes */ +}; + +int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size, bool rev3_or_later) +{ + int spkalloc, ati_sad, aud_synch; + int sink_desc_len = 0; + int pos, i; + + /* ATI/AMD does not have ELD, emulate it */ + + spkalloc = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SPEAKER_ALLOCATION, 0); + + if (spkalloc <= 0) { + codec_info(codec, "HDMI ATI/AMD: no speaker allocation for ELD\n"); + return -EINVAL; + } + + memset(buf, 0, ELD_FIXED_BYTES + ELD_MAX_MNL + ELD_MAX_SAD * 3); + + /* version */ + buf[0] = ELD_VER_CEA_861D << 3; + + /* speaker allocation from EDID */ + buf[7] = spkalloc & ATI_SPKALLOC_SPKALLOC; + + /* is DisplayPort? */ + if (spkalloc & ATI_SPKALLOC_TYPE_DISPLAYPORT) + buf[5] |= 0x04; + + pos = ELD_FIXED_BYTES; + + if (rev3_or_later) { + int sink_info; + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_LOW); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le32(sink_info, buf + 8); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PORT_ID_HIGH); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le32(sink_info, buf + 12); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_MANUFACTURER_ID); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le16(sink_info, buf + 16); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_PRODUCT_ID); + sink_info = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + put_unaligned_le16(sink_info, buf + 18); + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_LEN); + sink_desc_len = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + + if (sink_desc_len > ELD_MAX_MNL) { + codec_info(codec, "HDMI ATI/AMD: Truncating HDMI sink description with length %d\n", + sink_desc_len); + sink_desc_len = ELD_MAX_MNL; + } + + buf[4] |= sink_desc_len; + + for (i = 0; i < sink_desc_len; i++) { + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_SINK_INFO_INDEX, ATI_INFO_IDX_SINK_DESC_FIRST + i); + buf[pos++] = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_SINK_INFO_DATA, 0); + } + } + + for (i = AUDIO_CODING_TYPE_LPCM; i <= AUDIO_CODING_TYPE_WMAPRO; i++) { + if (i == AUDIO_CODING_TYPE_SACD || i == AUDIO_CODING_TYPE_DST) + continue; /* not handled by ATI/AMD */ + + snd_hda_codec_write(codec, nid, 0, ATI_VERB_SET_AUDIO_DESCRIPTOR, i << 3); + ati_sad = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_DESCRIPTOR, 0); + + if (ati_sad <= 0) + continue; + + if (ati_sad & ATI_AUDIODESC_RATES) { + /* format is supported, copy SAD as-is */ + buf[pos++] = (ati_sad & 0x0000ff) >> 0; + buf[pos++] = (ati_sad & 0x00ff00) >> 8; + buf[pos++] = (ati_sad & 0xff0000) >> 16; + } + + if (i == AUDIO_CODING_TYPE_LPCM + && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) + && (ati_sad & ATI_AUDIODESC_LPCM_STEREO_RATES) >> 16 != (ati_sad & ATI_AUDIODESC_RATES)) { + /* for PCM there is a separate stereo rate mask */ + buf[pos++] = ((ati_sad & 0x000000ff) & ~ATI_AUDIODESC_CHANNELS) | 0x1; + /* rates from the extra byte */ + buf[pos++] = (ati_sad & 0xff000000) >> 24; + buf[pos++] = (ati_sad & 0x00ff0000) >> 16; + } + } + + if (pos == ELD_FIXED_BYTES + sink_desc_len) { + codec_info(codec, "HDMI ATI/AMD: no audio descriptors for ELD\n"); + return -EINVAL; + } + + /* + * HDMI VSDB latency format: + * separately for both audio and video: + * 0 field not valid or unknown latency + * [1..251] msecs = (x-1)*2 (max 500ms with x = 251 = 0xfb) + * 255 audio/video not supported + * + * HDA latency format: + * single value indicating video latency relative to audio: + * 0 unknown or 0ms + * [1..250] msecs = x*2 (max 500ms with x = 250 = 0xfa) + * [251..255] reserved + */ + aud_synch = snd_hda_codec_read(codec, nid, 0, ATI_VERB_GET_AUDIO_VIDEO_DELAY, 0); + if ((aud_synch & ATI_DELAY_VIDEO_LATENCY) && (aud_synch & ATI_DELAY_AUDIO_LATENCY)) { + int video_latency_hdmi = (aud_synch & ATI_DELAY_VIDEO_LATENCY); + int audio_latency_hdmi = (aud_synch & ATI_DELAY_AUDIO_LATENCY) >> 8; + + if (video_latency_hdmi <= 0xfb && audio_latency_hdmi <= 0xfb && + video_latency_hdmi > audio_latency_hdmi) + buf[6] = video_latency_hdmi - audio_latency_hdmi; + /* else unknown/invalid or 0ms or video ahead of audio, so use zero */ + } + + /* SAD count */ + buf[5] |= ((pos - ELD_FIXED_BYTES - sink_desc_len) / 3) << 4; + + /* Baseline ELD block length is 4-byte aligned */ + pos = round_up(pos, 4); + + /* Baseline ELD length (4-byte header is not counted in) */ + buf[2] = (pos - 4) / 4; + + *eld_size = pos; + + return 0; +} diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b81d3d0b952..589e47c5aeb 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -23,836 +23,3576 @@ #include <linux/init.h> #include <linux/slab.h> #include <linux/export.h> +#include <linux/sort.h> +#include <linux/delay.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/bitops.h> +#include <linux/module.h> #include <sound/core.h> +#include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" +#include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_beep.h" +#include "hda_generic.h" -/* widget node for parsing */ -struct hda_gnode { - hda_nid_t nid; /* NID of this widget */ - unsigned short nconns; /* number of input connections */ - hda_nid_t *conn_list; - hda_nid_t slist[2]; /* temporay list */ - unsigned int wid_caps; /* widget capabilities */ - unsigned char type; /* widget type */ - unsigned char pin_ctl; /* pin controls */ - unsigned char checked; /* the flag indicates that the node is already parsed */ - unsigned int pin_caps; /* pin widget capabilities */ - unsigned int def_cfg; /* default configuration */ - unsigned int amp_out_caps; /* AMP out capabilities */ - unsigned int amp_in_caps; /* AMP in capabilities */ - struct list_head list; -}; -/* patch-specific record */ +/* initialize hda_gen_spec struct */ +int snd_hda_gen_spec_init(struct hda_gen_spec *spec) +{ + snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); + snd_array_init(&spec->paths, sizeof(struct nid_path), 8); + snd_array_init(&spec->loopback_list, sizeof(struct hda_amp_list), 8); + mutex_init(&spec->pcm_mutex); + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init); -#define MAX_PCM_VOLS 2 -struct pcm_vol { - struct hda_gnode *node; /* Node for PCM volume */ - unsigned int index; /* connection of PCM volume */ -}; +struct snd_kcontrol_new * +snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, + const struct snd_kcontrol_new *temp) +{ + struct snd_kcontrol_new *knew = snd_array_new(&spec->kctls); + if (!knew) + return NULL; + *knew = *temp; + if (name) + knew->name = kstrdup(name, GFP_KERNEL); + else if (knew->name) + knew->name = kstrdup(knew->name, GFP_KERNEL); + if (!knew->name) + return NULL; + return knew; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_add_kctl); -struct hda_gspec { - struct hda_gnode *dac_node[2]; /* DAC node */ - struct hda_gnode *out_pin_node[2]; /* Output pin (Line-Out) node */ - struct pcm_vol pcm_vol[MAX_PCM_VOLS]; /* PCM volumes */ - unsigned int pcm_vol_nodes; /* number of PCM volumes */ +static void free_kctls(struct hda_gen_spec *spec) +{ + if (spec->kctls.list) { + struct snd_kcontrol_new *kctl = spec->kctls.list; + int i; + for (i = 0; i < spec->kctls.used; i++) + kfree(kctl[i].name); + } + snd_array_free(&spec->kctls); +} - struct hda_gnode *adc_node; /* ADC node */ - struct hda_gnode *cap_vol_node; /* Node for capture volume */ - unsigned int cur_cap_src; /* current capture source */ - struct hda_input_mux input_mux; +static void snd_hda_gen_spec_free(struct hda_gen_spec *spec) +{ + if (!spec) + return; + free_kctls(spec); + snd_array_free(&spec->paths); + snd_array_free(&spec->loopback_list); +} - unsigned int def_amp_in_caps; - unsigned int def_amp_out_caps; +/* + * store user hints + */ +static void parse_user_hints(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int val; - struct hda_pcm pcm_rec; /* PCM information */ + val = snd_hda_get_bool_hint(codec, "jack_detect"); + if (val >= 0) + codec->no_jack_detect = !val; + val = snd_hda_get_bool_hint(codec, "inv_jack_detect"); + if (val >= 0) + codec->inv_jack_detect = !!val; + val = snd_hda_get_bool_hint(codec, "trigger_sense"); + if (val >= 0) + codec->no_trigger_sense = !val; + val = snd_hda_get_bool_hint(codec, "inv_eapd"); + if (val >= 0) + codec->inv_eapd = !!val; + val = snd_hda_get_bool_hint(codec, "pcm_format_first"); + if (val >= 0) + codec->pcm_format_first = !!val; + val = snd_hda_get_bool_hint(codec, "sticky_stream"); + if (val >= 0) + codec->no_sticky_stream = !val; + val = snd_hda_get_bool_hint(codec, "spdif_status_reset"); + if (val >= 0) + codec->spdif_status_reset = !!val; + val = snd_hda_get_bool_hint(codec, "pin_amp_workaround"); + if (val >= 0) + codec->pin_amp_workaround = !!val; + val = snd_hda_get_bool_hint(codec, "single_adc_amp"); + if (val >= 0) + codec->single_adc_amp = !!val; - struct list_head nid_list; /* list of widgets */ + val = snd_hda_get_bool_hint(codec, "auto_mute"); + if (val >= 0) + spec->suppress_auto_mute = !val; + val = snd_hda_get_bool_hint(codec, "auto_mic"); + if (val >= 0) + spec->suppress_auto_mic = !val; + val = snd_hda_get_bool_hint(codec, "line_in_auto_switch"); + if (val >= 0) + spec->line_in_auto_switch = !!val; + val = snd_hda_get_bool_hint(codec, "auto_mute_via_amp"); + if (val >= 0) + spec->auto_mute_via_amp = !!val; + val = snd_hda_get_bool_hint(codec, "need_dac_fix"); + if (val >= 0) + spec->need_dac_fix = !!val; + val = snd_hda_get_bool_hint(codec, "primary_hp"); + if (val >= 0) + spec->no_primary_hp = !val; + val = snd_hda_get_bool_hint(codec, "multi_io"); + if (val >= 0) + spec->no_multi_io = !val; + val = snd_hda_get_bool_hint(codec, "multi_cap_vol"); + if (val >= 0) + spec->multi_cap_vol = !!val; + val = snd_hda_get_bool_hint(codec, "inv_dmic_split"); + if (val >= 0) + spec->inv_dmic_split = !!val; + val = snd_hda_get_bool_hint(codec, "indep_hp"); + if (val >= 0) + spec->indep_hp = !!val; + val = snd_hda_get_bool_hint(codec, "add_stereo_mix_input"); + if (val >= 0) + spec->add_stereo_mix_input = !!val; + /* the following two are just for compatibility */ + val = snd_hda_get_bool_hint(codec, "add_out_jack_modes"); + if (val >= 0) + spec->add_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "add_in_jack_modes"); + if (val >= 0) + spec->add_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "add_jack_modes"); + if (val >= 0) + spec->add_jack_modes = !!val; + val = snd_hda_get_bool_hint(codec, "power_down_unused"); + if (val >= 0) + spec->power_down_unused = !!val; + val = snd_hda_get_bool_hint(codec, "add_hp_mic"); + if (val >= 0) + spec->hp_mic = !!val; + val = snd_hda_get_bool_hint(codec, "hp_mic_detect"); + if (val >= 0) + spec->suppress_hp_mic_detect = !val; -#ifdef CONFIG_PM -#define MAX_LOOPBACK_AMPS 7 - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[MAX_LOOPBACK_AMPS + 1]; -#endif -}; + if (!snd_hda_get_int_hint(codec, "mixer_nid", &val)) + spec->mixer_nid = val; +} /* - * retrieve the default device type from the default config value + * pin control value accesses */ -#define defcfg_type(node) (((node)->def_cfg & AC_DEFCFG_DEVICE) >> \ - AC_DEFCFG_DEVICE_SHIFT) -#define defcfg_location(node) (((node)->def_cfg & AC_DEFCFG_LOCATION) >> \ - AC_DEFCFG_LOCATION_SHIFT) -#define defcfg_port_conn(node) (((node)->def_cfg & AC_DEFCFG_PORT_CONN) >> \ - AC_DEFCFG_PORT_CONN_SHIFT) -/* - * destructor - */ -static void snd_hda_generic_free(struct hda_codec *codec) +#define update_pin_ctl(codec, pin, val) \ + snd_hda_codec_update_cache(codec, pin, 0, \ + AC_VERB_SET_PIN_WIDGET_CONTROL, val) + +/* restore the pinctl based on the cached value */ +static inline void restore_pin_ctl(struct hda_codec *codec, hda_nid_t pin) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node, *n; + update_pin_ctl(codec, pin, snd_hda_codec_get_pin_target(codec, pin)); +} - if (! spec) +/* set the pinctl target value and write it if requested */ +static void set_pin_target(struct hda_codec *codec, hda_nid_t pin, + unsigned int val, bool do_write) +{ + if (!pin) return; - /* free all widgets */ - list_for_each_entry_safe(node, n, &spec->nid_list, list) { - if (node->conn_list != node->slist) - kfree(node->conn_list); - kfree(node); - } - kfree(spec); + val = snd_hda_correct_pin_ctl(codec, pin, val); + snd_hda_codec_set_pin_target(codec, pin, val); + if (do_write) + update_pin_ctl(codec, pin, val); } +/* set pinctl target values for all given pins */ +static void set_pin_targets(struct hda_codec *codec, int num_pins, + hda_nid_t *pins, unsigned int val) +{ + int i; + for (i = 0; i < num_pins; i++) + set_pin_target(codec, pins[i], val, false); +} /* - * add a new widget node and read its attributes + * parsing paths */ -static int add_new_node(struct hda_codec *codec, struct hda_gspec *spec, hda_nid_t nid) + +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) { - struct hda_gnode *node; - int nconns; - hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (node == NULL) - return -ENOMEM; - node->nid = nid; - node->wid_caps = get_wcaps(codec, nid); - node->type = get_wcaps_type(node->wid_caps); - if (node->wid_caps & AC_WCAP_CONN_LIST) { - nconns = snd_hda_get_connections(codec, nid, conn_list, - HDA_MAX_CONNECTIONS); - if (nconns < 0) { - kfree(node); - return nconns; - } - } else { - nconns = 0; - } - if (nconns <= ARRAY_SIZE(node->slist)) - node->conn_list = node->slist; - else { - node->conn_list = kmalloc(sizeof(hda_nid_t) * nconns, - GFP_KERNEL); - if (! node->conn_list) { - snd_printk(KERN_ERR "hda-generic: cannot malloc\n"); - kfree(node); - return -ENOMEM; +/* return true if the given NID is contained in the path */ +static bool is_nid_contained(struct nid_path *path, hda_nid_t nid) +{ + return find_idx_in_nid_list(nid, path->path, path->depth) >= 0; +} + +static struct nid_path *get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid, + int anchor_nid) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if (path->depth <= 0) + continue; + if ((!from_nid || path->path[0] == from_nid) && + (!to_nid || path->path[path->depth - 1] == to_nid)) { + if (!anchor_nid || + (anchor_nid > 0 && is_nid_contained(path, anchor_nid)) || + (anchor_nid < 0 && !is_nid_contained(path, anchor_nid))) + return path; } } - memcpy(node->conn_list, conn_list, nconns * sizeof(hda_nid_t)); - node->nconns = nconns; + return NULL; +} + +/* get the path between the given NIDs; + * passing 0 to either @pin or @dac behaves as a wildcard + */ +struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid) +{ + return get_nid_path(codec, from_nid, to_nid, 0); +} +EXPORT_SYMBOL_GPL(snd_hda_get_nid_path); - if (node->type == AC_WID_PIN) { - node->pin_caps = snd_hda_query_pin_caps(codec, node->nid); - node->pin_ctl = snd_hda_codec_read(codec, node->nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - node->def_cfg = snd_hda_codec_get_pincfg(codec, node->nid); +/* get the index number corresponding to the path instance; + * the index starts from 1, for easier checking the invalid value + */ +int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *array = spec->paths.list; + ssize_t idx; + + if (!spec->paths.used) + return 0; + idx = path - array; + if (idx < 0 || idx >= spec->paths.used) + return 0; + return idx + 1; +} +EXPORT_SYMBOL_GPL(snd_hda_get_path_idx); + +/* get the path instance corresponding to the given index number */ +struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + + if (idx <= 0 || idx > spec->paths.used) + return NULL; + return snd_array_elem(&spec->paths, idx - 1); +} +EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx); + +/* check whether the given DAC is already found in any existing paths */ +static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if (path->path[0] == nid) + return true; } + return false; +} + +/* check whether the given two widgets can be connected */ +static bool is_reachable_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid) +{ + if (!from_nid || !to_nid) + return false; + return snd_hda_get_conn_index(codec, to_nid, from_nid, true) >= 0; +} + +/* nid, dir and idx */ +#define AMP_VAL_COMPARE_MASK (0xffff | (1U << 18) | (0x0f << 19)) + +/* check whether the given ctl is already assigned in any path elements */ +static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) +{ + struct hda_gen_spec *spec = codec->spec; + int i; - if (node->wid_caps & AC_WCAP_OUT_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_out_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_OUT_CAP); - if (! node->amp_out_caps) - node->amp_out_caps = spec->def_amp_out_caps; + val &= AMP_VAL_COMPARE_MASK; + for (i = 0; i < spec->paths.used; i++) { + struct nid_path *path = snd_array_elem(&spec->paths, i); + if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) + return true; } - if (node->wid_caps & AC_WCAP_IN_AMP) { - if (node->wid_caps & AC_WCAP_AMP_OVRD) - node->amp_in_caps = snd_hda_param_read(codec, node->nid, AC_PAR_AMP_IN_CAP); - if (! node->amp_in_caps) - node->amp_in_caps = spec->def_amp_in_caps; + return false; +} + +/* check whether a control with the given (nid, dir, idx) was assigned */ +static bool is_ctl_associated(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int type) +{ + unsigned int val = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir); + return is_ctl_used(codec, val, type); +} + +static void print_nid_path(struct hda_codec *codec, + const char *pfx, struct nid_path *path) +{ + char buf[40]; + int i; + + + buf[0] = 0; + for (i = 0; i < path->depth; i++) { + char tmp[4]; + sprintf(tmp, ":%02x", path->path[i]); + strlcat(buf, tmp, sizeof(buf)); } - list_add_tail(&node->list, &spec->nid_list); - return 0; + codec_dbg(codec, "%s path: depth=%d %s\n", pfx, path->depth, buf); } +/* called recursively */ +static bool __parse_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid, + int anchor_nid, struct nid_path *path, + int depth) +{ + const hda_nid_t *conn; + int i, nums; + + if (to_nid == anchor_nid) + anchor_nid = 0; /* anchor passed */ + else if (to_nid == (hda_nid_t)(-anchor_nid)) + return false; /* hit the exclusive nid */ + + nums = snd_hda_get_conn_list(codec, to_nid, &conn); + for (i = 0; i < nums; i++) { + if (conn[i] != from_nid) { + /* special case: when from_nid is 0, + * try to find an empty DAC + */ + if (from_nid || + get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT || + is_dac_already_used(codec, conn[i])) + continue; + } + /* anchor is not requested or already passed? */ + if (anchor_nid <= 0) + goto found; + } + if (depth >= MAX_NID_PATH_DEPTH) + return false; + for (i = 0; i < nums; i++) { + unsigned int type; + type = get_wcaps_type(get_wcaps(codec, conn[i])); + if (type == AC_WID_AUD_OUT || type == AC_WID_AUD_IN || + type == AC_WID_PIN) + continue; + if (__parse_nid_path(codec, from_nid, conn[i], + anchor_nid, path, depth + 1)) + goto found; + } + return false; + + found: + path->path[path->depth] = conn[i]; + path->idx[path->depth + 1] = i; + if (nums > 1 && get_wcaps_type(get_wcaps(codec, to_nid)) != AC_WID_AUD_MIX) + path->multi[path->depth + 1] = 1; + path->depth++; + return true; +} + +/* parse the widget path from the given nid to the target nid; + * when @from_nid is 0, try to find an empty DAC; + * when @anchor_nid is set to a positive value, only paths through the widget + * with the given value are evaluated. + * when @anchor_nid is set to a negative value, paths through the widget + * with the negative of given value are excluded, only other paths are chosen. + * when @anchor_nid is zero, no special handling about path selection. + */ +bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid, + struct nid_path *path) +{ + if (__parse_nid_path(codec, from_nid, to_nid, anchor_nid, path, 1)) { + path->path[path->depth] = to_nid; + path->depth++; + return true; + } + return false; +} +EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path); + /* - * build the AFG subtree + * parse the path between the given NIDs and add to the path list. + * if no valid path is found, return NULL */ -static int build_afg_tree(struct hda_codec *codec) +struct nid_path * +snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid) { - struct hda_gspec *spec = codec->spec; - int i, nodes, err; - hda_nid_t nid; + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; - if (snd_BUG_ON(!spec)) - return -EINVAL; + if (from_nid && to_nid && !is_reachable_path(codec, from_nid, to_nid)) + return NULL; - spec->def_amp_out_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_OUT_CAP); - spec->def_amp_in_caps = snd_hda_param_read(codec, codec->afg, AC_PAR_AMP_IN_CAP); + /* check whether the path has been already added */ + path = get_nid_path(codec, from_nid, to_nid, anchor_nid); + if (path) + return path; - nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); - if (! nid || nodes < 0) { - printk(KERN_ERR "Invalid AFG subtree\n"); - return -EINVAL; - } + path = snd_array_new(&spec->paths); + if (!path) + return NULL; + memset(path, 0, sizeof(*path)); + if (snd_hda_parse_nid_path(codec, from_nid, to_nid, anchor_nid, path)) + return path; + /* push back */ + spec->paths.used--; + return NULL; +} +EXPORT_SYMBOL_GPL(snd_hda_add_new_path); - /* parse all nodes belonging to the AFG */ - for (i = 0; i < nodes; i++, nid++) { - if ((err = add_new_node(codec, spec, nid)) < 0) - return err; +/* clear the given path as invalid so that it won't be picked up later */ +static void invalidate_nid_path(struct hda_codec *codec, int idx) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, idx); + if (!path) + return; + memset(path, 0, sizeof(*path)); +} + +/* return a DAC if paired to the given pin by codec driver */ +static hda_nid_t get_preferred_dac(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + const hda_nid_t *list = spec->preferred_dacs; + + if (!list) + return 0; + for (; *list; list += 2) + if (*list == pin) + return list[1]; + return 0; +} + +/* look for an empty DAC slot */ +static hda_nid_t look_for_dac(struct hda_codec *codec, hda_nid_t pin, + bool is_digital) +{ + struct hda_gen_spec *spec = codec->spec; + bool cap_digital; + int i; + + for (i = 0; i < spec->num_all_dacs; i++) { + hda_nid_t nid = spec->all_dacs[i]; + if (!nid || is_dac_already_used(codec, nid)) + continue; + cap_digital = !!(get_wcaps(codec, nid) & AC_WCAP_DIGITAL); + if (is_digital != cap_digital) + continue; + if (is_reachable_path(codec, nid, pin)) + return nid; } + return 0; +} + +/* replace the channels in the composed amp value with the given number */ +static unsigned int amp_val_replace_channels(unsigned int val, unsigned int chs) +{ + val &= ~(0x3U << 16); + val |= chs << 16; + return val; +} +/* check whether the widget has the given amp capability for the direction */ +static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int bits) +{ + if (!nid) + return false; + if (get_wcaps(codec, nid) & (1 << (dir + 1))) + if (query_amp_caps(codec, nid, dir) & bits) + return true; + return false; +} + +static bool same_amp_caps(struct hda_codec *codec, hda_nid_t nid1, + hda_nid_t nid2, int dir) +{ + if (!(get_wcaps(codec, nid1) & (1 << (dir + 1)))) + return !(get_wcaps(codec, nid2) & (1 << (dir + 1))); + return (query_amp_caps(codec, nid1, dir) == + query_amp_caps(codec, nid2, dir)); +} + +#define nid_has_mute(codec, nid, dir) \ + check_amp_caps(codec, nid, dir, (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) +#define nid_has_volume(codec, nid, dir) \ + check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) + +/* look for a widget suitable for assigning a mute switch in the path */ +static hda_nid_t look_for_out_mute_nid(struct hda_codec *codec, + struct nid_path *path) +{ + int i; + + for (i = path->depth - 1; i >= 0; i--) { + if (nid_has_mute(codec, path->path[i], HDA_OUTPUT)) + return path->path[i]; + if (i != path->depth - 1 && i != 0 && + nid_has_mute(codec, path->path[i], HDA_INPUT)) + return path->path[i]; + } return 0; } +/* look for a widget suitable for assigning a volume ctl in the path */ +static hda_nid_t look_for_out_vol_nid(struct hda_codec *codec, + struct nid_path *path) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = path->depth - 1; i >= 0; i--) { + hda_nid_t nid = path->path[i]; + if ((spec->out_vol_mask >> nid) & 1) + continue; + if (nid_has_volume(codec, nid, HDA_OUTPUT)) + return nid; + } + return 0; +} /* - * look for the node record for the given NID + * path activation / deactivation */ -/* FIXME: should avoid the braindead linear search */ -static struct hda_gnode *hda_get_node(struct hda_gspec *spec, hda_nid_t nid) + +/* can have the amp-in capability? */ +static bool has_amp_in(struct hda_codec *codec, struct nid_path *path, int idx) +{ + hda_nid_t nid = path->path[idx]; + unsigned int caps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_IN_AMP)) + return false; + if (type == AC_WID_PIN && idx > 0) /* only for input pins */ + return false; + return true; +} + +/* can have the amp-out capability? */ +static bool has_amp_out(struct hda_codec *codec, struct nid_path *path, int idx) +{ + hda_nid_t nid = path->path[idx]; + unsigned int caps = get_wcaps(codec, nid); + unsigned int type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_OUT_AMP)) + return false; + if (type == AC_WID_PIN && !idx) /* only for output pins */ + return false; + return true; +} + +/* check whether the given (nid,dir,idx) is active */ +static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, + unsigned int dir, unsigned int idx) { - struct hda_gnode *node; + struct hda_gen_spec *spec = codec->spec; + int i, n; - list_for_each_entry(node, &spec->nid_list, list) { - if (node->nid == nid) - return node; + for (n = 0; n < spec->paths.used; n++) { + struct nid_path *path = snd_array_elem(&spec->paths, n); + if (!path->active) + continue; + for (i = 0; i < path->depth; i++) { + if (path->path[i] == nid) { + if (dir == HDA_OUTPUT || path->idx[i] == idx) + return true; + break; + } + } } - return NULL; + return false; } -/* - * unmute (and set max vol) the output amplifier +/* check whether the NID is referred by any active paths */ +#define is_active_nid_for_any(codec, nid) \ + is_active_nid(codec, nid, HDA_OUTPUT, 0) + +/* get the default amp value for the target state */ +static int get_amp_val_to_activate(struct hda_codec *codec, hda_nid_t nid, + int dir, unsigned int caps, bool enable) +{ + unsigned int val = 0; + + if (caps & AC_AMPCAP_NUM_STEPS) { + /* set to 0dB */ + if (enable) + val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; + } + if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { + if (!enable) + val |= HDA_AMP_MUTE; + } + return val; +} + +/* initialize the amp value (only at the first time) */ +static void init_amp(struct hda_codec *codec, hda_nid_t nid, int dir, int idx) +{ + unsigned int caps = query_amp_caps(codec, nid, dir); + int val = get_amp_val_to_activate(codec, nid, dir, caps, false); + snd_hda_codec_amp_init_stereo(codec, nid, dir, idx, 0xff, val); +} + +/* calculate amp value mask we can modify; + * if the given amp is controlled by mixers, don't touch it */ -static int unmute_output(struct hda_codec *codec, struct hda_gnode *node) +static unsigned int get_amp_mask_to_modify(struct hda_codec *codec, + hda_nid_t nid, int dir, int idx, + unsigned int caps) { - unsigned int val, ofs; - snd_printdd("UNMUTE OUT: NID=0x%x\n", node->nid); - val = (node->amp_out_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_out_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - snd_hda_codec_amp_stereo(codec, node->nid, HDA_OUTPUT, 0, 0xff, val); - return 0; + unsigned int mask = 0xff; + + if (caps & (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE)) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_MUTE_CTL)) + mask &= ~0x80; + } + if (caps & AC_AMPCAP_NUM_STEPS) { + if (is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + mask &= ~0x7f; + } + return mask; } -/* - * unmute (and set max vol) the input amplifier +static void activate_amp(struct hda_codec *codec, hda_nid_t nid, int dir, + int idx, int idx_to_check, bool enable) +{ + unsigned int caps; + unsigned int mask, val; + + if (!enable && is_active_nid(codec, nid, dir, idx_to_check)) + return; + + caps = query_amp_caps(codec, nid, dir); + val = get_amp_val_to_activate(codec, nid, dir, caps, enable); + mask = get_amp_mask_to_modify(codec, nid, dir, idx_to_check, caps); + if (!mask) + return; + + val &= mask; + snd_hda_codec_amp_stereo(codec, nid, dir, idx, mask, val); +} + +static void activate_amp_out(struct hda_codec *codec, struct nid_path *path, + int i, bool enable) +{ + hda_nid_t nid = path->path[i]; + init_amp(codec, nid, HDA_OUTPUT, 0); + activate_amp(codec, nid, HDA_OUTPUT, 0, 0, enable); +} + +static void activate_amp_in(struct hda_codec *codec, struct nid_path *path, + int i, bool enable, bool add_aamix) +{ + struct hda_gen_spec *spec = codec->spec; + const hda_nid_t *conn; + int n, nums, idx; + int type; + hda_nid_t nid = path->path[i]; + + nums = snd_hda_get_conn_list(codec, nid, &conn); + type = get_wcaps_type(get_wcaps(codec, nid)); + if (type == AC_WID_PIN || + (type == AC_WID_AUD_IN && codec->single_adc_amp)) { + nums = 1; + idx = 0; + } else + idx = path->idx[i]; + + for (n = 0; n < nums; n++) + init_amp(codec, nid, HDA_INPUT, n); + + /* here is a little bit tricky in comparison with activate_amp_out(); + * when aa-mixer is available, we need to enable the path as well + */ + for (n = 0; n < nums; n++) { + if (n != idx && (!add_aamix || conn[n] != spec->mixer_merge_nid)) + continue; + activate_amp(codec, nid, HDA_INPUT, n, idx, enable); + } +} + +/* activate or deactivate the given path + * if @add_aamix is set, enable the input from aa-mix NID as well (if any) */ -static int unmute_input(struct hda_codec *codec, struct hda_gnode *node, unsigned int index) +void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, + bool enable, bool add_aamix) { - unsigned int val, ofs; - snd_printdd("UNMUTE IN: NID=0x%x IDX=0x%x\n", node->nid, index); - val = (node->amp_in_caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - ofs = (node->amp_in_caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - if (val >= ofs) - val -= ofs; - snd_hda_codec_amp_stereo(codec, node->nid, HDA_INPUT, index, 0xff, val); - return 0; + struct hda_gen_spec *spec = codec->spec; + int i; + + if (!enable) + path->active = false; + + for (i = path->depth - 1; i >= 0; i--) { + hda_nid_t nid = path->path[i]; + if (enable && spec->power_down_unused) { + /* make sure the widget is powered up */ + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + } + if (enable && path->multi[i]) + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + path->idx[i]); + if (has_amp_in(codec, path, i)) + activate_amp_in(codec, path, i, enable, add_aamix); + if (has_amp_out(codec, path, i)) + activate_amp_out(codec, path, i, enable); + } + + if (enable) + path->active = true; } +EXPORT_SYMBOL_GPL(snd_hda_activate_path); + +/* if the given path is inactive, put widgets into D3 (only if suitable) */ +static void path_power_down_sync(struct hda_codec *codec, struct nid_path *path) +{ + struct hda_gen_spec *spec = codec->spec; + bool changed = false; + int i; + + if (!spec->power_down_unused || path->active) + return; + + for (i = 0; i < path->depth; i++) { + hda_nid_t nid = path->path[i]; + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D3) && + !is_active_nid_for_any(codec, nid)) { + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + changed = true; + } + } + + if (changed) { + msleep(10); + snd_hda_codec_read(codec, path->path[0], 0, + AC_VERB_GET_POWER_STATE, 0); + } +} + +/* turn on/off EAPD on the given pin */ +static void set_pin_eapd(struct hda_codec *codec, hda_nid_t pin, bool enable) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->own_eapd_ctl || + !(snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD)) + return; + if (spec->keep_eapd_on && !enable) + return; + if (codec->inv_eapd) + enable = !enable; + snd_hda_codec_update_cache(codec, pin, 0, + AC_VERB_SET_EAPD_BTLENABLE, + enable ? 0x02 : 0x00); +} + +/* re-initialize the path specified by the given path index */ +static void resume_path_from_idx(struct hda_codec *codec, int path_idx) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); + if (path) + snd_hda_activate_path(codec, path, path->active, false); +} + /* - * select the input connection of the given node. + * Helper functions for creating mixer ctl elements */ -static int select_input_connection(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index) + +static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +enum { + HDA_CTL_WIDGET_VOL, + HDA_CTL_WIDGET_MUTE, + HDA_CTL_BIND_MUTE, +}; +static const struct snd_kcontrol_new control_templates[] = { + HDA_CODEC_VOLUME(NULL, 0, 0, 0), + /* only the put callback is replaced for handling the special mute */ + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .subdevice = HDA_SUBDEV_AMP_FLAG, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_amp_switch_get, + .put = hda_gen_mixer_mute_put, /* replaced */ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = snd_hda_mixer_amp_switch_info, + .get = snd_hda_mixer_bind_switch_get, + .put = hda_gen_bind_mute_put, /* replaced */ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0), + }, +}; + +/* add dynamic controls from template */ +static struct snd_kcontrol_new * +add_control(struct hda_gen_spec *spec, int type, const char *name, + int cidx, unsigned long val) { - snd_printdd("CONNECT: NID=0x%x IDX=0x%x\n", node->nid, index); - return snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_CONNECT_SEL, index); + struct snd_kcontrol_new *knew; + + knew = snd_hda_gen_add_kctl(spec, name, &control_templates[type]); + if (!knew) + return NULL; + knew->index = cidx; + if (get_amp_nid_(val)) + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + knew->private_value = val; + return knew; } -/* - * clear checked flag of each node in the node list +static int add_control_with_pfx(struct hda_gen_spec *spec, int type, + const char *pfx, const char *dir, + const char *sfx, int cidx, unsigned long val) +{ + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); + if (!add_control(spec, type, name, cidx, val)) + return -ENOMEM; + return 0; +} + +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) +#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) +#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) + +static int add_vol_ctl(struct hda_codec *codec, const char *pfx, int cidx, + unsigned int chs, struct nid_path *path) +{ + unsigned int val; + if (!path) + return 0; + val = path->ctls[NID_PATH_VOL_CTL]; + if (!val) + return 0; + val = amp_val_replace_channels(val, chs); + return __add_pb_vol_ctrl(codec->spec, HDA_CTL_WIDGET_VOL, pfx, cidx, val); +} + +/* return the channel bits suitable for the given path->ctls[] */ +static int get_default_ch_nums(struct hda_codec *codec, struct nid_path *path, + int type) +{ + int chs = 1; /* mono (left only) */ + if (path) { + hda_nid_t nid = get_amp_nid_(path->ctls[type]); + if (nid && (get_wcaps(codec, nid) & AC_WCAP_STEREO)) + chs = 3; /* stereo */ + } + return chs; +} + +static int add_stereo_vol(struct hda_codec *codec, const char *pfx, int cidx, + struct nid_path *path) +{ + int chs = get_default_ch_nums(codec, path, NID_PATH_VOL_CTL); + return add_vol_ctl(codec, pfx, cidx, chs, path); +} + +/* create a mute-switch for the given mixer widget; + * if it has multiple sources (e.g. DAC and loopback), create a bind-mute */ -static void clear_check_flags(struct hda_gspec *spec) +static int add_sw_ctl(struct hda_codec *codec, const char *pfx, int cidx, + unsigned int chs, struct nid_path *path) +{ + unsigned int val; + int type = HDA_CTL_WIDGET_MUTE; + + if (!path) + return 0; + val = path->ctls[NID_PATH_MUTE_CTL]; + if (!val) + return 0; + val = amp_val_replace_channels(val, chs); + if (get_amp_direction_(val) == HDA_INPUT) { + hda_nid_t nid = get_amp_nid_(val); + int nums = snd_hda_get_num_conns(codec, nid); + if (nums > 1) { + type = HDA_CTL_BIND_MUTE; + val |= nums << 19; + } + } + return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); +} + +static int add_stereo_sw(struct hda_codec *codec, const char *pfx, + int cidx, struct nid_path *path) +{ + int chs = get_default_ch_nums(codec, path, NID_PATH_MUTE_CTL); + return add_sw_ctl(codec, pfx, cidx, chs, path); +} + +/* playback mute control with the software mute bit check */ +static void sync_auto_mute_bits(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct hda_gnode *node; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; - list_for_each_entry(node, &spec->nid_list, list) { - node->checked = 0; + if (spec->auto_mute_via_amp) { + hda_nid_t nid = get_amp_nid(kcontrol); + bool enabled = !((spec->mute_bits >> nid) & 1); + ucontrol->value.integer.value[0] &= enabled; + ucontrol->value.integer.value[1] &= enabled; } } +static int hda_gen_mixer_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + sync_auto_mute_bits(kcontrol, ucontrol); + return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); +} + +static int hda_gen_bind_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + sync_auto_mute_bits(kcontrol, ucontrol); + return snd_hda_mixer_bind_switch_put(kcontrol, ucontrol); +} + +/* any ctl assigned to the path with the given index? */ +static bool path_has_mixer(struct hda_codec *codec, int path_idx, int ctl_type) +{ + struct nid_path *path = snd_hda_get_path_from_idx(codec, path_idx); + return path && path->ctls[ctl_type]; +} + +static const char * const channel_name[4] = { + "Front", "Surround", "CLFE", "Side" +}; + +/* give some appropriate ctl name prefix for the given line out channel */ +static const char *get_line_out_pfx(struct hda_codec *codec, int ch, + int *index, int ctl_type) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + *index = 0; + if (cfg->line_outs == 1 && !spec->multi_ios && + !cfg->hp_outs && !cfg->speaker_outs) + return spec->vmaster_mute.hook ? "PCM" : "Master"; + + /* if there is really a single DAC used in the whole output paths, + * use it master (or "PCM" if a vmaster hook is present) + */ + if (spec->multiout.num_dacs == 1 && !spec->mixer_nid && + !spec->multiout.hp_out_nid[0] && !spec->multiout.extra_out_nid[0]) + return spec->vmaster_mute.hook ? "PCM" : "Master"; + + /* multi-io channels */ + if (ch >= cfg->line_outs) + return channel_name[ch]; + + switch (cfg->line_out_type) { + case AUTO_PIN_SPEAKER_OUT: + /* if the primary channel vol/mute is shared with HP volume, + * don't name it as Speaker + */ + if (!ch && cfg->hp_outs && + !path_has_mixer(codec, spec->hp_paths[0], ctl_type)) + break; + if (cfg->line_outs == 1) + return "Speaker"; + if (cfg->line_outs == 2) + return ch ? "Bass Speaker" : "Speaker"; + break; + case AUTO_PIN_HP_OUT: + /* if the primary channel vol/mute is shared with spk volume, + * don't name it as Headphone + */ + if (!ch && cfg->speaker_outs && + !path_has_mixer(codec, spec->speaker_paths[0], ctl_type)) + break; + /* for multi-io case, only the primary out */ + if (ch && spec->multi_ios) + break; + *index = ch; + return "Headphone"; + } + + /* for a single channel output, we don't have to name the channel */ + if (cfg->line_outs == 1 && !spec->multi_ios) + return "PCM"; + + if (ch >= ARRAY_SIZE(channel_name)) { + snd_BUG(); + return "PCM"; + } + + return channel_name[ch]; +} + /* - * parse the output path recursively until reach to an audio output widget + * Parse output paths + */ + +/* badness definition */ +enum { + /* No primary DAC is found for the main output */ + BAD_NO_PRIMARY_DAC = 0x10000, + /* No DAC is found for the extra output */ + BAD_NO_DAC = 0x4000, + /* No possible multi-ios */ + BAD_MULTI_IO = 0x120, + /* No individual DAC for extra output */ + BAD_NO_EXTRA_DAC = 0x102, + /* No individual DAC for extra surrounds */ + BAD_NO_EXTRA_SURR_DAC = 0x101, + /* Primary DAC shared with main surrounds */ + BAD_SHARED_SURROUND = 0x100, + /* No independent HP possible */ + BAD_NO_INDEP_HP = 0x10, + /* Primary DAC shared with main CLFE */ + BAD_SHARED_CLFE = 0x10, + /* Primary DAC shared with extra surrounds */ + BAD_SHARED_EXTRA_SURROUND = 0x10, + /* Volume widget is shared */ + BAD_SHARED_VOL = 0x10, +}; + +/* look for widgets in the given path which are appropriate for + * volume and mute controls, and assign the values to ctls[]. * - * returns 0 if not found, 1 if found, or a negative error code. + * When no appropriate widget is found in the path, the badness value + * is incremented depending on the situation. The function returns the + * total badness for both volume and mute controls. */ -static int parse_output_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, int dac_idx) +static int assign_out_path_ctls(struct hda_codec *codec, struct nid_path *path) { - int i, err; - struct hda_gnode *child; + hda_nid_t nid; + unsigned int val; + int badness = 0; + + if (!path) + return BAD_SHARED_VOL * 2; + + if (path->ctls[NID_PATH_VOL_CTL] || + path->ctls[NID_PATH_MUTE_CTL]) + return 0; /* already evaluated */ - if (node->checked) + nid = look_for_out_vol_nid(codec, path); + if (nid) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (is_ctl_used(codec, val, NID_PATH_VOL_CTL)) + badness += BAD_SHARED_VOL; + else + path->ctls[NID_PATH_VOL_CTL] = val; + } else + badness += BAD_SHARED_VOL; + nid = look_for_out_mute_nid(codec, path); + if (nid) { + unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); + if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT || + nid_has_mute(codec, nid, HDA_OUTPUT)) + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); + if (is_ctl_used(codec, val, NID_PATH_MUTE_CTL)) + badness += BAD_SHARED_VOL; + else + path->ctls[NID_PATH_MUTE_CTL] = val; + } else + badness += BAD_SHARED_VOL; + return badness; +} + +const struct badness_table hda_main_out_badness = { + .no_primary_dac = BAD_NO_PRIMARY_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_PRIMARY_DAC, + .shared_surr = BAD_SHARED_SURROUND, + .shared_clfe = BAD_SHARED_CLFE, + .shared_surr_main = BAD_SHARED_SURROUND, +}; +EXPORT_SYMBOL_GPL(hda_main_out_badness); + +const struct badness_table hda_extra_out_badness = { + .no_primary_dac = BAD_NO_DAC, + .no_dac = BAD_NO_DAC, + .shared_primary = BAD_NO_EXTRA_DAC, + .shared_surr = BAD_SHARED_EXTRA_SURROUND, + .shared_clfe = BAD_SHARED_EXTRA_SURROUND, + .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, +}; +EXPORT_SYMBOL_GPL(hda_extra_out_badness); + +/* get the DAC of the primary output corresponding to the given array index */ +static hda_nid_t get_primary_out(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + if (cfg->line_outs > idx) + return spec->private_dac_nids[idx]; + idx -= cfg->line_outs; + if (spec->multi_ios > idx) + return spec->multi_io[idx].dac; + return 0; +} + +/* return the DAC if it's reachable, otherwise zero */ +static inline hda_nid_t try_dac(struct hda_codec *codec, + hda_nid_t dac, hda_nid_t pin) +{ + return is_reachable_path(codec, dac, pin) ? dac : 0; +} + +/* try to assign DACs to pins and return the resultant badness */ +static int try_assign_dacs(struct hda_codec *codec, int num_outs, + const hda_nid_t *pins, hda_nid_t *dacs, + int *path_idx, + const struct badness_table *bad) +{ + struct hda_gen_spec *spec = codec->spec; + int i, j; + int badness = 0; + hda_nid_t dac; + + if (!num_outs) return 0; - node->checked = 1; - if (node->type == AC_WID_AUD_OUT) { - if (node->wid_caps & AC_WCAP_DIGITAL) { - snd_printdd("Skip Digital OUT node %x\n", node->nid); - return 0; + for (i = 0; i < num_outs; i++) { + struct nid_path *path; + hda_nid_t pin = pins[i]; + + path = snd_hda_get_path_from_idx(codec, path_idx[i]); + if (path) { + badness += assign_out_path_ctls(codec, path); + continue; } - snd_printdd("AUD_OUT found %x\n", node->nid); - if (spec->dac_node[dac_idx]) { - /* already DAC node is assigned, just unmute & connect */ - return node == spec->dac_node[dac_idx]; + + dacs[i] = get_preferred_dac(codec, pin); + if (dacs[i]) { + if (is_dac_already_used(codec, dacs[i])) + badness += bad->shared_primary; + } + + if (!dacs[i]) + dacs[i] = look_for_dac(codec, pin, false); + if (!dacs[i] && !i) { + /* try to steal the DAC of surrounds for the front */ + for (j = 1; j < num_outs; j++) { + if (is_reachable_path(codec, dacs[j], pin)) { + dacs[0] = dacs[j]; + dacs[j] = 0; + invalidate_nid_path(codec, path_idx[j]); + path_idx[j] = 0; + break; + } + } } - spec->dac_node[dac_idx] = node; - if ((node->wid_caps & AC_WCAP_OUT_AMP) && - spec->pcm_vol_nodes < MAX_PCM_VOLS) { - spec->pcm_vol[spec->pcm_vol_nodes].node = node; - spec->pcm_vol[spec->pcm_vol_nodes].index = 0; - spec->pcm_vol_nodes++; + dac = dacs[i]; + if (!dac) { + if (num_outs > 2) + dac = try_dac(codec, get_primary_out(codec, i), pin); + if (!dac) + dac = try_dac(codec, dacs[0], pin); + if (!dac) + dac = try_dac(codec, get_primary_out(codec, i), pin); + if (dac) { + if (!i) + badness += bad->shared_primary; + else if (i == 1) + badness += bad->shared_surr; + else + badness += bad->shared_clfe; + } else if (is_reachable_path(codec, spec->private_dac_nids[0], pin)) { + dac = spec->private_dac_nids[0]; + badness += bad->shared_surr_main; + } else if (!i) + badness += bad->no_primary_dac; + else + badness += bad->no_dac; + } + if (!dac) + continue; + path = snd_hda_add_new_path(codec, dac, pin, -spec->mixer_nid); + if (!path && !i && spec->mixer_nid) { + /* try with aamix */ + path = snd_hda_add_new_path(codec, dac, pin, 0); + } + if (!path) { + dac = dacs[i] = 0; + badness += bad->no_dac; + } else { + /* print_nid_path(codec, "output", path); */ + path->active = true; + path_idx[i] = snd_hda_get_path_idx(codec, path); + badness += assign_out_path_ctls(codec, path); } - return 1; /* found */ } - for (i = 0; i < node->nconns; i++) { - child = hda_get_node(spec, node->conn_list[i]); - if (! child) + return badness; +} + +/* return NID if the given pin has only a single connection to a certain DAC */ +static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t nid_found = 0; + + for (i = 0; i < spec->num_all_dacs; i++) { + hda_nid_t nid = spec->all_dacs[i]; + if (!nid || is_dac_already_used(codec, nid)) continue; - err = parse_output_path(codec, spec, child, dac_idx); - if (err < 0) - return err; - else if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - if (spec->dac_node[dac_idx] && - spec->pcm_vol_nodes < MAX_PCM_VOLS && - !(spec->dac_node[dac_idx]->wid_caps & - AC_WCAP_OUT_AMP)) { - if ((node->wid_caps & AC_WCAP_IN_AMP) || - (node->wid_caps & AC_WCAP_OUT_AMP)) { - int n = spec->pcm_vol_nodes; - spec->pcm_vol[n].node = node; - spec->pcm_vol[n].index = i; - spec->pcm_vol_nodes++; - } - } - return 1; + if (is_reachable_path(codec, nid, pin)) { + if (nid_found) + return 0; + nid_found = nid; } } - return 0; + return nid_found; +} + +/* check whether the given pin can be a multi-io pin */ +static bool can_be_multiio_pin(struct hda_codec *codec, + unsigned int location, hda_nid_t nid) +{ + unsigned int defcfg, caps; + + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) + return false; + if (location && get_defcfg_location(defcfg) != location) + return false; + caps = snd_hda_query_pin_caps(codec, nid); + if (!(caps & AC_PINCAP_OUT)) + return false; + return true; +} + +/* count the number of input pins that are capable to be multi-io */ +static int count_multiio_pins(struct hda_codec *codec, hda_nid_t reference_pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); + int type, i; + int num_pins = 0; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != type) + continue; + if (can_be_multiio_pin(codec, location, + cfg->inputs[i].pin)) + num_pins++; + } + } + return num_pins; } /* - * Look for the output PIN widget with the given jack type - * and parse the output path to that PIN. + * multi-io helper * - * Returns the PIN node when the path to DAC is established. + * When hardwired is set, try to fill ony hardwired pins, and returns + * zero if any pins are filled, non-zero if nothing found. + * When hardwired is off, try to fill possible input pins, and returns + * the badness value. */ -static struct hda_gnode *parse_output_jack(struct hda_codec *codec, - struct hda_gspec *spec, - int jack_type) +static int fill_multi_ios(struct hda_codec *codec, + hda_nid_t reference_pin, + bool hardwired) { - struct hda_gnode *node; - int err; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int type, i, j, num_pins, old_pins; + unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); + unsigned int location = get_defcfg_location(defcfg); + int badness = 0; + struct nid_path *path; - list_for_each_entry(node, &spec->nid_list, list) { - if (node->type != AC_WID_PIN) - continue; - /* output capable? */ - if (! (node->pin_caps & AC_PINCAP_OUT)) - continue; - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - continue; /* unconnected */ - if (jack_type >= 0) { - if (jack_type != defcfg_type(node)) + old_pins = spec->multi_ios; + if (old_pins >= 2) + goto end_fill; + + num_pins = count_multiio_pins(codec, reference_pin); + if (num_pins < 2) + goto end_fill; + + for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + hda_nid_t dac = 0; + + if (cfg->inputs[i].type != type) continue; - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - } else { - /* output as default? */ - if (! (node->pin_ctl & AC_PINCTL_OUT_EN)) + if (!can_be_multiio_pin(codec, location, nid)) continue; + for (j = 0; j < spec->multi_ios; j++) { + if (nid == spec->multi_io[j].pin) + break; + } + if (j < spec->multi_ios) + continue; + + if (hardwired) + dac = get_dac_if_single(codec, nid); + else if (!dac) + dac = look_for_dac(codec, nid, false); + if (!dac) { + badness++; + continue; + } + path = snd_hda_add_new_path(codec, dac, nid, + -spec->mixer_nid); + if (!path) { + badness++; + continue; + } + /* print_nid_path(codec, "multiio", path); */ + spec->multi_io[spec->multi_ios].pin = nid; + spec->multi_io[spec->multi_ios].dac = dac; + spec->out_paths[cfg->line_outs + spec->multi_ios] = + snd_hda_get_path_idx(codec, path); + spec->multi_ios++; + if (spec->multi_ios >= 2) + break; + } + } + end_fill: + if (badness) + badness = BAD_MULTI_IO; + if (old_pins == spec->multi_ios) { + if (hardwired) + return 1; /* nothing found */ + else + return badness; /* no badness if nothing found */ + } + if (!hardwired && spec->multi_ios < 2) { + /* cancel newly assigned paths */ + spec->paths.used -= spec->multi_ios - old_pins; + spec->multi_ios = old_pins; + return badness; + } + + /* assign volume and mute controls */ + for (i = old_pins; i < spec->multi_ios; i++) { + path = snd_hda_get_path_from_idx(codec, spec->out_paths[cfg->line_outs + i]); + badness += assign_out_path_ctls(codec, path); + } + + return badness; +} + +/* map DACs for all pins in the list if they are single connections */ +static bool map_singles(struct hda_codec *codec, int outs, + const hda_nid_t *pins, hda_nid_t *dacs, int *path_idx) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + bool found = false; + for (i = 0; i < outs; i++) { + struct nid_path *path; + hda_nid_t dac; + if (dacs[i]) + continue; + dac = get_dac_if_single(codec, pins[i]); + if (!dac) + continue; + path = snd_hda_add_new_path(codec, dac, pins[i], + -spec->mixer_nid); + if (!path && !i && spec->mixer_nid) + path = snd_hda_add_new_path(codec, dac, pins[i], 0); + if (path) { + dacs[i] = dac; + found = true; + /* print_nid_path(codec, "output", path); */ + path->active = true; + path_idx[i] = snd_hda_get_path_idx(codec, path); } - clear_check_flags(spec); - err = parse_output_path(codec, spec, node, 0); + } + return found; +} + +/* create a new path including aamix if available, and return its index */ +static int check_aamix_out_path(struct hda_codec *codec, int path_idx) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + hda_nid_t path_dac, dac, pin; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path || !path->depth || + is_nid_contained(path, spec->mixer_nid)) + return 0; + path_dac = path->path[0]; + dac = spec->private_dac_nids[0]; + pin = path->path[path->depth - 1]; + path = snd_hda_add_new_path(codec, dac, pin, spec->mixer_nid); + if (!path) { + if (dac != path_dac) + dac = path_dac; + else if (spec->multiout.hp_out_nid[0]) + dac = spec->multiout.hp_out_nid[0]; + else if (spec->multiout.extra_out_nid[0]) + dac = spec->multiout.extra_out_nid[0]; + else + dac = 0; + if (dac) + path = snd_hda_add_new_path(codec, dac, pin, + spec->mixer_nid); + } + if (!path) + return 0; + /* print_nid_path(codec, "output-aamix", path); */ + path->active = false; /* unused as default */ + return snd_hda_get_path_idx(codec, path); +} + +/* check whether the independent HP is available with the current config */ +static bool indep_hp_possible(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct nid_path *path; + int i, idx; + + if (cfg->line_out_type == AUTO_PIN_HP_OUT) + idx = spec->out_paths[0]; + else + idx = spec->hp_paths[0]; + path = snd_hda_get_path_from_idx(codec, idx); + if (!path) + return false; + + /* assume no path conflicts unless aamix is involved */ + if (!spec->mixer_nid || !is_nid_contained(path, spec->mixer_nid)) + return true; + + /* check whether output paths contain aamix */ + for (i = 0; i < cfg->line_outs; i++) { + if (spec->out_paths[i] == idx) + break; + path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); + if (path && is_nid_contained(path, spec->mixer_nid)) + return false; + } + for (i = 0; i < cfg->speaker_outs; i++) { + path = snd_hda_get_path_from_idx(codec, spec->speaker_paths[i]); + if (path && is_nid_contained(path, spec->mixer_nid)) + return false; + } + + return true; +} + +/* fill the empty entries in the dac array for speaker/hp with the + * shared dac pointed by the paths + */ +static void refill_shared_dacs(struct hda_codec *codec, int num_outs, + hda_nid_t *dacs, int *path_idx) +{ + struct nid_path *path; + int i; + + for (i = 0; i < num_outs; i++) { + if (dacs[i]) + continue; + path = snd_hda_get_path_from_idx(codec, path_idx[i]); + if (!path) + continue; + dacs[i] = path->path[0]; + } +} + +/* fill in the dac_nids table from the parsed pin configuration */ +static int fill_and_eval_dacs(struct hda_codec *codec, + bool fill_hardwired, + bool fill_mio_first) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i, err, badness; + + /* set num_dacs once to full for look_for_dac() */ + spec->multiout.num_dacs = cfg->line_outs; + spec->multiout.dac_nids = spec->private_dac_nids; + memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); + memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); + memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); + spec->multi_ios = 0; + snd_array_free(&spec->paths); + + /* clear path indices */ + memset(spec->out_paths, 0, sizeof(spec->out_paths)); + memset(spec->hp_paths, 0, sizeof(spec->hp_paths)); + memset(spec->speaker_paths, 0, sizeof(spec->speaker_paths)); + memset(spec->aamix_out_paths, 0, sizeof(spec->aamix_out_paths)); + memset(spec->digout_paths, 0, sizeof(spec->digout_paths)); + memset(spec->input_paths, 0, sizeof(spec->input_paths)); + memset(spec->loopback_paths, 0, sizeof(spec->loopback_paths)); + memset(&spec->digin_path, 0, sizeof(spec->digin_path)); + + badness = 0; + + /* fill hard-wired DACs first */ + if (fill_hardwired) { + bool mapped; + do { + mapped = map_singles(codec, cfg->line_outs, + cfg->line_out_pins, + spec->private_dac_nids, + spec->out_paths); + mapped |= map_singles(codec, cfg->hp_outs, + cfg->hp_pins, + spec->multiout.hp_out_nid, + spec->hp_paths); + mapped |= map_singles(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid, + spec->speaker_paths); + if (!spec->no_multi_io && + fill_mio_first && cfg->line_outs == 1 && + cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = fill_multi_ios(codec, cfg->line_out_pins[0], true); + if (!err) + mapped = true; + } + } while (mapped); + } + + badness += try_assign_dacs(codec, cfg->line_outs, cfg->line_out_pins, + spec->private_dac_nids, spec->out_paths, + spec->main_out_badness); + + if (!spec->no_multi_io && fill_mio_first && + cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + /* try to fill multi-io first */ + err = fill_multi_ios(codec, cfg->line_out_pins[0], false); if (err < 0) - return NULL; - if (! err && spec->out_pin_node[0]) { - err = parse_output_path(codec, spec, node, 1); + return err; + /* we don't count badness at this stage yet */ + } + + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = try_assign_dacs(codec, cfg->hp_outs, cfg->hp_pins, + spec->multiout.hp_out_nid, + spec->hp_paths, + spec->extra_out_badness); + if (err < 0) + return err; + badness += err; + } + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = try_assign_dacs(codec, cfg->speaker_outs, + cfg->speaker_pins, + spec->multiout.extra_out_nid, + spec->speaker_paths, + spec->extra_out_badness); + if (err < 0) + return err; + badness += err; + } + if (!spec->no_multi_io && + cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = fill_multi_ios(codec, cfg->line_out_pins[0], false); + if (err < 0) + return err; + badness += err; + } + + if (spec->mixer_nid) { + spec->aamix_out_paths[0] = + check_aamix_out_path(codec, spec->out_paths[0]); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + spec->aamix_out_paths[1] = + check_aamix_out_path(codec, spec->hp_paths[0]); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + spec->aamix_out_paths[2] = + check_aamix_out_path(codec, spec->speaker_paths[0]); + } + + if (!spec->no_multi_io && + cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) + if (count_multiio_pins(codec, cfg->hp_pins[0]) >= 2) + spec->multi_ios = 1; /* give badness */ + + /* re-count num_dacs and squash invalid entries */ + spec->multiout.num_dacs = 0; + for (i = 0; i < cfg->line_outs; i++) { + if (spec->private_dac_nids[i]) + spec->multiout.num_dacs++; + else { + memmove(spec->private_dac_nids + i, + spec->private_dac_nids + i + 1, + sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); + spec->private_dac_nids[cfg->line_outs - 1] = 0; + } + } + + spec->ext_channel_count = spec->min_channel_count = + spec->multiout.num_dacs * 2; + + if (spec->multi_ios == 2) { + for (i = 0; i < 2; i++) + spec->private_dac_nids[spec->multiout.num_dacs++] = + spec->multi_io[i].dac; + } else if (spec->multi_ios) { + spec->multi_ios = 0; + badness += BAD_MULTI_IO; + } + + if (spec->indep_hp && !indep_hp_possible(codec)) + badness += BAD_NO_INDEP_HP; + + /* re-fill the shared DAC for speaker / headphone */ + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + refill_shared_dacs(codec, cfg->hp_outs, + spec->multiout.hp_out_nid, + spec->hp_paths); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + refill_shared_dacs(codec, cfg->speaker_outs, + spec->multiout.extra_out_nid, + spec->speaker_paths); + + return badness; +} + +#define DEBUG_BADNESS + +#ifdef DEBUG_BADNESS +#define debug_badness(fmt, args...) codec_dbg(codec, fmt, ##args) +#else +#define debug_badness(...) +#endif + +#ifdef DEBUG_BADNESS +static inline void print_nid_path_idx(struct hda_codec *codec, + const char *pfx, int idx) +{ + struct nid_path *path; + + path = snd_hda_get_path_from_idx(codec, idx); + if (path) + print_nid_path(codec, pfx, path); +} + +static void debug_show_configs(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + static const char * const lo_type[3] = { "LO", "SP", "HP" }; + int i; + + debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x (type %s)\n", + cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[3], + spec->multiout.dac_nids[0], + spec->multiout.dac_nids[1], + spec->multiout.dac_nids[2], + spec->multiout.dac_nids[3], + lo_type[cfg->line_out_type]); + for (i = 0; i < cfg->line_outs; i++) + print_nid_path_idx(codec, " out", spec->out_paths[i]); + if (spec->multi_ios > 0) + debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", + spec->multi_ios, + spec->multi_io[0].pin, spec->multi_io[1].pin, + spec->multi_io[0].dac, spec->multi_io[1].dac); + for (i = 0; i < spec->multi_ios; i++) + print_nid_path_idx(codec, " mio", + spec->out_paths[cfg->line_outs + i]); + if (cfg->hp_outs) + debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->hp_pins[0], cfg->hp_pins[1], + cfg->hp_pins[2], cfg->hp_pins[3], + spec->multiout.hp_out_nid[0], + spec->multiout.hp_out_nid[1], + spec->multiout.hp_out_nid[2], + spec->multiout.hp_out_nid[3]); + for (i = 0; i < cfg->hp_outs; i++) + print_nid_path_idx(codec, " hp ", spec->hp_paths[i]); + if (cfg->speaker_outs) + debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", + cfg->speaker_pins[0], cfg->speaker_pins[1], + cfg->speaker_pins[2], cfg->speaker_pins[3], + spec->multiout.extra_out_nid[0], + spec->multiout.extra_out_nid[1], + spec->multiout.extra_out_nid[2], + spec->multiout.extra_out_nid[3]); + for (i = 0; i < cfg->speaker_outs; i++) + print_nid_path_idx(codec, " spk", spec->speaker_paths[i]); + for (i = 0; i < 3; i++) + print_nid_path_idx(codec, " mix", spec->aamix_out_paths[i]); +} +#else +#define debug_show_configs(codec, cfg) /* NOP */ +#endif + +/* find all available DACs of the codec */ +static void fill_all_dac_nids(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t nid = codec->start_nid; + + spec->num_all_dacs = 0; + memset(spec->all_dacs, 0, sizeof(spec->all_dacs)); + for (i = 0; i < codec->num_nodes; i++, nid++) { + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_OUT) + continue; + if (spec->num_all_dacs >= ARRAY_SIZE(spec->all_dacs)) { + codec_err(codec, "Too many DACs!\n"); + break; + } + spec->all_dacs[spec->num_all_dacs++] = nid; + } +} + +static int parse_output_paths(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *best_cfg; + unsigned int val; + int best_badness = INT_MAX; + int badness; + bool fill_hardwired = true, fill_mio_first = true; + bool best_wired = true, best_mio = true; + bool hp_spk_swapped = false; + + best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); + if (!best_cfg) + return -ENOMEM; + *best_cfg = *cfg; + + for (;;) { + badness = fill_and_eval_dacs(codec, fill_hardwired, + fill_mio_first); + if (badness < 0) { + kfree(best_cfg); + return badness; + } + debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", + cfg->line_out_type, fill_hardwired, fill_mio_first, + badness); + debug_show_configs(codec, cfg); + if (badness < best_badness) { + best_badness = badness; + *best_cfg = *cfg; + best_wired = fill_hardwired; + best_mio = fill_mio_first; + } + if (!badness) + break; + fill_mio_first = !fill_mio_first; + if (!fill_mio_first) + continue; + fill_hardwired = !fill_hardwired; + if (!fill_hardwired) + continue; + if (hp_spk_swapped) + break; + hp_spk_swapped = true; + if (cfg->speaker_outs > 0 && + cfg->line_out_type == AUTO_PIN_HP_OUT) { + cfg->hp_outs = cfg->line_outs; + memcpy(cfg->hp_pins, cfg->line_out_pins, + sizeof(cfg->hp_pins)); + cfg->line_outs = cfg->speaker_outs; + memcpy(cfg->line_out_pins, cfg->speaker_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = 0; + memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); + cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; + fill_hardwired = true; + continue; + } + if (cfg->hp_outs > 0 && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + fill_hardwired = true; + continue; + } + break; + } + + if (badness) { + debug_badness("==> restoring best_cfg\n"); + *cfg = *best_cfg; + fill_and_eval_dacs(codec, best_wired, best_mio); + } + debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", + cfg->line_out_type, best_wired, best_mio); + debug_show_configs(codec, cfg); + + if (cfg->line_out_pins[0]) { + struct nid_path *path; + path = snd_hda_get_path_from_idx(codec, spec->out_paths[0]); + if (path) + spec->vmaster_nid = look_for_out_vol_nid(codec, path); + if (spec->vmaster_nid) + snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, + HDA_OUTPUT, spec->vmaster_tlv); + } + + /* set initial pinctl targets */ + if (spec->prefer_hp_amp || cfg->line_out_type == AUTO_PIN_HP_OUT) + val = PIN_HP; + else + val = PIN_OUT; + set_pin_targets(codec, cfg->line_outs, cfg->line_out_pins, val); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + set_pin_targets(codec, cfg->hp_outs, cfg->hp_pins, PIN_HP); + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + val = spec->prefer_hp_amp ? PIN_HP : PIN_OUT; + set_pin_targets(codec, cfg->speaker_outs, + cfg->speaker_pins, val); + } + + /* clear indep_hp flag if not available */ + if (spec->indep_hp && !indep_hp_possible(codec)) + spec->indep_hp = 0; + + kfree(best_cfg); + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int create_multi_out_ctls(struct hda_codec *codec, + const struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + int i, err, noutputs; + + noutputs = cfg->line_outs; + if (spec->multi_ios > 0 && cfg->line_outs < 3) + noutputs += spec->multi_ios; + + for (i = 0; i < noutputs; i++) { + const char *name; + int index; + struct nid_path *path; + + path = snd_hda_get_path_from_idx(codec, spec->out_paths[i]); + if (!path) + continue; + + name = get_line_out_pfx(codec, i, &index, NID_PATH_VOL_CTL); + if (!name || !strcmp(name, "CLFE")) { + /* Center/LFE */ + err = add_vol_ctl(codec, "Center", 0, 1, path); + if (err < 0) + return err; + err = add_vol_ctl(codec, "LFE", 0, 2, path); if (err < 0) - return NULL; + return err; + } else { + err = add_stereo_vol(codec, name, index, path); + if (err < 0) + return err; } - if (err > 0) { - /* unmute the PIN output */ - unmute_output(codec, node); - /* set PIN-Out enable */ - snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - AC_PINCTL_OUT_EN | - ((node->pin_caps & AC_PINCAP_HP_DRV) ? - AC_PINCTL_HP_EN : 0)); - return node; + + name = get_line_out_pfx(codec, i, &index, NID_PATH_MUTE_CTL); + if (!name || !strcmp(name, "CLFE")) { + err = add_sw_ctl(codec, "Center", 0, 1, path); + if (err < 0) + return err; + err = add_sw_ctl(codec, "LFE", 0, 2, path); + if (err < 0) + return err; + } else { + err = add_stereo_sw(codec, name, index, path); + if (err < 0) + return err; } } - return NULL; + return 0; } +static int create_extra_out(struct hda_codec *codec, int path_idx, + const char *pfx, int cidx) +{ + struct nid_path *path; + int err; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path) + return 0; + err = add_stereo_vol(codec, pfx, cidx, path); + if (err < 0) + return err; + err = add_stereo_sw(codec, pfx, cidx, path); + if (err < 0) + return err; + return 0; +} + +/* add playback controls for speaker and HP outputs */ +static int create_extra_outs(struct hda_codec *codec, int num_pins, + const int *paths, const char *pfx) +{ + int i; + + for (i = 0; i < num_pins; i++) { + const char *name; + char tmp[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + int err, idx = 0; + + if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) + name = "Bass Speaker"; + else if (num_pins >= 3) { + snprintf(tmp, sizeof(tmp), "%s %s", + pfx, channel_name[i]); + name = tmp; + } else { + name = pfx; + idx = i; + } + err = create_extra_out(codec, paths[i], name, idx); + if (err < 0) + return err; + } + return 0; +} + +static int create_hp_out_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + return create_extra_outs(codec, spec->autocfg.hp_outs, + spec->hp_paths, + "Headphone"); +} + +static int create_speaker_out_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + return create_extra_outs(codec, spec->autocfg.speaker_outs, + spec->speaker_paths, + "Speaker"); +} /* - * parse outputs + * independent HP controls */ -static int parse_output(struct hda_codec *codec) + +static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack); +static int indep_hp_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); +} - /* - * Look for the output PIN widget - */ - /* first, look for the line-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_LINE_OUT); - if (node) /* found, remember the PIN node */ - spec->out_pin_node[0] = node; - else { - /* if no line-out is found, try speaker out */ - node = parse_output_jack(codec, spec, AC_JACK_SPEAKER); - if (node) - spec->out_pin_node[0] = node; - } - /* look for the HP-out pin */ - node = parse_output_jack(codec, spec, AC_JACK_HP_OUT); - if (node) { - if (! spec->out_pin_node[0]) - spec->out_pin_node[0] = node; +static int indep_hp_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->indep_hp_enabled; + return 0; +} + +static void update_aamix_paths(struct hda_codec *codec, bool do_mix, + int nomix_path_idx, int mix_path_idx, + int out_type); + +static int indep_hp_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int select = ucontrol->value.enumerated.item[0]; + int ret = 0; + + mutex_lock(&spec->pcm_mutex); + if (spec->active_streams) { + ret = -EBUSY; + goto unlock; + } + + if (spec->indep_hp_enabled != select) { + hda_nid_t *dacp; + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dacp = &spec->private_dac_nids[0]; else - spec->out_pin_node[1] = node; + dacp = &spec->multiout.hp_out_nid[0]; + + /* update HP aamix paths in case it conflicts with indep HP */ + if (spec->have_aamix_ctl) { + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + update_aamix_paths(codec, spec->aamix_mode, + spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + else + update_aamix_paths(codec, spec->aamix_mode, + spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + } + + spec->indep_hp_enabled = select; + if (spec->indep_hp_enabled) + *dacp = 0; + else + *dacp = spec->alt_dac_nid; + + call_hp_automute(codec, NULL); + ret = 1; } + unlock: + mutex_unlock(&spec->pcm_mutex); + return ret; +} - if (! spec->out_pin_node[0]) { - /* no line-out or HP pins found, - * then choose for the first output pin - */ - spec->out_pin_node[0] = parse_output_jack(codec, spec, -1); - if (! spec->out_pin_node[0]) - snd_printd("hda_generic: no proper output path found\n"); +static const struct snd_kcontrol_new indep_hp_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Independent HP", + .info = indep_hp_info, + .get = indep_hp_get, + .put = indep_hp_put, +}; + + +static int create_indep_hp_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t dac; + + if (!spec->indep_hp) + return 0; + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + dac = spec->multiout.dac_nids[0]; + else + dac = spec->multiout.hp_out_nid[0]; + if (!dac) { + spec->indep_hp = 0; + return 0; } + spec->indep_hp_enabled = false; + spec->alt_dac_nid = dac; + if (!snd_hda_gen_add_kctl(spec, NULL, &indep_hp_ctl)) + return -ENOMEM; return 0; } /* - * input MUX + * channel mode enum control */ -/* control callbacks */ -static int capture_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int ch_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_info(&spec->input_mux, uinfo); + struct hda_gen_spec *spec = codec->spec; + int chs; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = spec->multi_ios + 1; + if (uinfo->value.enumerated.item > spec->multi_ios) + uinfo->value.enumerated.item = spec->multi_ios; + chs = uinfo->value.enumerated.item * 2 + spec->min_channel_count; + sprintf(uinfo->value.enumerated.name, "%dch", chs); + return 0; } -static int capture_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ch_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = + (spec->ext_channel_count - spec->min_channel_count) / 2; + return 0; +} + +static inline struct nid_path * +get_multiio_path(struct hda_codec *codec, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_get_path_from_idx(codec, + spec->out_paths[spec->autocfg.line_outs + idx]); +} + +static void update_automute_all(struct hda_codec *codec); + +/* Default value to be passed as aamix argument for snd_hda_activate_path(); + * used for output paths + */ +static bool aamix_default(struct hda_gen_spec *spec) +{ + return !spec->have_aamix_ctl || spec->aamix_mode; +} + +static int set_multi_io(struct hda_codec *codec, int idx, bool output) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t nid = spec->multi_io[idx].pin; + struct nid_path *path; + + path = get_multiio_path(codec, idx); + if (!path) + return -EINVAL; + + if (path->active == output) + return 0; + + if (output) { + set_pin_target(codec, nid, PIN_OUT, true); + snd_hda_activate_path(codec, path, true, aamix_default(spec)); + set_pin_eapd(codec, nid, true); + } else { + set_pin_eapd(codec, nid, false); + snd_hda_activate_path(codec, path, false, aamix_default(spec)); + set_pin_target(codec, nid, spec->multi_io[idx].ctl_in, true); + path_power_down_sync(codec, path); + } + + /* update jack retasking in case it modifies any of them */ + update_automute_all(codec); - ucontrol->value.enumerated.item[0] = spec->cur_cap_src; return 0; } -static int capture_source_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ch_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hda_gspec *spec = codec->spec; - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_node->nid, &spec->cur_cap_src); + struct hda_gen_spec *spec = codec->spec; + int i, ch; + + ch = ucontrol->value.enumerated.item[0]; + if (ch < 0 || ch > spec->multi_ios) + return -EINVAL; + if (ch == (spec->ext_channel_count - spec->min_channel_count) / 2) + return 0; + spec->ext_channel_count = ch * 2 + spec->min_channel_count; + for (i = 0; i < spec->multi_ios; i++) + set_multi_io(codec, i, i < ch); + spec->multiout.max_channels = max(spec->ext_channel_count, + spec->const_channel_count); + if (spec->need_dac_fix) + spec->multiout.num_dacs = spec->multiout.max_channels / 2; + return 1; +} + +static const struct snd_kcontrol_new channel_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Channel Mode", + .info = ch_mode_info, + .get = ch_mode_get, + .put = ch_mode_put, +}; + +static int create_multi_channel_mode(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->multi_ios > 0) { + if (!snd_hda_gen_add_kctl(spec, NULL, &channel_mode_enum)) + return -ENOMEM; + } + return 0; } /* - * return the string name of the given input PIN widget + * aamix loopback enable/disable switch */ -static const char *get_input_type(struct hda_gnode *node, unsigned int *pinctl) -{ - unsigned int location = defcfg_location(node); - switch (defcfg_type(node)) { - case AC_JACK_LINE_IN: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Line"; - return "Line"; - case AC_JACK_CD: -#if 0 - if (pinctl) - *pinctl |= AC_PINCTL_VREF_GRD; -#endif - return "CD"; - case AC_JACK_AUX: - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Aux"; - return "Aux"; - case AC_JACK_MIC_IN: - if (pinctl && - (node->pin_caps & - (AC_PINCAP_VREF_80 << AC_PINCAP_VREF_SHIFT))) - *pinctl |= AC_PINCTL_VREF_80; - if ((location & 0x0f) == AC_JACK_LOC_FRONT) - return "Front Mic"; - return "Mic"; - case AC_JACK_SPDIF_IN: - return "SPDIF"; - case AC_JACK_DIG_OTHER_IN: - return "Digital"; + +#define loopback_mixing_info indep_hp_info + +static int loopback_mixing_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + ucontrol->value.enumerated.item[0] = spec->aamix_mode; + return 0; +} + +static void update_aamix_paths(struct hda_codec *codec, bool do_mix, + int nomix_path_idx, int mix_path_idx, + int out_type) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *nomix_path, *mix_path; + + nomix_path = snd_hda_get_path_from_idx(codec, nomix_path_idx); + mix_path = snd_hda_get_path_from_idx(codec, mix_path_idx); + if (!nomix_path || !mix_path) + return; + + /* if HP aamix path is driven from a different DAC and the + * independent HP mode is ON, can't turn on aamix path + */ + if (out_type == AUTO_PIN_HP_OUT && spec->indep_hp_enabled && + mix_path->path[0] != spec->alt_dac_nid) + do_mix = false; + + if (do_mix) { + snd_hda_activate_path(codec, nomix_path, false, true); + snd_hda_activate_path(codec, mix_path, true, true); + path_power_down_sync(codec, nomix_path); + } else { + snd_hda_activate_path(codec, mix_path, false, false); + snd_hda_activate_path(codec, nomix_path, true, false); + path_power_down_sync(codec, mix_path); } - return NULL; +} + +static int loopback_mixing_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int val = ucontrol->value.enumerated.item[0]; + + if (val == spec->aamix_mode) + return 0; + spec->aamix_mode = val; + update_aamix_paths(codec, val, spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + update_aamix_paths(codec, val, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, val, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); + return 1; +} + +static const struct snd_kcontrol_new loopback_mixing_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Loopback Mixing", + .info = loopback_mixing_info, + .get = loopback_mixing_get, + .put = loopback_mixing_put, +}; + +static int create_loopback_mixing_ctl(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (!spec->mixer_nid) + return 0; + if (!(spec->aamix_out_paths[0] || spec->aamix_out_paths[1] || + spec->aamix_out_paths[2])) + return 0; + if (!snd_hda_gen_add_kctl(spec, NULL, &loopback_mixing_enum)) + return -ENOMEM; + spec->have_aamix_ctl = 1; + return 0; } /* - * parse the nodes recursively until reach to the input PIN - * - * returns 0 if not found, 1 if found, or a negative error code. + * shared headphone/mic handling */ -static int parse_adc_sub_nodes(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, int idx) + +static void call_update_outputs(struct hda_codec *codec); + +/* for shared I/O, change the pin-control accordingly */ +static void update_hp_mic(struct hda_codec *codec, int adc_mux, bool force) { - int i, err; - unsigned int pinctl; - const char *type; + struct hda_gen_spec *spec = codec->spec; + bool as_mic; + unsigned int val; + hda_nid_t pin; - if (node->checked) - return 0; + pin = spec->hp_mic_pin; + as_mic = spec->cur_mux[adc_mux] == spec->hp_mic_mux_idx; - node->checked = 1; - if (node->type != AC_WID_PIN) { - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child; - child = hda_get_node(spec, node->conn_list[i]); - if (! child) - continue; - err = parse_adc_sub_nodes(codec, spec, child, idx); - if (err < 0) - return err; - if (err > 0) { - /* found one, - * select the path, unmute both input and output - */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); - return err; - } + if (!force) { + val = snd_hda_codec_get_pin_target(codec, pin); + if (as_mic) { + if (val & PIN_IN) + return; + } else { + if (val & PIN_OUT) + return; + } + } + + val = snd_hda_get_default_vref(codec, pin); + /* if the HP pin doesn't support VREF and the codec driver gives an + * alternative pin, set up the VREF on that pin instead + */ + if (val == AC_PINCTL_VREF_HIZ && spec->shared_mic_vref_pin) { + const hda_nid_t vref_pin = spec->shared_mic_vref_pin; + unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); + if (vref_val != AC_PINCTL_VREF_HIZ) + snd_hda_set_pin_ctl_cache(codec, vref_pin, + PIN_IN | (as_mic ? vref_val : 0)); + } + + if (!spec->hp_mic_jack_modes) { + if (as_mic) + val |= PIN_IN; + else + val = PIN_HP; + set_pin_target(codec, pin, val, true); + call_hp_automute(codec, NULL); + } +} + +/* create a shared input with the headphone out */ +static int create_hp_mic(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int defcfg; + hda_nid_t nid; + + if (!spec->hp_mic) { + if (spec->suppress_hp_mic_detect) + return 0; + /* automatic detection: only if no input or a single internal + * input pin is found, try to detect the shared hp/mic + */ + if (cfg->num_inputs > 1) + return 0; + else if (cfg->num_inputs == 1) { + defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); + if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + return 0; } - return 0; } - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) + spec->hp_mic = 0; /* clear once */ + if (cfg->num_inputs >= AUTO_CFG_MAX_INS) return 0; - if (defcfg_port_conn(node) == AC_JACK_PORT_NONE) - return 0; /* unconnected */ + nid = 0; + if (cfg->line_out_type == AUTO_PIN_HP_OUT && cfg->line_outs > 0) + nid = cfg->line_out_pins[0]; + else if (cfg->hp_outs > 0) + nid = cfg->hp_pins[0]; + if (!nid) + return 0; - if (node->wid_caps & AC_WCAP_DIGITAL) - return 0; /* skip SPDIF */ + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) + return 0; /* no input */ - if (spec->input_mux.num_items >= HDA_MAX_NUM_INPUTS) { - snd_printk(KERN_ERR "hda_generic: Too many items for capture\n"); - return -EINVAL; + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = AUTO_PIN_MIC; + cfg->inputs[cfg->num_inputs].is_headphone_mic = 1; + cfg->num_inputs++; + spec->hp_mic = 1; + spec->hp_mic_pin = nid; + /* we can't handle auto-mic together with HP-mic */ + spec->suppress_auto_mic = 1; + codec_dbg(codec, "Enable shared I/O jack on NID 0x%x\n", nid); + return 0; +} + +/* + * output jack mode + */ + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin); + +static const char * const out_jack_texts[] = { + "Line Out", "Headphone Out", +}; + +static int out_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, out_jack_texts); +} + +static int out_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + if (snd_hda_codec_get_pin_target(codec, nid) == PIN_HP) + ucontrol->value.enumerated.item[0] = 1; + else + ucontrol->value.enumerated.item[0] = 0; + return 0; +} + +static int out_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int val; + + val = ucontrol->value.enumerated.item[0] ? PIN_HP : PIN_OUT; + if (snd_hda_codec_get_pin_target(codec, nid) == val) + return 0; + snd_hda_set_pin_ctl_cache(codec, nid, val); + return 1; +} + +static const struct snd_kcontrol_new out_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = out_jack_mode_info, + .get = out_jack_mode_get, + .put = out_jack_mode_put, +}; + +static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->kctls.used; i++) { + struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); + if (!strcmp(kctl->name, name) && kctl->index == idx) + return true; } + return false; +} - pinctl = AC_PINCTL_IN_EN; - /* create a proper capture source label */ - type = get_input_type(node, &pinctl); - if (! type) { - /* input as default? */ - if (! (node->pin_ctl & AC_PINCTL_IN_EN)) - return 0; - type = "Input"; +static void get_jack_mode_name(struct hda_codec *codec, hda_nid_t pin, + char *name, size_t name_len) +{ + struct hda_gen_spec *spec = codec->spec; + int idx = 0; + + snd_hda_get_pin_label(codec, pin, &spec->autocfg, name, name_len, &idx); + strlcat(name, " Jack Mode", name_len); + + for (; find_kctl_name(codec, name, idx); idx++) + ; +} + +static int get_out_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->add_jack_modes) { + unsigned int pincap = snd_hda_query_pin_caps(codec, pin); + if ((pincap & AC_PINCAP_OUT) && (pincap & AC_PINCAP_HP_DRV)) + return 2; } - snd_hda_add_imux_item(&spec->input_mux, type, idx, NULL); + return 1; +} + +static int create_out_jack_modes(struct hda_codec *codec, int num_pins, + hda_nid_t *pins) +{ + struct hda_gen_spec *spec = codec->spec; + int i; - /* unmute the PIN external input */ - unmute_input(codec, node, 0); /* index = 0? */ - /* set PIN-In enable */ - snd_hda_codec_write_cache(codec, node->nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); + for (i = 0; i < num_pins; i++) { + hda_nid_t pin = pins[i]; + if (pin == spec->hp_mic_pin) + continue; + if (get_out_jack_num_items(codec, pin) > 1) { + struct snd_kcontrol_new *knew; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + get_jack_mode_name(codec, pin, name, sizeof(name)); + knew = snd_hda_gen_add_kctl(spec, name, + &out_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + } + } - return 1; /* found */ + return 0; } /* - * parse input + * input jack mode */ -static int parse_input_path(struct hda_codec *codec, struct hda_gnode *adc_node) + +/* from AC_PINCTL_VREF_HIZ to AC_PINCTL_VREF_100 */ +#define NUM_VREFS 6 + +static const char * const vref_texts[NUM_VREFS] = { + "Line In", "Mic 50pc Bias", "Mic 0V Bias", + "", "Mic 80pc Bias", "Mic 100pc Bias" +}; + +static unsigned int get_vref_caps(struct hda_codec *codec, hda_nid_t pin) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int i, err; + unsigned int pincap; - snd_printdd("AUD_IN = %x\n", adc_node->nid); - clear_check_flags(spec); + pincap = snd_hda_query_pin_caps(codec, pin); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + /* filter out unusual vrefs */ + pincap &= ~(AC_PINCAP_VREF_GRD | AC_PINCAP_VREF_100); + return pincap; +} - // awk added - fixed no recording due to muted widget - unmute_input(codec, adc_node, 0); - - /* - * check each connection of the ADC - * if it reaches to a proper input PIN, add the path as the - * input path. - */ - /* first, check the direct connections to PIN widgets */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type == AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node, i); - if (err < 0) - return err; +/* convert from the enum item index to the vref ctl index (0=HIZ, 1=50%...) */ +static int get_vref_idx(unsigned int vref_caps, unsigned int item_idx) +{ + unsigned int i, n = 0; + + for (i = 0; i < NUM_VREFS; i++) { + if (vref_caps & (1 << i)) { + if (n == item_idx) + return i; + n++; } } - /* ... then check the rests, more complicated connections */ - for (i = 0; i < adc_node->nconns; i++) { - node = hda_get_node(spec, adc_node->conn_list[i]); - if (node && node->type != AC_WID_PIN) { - err = parse_adc_sub_nodes(codec, spec, node, i); - if (err < 0) - return err; - } + return 0; +} + +/* convert back from the vref ctl index to the enum item index */ +static int cvt_from_vref_idx(unsigned int vref_caps, unsigned int idx) +{ + unsigned int i, n = 0; + + for (i = 0; i < NUM_VREFS; i++) { + if (i == idx) + return n; + if (vref_caps & (1 << i)) + n++; } + return 0; +} - if (! spec->input_mux.num_items) - return 0; /* no input path found... */ +static int in_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); - snd_printdd("[Capture Source] NID=0x%x, #SRC=%d\n", adc_node->nid, spec->input_mux.num_items); - for (i = 0; i < spec->input_mux.num_items; i++) - snd_printdd(" [%s] IDX=0x%x\n", spec->input_mux.items[i].label, - spec->input_mux.items[i].index); + snd_hda_enum_helper_info(kcontrol, uinfo, hweight32(vref_caps), + vref_texts); + /* set the right text */ + strcpy(uinfo->value.enumerated.name, + vref_texts[get_vref_idx(vref_caps, uinfo->value.enumerated.item)]); + return 0; +} + +static int in_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); + unsigned int idx; + + idx = snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_VREFEN; + ucontrol->value.enumerated.item[0] = cvt_from_vref_idx(vref_caps, idx); + return 0; +} - spec->adc_node = adc_node; +static int in_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + unsigned int vref_caps = get_vref_caps(codec, nid); + unsigned int val, idx; + + val = snd_hda_codec_get_pin_target(codec, nid); + idx = cvt_from_vref_idx(vref_caps, val & AC_PINCTL_VREFEN); + if (idx == ucontrol->value.enumerated.item[0]) + return 0; + + val &= ~AC_PINCTL_VREFEN; + val |= get_vref_idx(vref_caps, ucontrol->value.enumerated.item[0]); + snd_hda_set_pin_ctl_cache(codec, nid, val); return 1; } +static const struct snd_kcontrol_new in_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = in_jack_mode_info, + .get = in_jack_mode_get, + .put = in_jack_mode_put, +}; + +static int get_in_jack_num_items(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + int nitems = 0; + if (spec->add_jack_modes) + nitems = hweight32(get_vref_caps(codec, pin)); + return nitems ? nitems : 1; +} + +static int create_in_jack_mode(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + unsigned int defcfg; + + if (pin == spec->hp_mic_pin) + return 0; /* already done in create_out_jack_mode() */ + + /* no jack mode for fixed pins */ + defcfg = snd_hda_codec_get_pincfg(codec, pin); + if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) + return 0; + + /* no multiple vref caps? */ + if (get_in_jack_num_items(codec, pin) <= 1) + return 0; + + get_jack_mode_name(codec, pin, name, sizeof(name)); + knew = snd_hda_gen_add_kctl(spec, name, &in_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + return 0; +} + /* - * parse input + * HP/mic shared jack mode */ -static int parse_input(struct hda_codec *codec) +static int hp_mic_jack_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int err; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + const char *text = NULL; + int idx; - /* - * At first we look for an audio input widget. - * If it reaches to certain input PINs, we take it as the - * input path. - */ - list_for_each_entry(node, &spec->nid_list, list) { - if (node->wid_caps & AC_WCAP_DIGITAL) - continue; /* skip SPDIF */ - if (node->type == AC_WID_AUD_IN) { - err = parse_input_path(codec, node); - if (err < 0) - return err; - else if (err > 0) - return 0; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = out_jacks + in_jacks; + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; + idx = uinfo->value.enumerated.item; + if (idx < out_jacks) { + if (out_jacks > 1) + text = out_jack_texts[idx]; + else + text = "Headphone Out"; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + text = vref_texts[get_vref_idx(vref_caps, idx)]; + } else + text = "Mic In"; + } + + strcpy(uinfo->value.enumerated.name, text); + return 0; +} + +static int get_cur_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t nid) +{ + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val = snd_hda_codec_get_pin_target(codec, nid); + int idx = 0; + + if (val & PIN_OUT) { + if (out_jacks > 1 && val == PIN_HP) + idx = 1; + } else if (val & PIN_IN) { + idx = out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val &= AC_PINCTL_VREFEN; + idx += cvt_from_vref_idx(vref_caps, val); } } - snd_printd("hda_generic: no proper input path found\n"); + return idx; +} + +static int hp_mic_jack_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + ucontrol->value.enumerated.item[0] = + get_cur_hp_mic_jack_mode(codec, nid); return 0; } -#ifdef CONFIG_PM -static void add_input_loopback(struct hda_codec *codec, hda_nid_t nid, - int dir, int idx) +static int hp_mic_jack_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct hda_gspec *spec = codec->spec; - struct hda_amp_list *p; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = kcontrol->private_value; + int out_jacks = get_out_jack_num_items(codec, nid); + int in_jacks = get_in_jack_num_items(codec, nid); + unsigned int val, oldval, idx; - if (spec->num_loopbacks >= MAX_LOOPBACK_AMPS) { - snd_printk(KERN_ERR "hda_generic: Too many loopback ctls\n"); - return; + oldval = get_cur_hp_mic_jack_mode(codec, nid); + idx = ucontrol->value.enumerated.item[0]; + if (oldval == idx) + return 0; + + if (idx < out_jacks) { + if (out_jacks > 1) + val = idx ? PIN_HP : PIN_OUT; + else + val = PIN_HP; + } else { + idx -= out_jacks; + if (in_jacks > 1) { + unsigned int vref_caps = get_vref_caps(codec, nid); + val = snd_hda_codec_get_pin_target(codec, nid); + val &= ~(AC_PINCTL_VREFEN | PIN_HP); + val |= get_vref_idx(vref_caps, idx) | PIN_IN; + } else + val = snd_hda_get_default_vref(codec, nid) | PIN_IN; } - p = &spec->loopback_list[spec->num_loopbacks++]; - p->nid = nid; - p->dir = dir; - p->idx = idx; - spec->loopback.amplist = spec->loopback_list; + snd_hda_set_pin_ctl_cache(codec, nid, val); + call_hp_automute(codec, NULL); + + return 1; +} + +static const struct snd_kcontrol_new hp_mic_jack_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = hp_mic_jack_mode_info, + .get = hp_mic_jack_mode_get, + .put = hp_mic_jack_mode_put, +}; + +static int create_hp_mic_jack_mode(struct hda_codec *codec, hda_nid_t pin) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + knew = snd_hda_gen_add_kctl(spec, "Headphone Mic Jack Mode", + &hp_mic_jack_mode_enum); + if (!knew) + return -ENOMEM; + knew->private_value = pin; + spec->hp_mic_jack_modes = 1; + return 0; } -#else -#define add_input_loopback(codec,nid,dir,idx) -#endif /* - * create mixer controls if possible + * Parse input paths */ -static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, - unsigned int index, const char *type, - const char *dir_sfx, int is_loopback) + +/* add the powersave loopback-list entry */ +static int add_loopback_list(struct hda_gen_spec *spec, hda_nid_t mix, int idx) { - char name[32]; - int err; - int created = 0; - struct snd_kcontrol_new knew; + struct hda_amp_list *list; - if (type) - sprintf(name, "%s %s Switch", type, dir_sfx); - else - sprintf(name, "%s Switch", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, index, HDA_INPUT); - if (is_loopback) - add_input_loopback(codec, node->nid, HDA_INPUT, index); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + list = snd_array_new(&spec->loopback_list); + if (!list) + return -ENOMEM; + list->nid = mix; + list->dir = HDA_INPUT; + list->idx = idx; + spec->loopback.amplist = spec->loopback_list.list; + return 0; +} + +/* return true if either a volume or a mute amp is found for the given + * aamix path; the amp has to be either in the mixer node or its direct leaf + */ +static bool look_for_mix_leaf_ctls(struct hda_codec *codec, hda_nid_t mix_nid, + hda_nid_t pin, unsigned int *mix_val, + unsigned int *mute_val) +{ + int idx, num_conns; + const hda_nid_t *list; + hda_nid_t nid; + + idx = snd_hda_get_conn_index(codec, mix_nid, pin, true); + if (idx < 0) + return false; + + *mix_val = *mute_val = 0; + if (nid_has_volume(codec, mix_nid, HDA_INPUT)) + *mix_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + if (nid_has_mute(codec, mix_nid, HDA_INPUT)) + *mute_val = HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT); + if (*mix_val && *mute_val) + return true; + + /* check leaf node */ + num_conns = snd_hda_get_conn_list(codec, mix_nid, &list); + if (num_conns < idx) + return false; + nid = list[idx]; + if (!*mix_val && nid_has_volume(codec, nid, HDA_OUTPUT) && + !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_VOL_CTL)) + *mix_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + if (!*mute_val && nid_has_mute(codec, nid, HDA_OUTPUT) && + !is_ctl_associated(codec, nid, HDA_OUTPUT, 0, NID_PATH_MUTE_CTL)) + *mute_val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + + return *mix_val || *mute_val; +} + +/* create input playback/capture controls for the given pin */ +static int new_analog_input(struct hda_codec *codec, int input_idx, + hda_nid_t pin, const char *ctlname, int ctlidx, + hda_nid_t mix_nid) +{ + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + unsigned int mix_val, mute_val; + int err, idx; + + if (!look_for_mix_leaf_ctls(codec, mix_nid, pin, &mix_val, &mute_val)) + return 0; + + path = snd_hda_add_new_path(codec, pin, mix_nid, 0); + if (!path) + return -EINVAL; + print_nid_path(codec, "loopback", path); + spec->loopback_paths[input_idx] = snd_hda_get_path_idx(codec, path); + + idx = path->idx[path->depth - 1]; + if (mix_val) { + err = __add_pb_vol_ctrl(spec, HDA_CTL_WIDGET_VOL, ctlname, ctlidx, mix_val); if (err < 0) return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_MUTE)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_MUTE(name, node->nid, 0, HDA_OUTPUT); - if (is_loopback) - add_input_loopback(codec, node->nid, HDA_OUTPUT, 0); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + path->ctls[NID_PATH_VOL_CTL] = mix_val; + } + + if (mute_val) { + err = __add_pb_sw_ctrl(spec, HDA_CTL_WIDGET_MUTE, ctlname, ctlidx, mute_val); if (err < 0) return err; - created = 1; + path->ctls[NID_PATH_MUTE_CTL] = mute_val; } - if (type) - sprintf(name, "%s %s Volume", type, dir_sfx); - else - sprintf(name, "%s Volume", dir_sfx); - if ((node->wid_caps & AC_WCAP_IN_AMP) && - (node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, index, HDA_INPUT); - snd_printdd("[%s] NID=0x%x, DIR=IN, IDX=0x%x\n", name, node->nid, index); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + path->active = true; + err = add_loopback_list(spec, mix_nid, idx); + if (err < 0) + return err; + + if (spec->mixer_nid != spec->mixer_merge_nid && + !spec->loopback_merge_path) { + path = snd_hda_add_new_path(codec, spec->mixer_nid, + spec->mixer_merge_nid, 0); + if (path) { + print_nid_path(codec, "loopback-merge", path); + path->active = true; + spec->loopback_merge_path = + snd_hda_get_path_idx(codec, path); + } + } + + return 0; +} + +static int is_input_pin(struct hda_codec *codec, hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + return (pincap & AC_PINCAP_IN) != 0; +} + +/* Parse the codec tree and retrieve ADCs */ +static int fill_adc_nids(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t nid; + hda_nid_t *adc_nids = spec->adc_nids; + int max_nums = ARRAY_SIZE(spec->adc_nids); + int i, nums = 0; + + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int caps = get_wcaps(codec, nid); + int type = get_wcaps_type(caps); + + if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) + continue; + adc_nids[nums] = nid; + if (++nums >= max_nums) + break; + } + spec->num_adc_nids = nums; + + /* copy the detected ADCs to all_adcs[] */ + spec->num_all_adcs = nums; + memcpy(spec->all_adcs, spec->adc_nids, nums * sizeof(hda_nid_t)); + + return nums; +} + +/* filter out invalid adc_nids that don't give all active input pins; + * if needed, check whether dynamic ADC-switching is available + */ +static int check_dyn_adc_switch(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + unsigned int ok_bits; + int i, n, nums; + + nums = 0; + ok_bits = 0; + for (n = 0; n < spec->num_adc_nids; n++) { + for (i = 0; i < imux->num_items; i++) { + if (!spec->input_paths[i][n]) + break; + } + if (i >= imux->num_items) { + ok_bits |= (1 << n); + nums++; + } + } + + if (!ok_bits) { + /* check whether ADC-switch is possible */ + for (i = 0; i < imux->num_items; i++) { + for (n = 0; n < spec->num_adc_nids; n++) { + if (spec->input_paths[i][n]) { + spec->dyn_adc_idx[i] = n; + break; + } + } + } + + codec_dbg(codec, "enabling ADC switching\n"); + spec->dyn_adc_switch = 1; + } else if (nums != spec->num_adc_nids) { + /* shrink the invalid adcs and input paths */ + nums = 0; + for (n = 0; n < spec->num_adc_nids; n++) { + if (!(ok_bits & (1 << n))) + continue; + if (n != nums) { + spec->adc_nids[nums] = spec->adc_nids[n]; + for (i = 0; i < imux->num_items; i++) { + invalidate_nid_path(codec, + spec->input_paths[i][nums]); + spec->input_paths[i][nums] = + spec->input_paths[i][n]; + } + } + nums++; + } + spec->num_adc_nids = nums; + } + + if (imux->num_items == 1 || + (imux->num_items == 2 && spec->hp_mic)) { + codec_dbg(codec, "reducing to a single ADC\n"); + spec->num_adc_nids = 1; /* reduce to a single ADC */ + } + + /* single index for individual volumes ctls */ + if (!spec->dyn_adc_switch && spec->multi_cap_vol) + spec->num_adc_nids = 1; + + return 0; +} + +/* parse capture source paths from the given pin and create imux items */ +static int parse_capture_source(struct hda_codec *codec, hda_nid_t pin, + int cfg_idx, int num_adcs, + const char *label, int anchor) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int imux_idx = imux->num_items; + bool imux_added = false; + int c; + + for (c = 0; c < num_adcs; c++) { + struct nid_path *path; + hda_nid_t adc = spec->adc_nids[c]; + + if (!is_reachable_path(codec, pin, adc)) + continue; + path = snd_hda_add_new_path(codec, pin, adc, anchor); + if (!path) + continue; + print_nid_path(codec, "input", path); + spec->input_paths[imux_idx][c] = + snd_hda_get_path_idx(codec, path); + + if (!imux_added) { + if (spec->hp_mic_pin == pin) + spec->hp_mic_mux_idx = imux->num_items; + spec->imux_pins[imux->num_items] = pin; + snd_hda_add_imux_item(imux, label, cfg_idx, NULL); + imux_added = true; + if (spec->dyn_adc_switch) + spec->dyn_adc_idx[imux_idx] = c; + } + } + + return 0; +} + +/* + * create playback/capture controls for input pins + */ + +/* fill the label for each input at first */ +static int fill_input_pin_labels(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin = cfg->inputs[i].pin; + const char *label; + int j, idx; + + if (!is_input_pin(codec, pin)) + continue; + + label = hda_get_autocfg_input_label(codec, cfg, i); + idx = 0; + for (j = i - 1; j >= 0; j--) { + if (spec->input_labels[j] && + !strcmp(spec->input_labels[j], label)) { + idx = spec->input_label_idxs[j] + 1; + break; + } + } + + spec->input_labels[i] = label; + spec->input_label_idxs[i] = idx; + } + + return 0; +} + +#define CFG_IDX_MIX 99 /* a dummy cfg->input idx for stereo mix */ + +static int create_input_ctls(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const struct auto_pin_cfg *cfg = &spec->autocfg; + hda_nid_t mixer = spec->mixer_nid; + int num_adcs; + int i, err; + unsigned int val; + + num_adcs = fill_adc_nids(codec); + if (num_adcs < 0) + return 0; + + err = fill_input_pin_labels(codec); + if (err < 0) + return err; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t pin; + + pin = cfg->inputs[i].pin; + if (!is_input_pin(codec, pin)) + continue; + + val = PIN_IN; + if (cfg->inputs[i].type == AUTO_PIN_MIC) + val |= snd_hda_get_default_vref(codec, pin); + if (pin != spec->hp_mic_pin) + set_pin_target(codec, pin, val, false); + + if (mixer) { + if (is_reachable_path(codec, pin, mixer)) { + err = new_analog_input(codec, i, pin, + spec->input_labels[i], + spec->input_label_idxs[i], + mixer); + if (err < 0) + return err; + } + } + + err = parse_capture_source(codec, pin, i, num_adcs, + spec->input_labels[i], -mixer); if (err < 0) return err; - created = 1; - } else if ((node->wid_caps & AC_WCAP_OUT_AMP) && - (node->amp_out_caps & AC_AMPCAP_NUM_STEPS)) { - knew = (struct snd_kcontrol_new)HDA_CODEC_VOLUME(name, node->nid, 0, HDA_OUTPUT); - snd_printdd("[%s] NID=0x%x, DIR=OUT\n", name, node->nid); - err = snd_hda_ctl_add(codec, node->nid, - snd_ctl_new1(&knew, codec)); + + if (spec->add_jack_modes) { + err = create_in_jack_mode(codec, pin); + if (err < 0) + return err; + } + } + + /* add stereo mix when explicitly enabled via hint */ + if (mixer && spec->add_stereo_mix_input && + snd_hda_get_bool_hint(codec, "add_stereo_mix_input") > 0) { + err = parse_capture_source(codec, mixer, CFG_IDX_MIX, num_adcs, + "Stereo Mix", 0); if (err < 0) return err; - created = 1; } - return created; + return 0; } + /* - * check whether the controls with the given name and direction suffix already exist + * input source mux */ -static int check_existing_control(struct hda_codec *codec, const char *type, const char *dir) + +/* get the input path specified by the given adc and imux indices */ +static struct nid_path *get_input_path(struct hda_codec *codec, int adc_idx, int imux_idx) { - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - sprintf(id.name, "%s %s Volume", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; - sprintf(id.name, "%s %s Switch", type, dir); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - if (snd_ctl_find_id(codec->bus->card, &id)) - return 1; + struct hda_gen_spec *spec = codec->spec; + if (imux_idx < 0 || imux_idx >= HDA_MAX_NUM_INPUTS) { + snd_BUG(); + return NULL; + } + if (spec->dyn_adc_switch) + adc_idx = spec->dyn_adc_idx[imux_idx]; + if (adc_idx < 0 || adc_idx >= AUTO_CFG_MAX_INS) { + snd_BUG(); + return NULL; + } + return snd_hda_get_path_from_idx(codec, spec->input_paths[imux_idx][adc_idx]); +} + +static int mux_select(struct hda_codec *codec, unsigned int adc_idx, + unsigned int idx); + +static int mux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + return snd_hda_input_mux_info(&spec->input_mux, uinfo); +} + +static int mux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + /* the ctls are created at once with multiple counts */ + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + + ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; return 0; } +static int mux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + return mux_select(codec, adc_idx, + ucontrol->value.enumerated.item[0]); +} + +static const struct snd_kcontrol_new cap_src_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .info = mux_enum_info, + .get = mux_enum_get, + .put = mux_enum_put, +}; + /* - * build output mixer controls + * capture volume and capture switch ctls */ -static int create_output_mixers(struct hda_codec *codec, - const char * const *names) + +typedef int (*put_call_t)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +/* call the given amp update function for all amps in the imux list at once */ +static int cap_put_caller(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol, + put_call_t func, int type) { - struct hda_gspec *spec = codec->spec; - int i, err; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + struct nid_path *path; + int i, adc_idx, err = 0; - for (i = 0; i < spec->pcm_vol_nodes; i++) { - err = create_mixer(codec, spec->pcm_vol[i].node, - spec->pcm_vol[i].index, - names[i], "Playback", 0); + imux = &spec->input_mux; + adc_idx = kcontrol->id.index; + mutex_lock(&codec->control_mutex); + /* we use the cache-only update at first since multiple input paths + * may shared the same amp; by updating only caches, the redundant + * writes to hardware can be reduced. + */ + codec->cached_write = 1; + for (i = 0; i < imux->num_items; i++) { + path = get_input_path(codec, adc_idx, i); + if (!path || !path->ctls[type]) + continue; + kcontrol->private_value = path->ctls[type]; + err = func(kcontrol, ucontrol); if (err < 0) - return err; + goto error; } - return 0; + error: + codec->cached_write = 0; + mutex_unlock(&codec->control_mutex); + snd_hda_codec_flush_cache(codec); /* flush the updates */ + if (err >= 0 && spec->cap_sync_hook) + spec->cap_sync_hook(codec, kcontrol, ucontrol); + return err; } -static int build_output_controls(struct hda_codec *codec) +/* capture volume ctl callbacks */ +#define cap_vol_info snd_hda_mixer_amp_volume_info +#define cap_vol_get snd_hda_mixer_amp_volume_get +#define cap_vol_tlv snd_hda_mixer_amp_tlv + +static int cap_vol_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct hda_gspec *spec = codec->spec; - static const char * const types_speaker[] = { "Speaker", "Headphone" }; - static const char * const types_line[] = { "Front", "Headphone" }; + return cap_put_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_volume_put, + NID_PATH_VOL_CTL); +} - switch (spec->pcm_vol_nodes) { - case 1: - return create_mixer(codec, spec->pcm_vol[0].node, - spec->pcm_vol[0].index, - "Master", "Playback", 0); - case 2: - if (defcfg_type(spec->out_pin_node[0]) == AC_JACK_SPEAKER) - return create_output_mixers(codec, types_speaker); - else - return create_output_mixers(codec, types_line); +static const struct snd_kcontrol_new cap_vol_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Volume", + .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), + .info = cap_vol_info, + .get = cap_vol_get, + .put = cap_vol_put, + .tlv = { .c = cap_vol_tlv }, +}; + +/* capture switch ctl callbacks */ +#define cap_sw_info snd_ctl_boolean_stereo_info +#define cap_sw_get snd_hda_mixer_amp_switch_get + +static int cap_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return cap_put_caller(kcontrol, ucontrol, + snd_hda_mixer_amp_switch_put, + NID_PATH_MUTE_CTL); +} + +static const struct snd_kcontrol_new cap_sw_temp = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Switch", + .info = cap_sw_info, + .get = cap_sw_get, + .put = cap_sw_put, +}; + +static int parse_capvol_in_path(struct hda_codec *codec, struct nid_path *path) +{ + hda_nid_t nid; + int i, depth; + + path->ctls[NID_PATH_VOL_CTL] = path->ctls[NID_PATH_MUTE_CTL] = 0; + for (depth = 0; depth < 3; depth++) { + if (depth >= path->depth) + return -EINVAL; + i = path->depth - depth - 1; + nid = path->path[i]; + if (!path->ctls[NID_PATH_VOL_CTL]) { + if (nid_has_volume(codec, nid, HDA_OUTPUT)) + path->ctls[NID_PATH_VOL_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else if (nid_has_volume(codec, nid, HDA_INPUT)) { + int idx = path->idx[i]; + if (!depth && codec->single_adc_amp) + idx = 0; + path->ctls[NID_PATH_VOL_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); + } + } + if (!path->ctls[NID_PATH_MUTE_CTL]) { + if (nid_has_mute(codec, nid, HDA_OUTPUT)) + path->ctls[NID_PATH_MUTE_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + else if (nid_has_mute(codec, nid, HDA_INPUT)) { + int idx = path->idx[i]; + if (!depth && codec->single_adc_amp) + idx = 0; + path->ctls[NID_PATH_MUTE_CTL] = + HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_INPUT); + } + } } return 0; } -/* create capture volume/switch */ -static int build_input_controls(struct hda_codec *codec) +static bool is_inv_dmic_pin(struct hda_codec *codec, hda_nid_t nid) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *adc_node = spec->adc_node; - int i, err; - static struct snd_kcontrol_new cap_sel = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = capture_source_info, - .get = capture_source_get, - .put = capture_source_put, - }; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int val; + int i; - if (! adc_node || ! spec->input_mux.num_items) - return 0; /* not found */ + if (!spec->inv_dmic_split) + return false; + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].pin != nid) + continue; + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return false; + val = snd_hda_codec_get_pincfg(codec, nid); + return snd_hda_get_input_pin_attr(val) == INPUT_PIN_ATTR_INT; + } + return false; +} - spec->cur_cap_src = 0; - select_input_connection(codec, adc_node, - spec->input_mux.items[0].index); +/* capture switch put callback for a single control with hook call */ +static int cap_single_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + int ret; - /* create capture volume and switch controls if the ADC has an amp */ - /* do we have only a single item? */ - if (spec->input_mux.num_items == 1) { - err = create_mixer(codec, adc_node, - spec->input_mux.items[0].index, - NULL, "Capture", 0); - if (err < 0) - return err; + ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + if (ret < 0) + return ret; + + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, kcontrol, ucontrol); + + return ret; +} + +static int add_single_cap_ctl(struct hda_codec *codec, const char *label, + int idx, bool is_switch, unsigned int ctl, + bool inv_dmic) +{ + struct hda_gen_spec *spec = codec->spec; + char tmpname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + int type = is_switch ? HDA_CTL_WIDGET_MUTE : HDA_CTL_WIDGET_VOL; + const char *sfx = is_switch ? "Switch" : "Volume"; + unsigned int chs = inv_dmic ? 1 : 3; + struct snd_kcontrol_new *knew; + + if (!ctl) return 0; - } - /* create input MUX if multiple sources are available */ - err = snd_hda_ctl_add(codec, spec->adc_node->nid, - snd_ctl_new1(&cap_sel, codec)); + if (label) + snprintf(tmpname, sizeof(tmpname), + "%s Capture %s", label, sfx); + else + snprintf(tmpname, sizeof(tmpname), + "Capture %s", sfx); + knew = add_control(spec, type, tmpname, idx, + amp_val_replace_channels(ctl, chs)); + if (!knew) + return -ENOMEM; + if (is_switch) + knew->put = cap_single_sw_put; + if (!inv_dmic) + return 0; + + /* Make independent right kcontrol */ + if (label) + snprintf(tmpname, sizeof(tmpname), + "Inverted %s Capture %s", label, sfx); + else + snprintf(tmpname, sizeof(tmpname), + "Inverted Capture %s", sfx); + knew = add_control(spec, type, tmpname, idx, + amp_val_replace_channels(ctl, 2)); + if (!knew) + return -ENOMEM; + if (is_switch) + knew->put = cap_single_sw_put; + return 0; +} + +/* create single (and simple) capture volume and switch controls */ +static int create_single_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl, + bool inv_dmic) +{ + int err; + err = add_single_cap_ctl(codec, NULL, idx, false, vol_ctl, inv_dmic); + if (err < 0) + return err; + err = add_single_cap_ctl(codec, NULL, idx, true, sw_ctl, inv_dmic); if (err < 0) return err; + return 0; +} - /* no volume control? */ - if (! (adc_node->wid_caps & AC_WCAP_IN_AMP) || - ! (adc_node->amp_in_caps & AC_AMPCAP_NUM_STEPS)) +/* create bound capture volume and switch controls */ +static int create_bind_cap_vol_ctl(struct hda_codec *codec, int idx, + unsigned int vol_ctl, unsigned int sw_ctl) +{ + struct hda_gen_spec *spec = codec->spec; + struct snd_kcontrol_new *knew; + + if (vol_ctl) { + knew = snd_hda_gen_add_kctl(spec, NULL, &cap_vol_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = vol_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + if (sw_ctl) { + knew = snd_hda_gen_add_kctl(spec, NULL, &cap_sw_temp); + if (!knew) + return -ENOMEM; + knew->index = idx; + knew->private_value = sw_ctl; + knew->subdevice = HDA_SUBDEV_AMP_FLAG; + } + return 0; +} + +/* return the vol ctl when used first in the imux list */ +static unsigned int get_first_cap_ctl(struct hda_codec *codec, int idx, int type) +{ + struct nid_path *path; + unsigned int ctl; + int i; + + path = get_input_path(codec, 0, idx); + if (!path) + return 0; + ctl = path->ctls[type]; + if (!ctl) return 0; + for (i = 0; i < idx - 1; i++) { + path = get_input_path(codec, 0, i); + if (path && path->ctls[type] == ctl) + return 0; + } + return ctl; +} + +/* create individual capture volume and switch controls per input */ +static int create_multi_cap_vol_ctl(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int i, err, type; + + for (i = 0; i < imux->num_items; i++) { + bool inv_dmic; + int idx; + + idx = imux->items[i].index; + if (idx >= spec->autocfg.num_inputs) + continue; + inv_dmic = is_inv_dmic_pin(codec, spec->imux_pins[i]); + + for (type = 0; type < 2; type++) { + err = add_single_cap_ctl(codec, + spec->input_labels[idx], + spec->input_label_idxs[idx], + type, + get_first_cap_ctl(codec, i, type), + inv_dmic); + if (err < 0) + return err; + } + } + return 0; +} + +static int create_capture_mixers(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + int i, n, nums, err; + + if (spec->dyn_adc_switch) + nums = 1; + else + nums = spec->num_adc_nids; + + if (!spec->auto_mic && imux->num_items > 1) { + struct snd_kcontrol_new *knew; + const char *name; + name = nums > 1 ? "Input Source" : "Capture Source"; + knew = snd_hda_gen_add_kctl(spec, name, &cap_src_temp); + if (!knew) + return -ENOMEM; + knew->count = nums; + } + + for (n = 0; n < nums; n++) { + bool multi = false; + bool multi_cap_vol = spec->multi_cap_vol; + bool inv_dmic = false; + int vol, sw; - for (i = 0; i < spec->input_mux.num_items; i++) { - struct snd_kcontrol_new knew; - char name[32]; - sprintf(name, "%s Capture Volume", - spec->input_mux.items[i].label); - knew = (struct snd_kcontrol_new) - HDA_CODEC_VOLUME(name, adc_node->nid, - spec->input_mux.items[i].index, - HDA_INPUT); - err = snd_hda_ctl_add(codec, adc_node->nid, - snd_ctl_new1(&knew, codec)); + vol = sw = 0; + for (i = 0; i < imux->num_items; i++) { + struct nid_path *path; + path = get_input_path(codec, n, i); + if (!path) + continue; + parse_capvol_in_path(codec, path); + if (!vol) + vol = path->ctls[NID_PATH_VOL_CTL]; + else if (vol != path->ctls[NID_PATH_VOL_CTL]) { + multi = true; + if (!same_amp_caps(codec, vol, + path->ctls[NID_PATH_VOL_CTL], HDA_INPUT)) + multi_cap_vol = true; + } + if (!sw) + sw = path->ctls[NID_PATH_MUTE_CTL]; + else if (sw != path->ctls[NID_PATH_MUTE_CTL]) { + multi = true; + if (!same_amp_caps(codec, sw, + path->ctls[NID_PATH_MUTE_CTL], HDA_INPUT)) + multi_cap_vol = true; + } + if (is_inv_dmic_pin(codec, spec->imux_pins[i])) + inv_dmic = true; + } + + if (!multi) + err = create_single_cap_vol_ctl(codec, n, vol, sw, + inv_dmic); + else if (!multi_cap_vol && !inv_dmic) + err = create_bind_cap_vol_ctl(codec, n, vol, sw); + else + err = create_multi_cap_vol_ctl(codec); if (err < 0) return err; } @@ -860,226 +3600,1818 @@ static int build_input_controls(struct hda_codec *codec) return 0; } +/* + * add mic boosts if needed + */ + +/* check whether the given amp is feasible as a boost volume */ +static bool check_boost_vol(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx) +{ + unsigned int step; + + if (!nid_has_volume(codec, nid, dir) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_VOL_CTL) || + is_ctl_associated(codec, nid, dir, idx, NID_PATH_BOOST_CTL)) + return false; + + step = (query_amp_caps(codec, nid, dir) & AC_AMPCAP_STEP_SIZE) + >> AC_AMPCAP_STEP_SIZE_SHIFT; + if (step < 0x20) + return false; + return true; +} + +/* look for a boost amp in a widget close to the pin */ +static unsigned int look_for_boost_amp(struct hda_codec *codec, + struct nid_path *path) +{ + unsigned int val = 0; + hda_nid_t nid; + int depth; + + for (depth = 0; depth < 3; depth++) { + if (depth >= path->depth - 1) + break; + nid = path->path[depth]; + if (depth && check_boost_vol(codec, nid, HDA_OUTPUT, 0)) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); + break; + } else if (check_boost_vol(codec, nid, HDA_INPUT, + path->idx[depth])) { + val = HDA_COMPOSE_AMP_VAL(nid, 3, path->idx[depth], + HDA_INPUT); + break; + } + } + + return val; +} + +static int parse_mic_boost(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + struct hda_input_mux *imux = &spec->input_mux; + int i; + + if (!spec->num_adc_nids) + return 0; + + for (i = 0; i < imux->num_items; i++) { + struct nid_path *path; + unsigned int val; + int idx; + char boost_label[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + + idx = imux->items[i].index; + if (idx >= imux->num_items) + continue; + + /* check only line-in and mic pins */ + if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) + continue; + + path = get_input_path(codec, 0, i); + if (!path) + continue; + + val = look_for_boost_amp(codec, path); + if (!val) + continue; + + /* create a boost control */ + snprintf(boost_label, sizeof(boost_label), + "%s Boost Volume", spec->input_labels[idx]); + if (!add_control(spec, HDA_CTL_WIDGET_VOL, boost_label, + spec->input_label_idxs[idx], val)) + return -ENOMEM; + + path->ctls[NID_PATH_BOOST_CTL] = val; + } + return 0; +} /* - * parse the nodes recursively until reach to the output PIN. - * - * returns 0 - if not found, - * 1 - if found, but no mixer is created - * 2 - if found and mixer was already created, (just skip) - * a negative error code + * parse digital I/Os and set up NIDs in BIOS auto-parse mode */ -static int parse_loopback_path(struct hda_codec *codec, struct hda_gspec *spec, - struct hda_gnode *node, struct hda_gnode *dest_node, - const char *type) +static void parse_digital(struct hda_codec *codec) { + struct hda_gen_spec *spec = codec->spec; + struct nid_path *path; + int i, nums; + hda_nid_t dig_nid, pin; + + /* support multiple SPDIFs; the secondary is set up as a slave */ + nums = 0; + for (i = 0; i < spec->autocfg.dig_outs; i++) { + pin = spec->autocfg.dig_out_pins[i]; + dig_nid = look_for_dac(codec, pin, true); + if (!dig_nid) + continue; + path = snd_hda_add_new_path(codec, dig_nid, pin, 0); + if (!path) + continue; + print_nid_path(codec, "digout", path); + path->active = true; + spec->digout_paths[i] = snd_hda_get_path_idx(codec, path); + set_pin_target(codec, pin, PIN_OUT, false); + if (!nums) { + spec->multiout.dig_out_nid = dig_nid; + spec->dig_out_type = spec->autocfg.dig_out_type[0]; + } else { + spec->multiout.slave_dig_outs = spec->slave_dig_outs; + if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) + break; + spec->slave_dig_outs[nums - 1] = dig_nid; + } + nums++; + } + + if (spec->autocfg.dig_in_pin) { + pin = spec->autocfg.dig_in_pin; + dig_nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, dig_nid++) { + unsigned int wcaps = get_wcaps(codec, dig_nid); + if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) + continue; + if (!(wcaps & AC_WCAP_DIGITAL)) + continue; + path = snd_hda_add_new_path(codec, pin, dig_nid, 0); + if (path) { + print_nid_path(codec, "digin", path); + path->active = true; + spec->dig_in_nid = dig_nid; + spec->digin_path = snd_hda_get_path_idx(codec, path); + set_pin_target(codec, pin, PIN_IN, false); + break; + } + } + } +} + + +/* + * input MUX handling + */ + +static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur); + +/* select the given imux item; either unmute exclusively or select the route */ +static int mux_select(struct hda_codec *codec, unsigned int adc_idx, + unsigned int idx) +{ + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + struct nid_path *old_path, *path; + + imux = &spec->input_mux; + if (!imux->num_items) + return 0; + + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->cur_mux[adc_idx] == idx) + return 0; + + old_path = get_input_path(codec, adc_idx, spec->cur_mux[adc_idx]); + if (!old_path) + return 0; + if (old_path->active) + snd_hda_activate_path(codec, old_path, false, false); + + spec->cur_mux[adc_idx] = idx; + + if (spec->hp_mic) + update_hp_mic(codec, adc_idx, false); + + if (spec->dyn_adc_switch) + dyn_adc_pcm_resetup(codec, idx); + + path = get_input_path(codec, adc_idx, idx); + if (!path) + return 0; + if (path->active) + return 0; + snd_hda_activate_path(codec, path, true, false); + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, NULL, NULL); + path_power_down_sync(codec, old_path); + return 1; +} + + +/* + * Jack detections for HP auto-mute and mic-switch + */ + +/* check each pin in the given array; returns true if any of them is plugged */ +static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) +{ + int i; + bool present = false; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + if (!nid) + break; + /* don't detect pins retasked as inputs */ + if (snd_hda_codec_get_pin_target(codec, nid) & AC_PINCTL_IN_EN) + continue; + if (snd_hda_jack_detect_state(codec, nid) == HDA_JACK_PRESENT) + present = true; + } + return present; +} + +/* standard HP/line-out auto-mute helper */ +static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, + int *paths, bool mute) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < num_pins; i++) { + hda_nid_t nid = pins[i]; + unsigned int val, oldval; + if (!nid) + break; + + if (spec->auto_mute_via_amp) { + struct nid_path *path; + hda_nid_t mute_nid; + + path = snd_hda_get_path_from_idx(codec, paths[i]); + if (!path) + continue; + mute_nid = get_amp_nid_(path->ctls[NID_PATH_MUTE_CTL]); + if (!mute_nid) + continue; + if (mute) + spec->mute_bits |= (1ULL << mute_nid); + else + spec->mute_bits &= ~(1ULL << mute_nid); + set_pin_eapd(codec, nid, !mute); + continue; + } + + oldval = snd_hda_codec_get_pin_target(codec, nid); + if (oldval & PIN_IN) + continue; /* no mute for inputs */ + /* don't reset VREF value in case it's controlling + * the amp (see alc861_fixup_asus_amp_vref_0f()) + */ + if (spec->keep_vref_in_automute) + val = oldval & ~PIN_HP; + else + val = 0; + if (!mute) + val |= oldval; + /* here we call update_pin_ctl() so that the pinctl is changed + * without changing the pinctl target value; + * the original target value will be still referred at the + * init / resume again + */ + update_pin_ctl(codec, nid, val); + set_pin_eapd(codec, nid, !mute); + } +} + +/* Toggle outputs muting */ +void snd_hda_gen_update_outputs(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int *paths; + int on; + + /* Control HP pins/amps depending on master_mute state; + * in general, HP pins/amps control should be enabled in all cases, + * but currently set only for master_mute, just to be safe + */ + if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) + paths = spec->out_paths; + else + paths = spec->hp_paths; + do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), + spec->autocfg.hp_pins, paths, spec->master_mute); + + if (!spec->automute_speaker) + on = 0; + else + on = spec->hp_jack_present | spec->line_jack_present; + on |= spec->master_mute; + spec->speaker_muted = on; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + paths = spec->out_paths; + else + paths = spec->speaker_paths; + do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), + spec->autocfg.speaker_pins, paths, on); + + /* toggle line-out mutes if needed, too */ + /* if LO is a copy of either HP or Speaker, don't need to handle it */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || + spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) + return; + if (!spec->automute_lo) + on = 0; + else + on = spec->hp_jack_present; + on |= spec->master_mute; + spec->line_out_muted = on; + paths = spec->out_paths; + do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins, paths, on); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_update_outputs); + +static void call_update_outputs(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->automute_hook) + spec->automute_hook(codec); + else + snd_hda_gen_update_outputs(codec); + + /* sync the whole vmaster slaves to reflect the new auto-mute status */ + if (spec->auto_mute_via_amp && !codec->bus->shutdown) + snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false); +} + +/* standard HP-automute helper */ +void snd_hda_gen_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t *pins = spec->autocfg.hp_pins; + int num_pins = ARRAY_SIZE(spec->autocfg.hp_pins); + + /* No detection for the first HP jack during indep-HP mode */ + if (spec->indep_hp_enabled) { + pins++; + num_pins--; + } + + spec->hp_jack_present = detect_jacks(codec, num_pins, pins); + if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) + return; + call_update_outputs(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute); + +/* standard line-out-automute helper */ +void snd_hda_gen_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + return; + /* check LO jack only when it's different from HP */ + if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) + return; + + spec->line_jack_present = + detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), + spec->autocfg.line_out_pins); + if (!spec->automute_speaker || !spec->detect_lo) + return; + call_update_outputs(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute); + +/* standard mic auto-switch helper */ +void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + if (!spec->auto_mic) + return; + + for (i = spec->am_num_entries - 1; i > 0; i--) { + hda_nid_t pin = spec->am_entry[i].pin; + /* don't detect pins retasked as outputs */ + if (snd_hda_codec_get_pin_target(codec, pin) & AC_PINCTL_OUT_EN) + continue; + if (snd_hda_jack_detect_state(codec, pin) == HDA_JACK_PRESENT) { + mux_select(codec, 0, spec->am_entry[i].idx); + return; + } + } + mux_select(codec, 0, spec->am_entry[0].idx); +} +EXPORT_SYMBOL_GPL(snd_hda_gen_mic_autoswitch); + +/* call appropriate hooks */ +static void call_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->hp_automute_hook) + spec->hp_automute_hook(codec, jack); + else + snd_hda_gen_hp_automute(codec, jack); +} + +static void call_line_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->line_automute_hook) + spec->line_automute_hook(codec, jack); + else + snd_hda_gen_line_automute(codec, jack); +} + +static void call_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->mic_autoswitch_hook) + spec->mic_autoswitch_hook(codec, jack); + else + snd_hda_gen_mic_autoswitch(codec, jack); +} + +/* update jack retasking */ +static void update_automute_all(struct hda_codec *codec) +{ + call_hp_automute(codec, NULL); + call_line_automute(codec, NULL); + call_mic_autoswitch(codec, NULL); +} + +/* + * Auto-Mute mode mixer enum support + */ +static int automute_mode_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + static const char * const texts3[] = { + "Disabled", "Speaker Only", "Line Out+Speaker" + }; + + if (spec->automute_speaker_possible && spec->automute_lo_possible) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); +} + +static int automute_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + unsigned int val = 0; + if (spec->automute_speaker) + val++; + if (spec->automute_lo) + val++; + + ucontrol->value.enumerated.item[0] = val; + return 0; +} + +static int automute_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_gen_spec *spec = codec->spec; + + switch (ucontrol->value.enumerated.item[0]) { + case 0: + if (!spec->automute_speaker && !spec->automute_lo) + return 0; + spec->automute_speaker = 0; + spec->automute_lo = 0; + break; + case 1: + if (spec->automute_speaker_possible) { + if (!spec->automute_lo && spec->automute_speaker) + return 0; + spec->automute_speaker = 1; + spec->automute_lo = 0; + } else if (spec->automute_lo_possible) { + if (spec->automute_lo) + return 0; + spec->automute_lo = 1; + } else + return -EINVAL; + break; + case 2: + if (!spec->automute_lo_possible || !spec->automute_speaker_possible) + return -EINVAL; + if (spec->automute_speaker && spec->automute_lo) + return 0; + spec->automute_speaker = 1; + spec->automute_lo = 1; + break; + default: + return -EINVAL; + } + call_update_outputs(codec); + return 1; +} + +static const struct snd_kcontrol_new automute_mode_enum = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Auto-Mute Mode", + .info = automute_mode_info, + .get = automute_mode_get, + .put = automute_mode_put, +}; + +static int add_automute_mode_enum(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (!snd_hda_gen_add_kctl(spec, NULL, &automute_mode_enum)) + return -ENOMEM; + return 0; +} + +/* + * Check the availability of HP/line-out auto-mute; + * Set up appropriately if really supported + */ +static int check_auto_mute_availability(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int present = 0; int i, err; - if (node->checked) + if (spec->suppress_auto_mute) return 0; - node->checked = 1; - if (node == dest_node) { - /* loopback connection found */ - return 1; + if (cfg->hp_pins[0]) + present++; + if (cfg->line_out_pins[0]) + present++; + if (cfg->speaker_pins[0]) + present++; + if (present < 2) /* need two different output types */ + return 0; + + if (!cfg->speaker_pins[0] && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = cfg->line_outs; + } + + if (!cfg->hp_pins[0] && + cfg->line_out_type == AUTO_PIN_HP_OUT) { + memcpy(cfg->hp_pins, cfg->line_out_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = cfg->line_outs; } - for (i = 0; i < node->nconns; i++) { - struct hda_gnode *child = hda_get_node(spec, node->conn_list[i]); - if (! child) + for (i = 0; i < cfg->hp_outs; i++) { + hda_nid_t nid = cfg->hp_pins[i]; + if (!is_jack_detectable(codec, nid)) continue; - err = parse_loopback_path(codec, spec, child, dest_node, type); - if (err < 0) - return err; - else if (err >= 1) { - if (err == 1) { - err = create_mixer(codec, node, i, type, - "Playback", 1); - if (err < 0) - return err; - if (err > 0) - return 2; /* ok, created */ - /* not created, maybe in the lower path */ - err = 1; + codec_dbg(codec, "Enable HP auto-muting on NID 0x%x\n", nid); + snd_hda_jack_detect_enable_callback(codec, nid, HDA_GEN_HP_EVENT, + call_hp_automute); + spec->detect_hp = 1; + } + + if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { + if (cfg->speaker_outs) + for (i = 0; i < cfg->line_outs; i++) { + hda_nid_t nid = cfg->line_out_pins[i]; + if (!is_jack_detectable(codec, nid)) + continue; + codec_dbg(codec, "Enable Line-Out auto-muting on NID 0x%x\n", nid); + snd_hda_jack_detect_enable_callback(codec, nid, + HDA_GEN_FRONT_EVENT, + call_line_automute); + spec->detect_lo = 1; } - /* connect and unmute */ - if (node->nconns > 1) - select_input_connection(codec, node, i); - unmute_input(codec, node, i); - unmute_output(codec, node); + spec->automute_lo_possible = spec->detect_hp; + } + + spec->automute_speaker_possible = cfg->speaker_outs && + (spec->detect_hp || spec->detect_lo); + + spec->automute_lo = spec->automute_lo_possible; + spec->automute_speaker = spec->automute_speaker_possible; + + if (spec->automute_speaker_possible || spec->automute_lo_possible) { + /* create a control for automute mode */ + err = add_automute_mode_enum(codec); + if (err < 0) return err; - } } return 0; } +/* check whether all auto-mic pins are valid; setup indices if OK */ +static bool auto_mic_check_imux(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + const struct hda_input_mux *imux; + int i; + + imux = &spec->input_mux; + for (i = 0; i < spec->am_num_entries; i++) { + spec->am_entry[i].idx = + find_idx_in_nid_list(spec->am_entry[i].pin, + spec->imux_pins, imux->num_items); + if (spec->am_entry[i].idx < 0) + return false; /* no corresponding imux */ + } + + /* we don't need the jack detection for the first pin */ + for (i = 1; i < spec->am_num_entries; i++) + snd_hda_jack_detect_enable_callback(codec, + spec->am_entry[i].pin, + HDA_GEN_MIC_EVENT, + call_mic_autoswitch); + return true; +} + +static int compare_attr(const void *ap, const void *bp) +{ + const struct automic_entry *a = ap; + const struct automic_entry *b = bp; + return (int)(a->attr - b->attr); +} + /* - * parse the tree and build the loopback controls + * Check the availability of auto-mic switch; + * Set up if really supported */ -static int build_loopback_controls(struct hda_codec *codec) +static int check_auto_mic_availability(struct hda_codec *codec) { - struct hda_gspec *spec = codec->spec; - struct hda_gnode *node; - int err; - const char *type; + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int types; + int i, num_pins; - if (! spec->out_pin_node[0]) + if (spec->suppress_auto_mic) return 0; - list_for_each_entry(node, &spec->nid_list, list) { - if (node->type != AC_WID_PIN) - continue; - /* input capable? */ - if (! (node->pin_caps & AC_PINCAP_IN)) + types = 0; + num_pins = 0; + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + unsigned int attr; + attr = snd_hda_codec_get_pincfg(codec, nid); + attr = snd_hda_get_input_pin_attr(attr); + if (types & (1 << attr)) + return 0; /* already occupied */ + switch (attr) { + case INPUT_PIN_ATTR_INT: + if (cfg->inputs[i].type != AUTO_PIN_MIC) + return 0; /* invalid type */ + break; + case INPUT_PIN_ATTR_UNUSED: + return 0; /* invalid entry */ + default: + if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) + return 0; /* invalid type */ + if (!spec->line_in_auto_switch && + cfg->inputs[i].type != AUTO_PIN_MIC) + return 0; /* only mic is allowed */ + if (!is_jack_detectable(codec, nid)) + return 0; /* no unsol support */ + break; + } + if (num_pins >= MAX_AUTO_MIC_PINS) return 0; - type = get_input_type(node, NULL); - if (type) { - if (check_existing_control(codec, type, "Playback")) - continue; - clear_check_flags(spec); - err = parse_loopback_path(codec, spec, - spec->out_pin_node[0], - node, type); + types |= (1 << attr); + spec->am_entry[num_pins].pin = nid; + spec->am_entry[num_pins].attr = attr; + num_pins++; + } + + if (num_pins < 2) + return 0; + + spec->am_num_entries = num_pins; + /* sort the am_entry in the order of attr so that the pin with a + * higher attr will be selected when the jack is plugged. + */ + sort(spec->am_entry, num_pins, sizeof(spec->am_entry[0]), + compare_attr, NULL); + + if (!auto_mic_check_imux(codec)) + return 0; + + spec->auto_mic = 1; + spec->num_adc_nids = 1; + spec->cur_mux[0] = spec->am_entry[0].idx; + codec_dbg(codec, "Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", + spec->am_entry[0].pin, + spec->am_entry[1].pin, + spec->am_entry[2].pin); + + return 0; +} + +/* power_filter hook; make inactive widgets into power down */ +unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + if (power_state != AC_PWRST_D0 || nid == codec->afg) + return power_state; + if (get_wcaps_type(get_wcaps(codec, nid)) >= AC_WID_POWER) + return power_state; + if (is_active_nid_for_any(codec, nid)) + return power_state; + return AC_PWRST_D3; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_path_power_filter); + +/* mute all aamix inputs initially; parse up to the first leaves */ +static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix) +{ + int i, nums; + const hda_nid_t *conn; + bool has_amp; + + nums = snd_hda_get_conn_list(codec, mix, &conn); + has_amp = nid_has_mute(codec, mix, HDA_INPUT); + for (i = 0; i < nums; i++) { + if (has_amp) + snd_hda_codec_amp_stereo(codec, mix, + HDA_INPUT, i, + 0xff, HDA_AMP_MUTE); + else if (nid_has_volume(codec, conn[i], HDA_OUTPUT)) + snd_hda_codec_amp_stereo(codec, conn[i], + HDA_OUTPUT, 0, + 0xff, HDA_AMP_MUTE); + } +} + +/* + * Parse the given BIOS configuration and set up the hda_gen_spec + * + * return 1 if successful, 0 if the proper config is not found, + * or a negative error code + */ +int snd_hda_gen_parse_auto_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg) +{ + struct hda_gen_spec *spec = codec->spec; + int err; + + parse_user_hints(codec); + + if (spec->mixer_nid && !spec->mixer_merge_nid) + spec->mixer_merge_nid = spec->mixer_nid; + + if (cfg != &spec->autocfg) { + spec->autocfg = *cfg; + cfg = &spec->autocfg; + } + + if (!spec->main_out_badness) + spec->main_out_badness = &hda_main_out_badness; + if (!spec->extra_out_badness) + spec->extra_out_badness = &hda_extra_out_badness; + + fill_all_dac_nids(codec); + + if (!cfg->line_outs) { + if (cfg->dig_outs || cfg->dig_in_pin) { + spec->multiout.max_channels = 2; + spec->no_analog = 1; + goto dig_only; + } + if (!cfg->num_inputs && !cfg->dig_in_pin) + return 0; /* can't find valid BIOS pin config */ + } + + if (!spec->no_primary_hp && + cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && + cfg->line_outs <= cfg->hp_outs) { + /* use HP as primary out */ + cfg->speaker_outs = cfg->line_outs; + memcpy(cfg->speaker_pins, cfg->line_out_pins, + sizeof(cfg->speaker_pins)); + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + } + + err = parse_output_paths(codec); + if (err < 0) + return err; + err = create_multi_channel_mode(codec); + if (err < 0) + return err; + err = create_multi_out_ctls(codec, cfg); + if (err < 0) + return err; + err = create_hp_out_ctls(codec); + if (err < 0) + return err; + err = create_speaker_out_ctls(codec); + if (err < 0) + return err; + err = create_indep_hp_ctls(codec); + if (err < 0) + return err; + err = create_loopback_mixing_ctl(codec); + if (err < 0) + return err; + err = create_hp_mic(codec); + if (err < 0) + return err; + err = create_input_ctls(codec); + if (err < 0) + return err; + + spec->const_channel_count = spec->ext_channel_count; + /* check the multiple speaker and headphone pins */ + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) + spec->const_channel_count = max(spec->const_channel_count, + cfg->speaker_outs * 2); + if (cfg->line_out_type != AUTO_PIN_HP_OUT) + spec->const_channel_count = max(spec->const_channel_count, + cfg->hp_outs * 2); + spec->multiout.max_channels = max(spec->ext_channel_count, + spec->const_channel_count); + + err = check_auto_mute_availability(codec); + if (err < 0) + return err; + + err = check_dyn_adc_switch(codec); + if (err < 0) + return err; + + err = check_auto_mic_availability(codec); + if (err < 0) + return err; + + /* add stereo mix if available and not enabled yet */ + if (!spec->auto_mic && spec->mixer_nid && + spec->add_stereo_mix_input && + spec->input_mux.num_items > 1 && + snd_hda_get_bool_hint(codec, "add_stereo_mix_input") < 0) { + err = parse_capture_source(codec, spec->mixer_nid, + CFG_IDX_MIX, spec->num_all_adcs, + "Stereo Mix", 0); + if (err < 0) + return err; + } + + + err = create_capture_mixers(codec); + if (err < 0) + return err; + + err = parse_mic_boost(codec); + if (err < 0) + return err; + + /* create "Headphone Mic Jack Mode" if no input selection is + * available (or user specifies add_jack_modes hint) + */ + if (spec->hp_mic_pin && + (spec->auto_mic || spec->input_mux.num_items == 1 || + spec->add_jack_modes)) { + err = create_hp_mic_jack_mode(codec, spec->hp_mic_pin); + if (err < 0) + return err; + } + + if (spec->add_jack_modes) { + if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { + err = create_out_jack_modes(codec, cfg->line_outs, + cfg->line_out_pins); + if (err < 0) + return err; + } + if (cfg->line_out_type != AUTO_PIN_HP_OUT) { + err = create_out_jack_modes(codec, cfg->hp_outs, + cfg->hp_pins); if (err < 0) return err; - if (! err) - continue; } } - return 0; + + /* mute all aamix input initially */ + if (spec->mixer_nid) + mute_all_mixer_nid(codec, spec->mixer_nid); + + dig_only: + parse_digital(codec); + + if (spec->power_down_unused) + codec->power_filter = snd_hda_gen_path_power_filter; + + if (!spec->no_analog && spec->beep_nid) { + err = snd_hda_attach_beep_device(codec, spec->beep_nid); + if (err < 0) + return err; + } + + return 1; } +EXPORT_SYMBOL_GPL(snd_hda_gen_parse_auto_config); + /* - * build mixer controls + * Build control elements */ -static int build_generic_controls(struct hda_codec *codec) + +/* slave controls for virtual master */ +static const char * const slave_pfxs[] = { + "Front", "Surround", "Center", "LFE", "Side", + "Headphone", "Speaker", "Mono", "Line Out", + "CLFE", "Bass Speaker", "PCM", + "Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side", + "Headphone Front", "Headphone Surround", "Headphone CLFE", + "Headphone Side", + NULL, +}; + +int snd_hda_gen_build_controls(struct hda_codec *codec) { + struct hda_gen_spec *spec = codec->spec; int err; - if ((err = build_input_controls(codec)) < 0 || - (err = build_output_controls(codec)) < 0 || - (err = build_loopback_controls(codec)) < 0) + if (spec->kctls.used) { + err = snd_hda_add_new_ctls(codec, spec->kctls.list); + if (err < 0) + return err; + } + + if (spec->multiout.dig_out_nid) { + err = snd_hda_create_dig_out_ctls(codec, + spec->multiout.dig_out_nid, + spec->multiout.dig_out_nid, + spec->pcm_rec[1].pcm_type); + if (err < 0) + return err; + if (!spec->no_analog) { + err = snd_hda_create_spdif_share_sw(codec, + &spec->multiout); + if (err < 0) + return err; + spec->multiout.share_spdif = 1; + } + } + if (spec->dig_in_nid) { + err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); + if (err < 0) + return err; + } + + /* if we have no master control, let's create it */ + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { + err = snd_hda_add_vmaster(codec, "Master Playback Volume", + spec->vmaster_tlv, slave_pfxs, + "Playback Volume"); + if (err < 0) + return err; + } + if (!spec->no_analog && + !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { + err = __snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch", + true, &spec->vmaster_mute.sw_kctl); + if (err < 0) + return err; + if (spec->vmaster_mute.hook) { + snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, + spec->vmaster_mute_enum); + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + } + } + + free_kctls(spec); /* no longer needed */ + + err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + if (err < 0) return err; return 0; } +EXPORT_SYMBOL_GPL(snd_hda_gen_build_controls); + /* - * PCM + * PCM definitions */ -static struct hda_pcm_stream generic_pcm_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; -static int generic_pcm2_prepare(struct hda_pcm_stream *hinfo, +static void call_pcm_playback_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->pcm_playback_hook) + spec->pcm_playback_hook(hinfo, codec, substream, action); +} + +static void call_pcm_capture_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct hda_gen_spec *spec = codec->spec; + if (spec->pcm_capture_hook) + spec->pcm_capture_hook(hinfo, codec, substream, action); +} + +/* + * Analog playback callbacks + */ +static int playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + int err; + + mutex_lock(&spec->pcm_mutex); + err = snd_hda_multi_out_analog_open(codec, + &spec->multiout, substream, + hinfo); + if (!err) { + spec->active_streams |= 1 << STREAM_MULTI_OUT; + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_OPEN); + } + mutex_unlock(&spec->pcm_mutex); + return err; +} + +static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream) { - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + int err; - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); - snd_hda_codec_setup_stream(codec, spec->dac_node[1]->nid, - stream_tag, 0, format); - return 0; + err = snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); + if (!err) + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return err; } -static int generic_pcm2_cleanup(struct hda_pcm_stream *hinfo, +static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; + int err; + err = snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + if (!err) + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return err; +} + +static int playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + mutex_lock(&spec->pcm_mutex); + spec->active_streams &= ~(1 << STREAM_MULTI_OUT); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLOSE); + mutex_unlock(&spec->pcm_mutex); + return 0; +} + +static int capture_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_OPEN); + return 0; +} + +static int capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} + +static int capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ snd_hda_codec_cleanup_stream(codec, hinfo->nid); - snd_hda_codec_cleanup_stream(codec, spec->dac_node[1]->nid); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); return 0; } -static int build_generic_pcms(struct hda_codec *codec) +static int capture_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { - struct hda_gspec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + call_pcm_capture_hook(hinfo, codec, substream, HDA_GEN_PCM_ACT_CLOSE); + return 0; +} - if (! spec->dac_node[0] && ! spec->adc_node) { - snd_printd("hda_generic: no PCM found\n"); - return 0; +static int alt_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + int err = 0; + + mutex_lock(&spec->pcm_mutex); + if (!spec->indep_hp_enabled) + err = -EBUSY; + else + spec->active_streams |= 1 << STREAM_INDEP_HP; + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_OPEN); + mutex_unlock(&spec->pcm_mutex); + return err; +} + +static int alt_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + mutex_lock(&spec->pcm_mutex); + spec->active_streams &= ~(1 << STREAM_INDEP_HP); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLOSE); + mutex_unlock(&spec->pcm_mutex); + return 0; +} + +static int alt_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} + +static int alt_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + call_pcm_playback_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return 0; +} + +/* + * Digital out + */ +static int dig_playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_open(codec, &spec->multiout); +} + +static int dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); +} + +static int dig_playback_pcm_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_dig_close(codec, &spec->multiout); +} + +/* + * Analog capture + */ +#define alt_capture_pcm_open capture_pcm_open +#define alt_capture_pcm_close capture_pcm_close + +static int alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + + snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], + stream_tag, 0, format); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_PREPARE); + return 0; +} + +static int alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + + snd_hda_codec_cleanup_stream(codec, + spec->adc_nids[substream->number + 1]); + call_pcm_capture_hook(hinfo, codec, substream, + HDA_GEN_PCM_ACT_CLEANUP); + return 0; +} + +/* + */ +static const struct hda_pcm_stream pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 8, + /* NID is set in build_pcms */ + .ops = { + .open = playback_pcm_open, + .close = playback_pcm_close, + .prepare = playback_pcm_prepare, + .cleanup = playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = capture_pcm_open, + .close = capture_pcm_close, + .prepare = capture_pcm_prepare, + .cleanup = capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_alt_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = alt_playback_pcm_open, + .close = alt_playback_pcm_close, + .prepare = alt_playback_pcm_prepare, + .cleanup = alt_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_analog_alt_capture = { + .substreams = 2, /* can be overridden */ + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = alt_capture_pcm_open, + .close = alt_capture_pcm_close, + .prepare = alt_capture_pcm_prepare, + .cleanup = alt_capture_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ + .ops = { + .open = dig_playback_pcm_open, + .close = dig_playback_pcm_close, + .prepare = dig_playback_pcm_prepare, + .cleanup = dig_playback_pcm_cleanup + }, +}; + +static const struct hda_pcm_stream pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + /* NID is set in build_pcms */ +}; + +/* Used by build_pcms to flag that a PCM has no playback stream */ +static const struct hda_pcm_stream pcm_null_stream = { + .substreams = 0, + .channels_min = 0, + .channels_max = 0, +}; + +/* + * dynamic changing ADC PCM streams + */ +static bool dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) +{ + struct hda_gen_spec *spec = codec->spec; + hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; + + if (spec->cur_adc && spec->cur_adc != new_adc) { + /* stream is running, let's swap the current ADC */ + __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); + spec->cur_adc = new_adc; + snd_hda_codec_setup_stream(codec, new_adc, + spec->cur_adc_stream_tag, 0, + spec->cur_adc_format); + return true; } + return false; +} + +/* analog capture with dynamic dual-adc changes */ +static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; + spec->cur_adc_stream_tag = stream_tag; + spec->cur_adc_format = format; + snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); + return 0; +} + +static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + snd_hda_codec_cleanup_stream(codec, spec->cur_adc); + spec->cur_adc = 0; + return 0; +} + +static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .nid = 0, /* fill later */ + .ops = { + .prepare = dyn_adc_capture_pcm_prepare, + .cleanup = dyn_adc_capture_pcm_cleanup + }, +}; + +static void fill_pcm_stream_name(char *str, size_t len, const char *sfx, + const char *chip_name) +{ + char *p; + + if (*str) + return; + strlcpy(str, chip_name, len); + + /* drop non-alnum chars after a space */ + for (p = strchr(str, ' '); p; p = strchr(p + 1, ' ')) { + if (!isalnum(p[1])) { + *p = 0; + break; + } + } + strlcat(str, sfx, len); +} + +/* build PCM streams based on the parsed results */ +int snd_hda_gen_build_pcms(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + const struct hda_pcm_stream *p; + bool have_multi_adcs; codec->num_pcms = 1; codec->pcm_info = info; - info->name = "HDA Generic"; - if (spec->dac_node[0]) { - info->stream[0] = generic_pcm_playback; - info->stream[0].nid = spec->dac_node[0]->nid; - if (spec->dac_node[1]) { - info->stream[0].ops.prepare = generic_pcm2_prepare; - info->stream[0].ops.cleanup = generic_pcm2_cleanup; + if (spec->no_analog) + goto skip_analog; + + fill_pcm_stream_name(spec->stream_name_analog, + sizeof(spec->stream_name_analog), + " Analog", codec->chip_name); + info->name = spec->stream_name_analog; + + if (spec->multiout.num_dacs > 0) { + p = spec->stream_analog_playback; + if (!p) + p = &pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && + spec->autocfg.line_outs == 2) + info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap = + snd_pcm_2_1_chmaps; + } + if (spec->num_adc_nids) { + p = spec->stream_analog_capture; + if (!p) { + if (spec->dyn_adc_switch) + p = &dyn_adc_pcm_analog_capture; + else + p = &pcm_analog_capture; } + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; } - if (spec->adc_node) { - info->stream[1] = generic_pcm_playback; - info->stream[1].nid = spec->adc_node->nid; + + skip_analog: + /* SPDIF for stream index #1 */ + if (spec->multiout.dig_out_nid || spec->dig_in_nid) { + fill_pcm_stream_name(spec->stream_name_digital, + sizeof(spec->stream_name_digital), + " Digital", codec->chip_name); + codec->num_pcms = 2; + codec->slave_dig_outs = spec->multiout.slave_dig_outs; + info = spec->pcm_rec + 1; + info->name = spec->stream_name_digital; + if (spec->dig_out_type) + info->pcm_type = spec->dig_out_type; + else + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->multiout.dig_out_nid) { + p = spec->stream_digital_playback; + if (!p) + p = &pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; + } + if (spec->dig_in_nid) { + p = spec->stream_digital_capture; + if (!p) + p = &pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; + } } + if (spec->no_analog) + return 0; + + /* If the use of more than one ADC is requested for the current + * model, configure a second analog capture-only PCM. + */ + have_multi_adcs = (spec->num_adc_nids > 1) && + !spec->dyn_adc_switch && !spec->auto_mic; + /* Additional Analaog capture for index #2 */ + if (spec->alt_dac_nid || have_multi_adcs) { + fill_pcm_stream_name(spec->stream_name_alt_analog, + sizeof(spec->stream_name_alt_analog), + " Alt Analog", codec->chip_name); + codec->num_pcms = 3; + info = spec->pcm_rec + 2; + info->name = spec->stream_name_alt_analog; + if (spec->alt_dac_nid) { + p = spec->stream_analog_alt_playback; + if (!p) + p = &pcm_analog_alt_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->alt_dac_nid; + } else { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; + } + if (have_multi_adcs) { + p = spec->stream_analog_alt_capture; + if (!p) + p = &pcm_analog_alt_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = + spec->adc_nids[1]; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = + spec->num_adc_nids - 1; + } else { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + pcm_null_stream; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; + } + } + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_build_pcms); + + +/* + * Standard auto-parser initializations + */ + +/* configure the given path as a proper output */ +static void set_output_and_unmute(struct hda_codec *codec, int path_idx) +{ + struct nid_path *path; + hda_nid_t pin; + + path = snd_hda_get_path_from_idx(codec, path_idx); + if (!path || !path->depth) + return; + pin = path->path[path->depth - 1]; + restore_pin_ctl(codec, pin); + snd_hda_activate_path(codec, path, path->active, + aamix_default(codec->spec)); + set_pin_eapd(codec, pin, path->active); +} + +/* initialize primary output paths */ +static void init_multi_out(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->autocfg.line_outs; i++) + set_output_and_unmute(codec, spec->out_paths[i]); +} + + +static void __init_extra_out(struct hda_codec *codec, int num_outs, int *paths) +{ + int i; + + for (i = 0; i < num_outs; i++) + set_output_and_unmute(codec, paths[i]); +} + +/* initialize hp and speaker paths */ +static void init_extra_out(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->autocfg.line_out_type != AUTO_PIN_HP_OUT) + __init_extra_out(codec, spec->autocfg.hp_outs, spec->hp_paths); + if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT) + __init_extra_out(codec, spec->autocfg.speaker_outs, + spec->speaker_paths); +} + +/* initialize multi-io paths */ +static void init_multi_io(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->multi_ios; i++) { + hda_nid_t pin = spec->multi_io[i].pin; + struct nid_path *path; + path = get_multiio_path(codec, i); + if (!path) + continue; + if (!spec->multi_io[i].ctl_in) + spec->multi_io[i].ctl_in = + snd_hda_codec_get_pin_target(codec, pin); + snd_hda_activate_path(codec, path, path->active, + aamix_default(spec)); + } +} + +static void init_aamix_paths(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (!spec->have_aamix_ctl) + return; + update_aamix_paths(codec, spec->aamix_mode, spec->out_paths[0], + spec->aamix_out_paths[0], + spec->autocfg.line_out_type); + update_aamix_paths(codec, spec->aamix_mode, spec->hp_paths[0], + spec->aamix_out_paths[1], + AUTO_PIN_HP_OUT); + update_aamix_paths(codec, spec->aamix_mode, spec->speaker_paths[0], + spec->aamix_out_paths[2], + AUTO_PIN_SPEAKER_OUT); +} + +/* set up input pins and loopback paths */ +static void init_analog_input(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + if (is_input_pin(codec, nid)) + restore_pin_ctl(codec, nid); + + /* init loopback inputs */ + if (spec->mixer_nid) { + resume_path_from_idx(codec, spec->loopback_paths[i]); + resume_path_from_idx(codec, spec->loopback_merge_path); + } + } +} + +/* initialize ADC paths */ +static void init_input_src(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + struct hda_input_mux *imux = &spec->input_mux; + struct nid_path *path; + int i, c, nums; + + if (spec->dyn_adc_switch) + nums = 1; + else + nums = spec->num_adc_nids; + + for (c = 0; c < nums; c++) { + for (i = 0; i < imux->num_items; i++) { + path = get_input_path(codec, c, i); + if (path) { + bool active = path->active; + if (i == spec->cur_mux[c]) + active = true; + snd_hda_activate_path(codec, path, active, false); + } + } + if (spec->hp_mic) + update_hp_mic(codec, c, true); + } + + if (spec->cap_sync_hook) + spec->cap_sync_hook(codec, NULL, NULL); +} + +/* set right pin controls for digital I/O */ +static void init_digital(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + int i; + hda_nid_t pin; + + for (i = 0; i < spec->autocfg.dig_outs; i++) + set_output_and_unmute(codec, spec->digout_paths[i]); + pin = spec->autocfg.dig_in_pin; + if (pin) { + restore_pin_ctl(codec, pin); + resume_path_from_idx(codec, spec->digin_path); + } +} + +/* clear unsol-event tags on unused pins; Conexant codecs seem to leave + * invalid unsol tags by some reason + */ +static void clear_unsol_on_unused_pins(struct hda_codec *codec) +{ + int i; + + for (i = 0; i < codec->init_pins.used; i++) { + struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); + hda_nid_t nid = pin->nid; + if (is_jack_detectable(codec, nid) && + !snd_hda_jack_tbl_get(codec, nid)) + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_UNSOLICITED_ENABLE, 0); + } +} + +/* + * initialize the generic spec; + * this can be put as patch_ops.init function + */ +int snd_hda_gen_init(struct hda_codec *codec) +{ + struct hda_gen_spec *spec = codec->spec; + + if (spec->init_hook) + spec->init_hook(codec); + + snd_hda_apply_verbs(codec); + + codec->cached_write = 1; + + init_multi_out(codec); + init_extra_out(codec); + init_multi_io(codec); + init_aamix_paths(codec); + init_analog_input(codec); + init_input_src(codec); + init_digital(codec); + + clear_unsol_on_unused_pins(codec); + + /* call init functions of standard auto-mute helpers */ + update_automute_all(codec); + + snd_hda_codec_flush_cache(codec); + + if (spec->vmaster_mute.sw_kctl && spec->vmaster_mute.hook) + snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + + hda_call_check_power_status(codec, 0x01); return 0; } +EXPORT_SYMBOL_GPL(snd_hda_gen_init); + +/* + * free the generic spec; + * this can be put as patch_ops.free function + */ +void snd_hda_gen_free(struct hda_codec *codec) +{ + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_FREE); + snd_hda_gen_spec_free(codec->spec); + kfree(codec->spec); + codec->spec = NULL; +} +EXPORT_SYMBOL_GPL(snd_hda_gen_free); #ifdef CONFIG_PM -static int generic_check_power_status(struct hda_codec *codec, hda_nid_t nid) +/* + * check the loopback power save state; + * this can be put as patch_ops.check_power_status function + */ +int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid) { - struct hda_gspec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); } +EXPORT_SYMBOL_GPL(snd_hda_gen_check_power_status); #endif /* + * the generic codec support */ -static struct hda_codec_ops generic_patch_ops = { - .build_controls = build_generic_controls, - .build_pcms = build_generic_pcms, - .free = snd_hda_generic_free, + +static const struct hda_codec_ops generic_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM - .check_power_status = generic_check_power_status, + .check_power_status = snd_hda_gen_check_power_status, #endif }; -/* - * the generic parser - */ int snd_hda_parse_generic_codec(struct hda_codec *codec) { - struct hda_gspec *spec; + struct hda_gen_spec *spec; int err; - if(!codec->afg) - return 0; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) { - printk(KERN_ERR "hda_generic: can't allocate spec\n"); + if (!spec) return -ENOMEM; - } + snd_hda_gen_spec_init(spec); codec->spec = spec; - INIT_LIST_HEAD(&spec->nid_list); - if ((err = build_afg_tree(codec)) < 0) - goto error; + err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); + if (err < 0) + return err; - if ((err = parse_input(codec)) < 0 || - (err = parse_output(codec)) < 0) + err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); + if (err < 0) goto error; codec->patch_ops = generic_patch_ops; - return 0; - error: - snd_hda_generic_free(codec); +error: + snd_hda_gen_free(codec); return err; } -EXPORT_SYMBOL(snd_hda_parse_generic_codec); +EXPORT_SYMBOL_GPL(snd_hda_parse_generic_codec); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic HD-audio codec parser"); diff --git a/sound/pci/hda/hda_generic.h b/sound/pci/hda/hda_generic.h new file mode 100644 index 00000000000..bb2dea74398 --- /dev/null +++ b/sound/pci/hda/hda_generic.h @@ -0,0 +1,342 @@ +/* + * Generic BIOS auto-parser helper functions for HD-audio + * + * Copyright (c) 2012 Takashi Iwai <tiwai@suse.de> + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef __SOUND_HDA_GENERIC_H +#define __SOUND_HDA_GENERIC_H + +/* unsol event tags */ +enum { + HDA_GEN_HP_EVENT = 1, HDA_GEN_FRONT_EVENT, HDA_GEN_MIC_EVENT, + HDA_GEN_LAST_EVENT = HDA_GEN_MIC_EVENT +}; + +/* table entry for multi-io paths */ +struct hda_multi_io { + hda_nid_t pin; /* multi-io widget pin NID */ + hda_nid_t dac; /* DAC to be connected */ + unsigned int ctl_in; /* cached input-pin control value */ +}; + +/* Widget connection path + * + * For output, stored in the order of DAC -> ... -> pin, + * for input, pin -> ... -> ADC. + * + * idx[i] contains the source index number to select on of the widget path[i]; + * e.g. idx[1] is the index of the DAC (path[0]) selected by path[1] widget + * multi[] indicates whether it's a selector widget with multi-connectors + * (i.e. the connection selection is mandatory) + * vol_ctl and mute_ctl contains the NIDs for the assigned mixers + */ + +#define MAX_NID_PATH_DEPTH 10 + +enum { + NID_PATH_VOL_CTL, + NID_PATH_MUTE_CTL, + NID_PATH_BOOST_CTL, + NID_PATH_NUM_CTLS +}; + +struct nid_path { + int depth; + hda_nid_t path[MAX_NID_PATH_DEPTH]; + unsigned char idx[MAX_NID_PATH_DEPTH]; + unsigned char multi[MAX_NID_PATH_DEPTH]; + unsigned int ctls[NID_PATH_NUM_CTLS]; /* NID_PATH_XXX_CTL */ + bool active; +}; + +/* mic/line-in auto switching entry */ + +#define MAX_AUTO_MIC_PINS 3 + +struct automic_entry { + hda_nid_t pin; /* pin */ + int idx; /* imux index, -1 = invalid */ + unsigned int attr; /* pin attribute (INPUT_PIN_ATTR_*) */ +}; + +/* active stream id */ +enum { STREAM_MULTI_OUT, STREAM_INDEP_HP }; + +/* PCM hook action */ +enum { + HDA_GEN_PCM_ACT_OPEN, + HDA_GEN_PCM_ACT_PREPARE, + HDA_GEN_PCM_ACT_CLEANUP, + HDA_GEN_PCM_ACT_CLOSE, +}; + +/* DAC assignment badness table */ +struct badness_table { + int no_primary_dac; /* no primary DAC */ + int no_dac; /* no secondary DACs */ + int shared_primary; /* primary DAC is shared with main output */ + int shared_surr; /* secondary DAC shared with main or primary */ + int shared_clfe; /* third DAC shared with main or primary */ + int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ +}; + +extern const struct badness_table hda_main_out_badness; +extern const struct badness_table hda_extra_out_badness; + +struct hda_gen_spec { + char stream_name_analog[32]; /* analog PCM stream */ + const struct hda_pcm_stream *stream_analog_playback; + const struct hda_pcm_stream *stream_analog_capture; + + char stream_name_alt_analog[32]; /* alternative analog PCM stream */ + const struct hda_pcm_stream *stream_analog_alt_playback; + const struct hda_pcm_stream *stream_analog_alt_capture; + + char stream_name_digital[32]; /* digital PCM stream */ + const struct hda_pcm_stream *stream_digital_playback; + const struct hda_pcm_stream *stream_digital_capture; + + /* PCM */ + unsigned int active_streams; + struct mutex pcm_mutex; + + /* playback */ + struct hda_multi_out multiout; /* playback set-up + * max_channels, dacs must be set + * dig_out_nid and hp_nid are optional + */ + hda_nid_t alt_dac_nid; + hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */ + int dig_out_type; + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t adc_nids[AUTO_CFG_MAX_INS]; + hda_nid_t dig_in_nid; /* digital-in NID; optional */ + hda_nid_t mixer_nid; /* analog-mixer NID */ + hda_nid_t mixer_merge_nid; /* aamix merge-point NID (optional) */ + const char *input_labels[HDA_MAX_NUM_INPUTS]; + int input_label_idxs[HDA_MAX_NUM_INPUTS]; + + /* capture setup for dynamic dual-adc switch */ + hda_nid_t cur_adc; + unsigned int cur_adc_stream_tag; + unsigned int cur_adc_format; + + /* capture source */ + struct hda_input_mux input_mux; + unsigned int cur_mux[3]; + + /* channel model */ + /* min_channel_count contains the minimum channel count for primary + * outputs. When multi_ios is set, the channels can be configured + * between min_channel_count and (min_channel_count + multi_ios * 2). + * + * ext_channel_count contains the current channel count of the primary + * out. This varies in the range above. + * + * Meanwhile, const_channel_count is the channel count for all outputs + * including headphone and speakers. It's a constant value, and the + * PCM is set up as max(ext_channel_count, const_channel_count). + */ + int min_channel_count; /* min. channel count for primary out */ + int ext_channel_count; /* current channel count for primary */ + int const_channel_count; /* channel count for all */ + + /* PCM information */ + struct hda_pcm pcm_rec[3]; /* used in build_pcms() */ + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + struct snd_array kctls; + hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; + unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; + /* shared hp/mic */ + hda_nid_t shared_mic_vref_pin; + hda_nid_t hp_mic_pin; + int hp_mic_mux_idx; + + /* DAC/ADC lists */ + int num_all_dacs; + hda_nid_t all_dacs[16]; + int num_all_adcs; + hda_nid_t all_adcs[AUTO_CFG_MAX_INS]; + + /* path list */ + struct snd_array paths; + + /* path indices */ + int out_paths[AUTO_CFG_MAX_OUTS]; + int hp_paths[AUTO_CFG_MAX_OUTS]; + int speaker_paths[AUTO_CFG_MAX_OUTS]; + int aamix_out_paths[3]; + int digout_paths[AUTO_CFG_MAX_OUTS]; + int input_paths[HDA_MAX_NUM_INPUTS][AUTO_CFG_MAX_INS]; + int loopback_paths[HDA_MAX_NUM_INPUTS]; + int loopback_merge_path; + int digin_path; + + /* auto-mic stuff */ + int am_num_entries; + struct automic_entry am_entry[MAX_AUTO_MIC_PINS]; + + /* for pin sensing */ + /* current status; set in hda_geneic.c */ + unsigned int hp_jack_present:1; + unsigned int line_jack_present:1; + unsigned int speaker_muted:1; /* current status of speaker mute */ + unsigned int line_out_muted:1; /* current status of LO mute */ + + /* internal states of automute / autoswitch behavior */ + unsigned int auto_mic:1; + unsigned int automute_speaker:1; /* automute speaker outputs */ + unsigned int automute_lo:1; /* automute LO outputs */ + + /* capabilities detected by parser */ + unsigned int detect_hp:1; /* Headphone detection enabled */ + unsigned int detect_lo:1; /* Line-out detection enabled */ + unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ + unsigned int automute_lo_possible:1; /* there are line outs and HP */ + + /* additional parameters set by codec drivers */ + unsigned int master_mute:1; /* master mute over all */ + unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ + unsigned int line_in_auto_switch:1; /* allow line-in auto switch */ + unsigned int auto_mute_via_amp:1; /* auto-mute via amp instead of pinctl */ + + /* parser behavior flags; set before snd_hda_gen_parse_auto_config() */ + unsigned int suppress_auto_mute:1; /* suppress input jack auto mute */ + unsigned int suppress_auto_mic:1; /* suppress input jack auto switch */ + + /* other parse behavior flags */ + unsigned int need_dac_fix:1; /* need to limit DACs for multi channels */ + unsigned int hp_mic:1; /* Allow HP as a mic-in */ + unsigned int suppress_hp_mic_detect:1; /* Don't detect HP/mic */ + unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ + unsigned int no_multi_io:1; /* Don't try multi I/O config */ + unsigned int multi_cap_vol:1; /* allow multiple capture xxx volumes */ + unsigned int inv_dmic_split:1; /* inverted dmic w/a for conexant */ + unsigned int own_eapd_ctl:1; /* set EAPD by own function */ + unsigned int keep_eapd_on:1; /* don't turn off EAPD automatically */ + unsigned int vmaster_mute_enum:1; /* add vmaster mute mode enum */ + unsigned int indep_hp:1; /* independent HP supported */ + unsigned int prefer_hp_amp:1; /* enable HP amp for speaker if any */ + unsigned int add_stereo_mix_input:1; /* add aamix as a capture src */ + unsigned int add_jack_modes:1; /* add i/o jack mode enum ctls */ + unsigned int power_down_unused:1; /* power down unused widgets */ + + /* other internal flags */ + unsigned int no_analog:1; /* digital I/O only */ + unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ + unsigned int indep_hp_enabled:1; /* independent HP enabled */ + unsigned int have_aamix_ctl:1; + unsigned int hp_mic_jack_modes:1; + + /* additional mute flags (only effective with auto_mute_via_amp=1) */ + u64 mute_bits; + + /* bitmask for skipping volume controls */ + u64 out_vol_mask; + + /* badness tables for output path evaluations */ + const struct badness_table *main_out_badness; + const struct badness_table *extra_out_badness; + + /* preferred pin/DAC pairs; an array of paired NIDs */ + const hda_nid_t *preferred_dacs; + + /* loopback mixing mode */ + bool aamix_mode; + + /* digital beep */ + hda_nid_t beep_nid; + + /* for virtual master */ + hda_nid_t vmaster_nid; + unsigned int vmaster_tlv[4]; + struct hda_vmaster_mute_hook vmaster_mute; + + struct hda_loopback_check loopback; + struct snd_array loopback_list; + + /* multi-io */ + int multi_ios; + struct hda_multi_io multi_io[4]; + + /* hooks */ + void (*init_hook)(struct hda_codec *codec); + void (*automute_hook)(struct hda_codec *codec); + void (*cap_sync_hook)(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + + /* PCM hooks */ + void (*pcm_playback_hook)(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); + void (*pcm_capture_hook)(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); + + /* automute / autoswitch hooks */ + void (*hp_automute_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); + void (*line_automute_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); + void (*mic_autoswitch_hook)(struct hda_codec *codec, + struct hda_jack_tbl *tbl); +}; + +int snd_hda_gen_spec_init(struct hda_gen_spec *spec); + +int snd_hda_gen_init(struct hda_codec *codec); +void snd_hda_gen_free(struct hda_codec *codec); + +struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec, + hda_nid_t from_nid, hda_nid_t to_nid); +int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path); +struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx); +bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid, + struct nid_path *path); +struct nid_path * +snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid, + hda_nid_t to_nid, int anchor_nid); +void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path, + bool enable, bool add_aamix); + +struct snd_kcontrol_new * +snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name, + const struct snd_kcontrol_new *temp); + +int snd_hda_gen_parse_auto_config(struct hda_codec *codec, + struct auto_pin_cfg *cfg); +int snd_hda_gen_build_controls(struct hda_codec *codec); +int snd_hda_gen_build_pcms(struct hda_codec *codec); + +/* standard jack event callbacks */ +void snd_hda_gen_hp_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_line_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_tbl *jack); +void snd_hda_gen_update_outputs(struct hda_codec *codec); + +#ifdef CONFIG_PM +int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid); +#endif +unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state); + +#endif /* __SOUND_HDA_GENERIC_H */ diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 1af86d40eb2..014a7849e8f 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -20,24 +20,13 @@ #include <linux/init.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/compat.h> -#include <linux/mutex.h> -#include <linux/ctype.h> -#include <linux/string.h> -#include <linux/export.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" #include <sound/hda_hwdep.h> #include <sound/minors.h> -/* hint string pair */ -struct hda_hint { - const char *key; - const char *val; /* contained in the same alloc as key */ -}; - /* * write/read an out-of-bound verb */ @@ -105,27 +94,7 @@ static int hda_hwdep_open(struct snd_hwdep *hw, struct file *file) return 0; } -static void clear_hwdep_elements(struct hda_codec *codec) -{ - int i; - - /* clear init verbs */ - snd_array_free(&codec->init_verbs); - /* clear hints */ - for (i = 0; i < codec->hints.used; i++) { - struct hda_hint *hint = snd_array_elem(&codec->hints, i); - kfree(hint->key); /* we don't need to free hint->val */ - } - snd_array_free(&codec->hints); - snd_array_free(&codec->user_pins); -} - -static void hwdep_free(struct snd_hwdep *hwdep) -{ - clear_hwdep_elements(hwdep->private_data); -} - -int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) +int snd_hda_create_hwdep(struct hda_codec *codec) { char hwname[16]; struct snd_hwdep *hwdep; @@ -139,8 +108,8 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) sprintf(hwdep->name, "HDA Codec %d", codec->addr); hwdep->iface = SNDRV_HWDEP_IFACE_HDA; hwdep->private_data = codec; - hwdep->private_free = hwdep_free; hwdep->exclusive = 1; + hwdep->groups = snd_hda_dev_attr_groups; hwdep->ops.open = hda_hwdep_open; hwdep->ops.ioctl = hda_hwdep_ioctl; @@ -148,657 +117,8 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) hwdep->ops.ioctl_compat = hda_hwdep_ioctl_compat; #endif - snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); - snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); - snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); - - return 0; -} - -#ifdef CONFIG_PM -static ssize_t power_on_acct_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - snd_hda_update_power_acct(codec); - return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); -} - -static ssize_t power_off_acct_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - snd_hda_update_power_acct(codec); - return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); -} - -static struct device_attribute power_attrs[] = { - __ATTR_RO(power_on_acct), - __ATTR_RO(power_off_acct), -}; - -int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) -{ - struct snd_hwdep *hwdep = codec->hwdep; - int i; - - for (i = 0; i < ARRAY_SIZE(power_attrs); i++) - snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, - hwdep->device, &power_attrs[i]); - return 0; -} -#endif /* CONFIG_PM */ - -#ifdef CONFIG_SND_HDA_RECONFIG - -/* - * sysfs interface - */ - -static int clear_codec(struct hda_codec *codec) -{ - int err; - - err = snd_hda_codec_reset(codec); - if (err < 0) { - snd_printk(KERN_ERR "The codec is being used, can't free.\n"); - return err; - } - clear_hwdep_elements(codec); - return 0; -} - -static int reconfig_codec(struct hda_codec *codec) -{ - int err; - - snd_hda_power_up(codec); - snd_printk(KERN_INFO "hda-codec: reconfiguring\n"); - err = snd_hda_codec_reset(codec); - if (err < 0) { - snd_printk(KERN_ERR - "The codec is being used, can't reconfigure.\n"); - goto error; - } - err = snd_hda_codec_configure(codec); - if (err < 0) - goto error; - /* rebuild PCMs */ - err = snd_hda_codec_build_pcms(codec); - if (err < 0) - goto error; - /* rebuild mixers */ - err = snd_hda_codec_build_controls(codec); - if (err < 0) - goto error; - err = snd_card_register(codec->bus->card); - error: - snd_hda_power_down(codec); - return err; -} - -/* - * allocate a string at most len chars, and remove the trailing EOL - */ -static char *kstrndup_noeol(const char *src, size_t len) -{ - char *s = kstrndup(src, len, GFP_KERNEL); - char *p; - if (!s) - return NULL; - p = strchr(s, '\n'); - if (p) - *p = 0; - return s; -} - -#define CODEC_INFO_SHOW(type) \ -static ssize_t type##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - return sprintf(buf, "0x%x\n", codec->type); \ -} - -#define CODEC_INFO_STR_SHOW(type) \ -static ssize_t type##_show(struct device *dev, \ - struct device_attribute *attr, \ - char *buf) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - return sprintf(buf, "%s\n", \ - codec->type ? codec->type : ""); \ -} - -CODEC_INFO_SHOW(vendor_id); -CODEC_INFO_SHOW(subsystem_id); -CODEC_INFO_SHOW(revision_id); -CODEC_INFO_SHOW(afg); -CODEC_INFO_SHOW(mfg); -CODEC_INFO_STR_SHOW(vendor_name); -CODEC_INFO_STR_SHOW(chip_name); -CODEC_INFO_STR_SHOW(modelname); - -#define CODEC_INFO_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - unsigned long val; \ - int err = strict_strtoul(buf, 0, &val); \ - if (err < 0) \ - return err; \ - codec->type = val; \ - return count; \ -} - -#define CODEC_INFO_STR_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - char *s = kstrndup_noeol(buf, 64); \ - if (!s) \ - return -ENOMEM; \ - kfree(codec->type); \ - codec->type = s; \ - return count; \ -} - -CODEC_INFO_STORE(vendor_id); -CODEC_INFO_STORE(subsystem_id); -CODEC_INFO_STORE(revision_id); -CODEC_INFO_STR_STORE(vendor_name); -CODEC_INFO_STR_STORE(chip_name); -CODEC_INFO_STR_STORE(modelname); - -#define CODEC_ACTION_STORE(type) \ -static ssize_t type##_store(struct device *dev, \ - struct device_attribute *attr, \ - const char *buf, size_t count) \ -{ \ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ - struct hda_codec *codec = hwdep->private_data; \ - int err = 0; \ - if (*buf) \ - err = type##_codec(codec); \ - return err < 0 ? err : count; \ -} - -CODEC_ACTION_STORE(reconfig); -CODEC_ACTION_STORE(clear); - -static ssize_t init_verbs_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - int i, len = 0; - for (i = 0; i < codec->init_verbs.used; i++) { - struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); - len += snprintf(buf + len, PAGE_SIZE - len, - "0x%02x 0x%03x 0x%04x\n", - v->nid, v->verb, v->param); - } - return len; -} - -static int parse_init_verbs(struct hda_codec *codec, const char *buf) -{ - struct hda_verb *v; - int nid, 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->nid = nid; - v->verb = verb; - v->param = param; - return 0; -} - -static ssize_t init_verbs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - int err = parse_init_verbs(codec, buf); - if (err < 0) - return err; - return count; -} - -static ssize_t hints_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - int i, len = 0; - for (i = 0; i < codec->hints.used; i++) { - struct hda_hint *hint = snd_array_elem(&codec->hints, i); - len += snprintf(buf + len, PAGE_SIZE - len, - "%s = %s\n", hint->key, hint->val); - } - return len; -} - -static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) -{ - int i; - - for (i = 0; i < codec->hints.used; i++) { - struct hda_hint *hint = snd_array_elem(&codec->hints, i); - if (!strcmp(hint->key, key)) - return hint; - } - return NULL; -} - -static void remove_trail_spaces(char *str) -{ - char *p; - if (!*str) - return; - p = str + strlen(str) - 1; - for (; isspace(*p); p--) { - *p = 0; - if (p == str) - return; - } -} - -#define MAX_HINTS 1024 - -static int parse_hints(struct hda_codec *codec, const char *buf) -{ - char *key, *val; - struct hda_hint *hint; - - buf = skip_spaces(buf); - if (!*buf || *buf == '#' || *buf == '\n') - return 0; - if (*buf == '=') - return -EINVAL; - key = kstrndup_noeol(buf, 1024); - if (!key) - return -ENOMEM; - /* extract key and val */ - val = strchr(key, '='); - if (!val) { - kfree(key); - return -EINVAL; - } - *val++ = 0; - val = skip_spaces(val); - remove_trail_spaces(key); - remove_trail_spaces(val); - hint = get_hint(codec, key); - if (hint) { - /* replace */ - kfree(hint->key); - hint->key = key; - hint->val = val; - return 0; - } - /* allocate a new hint entry */ - if (codec->hints.used >= MAX_HINTS) - hint = NULL; - else - hint = snd_array_new(&codec->hints); - if (!hint) { - kfree(key); - return -ENOMEM; - } - hint->key = key; - hint->val = val; - return 0; -} - -static ssize_t hints_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - int err = parse_hints(codec, buf); - if (err < 0) - return err; - return count; -} - -static ssize_t pin_configs_show(struct hda_codec *codec, - struct snd_array *list, - char *buf) -{ - int i, len = 0; - for (i = 0; i < list->used; i++) { - struct hda_pincfg *pin = snd_array_elem(list, i); - len += sprintf(buf + len, "0x%02x 0x%08x\n", - pin->nid, pin->cfg); - } - return len; -} - -static ssize_t init_pin_configs_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - return pin_configs_show(codec, &codec->init_pins, buf); -} - -static ssize_t user_pin_configs_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - return pin_configs_show(codec, &codec->user_pins, buf); -} - -static ssize_t driver_pin_configs_show(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - return pin_configs_show(codec, &codec->driver_pins, buf); -} - -#define MAX_PIN_CONFIGS 32 - -static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) -{ - int nid, cfg; - - if (sscanf(buf, "%i %i", &nid, &cfg) != 2) - return -EINVAL; - if (!nid) - return -EINVAL; - return snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); -} - -static ssize_t user_pin_configs_store(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct snd_hwdep *hwdep = dev_get_drvdata(dev); - struct hda_codec *codec = hwdep->private_data; - int err = parse_user_pin_configs(codec, buf); - if (err < 0) - return err; - return count; -} - -#define CODEC_ATTR_RW(type) \ - __ATTR(type, 0644, type##_show, type##_store) -#define CODEC_ATTR_RO(type) \ - __ATTR_RO(type) -#define CODEC_ATTR_WO(type) \ - __ATTR(type, 0200, NULL, type##_store) - -static struct device_attribute codec_attrs[] = { - CODEC_ATTR_RW(vendor_id), - CODEC_ATTR_RW(subsystem_id), - CODEC_ATTR_RW(revision_id), - CODEC_ATTR_RO(afg), - CODEC_ATTR_RO(mfg), - CODEC_ATTR_RW(vendor_name), - CODEC_ATTR_RW(chip_name), - CODEC_ATTR_RW(modelname), - CODEC_ATTR_RW(init_verbs), - CODEC_ATTR_RW(hints), - CODEC_ATTR_RO(init_pin_configs), - CODEC_ATTR_RW(user_pin_configs), - CODEC_ATTR_RO(driver_pin_configs), - CODEC_ATTR_WO(reconfig), - CODEC_ATTR_WO(clear), -}; - -/* - * create sysfs files on hwdep directory - */ -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) -{ - struct snd_hwdep *hwdep = codec->hwdep; - int i; - - for (i = 0; i < ARRAY_SIZE(codec_attrs); i++) - snd_add_device_sysfs_file(SNDRV_DEVICE_TYPE_HWDEP, hwdep->card, - hwdep->device, &codec_attrs[i]); - return 0; -} - -/* - * Look for hint string - */ -const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) -{ - struct hda_hint *hint = get_hint(codec, key); - return hint ? hint->val : NULL; -} -EXPORT_SYMBOL_HDA(snd_hda_get_hint); - -int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) -{ - const char *p = snd_hda_get_hint(codec, key); - if (!p || !*p) - return -ENOENT; - switch (toupper(*p)) { - case 'T': /* true */ - case 'Y': /* yes */ - case '1': - return 1; - } - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_get_bool_hint); - -#endif /* CONFIG_SND_HDA_RECONFIG */ - -#ifdef CONFIG_SND_HDA_PATCH_LOADER - -/* parser mode */ -enum { - LINE_MODE_NONE, - LINE_MODE_CODEC, - LINE_MODE_MODEL, - LINE_MODE_PINCFG, - LINE_MODE_VERB, - LINE_MODE_HINT, - LINE_MODE_VENDOR_ID, - LINE_MODE_SUBSYSTEM_ID, - LINE_MODE_REVISION_ID, - LINE_MODE_CHIP_NAME, - NUM_LINE_MODES, -}; + /* link to codec */ + hwdep->dev = &codec->dev; -static inline int strmatch(const char *a, const char *b) -{ - return strnicmp(a, b, strlen(b)) == 0; -} - -/* parse the contents after the line "[codec]" - * accept only the line with three numbers, and assign the current codec - */ -static void parse_codec_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - int vendorid, subid, caddr; - struct hda_codec *codec; - - *codecp = NULL; - if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { - list_for_each_entry(codec, &bus->codec_list, list) { - if ((vendorid <= 0 || codec->vendor_id == vendorid) && - (subid <= 0 || codec->subsystem_id == subid) && - codec->addr == caddr) { - *codecp = codec; - break; - } - } - } -} - -/* parse the contents after the other command tags, [pincfg], [verb], - * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model] - * just pass to the sysfs helper (only when any codec was specified) - */ -static void parse_pincfg_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - parse_user_pin_configs(*codecp, buf); -} - -static void parse_verb_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - parse_init_verbs(*codecp, buf); -} - -static void parse_hint_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - parse_hints(*codecp, buf); -} - -static void parse_model_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - kfree((*codecp)->modelname); - (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); -} - -static void parse_chip_name_mode(char *buf, struct hda_bus *bus, - struct hda_codec **codecp) -{ - kfree((*codecp)->chip_name); - (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL); -} - -#define DEFINE_PARSE_ID_MODE(name) \ -static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ - struct hda_codec **codecp) \ -{ \ - unsigned long val; \ - if (!strict_strtoul(buf, 0, &val)) \ - (*codecp)->name = val; \ -} - -DEFINE_PARSE_ID_MODE(vendor_id); -DEFINE_PARSE_ID_MODE(subsystem_id); -DEFINE_PARSE_ID_MODE(revision_id); - - -struct hda_patch_item { - const char *tag; - void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); - int need_codec; -}; - -static struct hda_patch_item patch_items[NUM_LINE_MODES] = { - [LINE_MODE_CODEC] = { "[codec]", parse_codec_mode, 0 }, - [LINE_MODE_MODEL] = { "[model]", parse_model_mode, 1 }, - [LINE_MODE_VERB] = { "[verb]", parse_verb_mode, 1 }, - [LINE_MODE_PINCFG] = { "[pincfg]", parse_pincfg_mode, 1 }, - [LINE_MODE_HINT] = { "[hint]", parse_hint_mode, 1 }, - [LINE_MODE_VENDOR_ID] = { "[vendor_id]", parse_vendor_id_mode, 1 }, - [LINE_MODE_SUBSYSTEM_ID] = { "[subsystem_id]", parse_subsystem_id_mode, 1 }, - [LINE_MODE_REVISION_ID] = { "[revision_id]", parse_revision_id_mode, 1 }, - [LINE_MODE_CHIP_NAME] = { "[chip_name]", parse_chip_name_mode, 1 }, -}; - -/* check the line starting with '[' -- change the parser mode accodingly */ -static int parse_line_mode(char *buf, struct hda_bus *bus) -{ - int i; - for (i = 0; i < ARRAY_SIZE(patch_items); i++) { - if (!patch_items[i].tag) - continue; - if (strmatch(buf, patch_items[i].tag)) - return i; - } - return LINE_MODE_NONE; -} - -/* copy one line from the buffer in fw, and update the fields in fw - * return zero if it reaches to the end of the buffer, or non-zero - * if successfully copied a line - * - * the spaces at the beginning and the end of the line are stripped - */ -static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, - const void **fw_data_p) -{ - int len; - size_t fw_size = *fw_size_p; - const char *p = *fw_data_p; - - while (isspace(*p) && fw_size) { - p++; - fw_size--; - } - if (!fw_size) - return 0; - - for (len = 0; len < fw_size; len++) { - if (!*p) - break; - if (*p == '\n') { - p++; - len++; - break; - } - if (len < size) - *buf++ = *p++; - } - *buf = 0; - *fw_size_p = fw_size - len; - *fw_data_p = p; - remove_trail_spaces(buf); - return 1; -} - -/* - * load a "patch" firmware file and parse it - */ -int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) -{ - char buf[128]; - struct hda_codec *codec; - int line_mode; - - line_mode = LINE_MODE_NONE; - codec = NULL; - while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) { - if (!*buf || *buf == '#' || *buf == '\n') - continue; - if (*buf == '[') - line_mode = parse_line_mode(buf, bus); - else if (patch_items[line_mode].parser && - (codec || !patch_items[line_mode].need_codec)) - patch_items[line_mode].parser(buf, bus, &codec); - } return 0; } -EXPORT_SYMBOL_HDA(snd_hda_load_patch); -#endif /* CONFIG_SND_HDA_PATCH_LOADER */ diff --git a/sound/pci/hda/hda_i915.c b/sound/pci/hda/hda_i915.c new file mode 100644 index 00000000000..8b4940ba33d --- /dev/null +++ b/sound/pci/hda/hda_i915.c @@ -0,0 +1,130 @@ +/* + * hda_i915.c - routines for Haswell HDA controller power well support + * + * 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 Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <sound/core.h> +#include <drm/i915_powerwell.h> +#include "hda_priv.h" +#include "hda_i915.h" + +/* Intel HSW/BDW display HDA controller Extended Mode registers. + * EM4 (M value) and EM5 (N Value) are used to convert CDClk (Core Display + * Clock) to 24MHz BCLK: BCLK = CDCLK * M / N + * The values will be lost when the display power well is disabled. + */ +#define ICH6_REG_EM4 0x100c +#define ICH6_REG_EM5 0x1010 + +static int (*get_power)(void); +static int (*put_power)(void); +static int (*get_cdclk)(void); + +int hda_display_power(bool enable) +{ + if (!get_power || !put_power) + return -ENODEV; + + pr_debug("HDA display power %s \n", + enable ? "Enable" : "Disable"); + if (enable) + return get_power(); + else + return put_power(); +} + +void haswell_set_bclk(struct azx *chip) +{ + int cdclk_freq; + unsigned int bclk_m, bclk_n; + + if (!get_cdclk) + return; + + cdclk_freq = get_cdclk(); + switch (cdclk_freq) { + case 337500: + bclk_m = 16; + bclk_n = 225; + break; + + case 450000: + default: /* default CDCLK 450MHz */ + bclk_m = 4; + bclk_n = 75; + break; + + case 540000: + bclk_m = 4; + bclk_n = 90; + break; + + case 675000: + bclk_m = 8; + bclk_n = 225; + break; + } + + azx_writew(chip, EM4, bclk_m); + azx_writew(chip, EM5, bclk_n); +} + + +int hda_i915_init(void) +{ + int err = 0; + + get_power = symbol_request(i915_request_power_well); + if (!get_power) { + pr_warn("hda-i915: get_power symbol get fail\n"); + return -ENODEV; + } + + put_power = symbol_request(i915_release_power_well); + if (!put_power) { + symbol_put(i915_request_power_well); + get_power = NULL; + return -ENODEV; + } + + get_cdclk = symbol_request(i915_get_cdclk_freq); + if (!get_cdclk) /* may have abnormal BCLK and audio playback rate */ + pr_warn("hda-i915: get_cdclk symbol get fail\n"); + + pr_debug("HDA driver get symbol successfully from i915 module\n"); + + return err; +} + +int hda_i915_exit(void) +{ + if (get_power) { + symbol_put(i915_request_power_well); + get_power = NULL; + } + if (put_power) { + symbol_put(i915_release_power_well); + put_power = NULL; + } + if (get_cdclk) { + symbol_put(i915_get_cdclk_freq); + get_cdclk = NULL; + } + + return 0; +} diff --git a/sound/pci/hda/hda_i915.h b/sound/pci/hda/hda_i915.h new file mode 100644 index 00000000000..e6072c62758 --- /dev/null +++ b/sound/pci/hda/hda_i915.h @@ -0,0 +1,37 @@ +/* + * 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 Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 + * Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __SOUND_HDA_I915_H +#define __SOUND_HDA_I915_H + +#ifdef CONFIG_SND_HDA_I915 +int hda_display_power(bool enable); +void haswell_set_bclk(struct azx *chip); +int hda_i915_init(void); +int hda_i915_exit(void); +#else +static inline int hda_display_power(bool enable) { return 0; } +static inline void haswell_set_bclk(struct azx *chip) { return; } +static inline int hda_i915_init(void) +{ + return -ENODEV; +} +static inline int hda_i915_exit(void) +{ + return 0; +} +#endif + +#endif diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 72b085ae7d4..83cd19017cf 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -47,6 +47,10 @@ #include <linux/reboot.h> #include <linux/io.h> #include <linux/pm_runtime.h> +#include <linux/clocksource.h> +#include <linux/time.h> +#include <linux/completion.h> + #ifdef CONFIG_X86 /* for snoop control */ #include <asm/pgtable.h> @@ -58,6 +62,9 @@ #include <linux/vga_switcheroo.h> #include <linux/firmware.h> #include "hda_codec.h" +#include "hda_controller.h" +#include "hda_priv.h" +#include "hda_i915.h" static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; @@ -68,6 +75,7 @@ static int position_fix[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int bdl_pos_adj[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_mask[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = -1}; static int probe_only[SNDRV_CARDS]; +static int jackpoll_ms[SNDRV_CARDS]; static bool single_cmd; static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER @@ -95,6 +103,8 @@ module_param_array(probe_mask, int, NULL, 0444); MODULE_PARM_DESC(probe_mask, "Bitmask to probe codecs (default = -1)."); module_param_array(probe_only, int, NULL, 0444); MODULE_PARM_DESC(probe_only, "Only probing and no codec initialization."); +module_param_array(jackpoll_ms, int, NULL, 0444); +MODULE_PARM_DESC(jackpoll_ms, "Ms between polling for jack events (default = 0, using unsol events only)"); module_param(single_cmd, bool, 0444); MODULE_PARM_DESC(single_cmd, "Use single command to communicate with codecs " "(for debugging only)."); @@ -119,6 +129,7 @@ static struct kernel_param_ops param_ops_xint = { #define param_check_xint param_check_int static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +static int *power_save_addr = &power_save; module_param(power_save, xint, 0644); MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " "(in second, 0 = disable)."); @@ -130,6 +141,8 @@ MODULE_PARM_DESC(power_save, "Automatic power-saving timeout " static bool power_save_controller = 1; module_param(power_save_controller, bool, 0644); MODULE_PARM_DESC(power_save_controller, "Reset controller in power save mode."); +#else +static int *power_save_addr; #endif /* CONFIG_PM */ static int align_buffer_size = -1; @@ -141,10 +154,8 @@ MODULE_PARM_DESC(align_buffer_size, static bool hda_snoop = true; module_param_named(snoop, hda_snoop, bool, 0444); MODULE_PARM_DESC(snoop, "Enable/disable snooping"); -#define azx_snoop(chip) (chip)->snoop #else #define hda_snoop true -#define azx_snoop(chip) true #endif @@ -161,6 +172,7 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{Intel, PPT}," "{Intel, LPT}," "{Intel, LPT_LP}," + "{Intel, WPT_LP}," "{Intel, HPT}," "{Intel, PBG}," "{Intel, SCH}," @@ -182,347 +194,22 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," "{ULI, M5461}}"); MODULE_DESCRIPTION("Intel HDA driver"); -#ifdef CONFIG_SND_VERBOSE_PRINTK -#define SFX /* nop */ -#else -#define SFX "hda-intel: " -#endif - #if defined(CONFIG_PM) && defined(CONFIG_VGA_SWITCHEROO) -#ifdef CONFIG_SND_HDA_CODEC_HDMI +#if IS_ENABLED(CONFIG_SND_HDA_CODEC_HDMI) #define SUPPORT_VGA_SWITCHEROO #endif #endif /* - * registers */ -#define ICH6_REG_GCAP 0x00 -#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ -#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ -#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ -#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ -#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ -#define ICH6_REG_VMIN 0x02 -#define ICH6_REG_VMAJ 0x03 -#define ICH6_REG_OUTPAY 0x04 -#define ICH6_REG_INPAY 0x06 -#define ICH6_REG_GCTL 0x08 -#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ -#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ -#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ -#define ICH6_REG_WAKEEN 0x0c -#define ICH6_REG_STATESTS 0x0e -#define ICH6_REG_GSTS 0x10 -#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ -#define ICH6_REG_INTCTL 0x20 -#define ICH6_REG_INTSTS 0x24 -#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ -#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ -#define ICH6_REG_SSYNC 0x38 -#define ICH6_REG_CORBLBASE 0x40 -#define ICH6_REG_CORBUBASE 0x44 -#define ICH6_REG_CORBWP 0x48 -#define ICH6_REG_CORBRP 0x4a -#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ -#define ICH6_REG_CORBCTL 0x4c -#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ -#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ -#define ICH6_REG_CORBSTS 0x4d -#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ -#define ICH6_REG_CORBSIZE 0x4e - -#define ICH6_REG_RIRBLBASE 0x50 -#define ICH6_REG_RIRBUBASE 0x54 -#define ICH6_REG_RIRBWP 0x58 -#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ -#define ICH6_REG_RINTCNT 0x5a -#define ICH6_REG_RIRBCTL 0x5c -#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ -#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ -#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ -#define ICH6_REG_RIRBSTS 0x5d -#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ -#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ -#define ICH6_REG_RIRBSIZE 0x5e - -#define ICH6_REG_IC 0x60 -#define ICH6_REG_IR 0x64 -#define ICH6_REG_IRS 0x68 -#define ICH6_IRS_VALID (1<<1) -#define ICH6_IRS_BUSY (1<<0) - -#define ICH6_REG_DPLBASE 0x70 -#define ICH6_REG_DPUBASE 0x74 -#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ - -/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ -enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; - -/* stream register offsets from stream base */ -#define ICH6_REG_SD_CTL 0x00 -#define ICH6_REG_SD_STS 0x03 -#define ICH6_REG_SD_LPIB 0x04 -#define ICH6_REG_SD_CBL 0x08 -#define ICH6_REG_SD_LVI 0x0c -#define ICH6_REG_SD_FIFOW 0x0e -#define ICH6_REG_SD_FIFOSIZE 0x10 -#define ICH6_REG_SD_FORMAT 0x12 -#define ICH6_REG_SD_BDLPL 0x18 -#define ICH6_REG_SD_BDLPU 0x1c - -/* PCI space */ -#define ICH6_PCIREG_TCSEL 0x44 - -/* - * other constants - */ - -/* max number of SDs */ -/* ICH, ATI and VIA have 4 playback and 4 capture */ -#define ICH6_NUM_CAPTURE 4 -#define ICH6_NUM_PLAYBACK 4 - -/* ULI has 6 playback and 5 capture */ -#define ULI_NUM_CAPTURE 5 -#define ULI_NUM_PLAYBACK 6 - -/* ATI HDMI has 1 playback and 0 capture */ -#define ATIHDMI_NUM_CAPTURE 0 -#define ATIHDMI_NUM_PLAYBACK 1 - -/* TERA has 4 playback and 3 capture */ -#define TERA_NUM_CAPTURE 3 -#define TERA_NUM_PLAYBACK 4 - -/* this number is statically defined for simplicity */ -#define MAX_AZX_DEV 16 - -/* max number of fragments - we may use more if allocating more pages for BDL */ -#define BDL_SIZE 4096 -#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) -#define AZX_MAX_FRAG 32 -/* max buffer size - no h/w limit, you can increase as you like */ -#define AZX_MAX_BUF_SIZE (1024*1024*1024) - -/* RIRB int mask: overrun[2], response[0] */ -#define RIRB_INT_RESPONSE 0x01 -#define RIRB_INT_OVERRUN 0x04 -#define RIRB_INT_MASK 0x05 - -/* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 8 -#define AZX_DEFAULT_CODECS 4 -#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) - -/* SD_CTL bits */ -#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ -#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ -#define SD_CTL_STRIPE (3 << 16) /* stripe control */ -#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ -#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ -#define SD_CTL_STREAM_TAG_MASK (0xf << 20) -#define SD_CTL_STREAM_TAG_SHIFT 20 - -/* SD_CTL and SD_STS */ -#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ -#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ -#define SD_INT_COMPLETE 0x04 /* completion interrupt */ -#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ - SD_INT_COMPLETE) - -/* SD_STS */ -#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ - -/* INTCTL and INTSTS */ -#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ -#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ -#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ - -/* below are so far hardcoded - should read registers in future */ -#define ICH6_MAX_CORB_ENTRIES 256 -#define ICH6_MAX_RIRB_ENTRIES 256 - -/* position fix mode */ -enum { - POS_FIX_AUTO, - POS_FIX_LPIB, - POS_FIX_POSBUF, - POS_FIX_VIACOMBO, - POS_FIX_COMBO, -}; - -/* Defines for ATI HD Audio support in SB450 south bridge */ -#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 -#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 - -/* Defines for Nvidia HDA support */ -#define NVIDIA_HDA_TRANSREG_ADDR 0x4e -#define NVIDIA_HDA_ENABLE_COHBITS 0x0f -#define NVIDIA_HDA_ISTRM_COH 0x4d -#define NVIDIA_HDA_OSTRM_COH 0x4c -#define NVIDIA_HDA_ENABLE_COHBIT 0x01 - -/* Defines for Intel SCH HDA snoop control */ -#define INTEL_SCH_HDA_DEVC 0x78 -#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) - -/* Define IN stream 0 FIFO size offset in VIA controller */ -#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 -/* Define VIA HD Audio Device ID*/ -#define VIA_HDAC_DEVICE_ID 0x3288 - -/* HD Audio class code */ -#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 - -/* - */ - -struct azx_dev { - struct snd_dma_buffer bdl; /* BDL buffer */ - u32 *posbuf; /* position buffer pointer */ - - unsigned int bufsize; /* size of the play buffer in bytes */ - unsigned int period_bytes; /* size of the period in bytes */ - unsigned int frags; /* number for period in the play buffer */ - unsigned int fifo_size; /* FIFO size */ - unsigned long start_wallclk; /* start + minimum wallclk */ - unsigned long period_wallclk; /* wallclk for period */ - - void __iomem *sd_addr; /* stream descriptor pointer */ - - u32 sd_int_sta_mask; /* stream int status mask */ - - /* pcm support */ - struct snd_pcm_substream *substream; /* assigned substream, - * set in PCM open - */ - unsigned int format_val; /* format value to be set in the - * controller and the codec - */ - unsigned char stream_tag; /* assigned stream */ - unsigned char index; /* stream index */ - int assigned_key; /* last device# key assigned to */ - - unsigned int opened :1; - unsigned int running :1; - unsigned int irq_pending :1; - /* - * For VIA: - * A flag to ensure DMA position is 0 - * when link position is not greater than FIFO size - */ - unsigned int insufficient :1; - unsigned int wc_marked:1; - unsigned int no_period_wakeup:1; -}; - -/* CORB/RIRB */ -struct azx_rb { - u32 *buf; /* CORB/RIRB buffer - * Each CORB entry is 4byte, RIRB is 8byte - */ - dma_addr_t addr; /* physical address of CORB/RIRB buffer */ - /* for RIRB */ - unsigned short rp, wp; /* read/write pointers */ - int cmds[AZX_MAX_CODECS]; /* number of pending requests */ - u32 res[AZX_MAX_CODECS]; /* last read value */ -}; - -struct azx_pcm { - struct azx *chip; - struct snd_pcm *pcm; - struct hda_codec *codec; - struct hda_pcm_stream *hinfo[2]; - struct list_head list; -}; - -struct azx { - struct snd_card *card; - struct pci_dev *pci; - int dev_index; - - /* chip type specific */ - int driver_type; - unsigned int driver_caps; - int playback_streams; - int playback_index_offset; - int capture_streams; - int capture_index_offset; - int num_streams; - - /* pci resources */ - unsigned long addr; - void __iomem *remap_addr; - int irq; - - /* locks */ - spinlock_t reg_lock; - struct mutex open_mutex; - - /* streams (x num_streams) */ - struct azx_dev *azx_dev; - - /* PCM */ - struct list_head pcm_list; /* azx_pcm list */ - - /* HD codec */ - unsigned short codec_mask; - int codec_probe_mask; /* copied from probe_mask option */ - struct hda_bus *bus; - unsigned int beep_mode; - - /* CORB/RIRB */ - struct azx_rb corb; - struct azx_rb rirb; - - /* CORB/RIRB and position buffers */ - struct snd_dma_buffer rb; - struct snd_dma_buffer posbuf; - -#ifdef CONFIG_SND_HDA_PATCH_LOADER - const struct firmware *fw; -#endif - - /* flags */ - int position_fix[2]; /* for both playback/capture streams */ - int poll_count; - unsigned int running :1; - unsigned int initialized :1; - unsigned int single_cmd :1; - unsigned int polling_mode :1; - unsigned int msi :1; - unsigned int irq_pending_warned :1; - unsigned int probing :1; /* codec probing phase */ - unsigned int snoop:1; - unsigned int align_buffer_size:1; - unsigned int region_requested:1; - - /* VGA-switcheroo setup */ - unsigned int use_vga_switcheroo:1; - unsigned int vga_switcheroo_registered:1; - unsigned int init_failed:1; /* delayed init failed */ - unsigned int disabled:1; /* disabled by VGA-switcher */ - - /* for debugging */ - unsigned int last_cmd[AZX_MAX_CODECS]; - - /* for pending irqs */ - struct work_struct irq_pending_work; - - /* reboot notifier (for mysterious hangup problem at power-down) */ - struct notifier_block reboot_notifier; - - /* card list (for power_save trigger) */ - struct list_head list; -}; /* driver types */ enum { AZX_DRIVER_ICH, AZX_DRIVER_PCH, AZX_DRIVER_SCH, + AZX_DRIVER_HDMI, AZX_DRIVER_ATI, AZX_DRIVER_ATIHDMI, AZX_DRIVER_ATIHDMI_NS, @@ -537,25 +224,24 @@ enum { AZX_NUM_DRIVERS, /* keep this as last entry */ }; -/* driver quirks (capabilities) */ -/* bits 0-7 are used for indicating driver type */ -#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ -#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ -#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */ -#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */ -#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */ -#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ -#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ -#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ -#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ -#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ -#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ -#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ -#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ -#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ -#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ -#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ -#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +/* quirks for Intel PCH */ +#define AZX_DCAPS_INTEL_PCH_NOPM \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \ + AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_REVERSE_ASSIGN) + +#define AZX_DCAPS_INTEL_PCH \ + (AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME) + +#define AZX_DCAPS_INTEL_HASWELL \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \ + AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \ + AZX_DCAPS_I915_POWERWELL) + +/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */ +#define AZX_DCAPS_INTEL_BROADWELL \ + (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \ + AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_PM_RUNTIME | \ + AZX_DCAPS_I915_POWERWELL) /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -569,7 +255,8 @@ enum { /* quirks for Nvidia */ #define AZX_DCAPS_PRESET_NVIDIA \ (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ - AZX_DCAPS_ALIGN_BUFSIZE) + AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\ + AZX_DCAPS_CORBRP_SELF_CLEAR) #define AZX_DCAPS_PRESET_CTHDA \ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) @@ -583,18 +270,11 @@ enum { #define use_vga_switcheroo(chip) 0 #endif -#if defined(SUPPORT_VGA_SWITCHEROO) || defined(CONFIG_SND_HDA_PATCH_LOADER) -#define DELAYED_INIT_MARK -#define DELAYED_INITDATA_MARK -#else -#define DELAYED_INIT_MARK __devinit -#define DELAYED_INITDATA_MARK __devinitdata -#endif - -static char *driver_short_names[] DELAYED_INITDATA_MARK = { +static char *driver_short_names[] = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", [AZX_DRIVER_SCH] = "HDA Intel MID", + [AZX_DRIVER_HDMI] = "HDA Intel HDMI", [AZX_DRIVER_ATI] = "HDA ATI SB", [AZX_DRIVER_ATIHDMI] = "HDA ATI HDMI", [AZX_DRIVER_ATIHDMI_NS] = "HDA ATI HDMI", @@ -608,62 +288,49 @@ static char *driver_short_names[] DELAYED_INITDATA_MARK = { [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; -/* - * macros for easy use - */ -#define azx_writel(chip,reg,value) \ - writel(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readl(chip,reg) \ - readl((chip)->remap_addr + ICH6_REG_##reg) -#define azx_writew(chip,reg,value) \ - writew(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readw(chip,reg) \ - readw((chip)->remap_addr + ICH6_REG_##reg) -#define azx_writeb(chip,reg,value) \ - writeb(value, (chip)->remap_addr + ICH6_REG_##reg) -#define azx_readb(chip,reg) \ - readb((chip)->remap_addr + ICH6_REG_##reg) - -#define azx_sd_writel(dev,reg,value) \ - writel(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readl(dev,reg) \ - readl((dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_writew(dev,reg,value) \ - writew(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readw(dev,reg) \ - readw((dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_writeb(dev,reg,value) \ - writeb(value, (dev)->sd_addr + ICH6_REG_##reg) -#define azx_sd_readb(dev,reg) \ - readb((dev)->sd_addr + ICH6_REG_##reg) - -/* for pcm support */ -#define get_azx_dev(substream) (substream->runtime->private_data) +struct hda_intel { + struct azx chip; +}; + #ifdef CONFIG_X86 -static void __mark_pages_wc(struct azx *chip, void *addr, size_t size, bool on) +static void __mark_pages_wc(struct azx *chip, struct snd_dma_buffer *dmab, bool on) { + int pages; + if (azx_snoop(chip)) return; - if (addr && size) { - int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (!dmab || !dmab->area || !dmab->bytes) + return; + +#ifdef CONFIG_SND_DMA_SGBUF + if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG) { + struct snd_sg_buf *sgbuf = dmab->private_data; if (on) - set_memory_wc((unsigned long)addr, pages); + set_pages_array_wc(sgbuf->page_table, sgbuf->pages); else - set_memory_wb((unsigned long)addr, pages); + set_pages_array_wb(sgbuf->page_table, sgbuf->pages); + return; } +#endif + + pages = (dmab->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT; + if (on) + set_memory_wc((unsigned long)dmab->area, pages); + else + set_memory_wb((unsigned long)dmab->area, pages); } static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, bool on) { - __mark_pages_wc(chip, buf->area, buf->bytes, on); + __mark_pages_wc(chip, buf, on); } static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) + struct snd_pcm_substream *substream, bool on) { if (azx_dev->wc_marked != on) { - __mark_pages_wc(chip, runtime->dma_area, runtime->dma_bytes, on); + __mark_pages_wc(chip, snd_pcm_get_dma_buf(substream), on); azx_dev->wc_marked = on; } } @@ -674,537 +341,12 @@ static inline void mark_pages_wc(struct azx *chip, struct snd_dma_buffer *buf, { } static inline void mark_runtime_wc(struct azx *chip, struct azx_dev *azx_dev, - struct snd_pcm_runtime *runtime, bool on) + struct snd_pcm_substream *substream, bool on) { } #endif static int azx_acquire_irq(struct azx *chip, int do_disconnect); -static int azx_send_cmd(struct hda_bus *bus, unsigned int val); -/* - * Interface for HD codec - */ - -/* - * CORB / RIRB interface - */ -static int azx_alloc_cmd_io(struct azx *chip) -{ - int err; - - /* single page (at least 4096 bytes) must suffice for both ringbuffes */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - PAGE_SIZE, &chip->rb); - if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate CORB/RIRB\n"); - return err; - } - mark_pages_wc(chip, &chip->rb, true); - return 0; -} - -static void azx_init_cmd_io(struct azx *chip) -{ - spin_lock_irq(&chip->reg_lock); - /* CORB set up */ - chip->corb.addr = chip->rb.addr; - chip->corb.buf = (u32 *)chip->rb.area; - azx_writel(chip, CORBLBASE, (u32)chip->corb.addr); - azx_writel(chip, CORBUBASE, upper_32_bits(chip->corb.addr)); - - /* set the corb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, CORBSIZE, 0x02); - /* set the corb write pointer to 0 */ - azx_writew(chip, CORBWP, 0); - /* reset the corb hw read pointer */ - azx_writew(chip, CORBRP, ICH6_CORBRP_RST); - /* enable corb dma */ - azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); - - /* RIRB set up */ - chip->rirb.addr = chip->rb.addr + 2048; - chip->rirb.buf = (u32 *)(chip->rb.area + 2048); - chip->rirb.wp = chip->rirb.rp = 0; - memset(chip->rirb.cmds, 0, sizeof(chip->rirb.cmds)); - azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); - azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); - - /* set the rirb size to 256 entries (ULI requires explicitly) */ - azx_writeb(chip, RIRBSIZE, 0x02); - /* reset the rirb hw write pointer */ - azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); - /* set N=1, get RIRB response interrupt for new entry */ - if (chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) - azx_writew(chip, RINTCNT, 0xc0); - else - azx_writew(chip, RINTCNT, 1); - /* enable rirb dma and response irq */ - azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); - spin_unlock_irq(&chip->reg_lock); -} - -static void azx_free_cmd_io(struct azx *chip) -{ - spin_lock_irq(&chip->reg_lock); - /* disable ringbuffer DMAs */ - azx_writeb(chip, RIRBCTL, 0); - azx_writeb(chip, CORBCTL, 0); - spin_unlock_irq(&chip->reg_lock); -} - -static unsigned int azx_command_addr(u32 cmd) -{ - unsigned int addr = cmd >> 28; - - if (addr >= AZX_MAX_CODECS) { - snd_BUG(); - addr = 0; - } - - return addr; -} - -static unsigned int azx_response_addr(u32 res) -{ - unsigned int addr = res & 0xf; - - if (addr >= AZX_MAX_CODECS) { - snd_BUG(); - addr = 0; - } - - return addr; -} - -/* send a command */ -static int azx_corb_send_cmd(struct hda_bus *bus, u32 val) -{ - struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); - unsigned int wp; - - spin_lock_irq(&chip->reg_lock); - - /* add command to corb */ - wp = azx_readb(chip, CORBWP); - wp++; - wp %= ICH6_MAX_CORB_ENTRIES; - - chip->rirb.cmds[addr]++; - chip->corb.buf[wp] = cpu_to_le32(val); - azx_writel(chip, CORBWP, wp); - - spin_unlock_irq(&chip->reg_lock); - - return 0; -} - -#define ICH6_RIRB_EX_UNSOL_EV (1<<4) - -/* retrieve RIRB entry - called from interrupt handler */ -static void azx_update_rirb(struct azx *chip) -{ - unsigned int rp, wp; - unsigned int addr; - u32 res, res_ex; - - wp = azx_readb(chip, RIRBWP); - if (wp == chip->rirb.wp) - return; - chip->rirb.wp = wp; - - while (chip->rirb.rp != wp) { - chip->rirb.rp++; - chip->rirb.rp %= ICH6_MAX_RIRB_ENTRIES; - - rp = chip->rirb.rp << 1; /* an RIRB entry is 8-bytes */ - res_ex = le32_to_cpu(chip->rirb.buf[rp + 1]); - res = le32_to_cpu(chip->rirb.buf[rp]); - addr = azx_response_addr(res_ex); - if (res_ex & ICH6_RIRB_EX_UNSOL_EV) - snd_hda_queue_unsol_event(chip->bus, res, res_ex); - else if (chip->rirb.cmds[addr]) { - chip->rirb.res[addr] = res; - smp_wmb(); - chip->rirb.cmds[addr]--; - } else - snd_printk(KERN_ERR SFX "spurious response %#x:%#x, " - "last cmd=%#08x\n", - res, res_ex, - chip->last_cmd[addr]); - } -} - -/* receive a response */ -static unsigned int azx_rirb_get_response(struct hda_bus *bus, - unsigned int addr) -{ - struct azx *chip = bus->private_data; - unsigned long timeout; - unsigned long loopcounter; - int do_poll = 0; - - again: - timeout = jiffies + msecs_to_jiffies(1000); - - for (loopcounter = 0;; loopcounter++) { - if (chip->polling_mode || do_poll) { - spin_lock_irq(&chip->reg_lock); - azx_update_rirb(chip); - spin_unlock_irq(&chip->reg_lock); - } - if (!chip->rirb.cmds[addr]) { - smp_rmb(); - bus->rirb_error = 0; - - if (!do_poll) - chip->poll_count = 0; - return chip->rirb.res[addr]; /* the last value */ - } - if (time_after(jiffies, timeout)) - break; - if (bus->needs_damn_long_delay || loopcounter > 3000) - msleep(2); /* temporary workaround */ - else { - udelay(10); - cond_resched(); - } - } - - if (!chip->polling_mode && chip->poll_count < 2) { - snd_printdd(SFX "azx_get_response timeout, " - "polling the codec once: last cmd=0x%08x\n", - chip->last_cmd[addr]); - do_poll = 1; - chip->poll_count++; - goto again; - } - - - if (!chip->polling_mode) { - snd_printk(KERN_WARNING SFX "azx_get_response timeout, " - "switching to polling mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); - chip->polling_mode = 1; - goto again; - } - - if (chip->msi) { - snd_printk(KERN_WARNING SFX "No response from codec, " - "disabling MSI: last cmd=0x%08x\n", - chip->last_cmd[addr]); - free_irq(chip->irq, chip); - chip->irq = -1; - pci_disable_msi(chip->pci); - chip->msi = 0; - if (azx_acquire_irq(chip, 1) < 0) { - bus->rirb_error = 1; - return -1; - } - goto again; - } - - if (chip->probing) { - /* If this critical timeout happens during the codec probing - * phase, this is likely an access to a non-existing codec - * slot. Better to return an error and reset the system. - */ - return -1; - } - - /* a fatal communication error; need either to reset or to fallback - * to the single_cmd mode - */ - bus->rirb_error = 1; - if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { - bus->response_reset = 1; - return -1; /* give a chance to retry */ - } - - snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " - "switching to single_cmd mode: last cmd=0x%08x\n", - chip->last_cmd[addr]); - chip->single_cmd = 1; - bus->response_reset = 0; - /* release CORB/RIRB */ - azx_free_cmd_io(chip); - /* disable unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); - return -1; -} - -/* - * Use the single immediate command instead of CORB/RIRB for simplicity - * - * Note: according to Intel, this is not preferred use. The command was - * intended for the BIOS only, and may get confused with unsolicited - * responses. So, we shouldn't use it for normal operation from the - * driver. - * I left the codes, however, for debugging/testing purposes. - */ - -/* receive a response */ -static int azx_single_wait_for_response(struct azx *chip, unsigned int addr) -{ - int timeout = 50; - - while (timeout--) { - /* check IRV busy bit */ - if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { - /* reuse rirb.res as the response return value */ - chip->rirb.res[addr] = azx_readl(chip, IR); - return 0; - } - udelay(1); - } - if (printk_ratelimit()) - snd_printd(SFX "get_response timeout: IRS=0x%x\n", - azx_readw(chip, IRS)); - chip->rirb.res[addr] = -1; - return -EIO; -} - -/* send a command */ -static int azx_single_send_cmd(struct hda_bus *bus, u32 val) -{ - struct azx *chip = bus->private_data; - unsigned int addr = azx_command_addr(val); - int timeout = 50; - - bus->rirb_error = 0; - while (timeout--) { - /* check ICB busy bit */ - if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { - /* Clear IRV valid bit */ - azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_VALID); - azx_writel(chip, IC, val); - azx_writew(chip, IRS, azx_readw(chip, IRS) | - ICH6_IRS_BUSY); - return azx_single_wait_for_response(chip, addr); - } - udelay(1); - } - if (printk_ratelimit()) - snd_printd(SFX "send_cmd timeout: IRS=0x%x, val=0x%x\n", - azx_readw(chip, IRS), val); - return -EIO; -} - -/* receive a response */ -static unsigned int azx_single_get_response(struct hda_bus *bus, - unsigned int addr) -{ - struct azx *chip = bus->private_data; - return chip->rirb.res[addr]; -} - -/* - * The below are the main callbacks from hda_codec. - * - * They are just the skeleton to call sub-callbacks according to the - * current setting of chip->single_cmd. - */ - -/* send a command */ -static int azx_send_cmd(struct hda_bus *bus, unsigned int val) -{ - struct azx *chip = bus->private_data; - - if (chip->disabled) - return 0; - chip->last_cmd[azx_command_addr(val)] = val; - if (chip->single_cmd) - return azx_single_send_cmd(bus, val); - else - return azx_corb_send_cmd(bus, val); -} - -/* get a response */ -static unsigned int azx_get_response(struct hda_bus *bus, - unsigned int addr) -{ - struct azx *chip = bus->private_data; - if (chip->disabled) - return 0; - if (chip->single_cmd) - return azx_single_get_response(bus, addr); - else - return azx_rirb_get_response(bus, addr); -} - -#ifdef CONFIG_PM -static void azx_power_notify(struct hda_bus *bus, bool power_up); -#endif - -/* reset codec link */ -static int azx_reset(struct azx *chip, int full_reset) -{ - int count; - - if (!full_reset) - goto __skip; - - /* clear STATESTS */ - azx_writeb(chip, STATESTS, STATESTS_INT_MASK); - - /* reset controller */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_RESET); - - count = 50; - while (azx_readb(chip, GCTL) && --count) - msleep(1); - - /* delay for >= 100us for codec PLL to settle per spec - * Rev 0.9 section 5.5.1 - */ - msleep(1); - - /* Bring controller out of reset */ - azx_writeb(chip, GCTL, azx_readb(chip, GCTL) | ICH6_GCTL_RESET); - - count = 50; - while (!azx_readb(chip, GCTL) && --count) - msleep(1); - - /* Brent Chartrand said to wait >= 540us for codecs to initialize */ - msleep(1); - - __skip: - /* check to see if controller is ready */ - if (!azx_readb(chip, GCTL)) { - snd_printd(SFX "azx_reset: controller not ready!\n"); - return -EBUSY; - } - - /* Accept unsolicited responses */ - if (!chip->single_cmd) - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | - ICH6_GCTL_UNSOL); - - /* detect codecs */ - if (!chip->codec_mask) { - chip->codec_mask = azx_readw(chip, STATESTS); - snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask); - } - - return 0; -} - - -/* - * Lowlevel interface - */ - -/* enable interrupts */ -static void azx_int_enable(struct azx *chip) -{ - /* enable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) | - ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN); -} - -/* disable interrupts */ -static void azx_int_disable(struct azx *chip) -{ - int i; - - /* disable interrupts in stream descriptor */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(azx_dev, SD_CTL, - azx_sd_readb(azx_dev, SD_CTL) & ~SD_INT_MASK); - } - - /* disable SIE for all streams */ - azx_writeb(chip, INTCTL, 0); - - /* disable controller CIE and GIE */ - azx_writel(chip, INTCTL, azx_readl(chip, INTCTL) & - ~(ICH6_INT_CTRL_EN | ICH6_INT_GLOBAL_EN)); -} - -/* clear interrupts */ -static void azx_int_clear(struct azx *chip) -{ - int i; - - /* clear stream status */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); - } - - /* clear STATESTS */ - azx_writeb(chip, STATESTS, STATESTS_INT_MASK); - - /* clear rirb status */ - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - - /* clear int status */ - azx_writel(chip, INTSTS, ICH6_INT_CTRL_EN | ICH6_INT_ALL_STREAM); -} - -/* start a stream */ -static void azx_stream_start(struct azx *chip, struct azx_dev *azx_dev) -{ - /* - * Before stream start, initialize parameter - */ - azx_dev->insufficient = 1; - - /* enable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) | (1 << azx_dev->index)); - /* set DMA start and interrupt mask */ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | - SD_CTL_DMA_START | SD_INT_MASK); -} - -/* stop DMA */ -static void azx_stream_clear(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) & - ~(SD_CTL_DMA_START | SD_INT_MASK)); - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); /* to be sure */ -} - -/* stop a stream */ -static void azx_stream_stop(struct azx *chip, struct azx_dev *azx_dev) -{ - azx_stream_clear(chip, azx_dev); - /* disable SIE */ - azx_writel(chip, INTCTL, - azx_readl(chip, INTCTL) & ~(1 << azx_dev->index)); -} - - -/* - * reset and start the controller registers - */ -static void azx_init_chip(struct azx *chip, int full_reset) -{ - if (chip->initialized) - return; - - /* reset controller */ - azx_reset(chip, full_reset); - - /* initialize interrupts */ - azx_int_clear(chip); - azx_int_enable(chip); - - /* initialize the codec command I/O */ - if (!chip->single_cmd) - azx_init_cmd_io(chip); - - /* program the position buffer */ - azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); - azx_writel(chip, DPUBASE, upper_32_bits(chip->posbuf.addr)); - - chip->initialized = 1; -} /* * initialize the PCI registers @@ -1230,7 +372,7 @@ static void azx_init_pci(struct azx *chip) * The PCI register TCSEL is defined in the Intel manuals. */ if (!(chip->driver_caps & AZX_DCAPS_NO_TCSEL)) { - snd_printdd(SFX "Clearing TCSEL\n"); + dev_dbg(chip->card->dev, "Clearing TCSEL\n"); update_pci_byte(chip->pci, ICH6_PCIREG_TCSEL, 0x07, 0); } @@ -1238,7 +380,8 @@ static void azx_init_pci(struct azx *chip) * we need to enable snoop. */ if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) { - snd_printdd(SFX "Setting ATI snoop: %d\n", azx_snoop(chip)); + dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n", + azx_snoop(chip)); update_pci_byte(chip->pci, ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR, 0x07, azx_snoop(chip) ? ATI_SB450_HDAUDIO_ENABLE_SNOOP : 0); @@ -1246,7 +389,8 @@ static void azx_init_pci(struct azx *chip) /* For NVIDIA HDA, enable snoop */ if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) { - snd_printdd(SFX "Setting Nvidia snoop: %d\n", azx_snoop(chip)); + dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n", + azx_snoop(chip)); update_pci_byte(chip->pci, NVIDIA_HDA_TRANSREG_ADDR, 0x0f, NVIDIA_HDA_ENABLE_COHBITS); @@ -1271,915 +415,31 @@ static void azx_init_pci(struct azx *chip) pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); } - snd_printdd(SFX "SCH snoop: %s\n", - (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) - ? "Disabled" : "Enabled"); + dev_dbg(chip->card->dev, "SCH snoop: %s\n", + (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) ? + "Disabled" : "Enabled"); } } - static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev); -/* - * interrupt handler - */ -static irqreturn_t azx_interrupt(int irq, void *dev_id) -{ - struct azx *chip = dev_id; - struct azx_dev *azx_dev; - u32 status; - u8 sd_status; - int i, ok; - -#ifdef CONFIG_PM_RUNTIME - if (chip->pci->dev.power.runtime_status != RPM_ACTIVE) - return IRQ_NONE; -#endif - - spin_lock(&chip->reg_lock); - - if (chip->disabled) { - spin_unlock(&chip->reg_lock); - return IRQ_NONE; - } - - status = azx_readl(chip, INTSTS); - if (status == 0) { - spin_unlock(&chip->reg_lock); - return IRQ_NONE; - } - - for (i = 0; i < chip->num_streams; i++) { - azx_dev = &chip->azx_dev[i]; - if (status & azx_dev->sd_int_sta_mask) { - sd_status = azx_sd_readb(azx_dev, SD_STS); - azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK); - if (!azx_dev->substream || !azx_dev->running || - !(sd_status & SD_INT_COMPLETE)) - continue; - /* check whether this IRQ is really acceptable */ - ok = azx_position_ok(chip, azx_dev); - if (ok == 1) { - azx_dev->irq_pending = 0; - spin_unlock(&chip->reg_lock); - snd_pcm_period_elapsed(azx_dev->substream); - spin_lock(&chip->reg_lock); - } else if (ok == 0 && chip->bus && chip->bus->workq) { - /* bogus IRQ, process it later */ - azx_dev->irq_pending = 1; - queue_work(chip->bus->workq, - &chip->irq_pending_work); - } - } - } - - /* clear rirb int */ - status = azx_readb(chip, RIRBSTS); - if (status & RIRB_INT_MASK) { - if (status & RIRB_INT_RESPONSE) { - if (chip->driver_caps & AZX_DCAPS_RIRB_PRE_DELAY) - udelay(80); - azx_update_rirb(chip); - } - azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); - } - -#if 0 - /* clear state status int */ - if (azx_readb(chip, STATESTS) & 0x04) - azx_writeb(chip, STATESTS, 0x04); -#endif - spin_unlock(&chip->reg_lock); - - return IRQ_HANDLED; -} - - -/* - * set up a BDL entry - */ -static int setup_bdle(struct azx *chip, - struct snd_pcm_substream *substream, - struct azx_dev *azx_dev, u32 **bdlp, - int ofs, int size, int with_ioc) -{ - u32 *bdl = *bdlp; - - while (size > 0) { - dma_addr_t addr; - int chunk; - - if (azx_dev->frags >= AZX_MAX_BDL_ENTRIES) - return -EINVAL; - - addr = snd_pcm_sgbuf_get_addr(substream, ofs); - /* program the address field of the BDL entry */ - bdl[0] = cpu_to_le32((u32)addr); - bdl[1] = cpu_to_le32(upper_32_bits(addr)); - /* program the size field of the BDL entry */ - chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); - /* one BDLE cannot cross 4K boundary on CTHDA chips */ - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { - u32 remain = 0x1000 - (ofs & 0xfff); - if (chunk > remain) - chunk = remain; - } - bdl[2] = cpu_to_le32(chunk); - /* program the IOC to enable interrupt - * only when the whole fragment is processed - */ - size -= chunk; - bdl[3] = (size || !with_ioc) ? 0 : cpu_to_le32(0x01); - bdl += 4; - azx_dev->frags++; - ofs += chunk; - } - *bdlp = bdl; - return ofs; -} - -/* - * set up BDL entries - */ -static int azx_setup_periods(struct azx *chip, - struct snd_pcm_substream *substream, - struct azx_dev *azx_dev) -{ - u32 *bdl; - int i, ofs, periods, period_bytes; - int pos_adj; - - /* reset BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, 0); - azx_sd_writel(azx_dev, SD_BDLPU, 0); - - period_bytes = azx_dev->period_bytes; - periods = azx_dev->bufsize / period_bytes; - - /* program the initial BDL entries */ - bdl = (u32 *)azx_dev->bdl.area; - ofs = 0; - azx_dev->frags = 0; - pos_adj = bdl_pos_adj[chip->dev_index]; - if (!azx_dev->no_period_wakeup && pos_adj > 0) { - struct snd_pcm_runtime *runtime = substream->runtime; - int pos_align = pos_adj; - pos_adj = (pos_adj * runtime->rate + 47999) / 48000; - if (!pos_adj) - pos_adj = pos_align; - else - pos_adj = ((pos_adj + pos_align - 1) / pos_align) * - pos_align; - pos_adj = frames_to_bytes(runtime, pos_adj); - if (pos_adj >= period_bytes) { - snd_printk(KERN_WARNING SFX "Too big adjustment %d\n", - bdl_pos_adj[chip->dev_index]); - pos_adj = 0; - } else { - ofs = setup_bdle(chip, substream, azx_dev, - &bdl, ofs, pos_adj, true); - if (ofs < 0) - goto error; - } - } else - pos_adj = 0; - for (i = 0; i < periods; i++) { - if (i == periods - 1 && pos_adj) - ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs, - period_bytes - pos_adj, 0); - else - ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs, - period_bytes, - !azx_dev->no_period_wakeup); - if (ofs < 0) - goto error; - } - return 0; - - error: - snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", - azx_dev->bufsize, period_bytes); - return -EINVAL; -} - -/* reset stream */ -static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned char val; - int timeout; - - azx_stream_clear(chip, azx_dev); - - azx_sd_writeb(azx_dev, SD_CTL, azx_sd_readb(azx_dev, SD_CTL) | - SD_CTL_STREAM_RESET); - udelay(3); - timeout = 300; - while (!((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && - --timeout) - ; - val &= ~SD_CTL_STREAM_RESET; - azx_sd_writeb(azx_dev, SD_CTL, val); - udelay(3); - - timeout = 300; - /* waiting for hardware to report that the stream is out of reset */ - while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) && - --timeout) - ; - - /* reset first position - may not be synced with hw at this time */ - *azx_dev->posbuf = 0; -} - -/* - * set up the SD for streaming - */ -static int azx_setup_controller(struct azx *chip, struct azx_dev *azx_dev) -{ - unsigned int val; - /* make sure the run bit is zero for SD */ - azx_stream_clear(chip, azx_dev); - /* program the stream_tag */ - val = azx_sd_readl(azx_dev, SD_CTL); - val = (val & ~SD_CTL_STREAM_TAG_MASK) | - (azx_dev->stream_tag << SD_CTL_STREAM_TAG_SHIFT); - if (!azx_snoop(chip)) - val |= SD_CTL_TRAFFIC_PRIO; - azx_sd_writel(azx_dev, SD_CTL, val); - - /* program the length of samples in cyclic buffer */ - azx_sd_writel(azx_dev, SD_CBL, azx_dev->bufsize); - - /* program the stream format */ - /* this value needs to be the same as the one programmed */ - azx_sd_writew(azx_dev, SD_FORMAT, azx_dev->format_val); - - /* program the stream LVI (last valid index) of the BDL */ - azx_sd_writew(azx_dev, SD_LVI, azx_dev->frags - 1); - - /* program the BDL address */ - /* lower BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, (u32)azx_dev->bdl.addr); - /* upper BDL address */ - azx_sd_writel(azx_dev, SD_BDLPU, upper_32_bits(azx_dev->bdl.addr)); - - /* enable the position buffer */ - if (chip->position_fix[0] != POS_FIX_LPIB || - chip->position_fix[1] != POS_FIX_LPIB) { - if (!(azx_readl(chip, DPLBASE) & ICH6_DPLBASE_ENABLE)) - azx_writel(chip, DPLBASE, - (u32)chip->posbuf.addr | ICH6_DPLBASE_ENABLE); - } - - /* set the interrupt enable bits in the descriptor control register */ - azx_sd_writel(azx_dev, SD_CTL, - azx_sd_readl(azx_dev, SD_CTL) | SD_INT_MASK); - - return 0; -} - -/* - * Probe the given codec address - */ -static int probe_codec(struct azx *chip, int addr) -{ - unsigned int cmd = (addr << 28) | (AC_NODE_ROOT << 20) | - (AC_VERB_PARAMETERS << 8) | AC_PAR_VENDOR_ID; - unsigned int res; - - mutex_lock(&chip->bus->cmd_mutex); - chip->probing = 1; - azx_send_cmd(chip->bus, cmd); - res = azx_get_response(chip->bus, addr); - chip->probing = 0; - mutex_unlock(&chip->bus->cmd_mutex); - if (res == -1) - return -EIO; - snd_printdd(SFX "codec #%d probed OK\n", addr); - return 0; -} - -static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm); -static void azx_stop_chip(struct azx *chip); - -static void azx_bus_reset(struct hda_bus *bus) -{ - struct azx *chip = bus->private_data; - - bus->in_reset = 1; - azx_stop_chip(chip); - azx_init_chip(chip, 1); -#ifdef CONFIG_PM - if (chip->initialized) { - struct azx_pcm *p; - list_for_each_entry(p, &chip->pcm_list, list) - snd_pcm_suspend_all(p->pcm); - snd_hda_suspend(chip->bus); - snd_hda_resume(chip->bus); - } -#endif - bus->in_reset = 0; -} - -/* - * Codec initialization - */ - -/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ -static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] DELAYED_INITDATA_MARK = { - [AZX_DRIVER_NVIDIA] = 8, - [AZX_DRIVER_TERA] = 1, -}; - -static int DELAYED_INIT_MARK azx_codec_create(struct azx *chip, const char *model) +/* called from IRQ */ +static int azx_position_check(struct azx *chip, struct azx_dev *azx_dev) { - struct hda_bus_template bus_temp; - int c, codecs, err; - int max_slots; - - memset(&bus_temp, 0, sizeof(bus_temp)); - bus_temp.private_data = chip; - bus_temp.modelname = model; - bus_temp.pci = chip->pci; - bus_temp.ops.command = azx_send_cmd; - bus_temp.ops.get_response = azx_get_response; - bus_temp.ops.attach_pcm = azx_attach_pcm_stream; - bus_temp.ops.bus_reset = azx_bus_reset; -#ifdef CONFIG_PM - bus_temp.power_save = &power_save; - bus_temp.ops.pm_notify = azx_power_notify; -#endif - - err = snd_hda_bus_new(chip->card, &bus_temp, &chip->bus); - if (err < 0) - return err; - - if (chip->driver_caps & AZX_DCAPS_RIRB_DELAY) { - snd_printd(SFX "Enable delay in RIRB handling\n"); - chip->bus->needs_damn_long_delay = 1; - } - - codecs = 0; - max_slots = azx_max_codecs[chip->driver_type]; - if (!max_slots) - max_slots = AZX_DEFAULT_CODECS; - - /* First try to probe all given codec slots */ - for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { - if (probe_codec(chip, c) < 0) { - /* Some BIOSen give you wrong codec addresses - * that don't exist - */ - snd_printk(KERN_WARNING SFX - "Codec #%d probe error; " - "disabling it...\n", c); - chip->codec_mask &= ~(1 << c); - /* More badly, accessing to a non-existing - * codec often screws up the controller chip, - * and disturbs the further communications. - * Thus if an error occurs during probing, - * better to reset the controller chip to - * get back to the sanity state. - */ - azx_stop_chip(chip); - azx_init_chip(chip, 1); - } - } - } - - /* AMD chipsets often cause the communication stalls upon certain - * sequence like the pin-detection. It seems that forcing the synced - * access works around the stall. Grrr... - */ - if (chip->driver_caps & AZX_DCAPS_SYNC_WRITE) { - snd_printd(SFX "Enable sync_write for stable communication\n"); - chip->bus->sync_write = 1; - chip->bus->allow_bus_reset = 1; - } - - /* Then create codec instances */ - for (c = 0; c < max_slots; c++) { - if ((chip->codec_mask & (1 << c)) & chip->codec_probe_mask) { - struct hda_codec *codec; - err = snd_hda_codec_new(chip->bus, c, &codec); - if (err < 0) - continue; - codec->beep_mode = chip->beep_mode; - codecs++; - } - } - if (!codecs) { - snd_printk(KERN_ERR SFX "no codecs initialized\n"); - return -ENXIO; - } - return 0; -} + int ok; -/* configure each codec instance */ -static int __devinit azx_codec_configure(struct azx *chip) -{ - struct hda_codec *codec; - list_for_each_entry(codec, &chip->bus->codec_list, list) { - snd_hda_codec_configure(codec); + ok = azx_position_ok(chip, azx_dev); + if (ok == 1) { + azx_dev->irq_pending = 0; + return ok; + } else if (ok == 0 && chip->bus && chip->bus->workq) { + /* bogus IRQ, process it later */ + azx_dev->irq_pending = 1; + queue_work(chip->bus->workq, &chip->irq_pending_work); } return 0; } - -/* - * PCM support - */ - -/* assign a stream for the PCM */ -static inline struct azx_dev * -azx_assign_device(struct azx *chip, struct snd_pcm_substream *substream) -{ - int dev, i, nums; - struct azx_dev *res = NULL; - /* make a non-zero unique key for the substream */ - int key = (substream->pcm->device << 16) | (substream->number << 2) | - (substream->stream + 1); - - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - dev = chip->playback_index_offset; - nums = chip->playback_streams; - } else { - dev = chip->capture_index_offset; - nums = chip->capture_streams; - } - for (i = 0; i < nums; i++, dev++) - if (!chip->azx_dev[dev].opened) { - res = &chip->azx_dev[dev]; - if (res->assigned_key == key) - break; - } - if (res) { - res->opened = 1; - res->assigned_key = key; - } - return res; -} - -/* release the assigned stream */ -static inline void azx_release_device(struct azx_dev *azx_dev) -{ - azx_dev->opened = 0; -} - -static struct snd_pcm_hardware azx_pcm_hw = { - .info = (SNDRV_PCM_INFO_MMAP | - SNDRV_PCM_INFO_INTERLEAVED | - SNDRV_PCM_INFO_BLOCK_TRANSFER | - SNDRV_PCM_INFO_MMAP_VALID | - /* No full-resume yet implemented */ - /* SNDRV_PCM_INFO_RESUME |*/ - SNDRV_PCM_INFO_PAUSE | - SNDRV_PCM_INFO_SYNC_START | - SNDRV_PCM_INFO_NO_PERIOD_WAKEUP), - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .rates = SNDRV_PCM_RATE_48000, - .rate_min = 48000, - .rate_max = 48000, - .channels_min = 2, - .channels_max = 2, - .buffer_bytes_max = AZX_MAX_BUF_SIZE, - .period_bytes_min = 128, - .period_bytes_max = AZX_MAX_BUF_SIZE / 2, - .periods_min = 2, - .periods_max = AZX_MAX_FRAG, - .fifo_size = 0, -}; - -static int azx_pcm_open(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned long flags; - int err; - int buff_step; - - mutex_lock(&chip->open_mutex); - azx_dev = azx_assign_device(chip, substream); - if (azx_dev == NULL) { - mutex_unlock(&chip->open_mutex); - return -EBUSY; - } - runtime->hw = azx_pcm_hw; - runtime->hw.channels_min = hinfo->channels_min; - runtime->hw.channels_max = hinfo->channels_max; - runtime->hw.formats = hinfo->formats; - runtime->hw.rates = hinfo->rates; - snd_pcm_limit_hw_rates(runtime); - snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); - if (chip->align_buffer_size) - /* constrain buffer sizes to be multiple of 128 - bytes. This is more efficient in terms of memory - access but isn't required by the HDA spec and - prevents users from specifying exact period/buffer - sizes. For example for 44.1kHz, a period size set - to 20ms will be rounded to 19.59ms. */ - buff_step = 128; - else - /* Don't enforce steps on buffer sizes, still need to - be multiple of 4 bytes (HDA spec). Tested on Intel - HDA controllers, may not work on all devices where - option needs to be disabled */ - buff_step = 4; - - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, - buff_step); - snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, - buff_step); - snd_hda_power_up_d3wait(apcm->codec); - err = hinfo->ops.open(hinfo, apcm->codec, substream); - if (err < 0) { - azx_release_device(azx_dev); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); - return err; - } - snd_pcm_limit_hw_rates(runtime); - /* sanity check */ - if (snd_BUG_ON(!runtime->hw.channels_min) || - snd_BUG_ON(!runtime->hw.channels_max) || - snd_BUG_ON(!runtime->hw.formats) || - snd_BUG_ON(!runtime->hw.rates)) { - azx_release_device(azx_dev); - hinfo->ops.close(hinfo, apcm->codec, substream); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); - return -EINVAL; - } - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = substream; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - - runtime->private_data = azx_dev; - snd_pcm_set_sync(substream); - mutex_unlock(&chip->open_mutex); - return 0; -} - -static int azx_pcm_close(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - unsigned long flags; - - mutex_lock(&chip->open_mutex); - spin_lock_irqsave(&chip->reg_lock, flags); - azx_dev->substream = NULL; - azx_dev->running = 0; - spin_unlock_irqrestore(&chip->reg_lock, flags); - azx_release_device(azx_dev); - hinfo->ops.close(hinfo, apcm->codec, substream); - snd_hda_power_down(apcm->codec); - mutex_unlock(&chip->open_mutex); - return 0; -} - -static int azx_pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; - struct azx_dev *azx_dev = get_azx_dev(substream); - int ret; - - mark_runtime_wc(chip, azx_dev, runtime, false); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) - return ret; - mark_runtime_wc(chip, azx_dev, runtime, true); - return ret; -} - -static int azx_pcm_hw_free(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx_dev *azx_dev = get_azx_dev(substream); - struct azx *chip = apcm->chip; - struct snd_pcm_runtime *runtime = substream->runtime; - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - - /* reset BDL address */ - azx_sd_writel(azx_dev, SD_BDLPL, 0); - azx_sd_writel(azx_dev, SD_BDLPU, 0); - azx_sd_writel(azx_dev, SD_CTL, 0); - azx_dev->bufsize = 0; - azx_dev->period_bytes = 0; - azx_dev->format_val = 0; - - snd_hda_codec_cleanup(apcm->codec, hinfo, substream); - - mark_runtime_wc(chip, azx_dev, runtime, false); - return snd_pcm_lib_free_pages(substream); -} - -static int azx_pcm_prepare(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - struct hda_pcm_stream *hinfo = apcm->hinfo[substream->stream]; - struct snd_pcm_runtime *runtime = substream->runtime; - unsigned int bufsize, period_bytes, format_val, stream_tag; - int err; - struct hda_spdif_out *spdif = - snd_hda_spdif_out_of_nid(apcm->codec, hinfo->nid); - unsigned short ctls = spdif ? spdif->ctls : 0; - - azx_stream_reset(chip, azx_dev); - format_val = snd_hda_calc_stream_format(runtime->rate, - runtime->channels, - runtime->format, - hinfo->maxbps, - ctls); - if (!format_val) { - snd_printk(KERN_ERR SFX - "invalid format_val, rate=%d, ch=%d, format=%d\n", - runtime->rate, runtime->channels, runtime->format); - return -EINVAL; - } - - bufsize = snd_pcm_lib_buffer_bytes(substream); - period_bytes = snd_pcm_lib_period_bytes(substream); - - snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", - bufsize, format_val); - - if (bufsize != azx_dev->bufsize || - period_bytes != azx_dev->period_bytes || - format_val != azx_dev->format_val || - runtime->no_period_wakeup != azx_dev->no_period_wakeup) { - azx_dev->bufsize = bufsize; - azx_dev->period_bytes = period_bytes; - azx_dev->format_val = format_val; - azx_dev->no_period_wakeup = runtime->no_period_wakeup; - err = azx_setup_periods(chip, substream, azx_dev); - if (err < 0) - return err; - } - - /* wallclk has 24Mhz clock source */ - azx_dev->period_wallclk = (((runtime->period_size * 24000) / - runtime->rate) * 1000); - azx_setup_controller(chip, azx_dev); - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1; - else - azx_dev->fifo_size = 0; - - stream_tag = azx_dev->stream_tag; - /* CA-IBG chips need the playback stream starting from 1 */ - if ((chip->driver_caps & AZX_DCAPS_CTX_WORKAROUND) && - stream_tag > chip->capture_streams) - stream_tag -= chip->capture_streams; - return snd_hda_codec_prepare(apcm->codec, hinfo, stream_tag, - azx_dev->format_val, substream); -} - -static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev; - struct snd_pcm_substream *s; - int rstart = 0, start, nsync = 0, sbits = 0; - int nwait, timeout; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - rstart = 1; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - case SNDRV_PCM_TRIGGER_RESUME: - start = 1; - break; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - case SNDRV_PCM_TRIGGER_SUSPEND: - case SNDRV_PCM_TRIGGER_STOP: - start = 0; - break; - default: - return -EINVAL; - } - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - sbits |= 1 << azx_dev->index; - nsync++; - snd_pcm_trigger_done(s, substream); - } - - spin_lock(&chip->reg_lock); - - /* first, set SYNC bits of corresponding streams */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) | sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) | sbits); - - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (start) { - azx_dev->start_wallclk = azx_readl(chip, WALLCLK); - if (!rstart) - azx_dev->start_wallclk -= - azx_dev->period_wallclk; - azx_stream_start(chip, azx_dev); - } else { - azx_stream_stop(chip, azx_dev); - } - azx_dev->running = start; - } - spin_unlock(&chip->reg_lock); - if (start) { - /* wait until all FIFOs get ready */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (!(azx_sd_readb(azx_dev, SD_STS) & - SD_STS_FIFO_READY)) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } else { - /* wait until all RUN bits are cleared */ - for (timeout = 5000; timeout; timeout--) { - nwait = 0; - snd_pcm_group_for_each_entry(s, substream) { - if (s->pcm->card != substream->pcm->card) - continue; - azx_dev = get_azx_dev(s); - if (azx_sd_readb(azx_dev, SD_CTL) & - SD_CTL_DMA_START) - nwait++; - } - if (!nwait) - break; - cpu_relax(); - } - } - spin_lock(&chip->reg_lock); - /* reset SYNC bits */ - if (chip->driver_caps & AZX_DCAPS_OLD_SSYNC) - azx_writel(chip, OLD_SSYNC, - azx_readl(chip, OLD_SSYNC) & ~sbits); - else - azx_writel(chip, SSYNC, azx_readl(chip, SSYNC) & ~sbits); - spin_unlock(&chip->reg_lock); - return 0; -} - -/* get the current DMA position with correction on VIA chips */ -static unsigned int azx_via_get_position(struct azx *chip, - struct azx_dev *azx_dev) -{ - unsigned int link_pos, mini_pos, bound_pos; - unsigned int mod_link_pos, mod_dma_pos, mod_mini_pos; - unsigned int fifo_size; - - link_pos = azx_sd_readl(azx_dev, SD_LPIB); - if (azx_dev->substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { - /* Playback, no problem using link position */ - return link_pos; - } - - /* Capture */ - /* For new chipset, - * use mod to get the DMA position just like old chipset - */ - mod_dma_pos = le32_to_cpu(*azx_dev->posbuf); - mod_dma_pos %= azx_dev->period_bytes; - - /* azx_dev->fifo_size can't get FIFO size of in stream. - * Get from base address + offset. - */ - fifo_size = readw(chip->remap_addr + VIA_IN_STREAM0_FIFO_SIZE_OFFSET); - - if (azx_dev->insufficient) { - /* Link position never gather than FIFO size */ - if (link_pos <= fifo_size) - return 0; - - azx_dev->insufficient = 0; - } - - if (link_pos <= fifo_size) - mini_pos = azx_dev->bufsize + link_pos - fifo_size; - else - mini_pos = link_pos - fifo_size; - - /* Find nearest previous boudary */ - mod_mini_pos = mini_pos % azx_dev->period_bytes; - mod_link_pos = link_pos % azx_dev->period_bytes; - if (mod_link_pos >= fifo_size) - bound_pos = link_pos - mod_link_pos; - else if (mod_dma_pos >= mod_mini_pos) - bound_pos = mini_pos - mod_mini_pos; - else { - bound_pos = mini_pos - mod_mini_pos + azx_dev->period_bytes; - if (bound_pos >= azx_dev->bufsize) - bound_pos = 0; - } - - /* Calculate real DMA position we want */ - return bound_pos + mod_dma_pos; -} - -static unsigned int azx_get_position(struct azx *chip, - struct azx_dev *azx_dev, - bool with_check) -{ - unsigned int pos; - int stream = azx_dev->substream->stream; - - switch (chip->position_fix[stream]) { - case POS_FIX_LPIB: - /* read LPIB */ - pos = azx_sd_readl(azx_dev, SD_LPIB); - break; - case POS_FIX_VIACOMBO: - pos = azx_via_get_position(chip, azx_dev); - break; - default: - /* use the position buffer */ - pos = le32_to_cpu(*azx_dev->posbuf); - if (with_check && chip->position_fix[stream] == POS_FIX_AUTO) { - if (!pos || pos == (u32)-1) { - printk(KERN_WARNING - "hda-intel: Invalid position buffer, " - "using LPIB read method instead.\n"); - chip->position_fix[stream] = POS_FIX_LPIB; - pos = azx_sd_readl(azx_dev, SD_LPIB); - } else - chip->position_fix[stream] = POS_FIX_POSBUF; - } - break; - } - - if (pos >= azx_dev->bufsize) - pos = 0; - - /* calculate runtime delay from LPIB */ - if (azx_dev->substream->runtime && - chip->position_fix[stream] == POS_FIX_POSBUF && - (chip->driver_caps & AZX_DCAPS_COUNT_LPIB_DELAY)) { - unsigned int lpib_pos = azx_sd_readl(azx_dev, SD_LPIB); - int delay; - if (stream == SNDRV_PCM_STREAM_PLAYBACK) - delay = pos - lpib_pos; - else - delay = lpib_pos - pos; - if (delay < 0) - delay += azx_dev->bufsize; - if (delay >= azx_dev->period_bytes) { - snd_printk(KERN_WARNING SFX - "Unstable LPIB (%d >= %d); " - "disabling LPIB delay counting\n", - delay, azx_dev->period_bytes); - delay = 0; - chip->driver_caps &= ~AZX_DCAPS_COUNT_LPIB_DELAY; - } - azx_dev->substream->runtime->delay = - bytes_to_frames(azx_dev->substream->runtime, delay); - } - return pos; -} - -static snd_pcm_uframes_t azx_pcm_pointer(struct snd_pcm_substream *substream) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - struct azx_dev *azx_dev = get_azx_dev(substream); - return bytes_to_frames(substream->runtime, - azx_get_position(chip, azx_dev, false)); -} - /* * Check whether the current DMA position is acceptable for updating * periods. Returns non-zero if it's OK. @@ -2193,13 +453,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) { u32 wallclk; unsigned int pos; - int stream; wallclk = azx_readl(chip, WALLCLK) - azx_dev->start_wallclk; if (wallclk < (azx_dev->period_wallclk * 2) / 3) return -1; /* bogus (too early) interrupt */ - stream = azx_dev->substream->stream; pos = azx_get_position(chip, azx_dev, true); if (WARN_ONCE(!azx_dev->period_bytes, @@ -2208,7 +466,7 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) if (wallclk < (azx_dev->period_wallclk * 5) / 4 && pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) /* NG - it's below the first next period boundary */ - return bdl_pos_adj[chip->dev_index] ? 0 : -1; + return chip->bdl_pos_adj[chip->dev_index] ? 0 : -1; azx_dev->start_wallclk += wallclk; return 1; /* OK, it's fine */ } @@ -2222,10 +480,9 @@ static void azx_irq_pending_work(struct work_struct *work) int i, pending, ok; if (!chip->irq_pending_warned) { - printk(KERN_WARNING - "hda-intel: IRQ timing workaround is activated " - "for card #%d. Suggest a bigger bdl_pos_adj.\n", - chip->card->number); + dev_info(chip->card->dev, + "IRQ timing workaround is activated for card #%d. Suggest a bigger bdl_pos_adj.\n", + chip->card->number); chip->irq_pending_warned = 1; } @@ -2267,137 +524,14 @@ static void azx_clear_irq_pending(struct azx *chip) spin_unlock_irq(&chip->reg_lock); } -#ifdef CONFIG_X86 -static int azx_pcm_mmap(struct snd_pcm_substream *substream, - struct vm_area_struct *area) -{ - struct azx_pcm *apcm = snd_pcm_substream_chip(substream); - struct azx *chip = apcm->chip; - if (!azx_snoop(chip)) - area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); - return snd_pcm_lib_default_mmap(substream, area); -} -#else -#define azx_pcm_mmap NULL -#endif - -static struct snd_pcm_ops azx_pcm_ops = { - .open = azx_pcm_open, - .close = azx_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = azx_pcm_hw_params, - .hw_free = azx_pcm_hw_free, - .prepare = azx_pcm_prepare, - .trigger = azx_pcm_trigger, - .pointer = azx_pcm_pointer, - .mmap = azx_pcm_mmap, - .page = snd_pcm_sgbuf_ops_page, -}; - -static void azx_pcm_free(struct snd_pcm *pcm) -{ - struct azx_pcm *apcm = pcm->private_data; - if (apcm) { - list_del(&apcm->list); - kfree(apcm); - } -} - -#define MAX_PREALLOC_SIZE (32 * 1024 * 1024) - -static int -azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, - struct hda_pcm *cpcm) -{ - struct azx *chip = bus->private_data; - struct snd_pcm *pcm; - struct azx_pcm *apcm; - int pcm_dev = cpcm->device; - unsigned int size; - int s, err; - - list_for_each_entry(apcm, &chip->pcm_list, list) { - if (apcm->pcm->device == pcm_dev) { - snd_printk(KERN_ERR SFX "PCM %d already exists\n", pcm_dev); - return -EBUSY; - } - } - err = snd_pcm_new(chip->card, cpcm->name, pcm_dev, - cpcm->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams, - cpcm->stream[SNDRV_PCM_STREAM_CAPTURE].substreams, - &pcm); - if (err < 0) - return err; - strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); - apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); - if (apcm == NULL) - return -ENOMEM; - apcm->chip = chip; - apcm->pcm = pcm; - apcm->codec = codec; - pcm->private_data = apcm; - pcm->private_free = azx_pcm_free; - if (cpcm->pcm_type == HDA_PCM_TYPE_MODEM) - pcm->dev_class = SNDRV_PCM_CLASS_MODEM; - list_add_tail(&apcm->list, &chip->pcm_list); - cpcm->pcm = pcm; - for (s = 0; s < 2; s++) { - apcm->hinfo[s] = &cpcm->stream[s]; - if (cpcm->stream[s].substreams) - snd_pcm_set_ops(pcm, s, &azx_pcm_ops); - } - /* buffer pre-allocation */ - size = CONFIG_SND_HDA_PREALLOC_SIZE * 1024; - if (size > MAX_PREALLOC_SIZE) - size = MAX_PREALLOC_SIZE; - snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, - snd_dma_pci_data(chip->pci), - size, MAX_PREALLOC_SIZE); - return 0; -} - -/* - * mixer creation - all stuff is implemented in hda module - */ -static int __devinit azx_mixer_create(struct azx *chip) -{ - return snd_hda_build_controls(chip->bus); -} - - -/* - * initialize SD streams - */ -static int __devinit azx_init_stream(struct azx *chip) -{ - int i; - - /* initialize each stream (aka device) - * assign the starting bdl address to each stream (device) - * and initialize - */ - for (i = 0; i < chip->num_streams; i++) { - struct azx_dev *azx_dev = &chip->azx_dev[i]; - azx_dev->posbuf = (u32 __iomem *)(chip->posbuf.area + i * 8); - /* offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ - azx_dev->sd_addr = chip->remap_addr + (0x20 * i + 0x80); - /* int mask: SDI0=0x01, SDI1=0x02, ... SDO3=0x80 */ - azx_dev->sd_int_sta_mask = 1 << i; - /* stream tag: must be non-zero and unique */ - azx_dev->index = i; - azx_dev->stream_tag = i + 1; - } - - return 0; -} - static int azx_acquire_irq(struct azx *chip, int do_disconnect) { if (request_irq(chip->pci->irq, azx_interrupt, chip->msi ? 0 : IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR "hda-intel: unable to grab IRQ %d, " - "disabling device\n", chip->pci->irq); + dev_err(chip->card->dev, + "unable to grab IRQ %d, disabling device\n", + chip->pci->irq); if (do_disconnect) snd_card_disconnect(chip->card); return -1; @@ -2407,38 +541,7 @@ static int azx_acquire_irq(struct azx *chip, int do_disconnect) return 0; } - -static void azx_stop_chip(struct azx *chip) -{ - if (!chip->initialized) - return; - - /* disable interrupts */ - azx_int_disable(chip); - azx_int_clear(chip); - - /* disable CORB/RIRB */ - azx_free_cmd_io(chip); - - /* disable position buffer */ - azx_writel(chip, DPLBASE, 0); - azx_writel(chip, DPUBASE, 0); - - chip->initialized = 0; -} - #ifdef CONFIG_PM -/* power-up/down the controller */ -static void azx_power_notify(struct hda_bus *bus, bool power_up) -{ - struct azx *chip = bus->private_data; - - if (power_up) - pm_runtime_get_sync(&chip->pci->dev); - else - pm_runtime_put_sync(&chip->pci->dev); -} - static DEFINE_MUTEX(card_list_lock); static LIST_HEAD(card_list); @@ -2493,6 +596,9 @@ static int azx_suspend(struct device *dev) struct azx *chip = card->private_data; struct azx_pcm *p; + if (chip->disabled || chip->init_failed) + return 0; + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); azx_clear_irq_pending(chip); list_for_each_entry(p, &chip->pcm_list, list) @@ -2500,15 +606,19 @@ static int azx_suspend(struct device *dev) if (chip->initialized) snd_hda_suspend(chip->bus); azx_stop_chip(chip); + azx_enter_link_reset(chip); if (chip->irq >= 0) { free_irq(chip->irq, chip); chip->irq = -1; } + if (chip->msi) pci_disable_msi(chip->pci); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, PCI_D3hot); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(false); return 0; } @@ -2518,11 +628,18 @@ static int azx_resume(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; + if (chip->disabled || chip->init_failed) + return 0; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + hda_display_power(true); + haswell_set_bclk(chip); + } 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"); + dev_err(chip->card->dev, + "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2534,7 +651,7 @@ static int azx_resume(struct device *dev) return -EIO; azx_init_pci(chip); - azx_init_chip(chip, 1); + azx_init_chip(chip, true); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2548,11 +665,22 @@ static int azx_runtime_suspend(struct device *dev) struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; - if (!power_save_controller) - return -EAGAIN; + if (chip->disabled || chip->init_failed) + return 0; + + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return 0; + + /* enable controller wake up event */ + azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) | + STATESTS_INT_MASK); azx_stop_chip(chip); + azx_enter_link_reset(chip); azx_clear_irq_pending(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + hda_display_power(false); + return 0; } @@ -2560,17 +688,63 @@ static int azx_runtime_resume(struct device *dev) { struct snd_card *card = dev_get_drvdata(dev); struct azx *chip = card->private_data; + struct hda_bus *bus; + struct hda_codec *codec; + int status; + + if (chip->disabled || chip->init_failed) + return 0; + + if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return 0; + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + hda_display_power(true); + haswell_set_bclk(chip); + } + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); azx_init_pci(chip); - azx_init_chip(chip, 1); + azx_init_chip(chip, true); + + bus = chip->bus; + if (status && bus) { + list_for_each_entry(codec, &bus->codec_list, list) + if (status & (1 << codec->addr)) + queue_delayed_work(codec->bus->workq, + &codec->jackpoll_work, codec->jackpoll_interval); + } + + /* disable controller Wake Up event*/ + azx_writew(chip, WAKEEN, azx_readw(chip, WAKEEN) & + ~STATESTS_INT_MASK); + + return 0; +} + +static int azx_runtime_idle(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + + if (chip->disabled || chip->init_failed) + return 0; + + if (!power_save_controller || + !(chip->driver_caps & AZX_DCAPS_PM_RUNTIME)) + return -EBUSY; + return 0; } + #endif /* CONFIG_PM_RUNTIME */ #ifdef CONFIG_PM static const struct dev_pm_ops azx_pm = { SET_SYSTEM_SLEEP_PM_OPS(azx_suspend, azx_resume) - SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, NULL) + SET_RUNTIME_PM_OPS(azx_runtime_suspend, azx_runtime_resume, azx_runtime_idle) }; #define AZX_PM_OPS &azx_pm @@ -2602,11 +776,10 @@ static void azx_notifier_unregister(struct azx *chip) unregister_reboot_notifier(&chip->reboot_notifier); } -static int DELAYED_INIT_MARK azx_first_init(struct azx *chip); -static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip); +static int azx_probe_continue(struct azx *chip); #ifdef SUPPORT_VGA_SWITCHEROO -static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci); +static struct pci_dev *get_bound_vga(struct pci_dev *pci); static void azx_vs_set_state(struct pci_dev *pci, enum vga_switcheroo_state state) @@ -2615,6 +788,7 @@ static void azx_vs_set_state(struct pci_dev *pci, struct azx *chip = card->private_data; bool disabled; + wait_for_completion(&chip->probe_wait); if (chip->init_failed) return; @@ -2625,32 +799,32 @@ static void azx_vs_set_state(struct pci_dev *pci, if (!chip->bus) { chip->disabled = disabled; if (!disabled) { - snd_printk(KERN_INFO SFX - "%s: Start delayed initialization\n", - pci_name(chip->pci)); - if (azx_first_init(chip) < 0 || - azx_probe_continue(chip) < 0) { - snd_printk(KERN_ERR SFX - "%s: initialization error\n", - pci_name(chip->pci)); + dev_info(chip->card->dev, + "Start delayed initialization\n"); + if (azx_probe_continue(chip) < 0) { + dev_err(chip->card->dev, "initialization error\n"); chip->init_failed = true; } } } else { - snd_printk(KERN_INFO SFX - "%s %s via VGA-switcheroo\n", - disabled ? "Disabling" : "Enabling", - pci_name(chip->pci)); + dev_info(chip->card->dev, "%s via VGA-switcheroo\n", + disabled ? "Disabling" : "Enabling"); if (disabled) { - azx_suspend(&pci->dev); + pm_runtime_put_sync_suspend(card->dev); + azx_suspend(card->dev); + /* when we get suspended by vga switcheroo we end up in D3cold, + * however we have no ACPI handle, so pci/acpi can't put us there, + * put ourselves there */ + pci->current_state = PCI_D3cold; chip->disabled = true; if (snd_hda_lock_devices(chip->bus)) - snd_printk(KERN_WARNING SFX - "Cannot lock devices!\n"); + dev_warn(chip->card->dev, + "Cannot lock devices!\n"); } else { snd_hda_unlock_devices(chip->bus); + pm_runtime_get_noresume(card->dev); chip->disabled = false; - azx_resume(&pci->dev); + azx_resume(card->dev); } } } @@ -2660,6 +834,7 @@ static bool azx_vs_can_switch(struct pci_dev *pci) struct snd_card *card = pci_get_drvdata(pci); struct azx *chip = card->private_data; + wait_for_completion(&chip->probe_wait); if (chip->init_failed) return false; if (chip->disabled || !chip->bus) @@ -2670,13 +845,12 @@ static bool azx_vs_can_switch(struct pci_dev *pci) return true; } -static void __devinit init_vga_switcheroo(struct azx *chip) +static void init_vga_switcheroo(struct azx *chip) { struct pci_dev *p = get_bound_vga(chip->pci); if (p) { - snd_printk(KERN_INFO SFX - "%s: Handle VGA-switcheroo audio client\n", - pci_name(chip->pci)); + dev_info(chip->card->dev, + "Handle VGA-switcheroo audio client\n"); chip->use_vga_switcheroo = 1; pci_dev_put(p); } @@ -2687,7 +861,7 @@ static const struct vga_switcheroo_client_ops azx_vs_ops = { .can_switch = azx_vs_can_switch, }; -static int __devinit register_vga_switcheroo(struct azx *chip) +static int register_vga_switcheroo(struct azx *chip) { int err; @@ -2702,6 +876,10 @@ static int __devinit register_vga_switcheroo(struct azx *chip) if (err < 0) return err; chip->vga_switcheroo_registered = 1; + + /* register as an optimus hdmi audio power domain */ + vga_switcheroo_init_domain_pm_optimus_hdmi_audio(chip->card->dev, + &chip->hdmi_pm_domain); return 0; } #else @@ -2715,12 +893,22 @@ static int __devinit register_vga_switcheroo(struct azx *chip) */ static int azx_free(struct azx *chip) { + struct pci_dev *pci = chip->pci; + struct hda_intel *hda = container_of(chip, struct hda_intel, chip); + int i; + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) + && chip->running) + pm_runtime_get_noresume(&pci->dev); + azx_del_card_list(chip); azx_notifier_unregister(chip); + chip->init_failed = 1; /* to be sure */ + complete_all(&chip->probe_wait); + if (use_vga_switcheroo(chip)) { if (chip->disabled && chip->bus) snd_hda_unlock_devices(chip->bus); @@ -2742,21 +930,7 @@ static int azx_free(struct azx *chip) if (chip->remap_addr) iounmap(chip->remap_addr); - if (chip->azx_dev) { - for (i = 0; i < chip->num_streams; i++) - if (chip->azx_dev[i].bdl.area) { - mark_pages_wc(chip, &chip->azx_dev[i].bdl, false); - snd_dma_free_pages(&chip->azx_dev[i].bdl); - } - } - if (chip->rb.area) { - mark_pages_wc(chip, &chip->rb, false); - snd_dma_free_pages(&chip->rb); - } - if (chip->posbuf.area) { - mark_pages_wc(chip, &chip->posbuf, false); - snd_dma_free_pages(&chip->posbuf); - } + azx_free_stream_pages(chip); if (chip->region_requested) pci_release_regions(chip->pci); pci_disable_device(chip->pci); @@ -2765,7 +939,11 @@ static int azx_free(struct azx *chip) if (chip->fw) release_firmware(chip->fw); #endif - kfree(chip); + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { + hda_display_power(false); + hda_i915_exit(); + } + kfree(hda); return 0; } @@ -2779,7 +957,7 @@ static int azx_dev_free(struct snd_device *device) /* * Check of disabled HDMI controller by vga-switcheroo */ -static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci) +static struct pci_dev *get_bound_vga(struct pci_dev *pci) { struct pci_dev *p; @@ -2802,7 +980,7 @@ static struct pci_dev __devinit *get_bound_vga(struct pci_dev *pci) return NULL; } -static bool __devinit check_hdmi_disabled(struct pci_dev *pci) +static bool check_hdmi_disabled(struct pci_dev *pci) { bool vga_inactive = false; struct pci_dev *p = get_bound_vga(pci); @@ -2819,7 +997,7 @@ static bool __devinit check_hdmi_disabled(struct pci_dev *pci) /* * white/black-listing for position_fix */ -static struct snd_pci_quirk position_fix_list[] __devinitdata = { +static struct snd_pci_quirk position_fix_list[] = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), @@ -2837,7 +1015,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { {} }; -static int __devinit check_position_fix(struct azx *chip, int fix) +static int check_position_fix(struct azx *chip, int fix) { const struct snd_pci_quirk *q; @@ -2852,20 +1030,19 @@ static int __devinit check_position_fix(struct azx *chip, int fix) 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); + dev_info(chip->card->dev, + "position_fix set to %d for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); return q->value; } /* Check VIA/ATI HD Audio Controller exist */ if (chip->driver_caps & AZX_DCAPS_POSFIX_VIA) { - snd_printd(SFX "Using VIACOMBO position fix\n"); + dev_dbg(chip->card->dev, "Using VIACOMBO position fix\n"); return POS_FIX_VIACOMBO; } if (chip->driver_caps & AZX_DCAPS_POSFIX_LPIB) { - snd_printd(SFX "Using LPIB position fix\n"); + dev_dbg(chip->card->dev, "Using LPIB position fix\n"); return POS_FIX_LPIB; } return POS_FIX_AUTO; @@ -2874,7 +1051,7 @@ static int __devinit check_position_fix(struct azx *chip, int fix) /* * black-lists for probe_mask */ -static struct snd_pci_quirk probe_mask_list[] __devinitdata = { +static struct snd_pci_quirk probe_mask_list[] = { /* Thinkpad often breaks the controller communication when accessing * to the non-working (or non-existing) modem codec slot. */ @@ -2895,7 +1072,7 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { #define AZX_FORCE_CODEC_MASK 0x100 -static void __devinit check_probe_mask(struct azx *chip, int dev) +static void check_probe_mask(struct azx *chip, int dev) { const struct snd_pci_quirk *q; @@ -2903,10 +1080,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) if (chip->codec_probe_mask == -1) { q = snd_pci_quirk_lookup(chip->pci, probe_mask_list); if (q) { - printk(KERN_INFO - "hda_intel: probe_mask set to 0x%x " - "for device %04x:%04x\n", - q->value, q->subvendor, q->subdevice); + dev_info(chip->card->dev, + "probe_mask set to 0x%x for device %04x:%04x\n", + q->value, q->subvendor, q->subdevice); chip->codec_probe_mask = q->value; } } @@ -2915,24 +1091,29 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) if (chip->codec_probe_mask != -1 && (chip->codec_probe_mask & AZX_FORCE_CODEC_MASK)) { chip->codec_mask = chip->codec_probe_mask & 0xff; - printk(KERN_INFO "hda_intel: codec_mask forced to 0x%x\n", - chip->codec_mask); + dev_info(chip->card->dev, "codec_mask forced to 0x%x\n", + chip->codec_mask); } } /* * white/black-list for enable_msi */ -static struct snd_pci_quirk msi_black_list[] __devinitdata = { +static struct snd_pci_quirk msi_black_list[] = { + SND_PCI_QUIRK(0x103c, 0x2191, "HP", 0), /* AMD Hudson */ + SND_PCI_QUIRK(0x103c, 0x2192, "HP", 0), /* AMD Hudson */ + SND_PCI_QUIRK(0x103c, 0x21f7, "HP", 0), /* AMD Hudson */ + SND_PCI_QUIRK(0x103c, 0x21fa, "HP", 0), /* AMD Hudson */ SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */ SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */ + SND_PCI_QUIRK(0x1179, 0xfb44, "Toshiba Satellite C870", 0), /* AMD Hudson */ SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */ SND_PCI_QUIRK(0xa0a0, 0x0575, "Aopen MZ915-M", 0), /* ICH6 */ {} }; -static void __devinit check_msi(struct azx *chip) +static void check_msi(struct azx *chip) { const struct snd_pci_quirk *q; @@ -2943,22 +1124,22 @@ static void __devinit check_msi(struct azx *chip) chip->msi = 1; /* enable MSI as default */ q = snd_pci_quirk_lookup(chip->pci, msi_black_list); if (q) { - printk(KERN_INFO - "hda_intel: msi for device %04x:%04x set to %d\n", - q->subvendor, q->subdevice, q->value); + dev_info(chip->card->dev, + "msi for device %04x:%04x set to %d\n", + q->subvendor, q->subdevice, q->value); chip->msi = q->value; return; } /* NVidia chipsets seem to cause troubles with MSI */ if (chip->driver_caps & AZX_DCAPS_NO_MSI) { - printk(KERN_INFO "hda_intel: Disabling MSI\n"); + dev_info(chip->card->dev, "Disabling MSI\n"); chip->msi = 0; } } /* check the snoop mode availability */ -static void __devinit azx_check_snoop_available(struct azx *chip) +static void azx_check_snoop_available(struct azx *chip) { bool snoop = chip->snoop; @@ -2978,25 +1159,35 @@ static void __devinit azx_check_snoop_available(struct azx *chip) /* new ATI HDMI requires non-snoop */ snoop = false; break; + case AZX_DRIVER_CTHDA: + snoop = false; + break; } if (snoop != chip->snoop) { - snd_printk(KERN_INFO SFX "Force to %s mode\n", - snoop ? "snoop" : "non-snoop"); + dev_info(chip->card->dev, "Force to %s mode\n", + snoop ? "snoop" : "non-snoop"); chip->snoop = snoop; } } +static void azx_probe_work(struct work_struct *work) +{ + azx_probe_continue(container_of(work, struct azx, probe_work)); +} + /* * constructor */ -static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, - int dev, unsigned int driver_caps, - struct azx **rchip) +static int azx_create(struct snd_card *card, struct pci_dev *pci, + int dev, unsigned int driver_caps, + const struct hda_controller_ops *hda_ops, + struct azx **rchip) { static struct snd_device_ops ops = { .dev_free = azx_dev_free, }; + struct hda_intel *hda; struct azx *chip; int err; @@ -3006,26 +1197,30 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, if (err < 0) return err; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (!chip) { - snd_printk(KERN_ERR SFX "cannot allocate chip\n"); + hda = kzalloc(sizeof(*hda), GFP_KERNEL); + if (!hda) { + dev_err(card->dev, "Cannot allocate hda\n"); pci_disable_device(pci); return -ENOMEM; } + chip = &hda->chip; spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; + chip->ops = hda_ops; chip->irq = -1; chip->driver_caps = driver_caps; chip->driver_type = driver_caps & 0xff; check_msi(chip); chip->dev_index = dev; + chip->jackpoll_ms = jackpoll_ms; INIT_WORK(&chip->irq_pending_work, azx_irq_pending_work); INIT_LIST_HEAD(&chip->pcm_list); INIT_LIST_HEAD(&chip->list); init_vga_switcheroo(chip); + init_completion(&chip->probe_wait); chip->position_fix[0] = chip->position_fix[1] = check_position_fix(chip, position_fix[dev]); @@ -3052,44 +1247,29 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, break; } } + chip->bdl_pos_adj = bdl_pos_adj; - if (check_hdmi_disabled(pci)) { - snd_printk(KERN_INFO SFX "VGA controller for %s is disabled\n", - pci_name(pci)); - if (use_vga_switcheroo(chip)) { - snd_printk(KERN_INFO SFX "Delaying initialization\n"); - chip->disabled = true; - goto ok; - } - kfree(chip); - pci_disable_device(pci); - return -ENXIO; - } - - err = azx_first_init(chip); - if (err < 0) { - azx_free(chip); - return err; - } - - ok: err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); + dev_err(card->dev, "Error creating device [card]!\n"); azx_free(chip); return err; } + /* continue probing in work context as may trigger request module */ + INIT_WORK(&chip->probe_work, azx_probe_work); + *rchip = chip; + return 0; } -static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) +static int azx_first_init(struct azx *chip) { int dev = chip->dev_index; struct pci_dev *pci = chip->pci; struct snd_card *card = chip->card; - int i, err; + int err; unsigned short gcap; #if BITS_PER_LONG != 64 @@ -3110,7 +1290,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) chip->addr = pci_resource_start(pci, 0); chip->remap_addr = pci_ioremap_bar(pci, 0); if (chip->remap_addr == NULL) { - snd_printk(KERN_ERR SFX "ioremap error\n"); + dev_err(card->dev, "ioremap error\n"); return -ENXIO; } @@ -3125,7 +1305,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) synchronize_irq(chip->irq); gcap = azx_readw(chip, GCAP); - snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); + dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); /* disable SB600 64bit support for safety */ if (chip->pci->vendor == PCI_VENDOR_ID_ATI) { @@ -3142,7 +1322,7 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) /* disable 64bit DMA address on some devices */ if (chip->driver_caps & AZX_DCAPS_NO_64BIT) { - snd_printd(SFX "Disabling 64bit DMA\n"); + dev_dbg(card->dev, "Disabling 64bit DMA\n"); gcap &= ~ICH6_GCAP_64OK; } @@ -3197,32 +1377,11 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), GFP_KERNEL); if (!chip->azx_dev) { - snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n"); + dev_err(card->dev, "cannot malloc azx_dev\n"); return -ENOMEM; } - for (i = 0; i < chip->num_streams; i++) { - /* allocate memory for the BDL for each stream */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - BDL_SIZE, &chip->azx_dev[i].bdl); - if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate BDL\n"); - return -ENOMEM; - } - mark_pages_wc(chip, &chip->azx_dev[i].bdl, true); - } - /* allocate memory for the position buffer */ - err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, - snd_dma_pci_data(chip->pci), - chip->num_streams * 8, &chip->posbuf); - if (err < 0) { - snd_printk(KERN_ERR SFX "cannot allocate posbuf\n"); - return -ENOMEM; - } - mark_pages_wc(chip, &chip->posbuf, true); - /* allocate CORB/RIRB */ - err = azx_alloc_cmd_io(chip); + err = azx_alloc_stream_pages(chip); if (err < 0) return err; @@ -3231,11 +1390,15 @@ static int DELAYED_INIT_MARK azx_first_init(struct azx *chip) /* initialize chip */ azx_init_pci(chip); + + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + haswell_set_bclk(chip); + azx_init_chip(chip, (probe_only[dev] & 2) == 0); /* codec detection */ if (!chip->codec_mask) { - snd_printk(KERN_ERR SFX "no codecs found!\n"); + dev_err(card->dev, "no codecs found!\n"); return -ENODEV; } @@ -3271,7 +1434,7 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) struct pci_dev *pci = chip->pci; if (!fw) { - snd_printk(KERN_ERR SFX "Cannot load firmware, aborting\n"); + dev_err(card->dev, "Cannot load firmware, aborting\n"); goto error; } @@ -3289,13 +1452,139 @@ static void azx_firmware_cb(const struct firmware *fw, void *context) } #endif -static int __devinit azx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +/* + * HDA controller ops. + */ + +/* PCI register access. */ +static void pci_azx_writel(u32 value, u32 __iomem *addr) +{ + writel(value, addr); +} + +static u32 pci_azx_readl(u32 __iomem *addr) +{ + return readl(addr); +} + +static void pci_azx_writew(u16 value, u16 __iomem *addr) +{ + writew(value, addr); +} + +static u16 pci_azx_readw(u16 __iomem *addr) +{ + return readw(addr); +} + +static void pci_azx_writeb(u8 value, u8 __iomem *addr) +{ + writeb(value, addr); +} + +static u8 pci_azx_readb(u8 __iomem *addr) +{ + return readb(addr); +} + +static int disable_msi_reset_irq(struct azx *chip) +{ + int err; + + free_irq(chip->irq, chip); + chip->irq = -1; + pci_disable_msi(chip->pci); + chip->msi = 0; + err = azx_acquire_irq(chip, 1); + if (err < 0) + return err; + + return 0; +} + +/* DMA page allocation helpers. */ +static int dma_alloc_pages(struct azx *chip, + int type, + size_t size, + struct snd_dma_buffer *buf) +{ + int err; + + err = snd_dma_alloc_pages(type, + chip->card->dev, + size, buf); + if (err < 0) + return err; + mark_pages_wc(chip, buf, true); + return 0; +} + +static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf) +{ + mark_pages_wc(chip, buf, false); + snd_dma_free_pages(buf); +} + +static int substream_alloc_pages(struct azx *chip, + struct snd_pcm_substream *substream, + size_t size) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + int ret; + + mark_runtime_wc(chip, azx_dev, substream, false); + azx_dev->bufsize = 0; + azx_dev->period_bytes = 0; + azx_dev->format_val = 0; + ret = snd_pcm_lib_malloc_pages(substream, size); + if (ret < 0) + return ret; + mark_runtime_wc(chip, azx_dev, substream, true); + return 0; +} + +static int substream_free_pages(struct azx *chip, + struct snd_pcm_substream *substream) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + mark_runtime_wc(chip, azx_dev, substream, false); + return snd_pcm_lib_free_pages(substream); +} + +static void pcm_mmap_prepare(struct snd_pcm_substream *substream, + struct vm_area_struct *area) +{ +#ifdef CONFIG_X86 + struct azx_pcm *apcm = snd_pcm_substream_chip(substream); + struct azx *chip = apcm->chip; + if (!azx_snoop(chip)) + area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); +#endif +} + +static const struct hda_controller_ops pci_hda_ops = { + .reg_writel = pci_azx_writel, + .reg_readl = pci_azx_readl, + .reg_writew = pci_azx_writew, + .reg_readw = pci_azx_readw, + .reg_writeb = pci_azx_writeb, + .reg_readb = pci_azx_readb, + .disable_msi_reset_irq = disable_msi_reset_irq, + .dma_alloc_pages = dma_alloc_pages, + .dma_free_pages = dma_free_pages, + .substream_alloc_pages = substream_alloc_pages, + .substream_free_pages = substream_free_pages, + .pcm_mmap_prepare = pcm_mmap_prepare, + .position_check = azx_position_check, +}; + +static int azx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; struct azx *chip; - bool probe_now; + bool schedule_probe; int err; if (dev >= SNDRV_CARDS) @@ -3305,52 +1594,59 @@ static int __devinit azx_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating card!\n"); + dev_err(&pci->dev, "Error creating card!\n"); return err; } - snd_card_set_dev(card, &pci->dev); - - err = azx_create(card, pci, dev, pci_id->driver_data, &chip); + err = azx_create(card, pci, dev, pci_id->driver_data, + &pci_hda_ops, &chip); if (err < 0) goto out_free; card->private_data = chip; - probe_now = !chip->disabled; + + pci_set_drvdata(pci, card); + + err = register_vga_switcheroo(chip); + if (err < 0) { + dev_err(card->dev, "Error registering VGA-switcheroo client\n"); + goto out_free; + } + + if (check_hdmi_disabled(pci)) { + dev_info(card->dev, "VGA controller is disabled\n"); + dev_info(card->dev, "Delaying initialization\n"); + chip->disabled = true; + } + + schedule_probe = !chip->disabled; #ifdef CONFIG_SND_HDA_PATCH_LOADER if (patch[dev] && *patch[dev]) { - snd_printk(KERN_ERR SFX "Applying patch firmware '%s'\n", - patch[dev]); + dev_info(card->dev, "Applying patch firmware '%s'\n", + patch[dev]); err = request_firmware_nowait(THIS_MODULE, true, patch[dev], &pci->dev, GFP_KERNEL, card, azx_firmware_cb); if (err < 0) goto out_free; - probe_now = false; /* continued in azx_firmware_cb() */ + schedule_probe = false; /* continued in azx_firmware_cb() */ } #endif /* CONFIG_SND_HDA_PATCH_LOADER */ - if (probe_now) { - err = azx_probe_continue(chip); - if (err < 0) - goto out_free; - } - - pci_set_drvdata(pci, card); - - if (pci_dev_run_wake(pci)) - pm_runtime_put_noidle(&pci->dev); +#ifndef CONFIG_SND_HDA_I915 + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) + dev_err(card->dev, "Haswell must build in CONFIG_SND_HDA_I915\n"); +#endif - err = register_vga_switcheroo(chip); - if (err < 0) { - snd_printk(KERN_ERR SFX - "Error registering VGA-switcheroo client\n"); - goto out_free; - } + if (schedule_probe) + schedule_work(&chip->probe_work); dev++; + if (chip->disabled) + complete_all(&chip->probe_wait); return 0; out_free: @@ -3358,17 +1654,49 @@ out_free: return err; } -static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) +/* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ +static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] = { + [AZX_DRIVER_NVIDIA] = 8, + [AZX_DRIVER_TERA] = 1, +}; + +static int azx_probe_continue(struct azx *chip) { + struct pci_dev *pci = chip->pci; int dev = chip->dev_index; int err; + /* Request power well for Haswell HDA controller and codec */ + if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) { +#ifdef CONFIG_SND_HDA_I915 + err = hda_i915_init(); + if (err < 0) { + dev_err(chip->card->dev, + "Error request power-well from i915\n"); + goto out_free; + } + err = hda_display_power(true); + if (err < 0) { + dev_err(chip->card->dev, + "Cannot turn on display power on i915\n"); + goto out_free; + } +#endif + } + + err = azx_first_init(chip); + if (err < 0) + goto out_free; + #ifdef CONFIG_SND_HDA_INPUT_BEEP chip->beep_mode = beep_mode[dev]; #endif /* create codec instances */ - err = azx_codec_create(chip, model[dev]); + err = azx_codec_create(chip, model[dev], + azx_max_codecs[chip->driver_type], + power_save_addr); + if (err < 0) goto out_free; #ifdef CONFIG_SND_HDA_PATCH_LOADER @@ -3377,8 +1705,10 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) chip->fw->data); if (err < 0) goto out_free; +#ifndef CONFIG_PM release_firmware(chip->fw); /* no longer needed */ chip->fw = NULL; +#endif } #endif if ((probe_only[dev] & 1) == 0) { @@ -3405,70 +1735,77 @@ static int DELAYED_INIT_MARK azx_probe_continue(struct azx *chip) power_down_all_codecs(chip); azx_notifier_register(chip); azx_add_card_list(chip); - - return 0; + if ((chip->driver_caps & AZX_DCAPS_PM_RUNTIME) || chip->use_vga_switcheroo) + pm_runtime_put_noidle(&pci->dev); out_free: - chip->init_failed = 1; + if (err < 0) + chip->init_failed = 1; + complete_all(&chip->probe_wait); return err; } -static void __devexit azx_remove(struct pci_dev *pci) +static void azx_remove(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); - if (pci_dev_run_wake(pci)) - pm_runtime_get_noresume(&pci->dev); - if (card) snd_card_free(card); - pci_set_drvdata(pci, NULL); } /* PCI IDs */ -static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { +static const struct pci_device_id azx_ids[] = { /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* PBG */ { PCI_DEVICE(0x8086, 0x1d20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE}, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* Panther Point */ { PCI_DEVICE(0x8086, 0x1e20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point */ { PCI_DEVICE(0x8086, 0x8c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + /* 9 Series */ + { PCI_DEVICE(0x8086, 0x8ca0), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + /* Wellsburg */ + { PCI_DEVICE(0x8086, 0x8d20), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + { PCI_DEVICE(0x8086, 0x8d21), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c20), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Lynx Point-LP */ { PCI_DEVICE(0x8086, 0x9c21), - .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, + /* Wildcat Point-LP */ + { PCI_DEVICE(0x8086, 0x9ca0), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH }, /* Haswell */ + { PCI_DEVICE(0x8086, 0x0a0c), + .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, { PCI_DEVICE(0x8086, 0x0c0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, { PCI_DEVICE(0x8086, 0x0d0c), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, + .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_HASWELL }, + /* Broadwell */ + { PCI_DEVICE(0x8086, 0x160c), + .driver_data = AZX_DRIVER_HDMI | AZX_DCAPS_INTEL_BROADWELL }, /* 5 Series/3400 */ { PCI_DEVICE(0x8086, 0x3b56), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY }, - /* SCH */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* Poulsbo */ { PCI_DEVICE(0x8086, 0x811b), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Poulsbo */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* Oaktrail */ { PCI_DEVICE(0x8086, 0x080a), - .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_SCH_SNOOP | - AZX_DCAPS_BUFSIZE | AZX_DCAPS_POSFIX_LPIB }, /* Oaktrail */ + .driver_data = AZX_DRIVER_SCH | AZX_DCAPS_INTEL_PCH_NOPM }, + /* BayTrail */ + { PCI_DEVICE(0x8086, 0x0f04), + .driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH_NOPM }, /* ICH */ { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC | @@ -3536,6 +1873,22 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(0x1002, 0xaa48), .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa50), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa58), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa60), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa68), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa80), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa88), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa90), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, + { PCI_DEVICE(0x1002, 0xaa98), + .driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(0x1002, 0x9902), .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI }, { PCI_DEVICE(0x1002, 0xaaa0), @@ -3563,13 +1916,15 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { /* Teradici */ { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, + { PCI_DEVICE(0x6549, 0x2200), + .driver_data = AZX_DRIVER_TERA | AZX_DCAPS_NO_64BIT }, /* Creative X-Fi (CA0110-IBG) */ /* CTHDA chips */ { PCI_DEVICE(0x1102, 0x0010), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, { PCI_DEVICE(0x1102, 0x0012), .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, -#if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) +#if !IS_ENABLED(CONFIG_SND_CTXFI) /* the following entry conflicts with snd-ctxfi driver, * as ctxfi driver mutates from HD-audio to native mode with * a special command sequence. @@ -3607,7 +1962,7 @@ static struct pci_driver azx_driver = { .name = KBUILD_MODNAME, .id_table = azx_ids, .probe = azx_probe, - .remove = __devexit_p(azx_remove), + .remove = azx_remove, .driver = { .pm = AZX_PM_OPS, }, diff --git a/sound/pci/hda/hda_intel_trace.h b/sound/pci/hda/hda_intel_trace.h new file mode 100644 index 00000000000..7b5e4c2cf9d --- /dev/null +++ b/sound/pci/hda/hda_intel_trace.h @@ -0,0 +1,62 @@ +#undef TRACE_SYSTEM +#define TRACE_SYSTEM hda_intel +#define TRACE_INCLUDE_FILE hda_intel_trace + +#if !defined(_TRACE_HDA_INTEL_H) || defined(TRACE_HEADER_MULTI_READ) +#define _TRACE_HDA_INTEL_H + +#include <linux/tracepoint.h> + +struct azx; +struct azx_dev; + +TRACE_EVENT(azx_pcm_trigger, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, int cmd), + + TP_ARGS(chip, dev, cmd), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( int, cmd ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->cmd = cmd; + ), + + TP_printk("[%d:%d] cmd=%d", __entry->card, __entry->idx, __entry->cmd) +); + +TRACE_EVENT(azx_get_position, + + TP_PROTO(struct azx *chip, struct azx_dev *dev, unsigned int pos, unsigned int delay), + + TP_ARGS(chip, dev, pos, delay), + + TP_STRUCT__entry( + __field( int, card ) + __field( int, idx ) + __field( unsigned int, pos ) + __field( unsigned int, delay ) + ), + + TP_fast_assign( + __entry->card = (chip)->card->number; + __entry->idx = (dev)->index; + __entry->pos = pos; + __entry->delay = delay; + ), + + TP_printk("[%d:%d] pos=%u, delay=%u", __entry->card, __entry->idx, __entry->pos, __entry->delay) +); + +#endif /* _TRACE_HDA_INTEL_H */ + +/* This part must be outside protection */ +#undef TRACE_INCLUDE_PATH +#define TRACE_INCLUDE_PATH . +#include <trace/define_trace.h> diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c index 5c690cb873d..9746d73cec5 100644 --- a/sound/pci/hda/hda_jack.c +++ b/sound/pci/hda/hda_jack.c @@ -29,16 +29,18 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) if (get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & AC_DEFCFG_MISC_NO_PRESENCE) return false; - if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP)) + if (!(get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) && + !codec->jackpoll_interval) return false; return true; } -EXPORT_SYMBOL_HDA(is_jack_detectable); +EXPORT_SYMBOL_GPL(is_jack_detectable); /* execute pin sense measurement */ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) { u32 pincap; + u32 val; if (!codec->no_trigger_sense) { pincap = snd_hda_query_pin_caps(codec, nid); @@ -46,8 +48,11 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid) snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); } - return snd_hda_codec_read(codec, nid, 0, + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); + if (codec->inv_jack_detect) + val ^= AC_PINSENSE_PRESENCE; + return val; } /** @@ -66,7 +71,7 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid) return jack; return NULL; } -EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get); +EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get); /** * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag @@ -84,7 +89,7 @@ snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag) return jack; return NULL; } -EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_get_from_tag); +EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag); /** * snd_hda_jack_tbl_new - create a jack-table entry for the given NID @@ -95,7 +100,6 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); if (jack) return jack; - snd_array_init(&codec->jacktbl, sizeof(*jack), 16); jack = snd_array_new(&codec->jacktbl); if (!jack) return NULL; @@ -104,7 +108,7 @@ snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid) jack->tag = codec->jacktbl.used; return jack; } -EXPORT_SYMBOL_HDA(snd_hda_jack_tbl_new); +EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_new); void snd_hda_jack_tbl_clear(struct hda_codec *codec) { @@ -122,6 +126,8 @@ void snd_hda_jack_tbl_clear(struct hda_codec *codec) snd_array_free(&codec->jacktbl); } +#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) + /* update the cached value and notification flag if needed */ static void jack_detect_update(struct hda_codec *codec, struct hda_jack_tbl *jack) @@ -134,7 +140,21 @@ static void jack_detect_update(struct hda_codec *codec, else jack->pin_sense = read_pin_sense(codec, jack->nid); + /* A gating jack indicates the jack is invalid if gating is unplugged */ + if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack)) + jack->pin_sense &= ~AC_PINSENSE_PRESENCE; + jack->jack_dirty = 0; + + /* If a jack is gated by this one update it. */ + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated) { + gated->jack_dirty = 1; + jack_detect_update(codec, gated); + } + } } /** @@ -152,7 +172,7 @@ void snd_hda_jack_set_dirty_all(struct hda_codec *codec) if (jack->nid) jack->jack_dirty = 1; } -EXPORT_SYMBOL_HDA(snd_hda_jack_set_dirty_all); +EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all); /** * snd_hda_pin_sense - execute pin sense measurement @@ -171,23 +191,27 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) } return read_pin_sense(codec, nid); } -EXPORT_SYMBOL_HDA(snd_hda_pin_sense); - -#define get_jack_plug_state(sense) !!(sense & AC_PINSENSE_PRESENCE) +EXPORT_SYMBOL_GPL(snd_hda_pin_sense); /** - * snd_hda_jack_detect - query pin Presence Detect status + * snd_hda_jack_detect_state - query pin Presence Detect status * @codec: the CODEC to sense * @nid: the pin NID to sense * - * Query and return the pin's Presence Detect status. + * Query and return the pin's Presence Detect status, as either + * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM. */ -int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid) { - u32 sense = snd_hda_pin_sense(codec, nid); - return get_jack_plug_state(sense); + struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid); + if (jack && jack->phantom_jack) + return HDA_JACK_PHANTOM; + else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE) + return HDA_JACK_PRESENT; + else + return HDA_JACK_NOT_PRESENT; } -EXPORT_SYMBOL_HDA(snd_hda_jack_detect); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state); /** * snd_hda_jack_detect_enable - enable the jack-detection @@ -206,31 +230,63 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, jack->action = action; if (cb) jack->callback = cb; + if (codec->jackpoll_interval > 0) + return 0; /* No unsol if we're polling instead */ return snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | jack->tag); } -EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable_callback); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback); int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid, unsigned char action) { return snd_hda_jack_detect_enable_callback(codec, nid, action, NULL); } -EXPORT_SYMBOL_HDA(snd_hda_jack_detect_enable); +EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable); + +/** + * snd_hda_jack_set_gating_jack - Set gating jack. + * + * Indicates the gated jack is only valid when the gating jack is plugged. + */ +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_nid) +{ + struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid); + struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid); + + if (!gated || !gating) + return -EINVAL; + + gated->gating_jack = gating_nid; + gating->gated_jack = gated_nid; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack); /** * snd_hda_jack_report_sync - sync the states of all jacks and report if changed */ void snd_hda_jack_report_sync(struct hda_codec *codec) { - struct hda_jack_tbl *jack = codec->jacktbl.list; + struct hda_jack_tbl *jack; int i, state; + /* update all jacks at first */ + jack = codec->jacktbl.list; for (i = 0; i < codec->jacktbl.used; i++, jack++) - if (jack->nid) { + if (jack->nid) jack_detect_update(codec, jack); - if (!jack->kctl) + + /* report the updated jacks; it's done after updating all jacks + * to make sure that all gating jacks properly have been set + */ + jack = codec->jacktbl.list; + for (i = 0; i < codec->jacktbl.used; i++, jack++) + if (jack->nid) { + if (!jack->kctl || jack->block_report) continue; state = get_jack_plug_state(jack->pin_sense); snd_kctl_jack_report(codec->bus->card, jack->kctl, state); @@ -241,7 +297,7 @@ void snd_hda_jack_report_sync(struct hda_codec *codec) #endif } } -EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync); +EXPORT_SYMBOL_GPL(snd_hda_jack_report_sync); #ifdef CONFIG_SND_HDA_INPUT_JACK /* guess the jack type from the pin-config */ @@ -321,7 +377,7 @@ int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid, { return __snd_hda_jack_add_kctl(codec, nid, name, idx, false); } -EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctl); +EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl); /* get the unique index number for the given kctl name */ static int get_unique_index(struct hda_codec *codec, const char *name, int idx) @@ -344,10 +400,11 @@ static int get_unique_index(struct hda_codec *codec, const char *name, int idx) } static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg) + const struct auto_pin_cfg *cfg, + const char *base_name) { unsigned int def_conf, conn; - char name[44]; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; int idx, err; bool phantom_jack; @@ -360,7 +417,11 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid, phantom_jack = (conn != AC_JACK_PORT_COMPLEX) || !is_jack_detectable(codec, nid); - snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); + if (base_name) { + strlcpy(name, base_name, sizeof(name)); + idx = 0; + } else + snd_hda_get_pin_label(codec, nid, cfg, name, sizeof(name), &idx); if (phantom_jack) /* Example final name: "Internal Mic Phantom Jack" */ strncat(name, " Phantom", sizeof(name) - strlen(name) - 1); @@ -383,44 +444,69 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec, const hda_nid_t *p; int i, err; + for (i = 0; i < cfg->num_inputs; i++) { + /* If we have headphone mics; make sure they get the right name + before grabbed by output pins */ + if (cfg->inputs[i].is_headphone_mic) { + if (auto_cfg_hp_outs(cfg) == 1) + err = add_jack_kctl(codec, auto_cfg_hp_pins(cfg)[0], + cfg, "Headphone Mic"); + else + err = add_jack_kctl(codec, cfg->inputs[i].pin, + cfg, "Headphone Mic"); + } else + err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg, + NULL); + if (err < 0) + return err; + } + for (i = 0, p = cfg->line_out_pins; i < cfg->line_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } for (i = 0, p = cfg->hp_pins; i < cfg->hp_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } for (i = 0, p = cfg->speaker_pins; i < cfg->speaker_outs; i++, p++) { if (*p == *cfg->line_out_pins) /* might be duplicated */ break; - err = add_jack_kctl(codec, *p, cfg); - if (err < 0) - return err; - } - for (i = 0; i < cfg->num_inputs; i++) { - err = add_jack_kctl(codec, cfg->inputs[i].pin, cfg); + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } for (i = 0, p = cfg->dig_out_pins; i < cfg->dig_outs; i++, p++) { - err = add_jack_kctl(codec, *p, cfg); + err = add_jack_kctl(codec, *p, cfg, NULL); if (err < 0) return err; } - err = add_jack_kctl(codec, cfg->dig_in_pin, cfg); + err = add_jack_kctl(codec, cfg->dig_in_pin, cfg, NULL); if (err < 0) return err; - err = add_jack_kctl(codec, cfg->mono_out_pin, cfg); + err = add_jack_kctl(codec, cfg->mono_out_pin, cfg, NULL); if (err < 0) return err; return 0; } -EXPORT_SYMBOL_HDA(snd_hda_jack_add_kctls); +EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctls); + +static void call_jack_callback(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + if (jack->callback) + jack->callback(codec, jack); + if (jack->gated_jack) { + struct hda_jack_tbl *gated = + snd_hda_jack_tbl_get(codec, jack->gated_jack); + if (gated && gated->callback) + gated->callback(codec, gated); + } +} void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -432,10 +518,29 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res) return; event->jack_dirty = 1; - if (event->callback) - event->callback(codec, event); - + call_jack_callback(codec, event); snd_hda_jack_report_sync(codec); } -EXPORT_SYMBOL_HDA(snd_hda_jack_unsol_event); +EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event); + +void snd_hda_jack_poll_all(struct hda_codec *codec) +{ + struct hda_jack_tbl *jack = codec->jacktbl.list; + int i, changes = 0; + + for (i = 0; i < codec->jacktbl.used; i++, jack++) { + unsigned int old_sense; + if (!jack->nid || !jack->jack_dirty || jack->phantom_jack) + continue; + old_sense = get_jack_plug_state(jack->pin_sense); + jack_detect_update(codec, jack); + if (old_sense == get_jack_plug_state(jack->pin_sense)) + continue; + changes = 1; + call_jack_callback(codec, jack); + } + if (changes) + snd_hda_jack_report_sync(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_jack_poll_all); diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h index af8dd4724da..46e1ea83ce3 100644 --- a/sound/pci/hda/hda_jack.h +++ b/sound/pci/hda/hda_jack.h @@ -28,6 +28,9 @@ struct hda_jack_tbl { unsigned int jack_detect:1; /* capable of jack-detection? */ unsigned int jack_dirty:1; /* needs to update? */ unsigned int phantom_jack:1; /* a fixed, always present port? */ + unsigned int block_report:1; /* in a transitional state - do not report to userspace */ + hda_nid_t gating_jack; /* valid when gating jack plugged */ + hda_nid_t gated_jack; /* gated is dependent on this jack */ struct snd_kcontrol *kctl; /* assigned kctl for jack-detection */ #ifdef CONFIG_SND_HDA_INPUT_JACK int type; @@ -69,9 +72,22 @@ int snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid, unsigned char action, hda_jack_callback cb); +int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid, + hda_nid_t gating_nid); u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); + +/* the jack state returned from snd_hda_jack_detect_state() */ +enum { + HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT, HDA_JACK_PHANTOM, +}; + +int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid); + +static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +{ + return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT; +} bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid); @@ -84,4 +100,6 @@ void snd_hda_jack_report_sync(struct hda_codec *codec); void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res); +void snd_hda_jack_poll_all(struct hda_codec *codec); + #endif /* __SOUND_HDA_JACK_H */ diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 09dbdc37f78..4e2d4863daa 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -133,9 +133,11 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, int mask, int val); -#ifdef CONFIG_PM +int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch, + int direction, int idx, int mask, int val); +int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid, + int dir, int idx, int mask, int val); void snd_hda_codec_resume_amp(struct hda_codec *codec); -#endif void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv); @@ -240,9 +242,11 @@ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, /* * SPDIF I/O */ -int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, - hda_nid_t associated_nid, - hda_nid_t cvt_nid); +int snd_hda_create_dig_out_ctls(struct hda_codec *codec, + hda_nid_t associated_nid, + hda_nid_t cvt_nid, int type); +#define snd_hda_create_spdif_out_ctls(codec, anid, cnid) \ + snd_hda_create_dig_out_ctls(codec, anid, cnid, HDA_PCM_TYPE_SPDIF) int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid); /* @@ -348,14 +352,8 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, /* * generic codec parser */ -#ifdef CONFIG_SND_HDA_GENERIC int snd_hda_parse_generic_codec(struct hda_codec *codec); -#else -static inline int snd_hda_parse_generic_codec(struct hda_codec *codec) -{ - return -ENODEV; -} -#endif +int snd_hda_parse_hdmi_codec(struct hda_codec *codec); /* * generic proc interface @@ -382,6 +380,97 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, const struct snd_kcontrol_new *knew); /* + * Fix-up pin default configurations and add default verbs + */ + +struct hda_pintbl { + hda_nid_t nid; + u32 val; +}; + +struct hda_model_fixup { + const int id; + const char *name; +}; + +struct hda_fixup { + int type; + bool chained:1; /* call the chained fixup(s) after this */ + bool chained_before:1; /* call the chained fixup(s) before this */ + int chain_id; + union { + const struct hda_pintbl *pins; + const struct hda_verb *verbs; + void (*func)(struct hda_codec *codec, + const struct hda_fixup *fix, + int action); + } v; +}; + +struct snd_hda_pin_quirk { + unsigned int codec; /* Codec vendor/device ID */ + unsigned short subvendor; /* PCI subvendor ID */ + const struct hda_pintbl *pins; /* list of matching pins */ +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *name; +#endif + int value; /* quirk value */ +}; + +#ifdef CONFIG_SND_DEBUG_VERBOSE + +#define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \ + { .codec = _codec,\ + .subvendor = _subvendor,\ + .name = _name,\ + .value = _value,\ + .pins = (const struct hda_pintbl[]) { _pins } \ + } +#else + +#define SND_HDA_PIN_QUIRK(_codec, _subvendor, _name, _value, _pins...) \ + { .codec = _codec,\ + .subvendor = _subvendor,\ + .value = _value,\ + .pins = (const struct hda_pintbl[]) { _pins } \ + } + +#endif + + +/* fixup types */ +enum { + HDA_FIXUP_INVALID, + HDA_FIXUP_PINS, + HDA_FIXUP_VERBS, + HDA_FIXUP_FUNC, + HDA_FIXUP_PINCTLS, +}; + +/* fixup action definitions */ +enum { + HDA_FIXUP_ACT_PRE_PROBE, + HDA_FIXUP_ACT_PROBE, + HDA_FIXUP_ACT_INIT, + HDA_FIXUP_ACT_BUILD, + HDA_FIXUP_ACT_FREE, +}; + +int snd_hda_add_verbs(struct hda_codec *codec, const struct hda_verb *list); +void snd_hda_apply_verbs(struct hda_codec *codec); +void snd_hda_apply_pincfgs(struct hda_codec *codec, + const struct hda_pintbl *cfg); +void snd_hda_apply_fixup(struct hda_codec *codec, int action); +void snd_hda_pick_fixup(struct hda_codec *codec, + const struct hda_model_fixup *models, + const struct snd_pci_quirk *quirk, + const struct hda_fixup *fixlist); +void snd_hda_pick_pin_fixup(struct hda_codec *codec, + const struct snd_hda_pin_quirk *pin_quirk, + const struct hda_fixup *fixlist); + + +/* * unsolicited event handler */ @@ -429,6 +518,8 @@ struct hda_bus_unsolicited { #define PIN_HP_AMP (AC_PINCTL_HP_EN) unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin); +unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec, + hda_nid_t pin, unsigned int val); int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val, bool cached); @@ -468,6 +559,10 @@ snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin, return _snd_hda_set_pin_ctl(codec, pin, val, true); } +int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid); +int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid, + unsigned int val); + /* * get widget capabilities */ @@ -497,6 +592,14 @@ static inline unsigned int get_wcaps_channels(u32 wcaps) return chans; } +static inline void snd_hda_override_wcaps(struct hda_codec *codec, + hda_nid_t nid, u32 val) +{ + if (nid >= codec->start_nid && + nid < codec->start_nid + codec->num_nodes) + codec->wcaps[nid - codec->start_nid] = val; +} + u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); @@ -529,27 +632,15 @@ int snd_hda_create_hwdep(struct hda_codec *codec); static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif -#if defined(CONFIG_PM) && defined(CONFIG_SND_HDA_HWDEP) -int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec); -#else -static inline int snd_hda_hwdep_add_power_sysfs(struct hda_codec *codec) -{ - return 0; -} -#endif +void snd_hda_sysfs_init(struct hda_codec *codec); +void snd_hda_sysfs_clear(struct hda_codec *codec); -#ifdef CONFIG_SND_HDA_RECONFIG -int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); -#else -static inline int snd_hda_hwdep_add_sysfs(struct hda_codec *codec) -{ - return 0; -} -#endif +extern const struct attribute_group *snd_hda_dev_attr_groups[]; #ifdef CONFIG_SND_HDA_RECONFIG const char *snd_hda_get_hint(struct hda_codec *codec, const char *key); int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key); +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp); #else static inline const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) @@ -562,6 +653,12 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) { return -ENOENT; } + +static inline +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) +{ + return -ENOENT; +} #endif /* @@ -585,6 +682,23 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid); +/* check whether the actual power state matches with the target state */ +static inline bool +snd_hda_check_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int target_state) +{ + unsigned int state = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_POWER_STATE, 0); + if (state & AC_PWRST_ERROR) + return true; + state = (state >> 4) & 0x0f; + return (state == target_state); +} + +unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state); + /* * AMP control callbacks */ @@ -594,11 +708,21 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction_(pv) (((pv) >> 18) & 0x1) #define get_amp_direction(kc) get_amp_direction_((kc)->private_value) -#define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) +#define get_amp_index_(pv) (((pv) >> 19) & 0xf) +#define get_amp_index(kc) get_amp_index_((kc)->private_value) #define get_amp_offset(kc) (((kc)->private_value >> 23) & 0x3f) #define get_amp_min_mute(kc) (((kc)->private_value >> 29) & 0x1) /* + * enum control helper + */ +int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo, + int num_entries, const char * const *texts); +#define snd_hda_enum_bool_helper_info(kcontrol, uinfo) \ + snd_hda_enum_helper_info(kcontrol, uinfo, 0, NULL) + +/* * CEA Short Audio Descriptor data */ struct cea_sad { @@ -618,10 +742,10 @@ struct cea_sad { /* * ELD: EDID Like Data */ -struct hdmi_eld { - bool monitor_present; - bool eld_valid; - int eld_size; +struct parsed_hdmi_eld { + /* + * all fields will be cleared before updating ELD + */ int baseline_len; int eld_ver; int cea_edid_ver; @@ -636,39 +760,44 @@ struct hdmi_eld { int spk_alloc; int sad_count; struct cea_sad sad[ELD_MAX_SAD]; - /* - * all fields above eld_buffer will be cleared before updating ELD - */ +}; + +struct hdmi_eld { + bool monitor_present; + bool eld_valid; + int eld_size; char eld_buffer[ELD_MAX_SIZE]; -#ifdef CONFIG_PROC_FS - struct snd_info_entry *proc_entry; -#endif + struct parsed_hdmi_eld info; }; int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid); -int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); -void snd_hdmi_show_eld(struct hdmi_eld *eld); -void snd_hdmi_eld_update_pcm_info(struct hdmi_eld *eld, +int snd_hdmi_get_eld(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size); +int snd_hdmi_parse_eld(struct parsed_hdmi_eld *e, + const unsigned char *buf, int size); +void snd_hdmi_show_eld(struct parsed_hdmi_eld *e); +void snd_hdmi_eld_update_pcm_info(struct parsed_hdmi_eld *e, struct hda_pcm_stream *hinfo); +int snd_hdmi_get_eld_ati(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size, + bool rev3_or_later); + #ifdef CONFIG_PROC_FS -int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, - int index); -void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld); -#else -static inline int snd_hda_eld_proc_new(struct hda_codec *codec, - struct hdmi_eld *eld, - int index) -{ - return 0; -} -static inline void snd_hda_eld_proc_free(struct hda_codec *codec, - struct hdmi_eld *eld) -{ -} +void snd_hdmi_print_eld_info(struct hdmi_eld *eld, + struct snd_info_buffer *buffer); +void snd_hdmi_write_eld_info(struct hdmi_eld *eld, + struct snd_info_buffer *buffer); #endif #define SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE 80 void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen); +/* + */ +#define codec_err(codec, fmt, args...) dev_err(&(codec)->dev, fmt, ##args) +#define codec_warn(codec, fmt, args...) dev_warn(&(codec)->dev, fmt, ##args) +#define codec_info(codec, fmt, args...) dev_info(&(codec)->dev, fmt, ##args) +#define codec_dbg(codec, fmt, args...) dev_dbg(&(codec)->dev, fmt, ##args) + #endif /* __SOUND_HDA_LOCAL_H */ diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h new file mode 100644 index 00000000000..e9d1a5762a5 --- /dev/null +++ b/sound/pci/hda/hda_priv.h @@ -0,0 +1,465 @@ +/* + * Common defines for the alsa driver code base for HD Audio. + * + * 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 Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + */ + +#ifndef __SOUND_HDA_PRIV_H +#define __SOUND_HDA_PRIV_H + +#include <linux/clocksource.h> +#include <sound/core.h> +#include <sound/pcm.h> + +/* + * registers + */ +#define ICH6_REG_GCAP 0x00 +#define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ +#define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ +#define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ +#define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ +#define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ +#define ICH6_REG_VMIN 0x02 +#define ICH6_REG_VMAJ 0x03 +#define ICH6_REG_OUTPAY 0x04 +#define ICH6_REG_INPAY 0x06 +#define ICH6_REG_GCTL 0x08 +#define ICH6_GCTL_RESET (1 << 0) /* controller reset */ +#define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ +#define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ +#define ICH6_REG_WAKEEN 0x0c +#define ICH6_REG_STATESTS 0x0e +#define ICH6_REG_GSTS 0x10 +#define ICH6_GSTS_FSTS (1 << 1) /* flush status */ +#define ICH6_REG_INTCTL 0x20 +#define ICH6_REG_INTSTS 0x24 +#define ICH6_REG_WALLCLK 0x30 /* 24Mhz source */ +#define ICH6_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */ +#define ICH6_REG_SSYNC 0x38 +#define ICH6_REG_CORBLBASE 0x40 +#define ICH6_REG_CORBUBASE 0x44 +#define ICH6_REG_CORBWP 0x48 +#define ICH6_REG_CORBRP 0x4a +#define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ +#define ICH6_REG_CORBCTL 0x4c +#define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ +#define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ +#define ICH6_REG_CORBSTS 0x4d +#define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ +#define ICH6_REG_CORBSIZE 0x4e + +#define ICH6_REG_RIRBLBASE 0x50 +#define ICH6_REG_RIRBUBASE 0x54 +#define ICH6_REG_RIRBWP 0x58 +#define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ +#define ICH6_REG_RINTCNT 0x5a +#define ICH6_REG_RIRBCTL 0x5c +#define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ +#define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ +#define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ +#define ICH6_REG_RIRBSTS 0x5d +#define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ +#define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ +#define ICH6_REG_RIRBSIZE 0x5e + +#define ICH6_REG_IC 0x60 +#define ICH6_REG_IR 0x64 +#define ICH6_REG_IRS 0x68 +#define ICH6_IRS_VALID (1<<1) +#define ICH6_IRS_BUSY (1<<0) + +#define ICH6_REG_DPLBASE 0x70 +#define ICH6_REG_DPUBASE 0x74 +#define ICH6_DPLBASE_ENABLE 0x1 /* Enable position buffer */ + +/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */ +enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; + +/* stream register offsets from stream base */ +#define ICH6_REG_SD_CTL 0x00 +#define ICH6_REG_SD_STS 0x03 +#define ICH6_REG_SD_LPIB 0x04 +#define ICH6_REG_SD_CBL 0x08 +#define ICH6_REG_SD_LVI 0x0c +#define ICH6_REG_SD_FIFOW 0x0e +#define ICH6_REG_SD_FIFOSIZE 0x10 +#define ICH6_REG_SD_FORMAT 0x12 +#define ICH6_REG_SD_BDLPL 0x18 +#define ICH6_REG_SD_BDLPU 0x1c + +/* PCI space */ +#define ICH6_PCIREG_TCSEL 0x44 + +/* + * other constants + */ + +/* max number of SDs */ +/* ICH, ATI and VIA have 4 playback and 4 capture */ +#define ICH6_NUM_CAPTURE 4 +#define ICH6_NUM_PLAYBACK 4 + +/* ULI has 6 playback and 5 capture */ +#define ULI_NUM_CAPTURE 5 +#define ULI_NUM_PLAYBACK 6 + +/* ATI HDMI may have up to 8 playbacks and 0 capture */ +#define ATIHDMI_NUM_CAPTURE 0 +#define ATIHDMI_NUM_PLAYBACK 8 + +/* TERA has 4 playback and 3 capture */ +#define TERA_NUM_CAPTURE 3 +#define TERA_NUM_PLAYBACK 4 + +/* this number is statically defined for simplicity */ +#define MAX_AZX_DEV 16 + +/* max number of fragments - we may use more if allocating more pages for BDL */ +#define BDL_SIZE 4096 +#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16) +#define AZX_MAX_FRAG 32 +/* max buffer size - no h/w limit, you can increase as you like */ +#define AZX_MAX_BUF_SIZE (1024*1024*1024) + +/* RIRB int mask: overrun[2], response[0] */ +#define RIRB_INT_RESPONSE 0x01 +#define RIRB_INT_OVERRUN 0x04 +#define RIRB_INT_MASK 0x05 + +/* STATESTS int mask: S3,SD2,SD1,SD0 */ +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 +#define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) + +/* SD_CTL bits */ +#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */ +#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */ +#define SD_CTL_STRIPE (3 << 16) /* stripe control */ +#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */ +#define SD_CTL_DIR (1 << 19) /* bi-directional stream */ +#define SD_CTL_STREAM_TAG_MASK (0xf << 20) +#define SD_CTL_STREAM_TAG_SHIFT 20 + +/* SD_CTL and SD_STS */ +#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */ +#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */ +#define SD_INT_COMPLETE 0x04 /* completion interrupt */ +#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\ + SD_INT_COMPLETE) + +/* SD_STS */ +#define SD_STS_FIFO_READY 0x20 /* FIFO ready */ + +/* INTCTL and INTSTS */ +#define ICH6_INT_ALL_STREAM 0xff /* all stream interrupts */ +#define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ +#define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ + +/* below are so far hardcoded - should read registers in future */ +#define ICH6_MAX_CORB_ENTRIES 256 +#define ICH6_MAX_RIRB_ENTRIES 256 + +/* driver quirks (capabilities) */ +/* bits 0-7 are used for indicating driver type */ +#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */ +#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */ +#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */ +#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */ +#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */ +#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */ +#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */ +#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */ +#define AZX_DCAPS_POSFIX_LPIB (1 << 16) /* Use LPIB as default */ +#define AZX_DCAPS_POSFIX_VIA (1 << 17) /* Use VIACOMBO as default */ +#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */ +#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */ +#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ +#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ +#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ +#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ +#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */ +#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */ +#define AZX_DCAPS_PM_RUNTIME (1 << 26) /* runtime PM support */ +#define AZX_DCAPS_I915_POWERWELL (1 << 27) /* HSW i915 powerwell support */ +#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */ + +/* position fix mode */ +enum { + POS_FIX_AUTO, + POS_FIX_LPIB, + POS_FIX_POSBUF, + POS_FIX_VIACOMBO, + POS_FIX_COMBO, +}; + +/* Defines for ATI HD Audio support in SB450 south bridge */ +#define ATI_SB450_HDAUDIO_MISC_CNTR2_ADDR 0x42 +#define ATI_SB450_HDAUDIO_ENABLE_SNOOP 0x02 + +/* Defines for Nvidia HDA support */ +#define NVIDIA_HDA_TRANSREG_ADDR 0x4e +#define NVIDIA_HDA_ENABLE_COHBITS 0x0f +#define NVIDIA_HDA_ISTRM_COH 0x4d +#define NVIDIA_HDA_OSTRM_COH 0x4c +#define NVIDIA_HDA_ENABLE_COHBIT 0x01 + +/* Defines for Intel SCH HDA snoop control */ +#define INTEL_SCH_HDA_DEVC 0x78 +#define INTEL_SCH_HDA_DEVC_NOSNOOP (0x1<<11) + +/* Define IN stream 0 FIFO size offset in VIA controller */ +#define VIA_IN_STREAM0_FIFO_SIZE_OFFSET 0x90 +/* Define VIA HD Audio Device ID*/ +#define VIA_HDAC_DEVICE_ID 0x3288 + +/* HD Audio class code */ +#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403 + +struct azx_dev { + struct snd_dma_buffer bdl; /* BDL buffer */ + u32 *posbuf; /* position buffer pointer */ + + unsigned int bufsize; /* size of the play buffer in bytes */ + unsigned int period_bytes; /* size of the period in bytes */ + unsigned int frags; /* number for period in the play buffer */ + unsigned int fifo_size; /* FIFO size */ + unsigned long start_wallclk; /* start + minimum wallclk */ + unsigned long period_wallclk; /* wallclk for period */ + + void __iomem *sd_addr; /* stream descriptor pointer */ + + u32 sd_int_sta_mask; /* stream int status mask */ + + /* pcm support */ + struct snd_pcm_substream *substream; /* assigned substream, + * set in PCM open + */ + unsigned int format_val; /* format value to be set in the + * controller and the codec + */ + unsigned char stream_tag; /* assigned stream */ + unsigned char index; /* stream index */ + int assigned_key; /* last device# key assigned to */ + + unsigned int opened:1; + unsigned int running:1; + unsigned int irq_pending:1; + unsigned int prepared:1; + unsigned int locked:1; + /* + * For VIA: + * A flag to ensure DMA position is 0 + * when link position is not greater than FIFO size + */ + unsigned int insufficient:1; + unsigned int wc_marked:1; + unsigned int no_period_wakeup:1; + + struct timecounter azx_tc; + struct cyclecounter azx_cc; + + int delay_negative_threshold; + +#ifdef CONFIG_SND_HDA_DSP_LOADER + /* Allows dsp load to have sole access to the playback stream. */ + struct mutex dsp_mutex; +#endif +}; + +/* CORB/RIRB */ +struct azx_rb { + u32 *buf; /* CORB/RIRB buffer + * Each CORB entry is 4byte, RIRB is 8byte + */ + dma_addr_t addr; /* physical address of CORB/RIRB buffer */ + /* for RIRB */ + unsigned short rp, wp; /* read/write pointers */ + int cmds[AZX_MAX_CODECS]; /* number of pending requests */ + u32 res[AZX_MAX_CODECS]; /* last read value */ +}; + +struct azx; + +/* Functions to read/write to hda registers. */ +struct hda_controller_ops { + /* Register Access */ + void (*reg_writel)(u32 value, u32 __iomem *addr); + u32 (*reg_readl)(u32 __iomem *addr); + void (*reg_writew)(u16 value, u16 __iomem *addr); + u16 (*reg_readw)(u16 __iomem *addr); + void (*reg_writeb)(u8 value, u8 __iomem *addr); + u8 (*reg_readb)(u8 __iomem *addr); + /* Disable msi if supported, PCI only */ + int (*disable_msi_reset_irq)(struct azx *); + /* Allocation ops */ + int (*dma_alloc_pages)(struct azx *chip, + int type, + size_t size, + struct snd_dma_buffer *buf); + void (*dma_free_pages)(struct azx *chip, struct snd_dma_buffer *buf); + int (*substream_alloc_pages)(struct azx *chip, + struct snd_pcm_substream *substream, + size_t size); + int (*substream_free_pages)(struct azx *chip, + struct snd_pcm_substream *substream); + void (*pcm_mmap_prepare)(struct snd_pcm_substream *substream, + struct vm_area_struct *area); + /* Check if current position is acceptable */ + int (*position_check)(struct azx *chip, struct azx_dev *azx_dev); +}; + +struct azx_pcm { + struct azx *chip; + struct snd_pcm *pcm; + struct hda_codec *codec; + struct hda_pcm_stream *hinfo[2]; + struct list_head list; +}; + +struct azx { + struct snd_card *card; + struct pci_dev *pci; + int dev_index; + + /* chip type specific */ + int driver_type; + unsigned int driver_caps; + int playback_streams; + int playback_index_offset; + int capture_streams; + int capture_index_offset; + int num_streams; + const int *jackpoll_ms; /* per-card jack poll interval */ + + /* Register interaction. */ + const struct hda_controller_ops *ops; + + /* pci resources */ + unsigned long addr; + void __iomem *remap_addr; + int irq; + + /* locks */ + spinlock_t reg_lock; + struct mutex open_mutex; /* Prevents concurrent open/close operations */ + struct completion probe_wait; + + /* streams (x num_streams) */ + struct azx_dev *azx_dev; + + /* PCM */ + struct list_head pcm_list; /* azx_pcm list */ + + /* HD codec */ + unsigned short codec_mask; + int codec_probe_mask; /* copied from probe_mask option */ + struct hda_bus *bus; + unsigned int beep_mode; + + /* CORB/RIRB */ + struct azx_rb corb; + struct azx_rb rirb; + + /* CORB/RIRB and position buffers */ + struct snd_dma_buffer rb; + struct snd_dma_buffer posbuf; + +#ifdef CONFIG_SND_HDA_PATCH_LOADER + const struct firmware *fw; +#endif + + /* flags */ + int position_fix[2]; /* for both playback/capture streams */ + const int *bdl_pos_adj; + int poll_count; + unsigned int running:1; + unsigned int initialized:1; + unsigned int single_cmd:1; + unsigned int polling_mode:1; + unsigned int msi:1; + unsigned int irq_pending_warned:1; + unsigned int probing:1; /* codec probing phase */ + unsigned int snoop:1; + unsigned int align_buffer_size:1; + unsigned int region_requested:1; + + /* VGA-switcheroo setup */ + unsigned int use_vga_switcheroo:1; + unsigned int vga_switcheroo_registered:1; + unsigned int init_failed:1; /* delayed init failed */ + unsigned int disabled:1; /* disabled by VGA-switcher */ + + /* for debugging */ + unsigned int last_cmd[AZX_MAX_CODECS]; + + /* for pending irqs */ + struct work_struct irq_pending_work; + + struct work_struct probe_work; + + /* reboot notifier (for mysterious hangup problem at power-down) */ + struct notifier_block reboot_notifier; + + /* card list (for power_save trigger) */ + struct list_head list; + +#ifdef CONFIG_SND_HDA_DSP_LOADER + struct azx_dev saved_azx_dev; +#endif + + /* secondary power domain for hdmi audio under vga device */ + struct dev_pm_domain hdmi_pm_domain; +}; + +#ifdef CONFIG_SND_VERBOSE_PRINTK +#define SFX /* nop */ +#else +#define SFX "hda-intel " +#endif + +#ifdef CONFIG_X86 +#define azx_snoop(chip) ((chip)->snoop) +#else +#define azx_snoop(chip) true +#endif + +/* + * macros for easy use + */ + +#define azx_writel(chip, reg, value) \ + ((chip)->ops->reg_writel(value, (chip)->remap_addr + ICH6_REG_##reg)) +#define azx_readl(chip, reg) \ + ((chip)->ops->reg_readl((chip)->remap_addr + ICH6_REG_##reg)) +#define azx_writew(chip, reg, value) \ + ((chip)->ops->reg_writew(value, (chip)->remap_addr + ICH6_REG_##reg)) +#define azx_readw(chip, reg) \ + ((chip)->ops->reg_readw((chip)->remap_addr + ICH6_REG_##reg)) +#define azx_writeb(chip, reg, value) \ + ((chip)->ops->reg_writeb(value, (chip)->remap_addr + ICH6_REG_##reg)) +#define azx_readb(chip, reg) \ + ((chip)->ops->reg_readb((chip)->remap_addr + ICH6_REG_##reg)) + +#define azx_sd_writel(chip, dev, reg, value) \ + ((chip)->ops->reg_writel(value, (dev)->sd_addr + ICH6_REG_##reg)) +#define azx_sd_readl(chip, dev, reg) \ + ((chip)->ops->reg_readl((dev)->sd_addr + ICH6_REG_##reg)) +#define azx_sd_writew(chip, dev, reg, value) \ + ((chip)->ops->reg_writew(value, (dev)->sd_addr + ICH6_REG_##reg)) +#define azx_sd_readw(chip, dev, reg) \ + ((chip)->ops->reg_readw((dev)->sd_addr + ICH6_REG_##reg)) +#define azx_sd_writeb(chip, dev, reg, value) \ + ((chip)->ops->reg_writeb(value, (dev)->sd_addr + ICH6_REG_##reg)) +#define azx_sd_readb(chip, dev, reg) \ + ((chip)->ops->reg_readb((dev)->sd_addr + ICH6_REG_##reg)) + +#endif /* __SOUND_HDA_PRIV_H */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 045e5d32f5d..ce5a6da8341 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -22,10 +22,16 @@ */ #include <linux/init.h> +#include <linux/slab.h> #include <sound/core.h> +#include <linux/module.h> #include "hda_codec.h" #include "hda_local.h" +static int dump_coef = -1; +module_param(dump_coef, int, 0644); +MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)"); + static char *bits_names(unsigned int bits, char *names[], int size) { int i, n; @@ -138,16 +144,17 @@ static void print_amp_vals(struct snd_info_buffer *buffer, dir = dir == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; for (i = 0; i < indices; i++) { snd_iprintf(buffer, " ["); + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, + AC_AMP_GET_LEFT | dir | i); + snd_iprintf(buffer, "0x%02x", val); if (stereo) { val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_LEFT | dir | i); - snd_iprintf(buffer, "0x%02x ", val); + AC_AMP_GET_RIGHT | dir | i); + snd_iprintf(buffer, " 0x%02x", val); } - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_RIGHT | dir | i); - snd_iprintf(buffer, "0x%02x]", val); + snd_iprintf(buffer, "]"); } snd_iprintf(buffer, "\n"); } @@ -486,14 +493,39 @@ static void print_unsol_cap(struct snd_info_buffer *buffer, (unsol & AC_UNSOL_ENABLED) ? 1 : 0); } +static inline bool can_dump_coef(struct hda_codec *codec) +{ + switch (dump_coef) { + case 0: return false; + case 1: return true; + default: return codec->dump_coef; + } +} + static void print_proc_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) { + unsigned int i, ncoeff, oldindex; unsigned int proc_caps = snd_hda_param_read(codec, nid, AC_PAR_PROC_CAP); + ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT; snd_iprintf(buffer, " Processing caps: benign=%d, ncoeff=%d\n", - proc_caps & AC_PCAP_BENIGN, - (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT); + proc_caps & AC_PCAP_BENIGN, ncoeff); + + if (!can_dump_coef(codec)) + return; + + /* Note: This is racy - another process could run in parallel and change + the coef index too. */ + oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0); + for (i = 0; i < ncoeff; i++) { + unsigned int val; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i); + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, + 0); + snd_iprintf(buffer, " Coeff 0x%02x: 0x%04x\n", i, val); + } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex); } static void print_conn_list(struct snd_info_buffer *buffer, @@ -502,6 +534,8 @@ static void print_conn_list(struct snd_info_buffer *buffer, int conn_len) { int c, curr = -1; + const hda_nid_t *list; + int cache_len; if (conn_len > 1 && wid_type != AC_WID_AUD_MIX && @@ -519,6 +553,19 @@ static void print_conn_list(struct snd_info_buffer *buffer, } snd_iprintf(buffer, "\n"); } + + /* Get Cache connections info */ + cache_len = snd_hda_get_conn_list(codec, nid, &list); + if (cache_len != conn_len + || memcmp(list, conn, conn_len)) { + snd_iprintf(buffer, " In-driver Connection: %d\n", cache_len); + if (cache_len > 0) { + snd_iprintf(buffer, " "); + for (c = 0; c < cache_len; c++) + snd_iprintf(buffer, " 0x%02x", list[c]); + snd_iprintf(buffer, "\n"); + } + } } static void print_gpio(struct snd_info_buffer *buffer, @@ -565,6 +612,36 @@ static void print_gpio(struct snd_info_buffer *buffer, print_nid_array(buffer, codec, nid, &codec->nids); } +static void print_device_list(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int i, curr = -1; + u8 dev_list[AC_MAX_DEV_LIST_LEN]; + int devlist_len; + + devlist_len = snd_hda_get_devices(codec, nid, dev_list, + AC_MAX_DEV_LIST_LEN); + snd_iprintf(buffer, " Devices: %d\n", devlist_len); + if (devlist_len <= 0) + return; + + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_DEVICE_SEL, 0); + + for (i = 0; i < devlist_len; i++) { + if (i == curr) + snd_iprintf(buffer, " *"); + else + snd_iprintf(buffer, " "); + + snd_iprintf(buffer, + "Dev %02d: PD = %d, ELDV = %d, IA = %d\n", i, + !!(dev_list[i] & AC_DE_PD), + !!(dev_list[i] & AC_DE_ELDV), + !!(dev_list[i] & AC_DE_IA)); + } +} + static void print_codec_info(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { @@ -603,6 +680,8 @@ static void print_codec_info(struct snd_info_entry *entry, print_amp_caps(buffer, codec, codec->afg, HDA_INPUT); snd_iprintf(buffer, "Default Amp-Out caps: "); print_amp_caps(buffer, codec, codec->afg, HDA_OUTPUT); + snd_iprintf(buffer, "State of AFG node 0x%02x:\n", codec->afg); + print_power_state(buffer, codec, codec->afg); nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (! nid || nodes < 0) { @@ -620,7 +699,7 @@ static void print_codec_info(struct snd_info_entry *entry, snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); unsigned int wid_type = get_wcaps_type(wid_caps); - hda_nid_t conn[HDA_MAX_CONNECTIONS]; + hda_nid_t *conn = NULL; int conn_len = 0; snd_iprintf(buffer, "Node 0x%02x [%s] wcaps 0x%x:", nid, @@ -657,9 +736,18 @@ static void print_codec_info(struct snd_info_entry *entry, if (wid_type == AC_WID_VOL_KNB) wid_caps |= AC_WCAP_CONN_LIST; - if (wid_caps & AC_WCAP_CONN_LIST) - conn_len = snd_hda_get_raw_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); + if (wid_caps & AC_WCAP_CONN_LIST) { + conn_len = snd_hda_get_num_raw_conns(codec, nid); + if (conn_len > 0) { + conn = kmalloc(sizeof(hda_nid_t) * conn_len, + GFP_KERNEL); + if (!conn) + return; + if (snd_hda_get_raw_connections(codec, nid, conn, + conn_len) < 0) + conn_len = 0; + } + } if (wid_caps & AC_WCAP_IN_AMP) { snd_iprintf(buffer, " Amp-In caps: "); @@ -723,6 +811,9 @@ static void print_codec_info(struct snd_info_entry *entry, (wid_caps & AC_WCAP_DELAY) >> AC_WCAP_DELAY_SHIFT); + if (wid_type == AC_WID_PIN && codec->dp_mst) + print_device_list(buffer, codec, nid); + if (wid_caps & AC_WCAP_CONN_LIST) print_conn_list(buffer, codec, nid, wid_type, conn, conn_len); @@ -732,6 +823,8 @@ static void print_codec_info(struct snd_info_entry *entry, if (codec->proc_widget_hook) codec->proc_widget_hook(buffer, codec, nid); + + kfree(conn); } snd_hda_power_down(codec); } diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c new file mode 100644 index 00000000000..e2079090ca6 --- /dev/null +++ b/sound/pci/hda/hda_sysfs.c @@ -0,0 +1,780 @@ +/* + * sysfs interface for HD-audio codec + * + * Copyright (c) 2014 Takashi Iwai <tiwai@suse.de> + * + * split from hda_hwdep.c + */ + +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/compat.h> +#include <linux/mutex.h> +#include <linux/ctype.h> +#include <linux/string.h> +#include <linux/export.h> +#include <sound/core.h> +#include "hda_codec.h" +#include "hda_local.h" +#include <sound/hda_hwdep.h> +#include <sound/minors.h> + +/* hint string pair */ +struct hda_hint { + const char *key; + const char *val; /* contained in the same alloc as key */ +}; + +#ifdef CONFIG_PM +static ssize_t power_on_acct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + snd_hda_update_power_acct(codec); + return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_on_acct)); +} + +static ssize_t power_off_acct_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + snd_hda_update_power_acct(codec); + return sprintf(buf, "%u\n", jiffies_to_msecs(codec->power_off_acct)); +} + +static DEVICE_ATTR_RO(power_on_acct); +static DEVICE_ATTR_RO(power_off_acct); +#endif /* CONFIG_PM */ + +#define CODEC_INFO_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct hda_codec *codec = dev_get_drvdata(dev); \ + return sprintf(buf, "0x%x\n", codec->type); \ +} + +#define CODEC_INFO_STR_SHOW(type) \ +static ssize_t type##_show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + struct hda_codec *codec = dev_get_drvdata(dev); \ + return sprintf(buf, "%s\n", \ + codec->type ? codec->type : ""); \ +} + +CODEC_INFO_SHOW(vendor_id); +CODEC_INFO_SHOW(subsystem_id); +CODEC_INFO_SHOW(revision_id); +CODEC_INFO_SHOW(afg); +CODEC_INFO_SHOW(mfg); +CODEC_INFO_STR_SHOW(vendor_name); +CODEC_INFO_STR_SHOW(chip_name); +CODEC_INFO_STR_SHOW(modelname); + +static ssize_t pin_configs_show(struct hda_codec *codec, + struct snd_array *list, + char *buf) +{ + int i, len = 0; + mutex_lock(&codec->user_mutex); + for (i = 0; i < list->used; i++) { + struct hda_pincfg *pin = snd_array_elem(list, i); + len += sprintf(buf + len, "0x%02x 0x%08x\n", + pin->nid, pin->cfg); + } + mutex_unlock(&codec->user_mutex); + return len; +} + +static ssize_t init_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + return pin_configs_show(codec, &codec->init_pins, buf); +} + +static ssize_t driver_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + return pin_configs_show(codec, &codec->driver_pins, buf); +} + +#ifdef CONFIG_SND_HDA_RECONFIG + +/* + * sysfs interface + */ + +static int clear_codec(struct hda_codec *codec) +{ + int err; + + err = snd_hda_codec_reset(codec); + if (err < 0) { + codec_err(codec, "The codec is being used, can't free.\n"); + return err; + } + snd_hda_sysfs_clear(codec); + return 0; +} + +static int reconfig_codec(struct hda_codec *codec) +{ + int err; + + snd_hda_power_up(codec); + codec_info(codec, "hda-codec: reconfiguring\n"); + err = snd_hda_codec_reset(codec); + if (err < 0) { + codec_err(codec, + "The codec is being used, can't reconfigure.\n"); + goto error; + } + err = snd_hda_codec_configure(codec); + if (err < 0) + goto error; + /* rebuild PCMs */ + err = snd_hda_codec_build_pcms(codec); + if (err < 0) + goto error; + /* rebuild mixers */ + err = snd_hda_codec_build_controls(codec); + if (err < 0) + goto error; + err = snd_card_register(codec->bus->card); + error: + snd_hda_power_down(codec); + return err; +} + +/* + * allocate a string at most len chars, and remove the trailing EOL + */ +static char *kstrndup_noeol(const char *src, size_t len) +{ + char *s = kstrndup(src, len, GFP_KERNEL); + char *p; + if (!s) + return NULL; + p = strchr(s, '\n'); + if (p) + *p = 0; + return s; +} + +#define CODEC_INFO_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct hda_codec *codec = dev_get_drvdata(dev); \ + unsigned long val; \ + int err = kstrtoul(buf, 0, &val); \ + if (err < 0) \ + return err; \ + codec->type = val; \ + return count; \ +} + +#define CODEC_INFO_STR_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct hda_codec *codec = dev_get_drvdata(dev); \ + char *s = kstrndup_noeol(buf, 64); \ + if (!s) \ + return -ENOMEM; \ + kfree(codec->type); \ + codec->type = s; \ + return count; \ +} + +CODEC_INFO_STORE(vendor_id); +CODEC_INFO_STORE(subsystem_id); +CODEC_INFO_STORE(revision_id); +CODEC_INFO_STR_STORE(vendor_name); +CODEC_INFO_STR_STORE(chip_name); +CODEC_INFO_STR_STORE(modelname); + +#define CODEC_ACTION_STORE(type) \ +static ssize_t type##_store(struct device *dev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ +{ \ + struct hda_codec *codec = dev_get_drvdata(dev); \ + int err = 0; \ + if (*buf) \ + err = type##_codec(codec); \ + return err < 0 ? err : count; \ +} + +CODEC_ACTION_STORE(reconfig); +CODEC_ACTION_STORE(clear); + +static ssize_t init_verbs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + int i, len = 0; + mutex_lock(&codec->user_mutex); + for (i = 0; i < codec->init_verbs.used; i++) { + struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); + len += snprintf(buf + len, PAGE_SIZE - len, + "0x%02x 0x%03x 0x%04x\n", + v->nid, v->verb, v->param); + } + mutex_unlock(&codec->user_mutex); + return len; +} + +static int parse_init_verbs(struct hda_codec *codec, const char *buf) +{ + struct hda_verb *v; + int nid, verb, param; + + if (sscanf(buf, "%i %i %i", &nid, &verb, ¶m) != 3) + return -EINVAL; + if (!nid || !verb) + return -EINVAL; + mutex_lock(&codec->user_mutex); + v = snd_array_new(&codec->init_verbs); + if (!v) { + mutex_unlock(&codec->user_mutex); + return -ENOMEM; + } + v->nid = nid; + v->verb = verb; + v->param = param; + mutex_unlock(&codec->user_mutex); + return 0; +} + +static ssize_t init_verbs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + int err = parse_init_verbs(codec, buf); + if (err < 0) + return err; + return count; +} + +static ssize_t hints_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + int i, len = 0; + mutex_lock(&codec->user_mutex); + for (i = 0; i < codec->hints.used; i++) { + struct hda_hint *hint = snd_array_elem(&codec->hints, i); + len += snprintf(buf + len, PAGE_SIZE - len, + "%s = %s\n", hint->key, hint->val); + } + mutex_unlock(&codec->user_mutex); + return len; +} + +static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) +{ + int i; + + for (i = 0; i < codec->hints.used; i++) { + struct hda_hint *hint = snd_array_elem(&codec->hints, i); + if (!strcmp(hint->key, key)) + return hint; + } + return NULL; +} + +static void remove_trail_spaces(char *str) +{ + char *p; + if (!*str) + return; + p = str + strlen(str) - 1; + for (; isspace(*p); p--) { + *p = 0; + if (p == str) + return; + } +} + +#define MAX_HINTS 1024 + +static int parse_hints(struct hda_codec *codec, const char *buf) +{ + char *key, *val; + struct hda_hint *hint; + int err = 0; + + buf = skip_spaces(buf); + if (!*buf || *buf == '#' || *buf == '\n') + return 0; + if (*buf == '=') + return -EINVAL; + key = kstrndup_noeol(buf, 1024); + if (!key) + return -ENOMEM; + /* extract key and val */ + val = strchr(key, '='); + if (!val) { + kfree(key); + return -EINVAL; + } + *val++ = 0; + val = skip_spaces(val); + remove_trail_spaces(key); + remove_trail_spaces(val); + mutex_lock(&codec->user_mutex); + hint = get_hint(codec, key); + if (hint) { + /* replace */ + kfree(hint->key); + hint->key = key; + hint->val = val; + goto unlock; + } + /* allocate a new hint entry */ + if (codec->hints.used >= MAX_HINTS) + hint = NULL; + else + hint = snd_array_new(&codec->hints); + if (hint) { + hint->key = key; + hint->val = val; + } else { + err = -ENOMEM; + } + unlock: + mutex_unlock(&codec->user_mutex); + if (err) + kfree(key); + return err; +} + +static ssize_t hints_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + int err = parse_hints(codec, buf); + if (err < 0) + return err; + return count; +} + +static ssize_t user_pin_configs_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + return pin_configs_show(codec, &codec->user_pins, buf); +} + +#define MAX_PIN_CONFIGS 32 + +static int parse_user_pin_configs(struct hda_codec *codec, const char *buf) +{ + int nid, cfg, err; + + if (sscanf(buf, "%i %i", &nid, &cfg) != 2) + return -EINVAL; + if (!nid) + return -EINVAL; + mutex_lock(&codec->user_mutex); + err = snd_hda_add_pincfg(codec, &codec->user_pins, nid, cfg); + mutex_unlock(&codec->user_mutex); + return err; +} + +static ssize_t user_pin_configs_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hda_codec *codec = dev_get_drvdata(dev); + int err = parse_user_pin_configs(codec, buf); + if (err < 0) + return err; + return count; +} + +/* sysfs attributes exposed only when CONFIG_SND_HDA_RECONFIG=y */ +static DEVICE_ATTR_RW(init_verbs); +static DEVICE_ATTR_RW(hints); +static DEVICE_ATTR_RW(user_pin_configs); +static DEVICE_ATTR_WO(reconfig); +static DEVICE_ATTR_WO(clear); + +/* + * Look for hint string + */ +const char *snd_hda_get_hint(struct hda_codec *codec, const char *key) +{ + struct hda_hint *hint = get_hint(codec, key); + return hint ? hint->val : NULL; +} +EXPORT_SYMBOL_GPL(snd_hda_get_hint); + +int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key) +{ + const char *p; + int ret; + + mutex_lock(&codec->user_mutex); + p = snd_hda_get_hint(codec, key); + if (!p || !*p) + ret = -ENOENT; + else { + switch (toupper(*p)) { + case 'T': /* true */ + case 'Y': /* yes */ + case '1': + ret = 1; + break; + default: + ret = 0; + break; + } + } + mutex_unlock(&codec->user_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint); + +int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp) +{ + const char *p; + unsigned long val; + int ret; + + mutex_lock(&codec->user_mutex); + p = snd_hda_get_hint(codec, key); + if (!p) + ret = -ENOENT; + else if (kstrtoul(p, 0, &val)) + ret = -EINVAL; + else { + *valp = val; + ret = 0; + } + mutex_unlock(&codec->user_mutex); + return ret; +} +EXPORT_SYMBOL_GPL(snd_hda_get_int_hint); +#endif /* CONFIG_SND_HDA_RECONFIG */ + +/* + * common sysfs attributes + */ +#ifdef CONFIG_SND_HDA_RECONFIG +#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RW(name) +#else +#define RECONFIG_DEVICE_ATTR(name) DEVICE_ATTR_RO(name) +#endif +static RECONFIG_DEVICE_ATTR(vendor_id); +static RECONFIG_DEVICE_ATTR(subsystem_id); +static RECONFIG_DEVICE_ATTR(revision_id); +static DEVICE_ATTR_RO(afg); +static DEVICE_ATTR_RO(mfg); +static RECONFIG_DEVICE_ATTR(vendor_name); +static RECONFIG_DEVICE_ATTR(chip_name); +static RECONFIG_DEVICE_ATTR(modelname); +static DEVICE_ATTR_RO(init_pin_configs); +static DEVICE_ATTR_RO(driver_pin_configs); + + +#ifdef CONFIG_SND_HDA_PATCH_LOADER + +/* parser mode */ +enum { + LINE_MODE_NONE, + LINE_MODE_CODEC, + LINE_MODE_MODEL, + LINE_MODE_PINCFG, + LINE_MODE_VERB, + LINE_MODE_HINT, + LINE_MODE_VENDOR_ID, + LINE_MODE_SUBSYSTEM_ID, + LINE_MODE_REVISION_ID, + LINE_MODE_CHIP_NAME, + NUM_LINE_MODES, +}; + +static inline int strmatch(const char *a, const char *b) +{ + return strnicmp(a, b, strlen(b)) == 0; +} + +/* parse the contents after the line "[codec]" + * accept only the line with three numbers, and assign the current codec + */ +static void parse_codec_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + int vendorid, subid, caddr; + struct hda_codec *codec; + + *codecp = NULL; + if (sscanf(buf, "%i %i %i", &vendorid, &subid, &caddr) == 3) { + list_for_each_entry(codec, &bus->codec_list, list) { + if ((vendorid <= 0 || codec->vendor_id == vendorid) && + (subid <= 0 || codec->subsystem_id == subid) && + codec->addr == caddr) { + *codecp = codec; + break; + } + } + } +} + +/* parse the contents after the other command tags, [pincfg], [verb], + * [vendor_id], [subsystem_id], [revision_id], [chip_name], [hint] and [model] + * just pass to the sysfs helper (only when any codec was specified) + */ +static void parse_pincfg_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + parse_user_pin_configs(*codecp, buf); +} + +static void parse_verb_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + parse_init_verbs(*codecp, buf); +} + +static void parse_hint_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + parse_hints(*codecp, buf); +} + +static void parse_model_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + kfree((*codecp)->modelname); + (*codecp)->modelname = kstrdup(buf, GFP_KERNEL); +} + +static void parse_chip_name_mode(char *buf, struct hda_bus *bus, + struct hda_codec **codecp) +{ + kfree((*codecp)->chip_name); + (*codecp)->chip_name = kstrdup(buf, GFP_KERNEL); +} + +#define DEFINE_PARSE_ID_MODE(name) \ +static void parse_##name##_mode(char *buf, struct hda_bus *bus, \ + struct hda_codec **codecp) \ +{ \ + unsigned long val; \ + if (!kstrtoul(buf, 0, &val)) \ + (*codecp)->name = val; \ +} + +DEFINE_PARSE_ID_MODE(vendor_id); +DEFINE_PARSE_ID_MODE(subsystem_id); +DEFINE_PARSE_ID_MODE(revision_id); + + +struct hda_patch_item { + const char *tag; + const char *alias; + void (*parser)(char *buf, struct hda_bus *bus, struct hda_codec **retc); +}; + +static struct hda_patch_item patch_items[NUM_LINE_MODES] = { + [LINE_MODE_CODEC] = { + .tag = "[codec]", + .parser = parse_codec_mode, + }, + [LINE_MODE_MODEL] = { + .tag = "[model]", + .parser = parse_model_mode, + }, + [LINE_MODE_VERB] = { + .tag = "[verb]", + .alias = "[init_verbs]", + .parser = parse_verb_mode, + }, + [LINE_MODE_PINCFG] = { + .tag = "[pincfg]", + .alias = "[user_pin_configs]", + .parser = parse_pincfg_mode, + }, + [LINE_MODE_HINT] = { + .tag = "[hint]", + .alias = "[hints]", + .parser = parse_hint_mode + }, + [LINE_MODE_VENDOR_ID] = { + .tag = "[vendor_id]", + .parser = parse_vendor_id_mode, + }, + [LINE_MODE_SUBSYSTEM_ID] = { + .tag = "[subsystem_id]", + .parser = parse_subsystem_id_mode, + }, + [LINE_MODE_REVISION_ID] = { + .tag = "[revision_id]", + .parser = parse_revision_id_mode, + }, + [LINE_MODE_CHIP_NAME] = { + .tag = "[chip_name]", + .parser = parse_chip_name_mode, + }, +}; + +/* check the line starting with '[' -- change the parser mode accodingly */ +static int parse_line_mode(char *buf, struct hda_bus *bus) +{ + int i; + for (i = 0; i < ARRAY_SIZE(patch_items); i++) { + if (!patch_items[i].tag) + continue; + if (strmatch(buf, patch_items[i].tag)) + return i; + if (patch_items[i].alias && strmatch(buf, patch_items[i].alias)) + return i; + } + return LINE_MODE_NONE; +} + +/* copy one line from the buffer in fw, and update the fields in fw + * return zero if it reaches to the end of the buffer, or non-zero + * if successfully copied a line + * + * the spaces at the beginning and the end of the line are stripped + */ +static int get_line_from_fw(char *buf, int size, size_t *fw_size_p, + const void **fw_data_p) +{ + int len; + size_t fw_size = *fw_size_p; + const char *p = *fw_data_p; + + while (isspace(*p) && fw_size) { + p++; + fw_size--; + } + if (!fw_size) + return 0; + + for (len = 0; len < fw_size; len++) { + if (!*p) + break; + if (*p == '\n') { + p++; + len++; + break; + } + if (len < size) + *buf++ = *p++; + } + *buf = 0; + *fw_size_p = fw_size - len; + *fw_data_p = p; + remove_trail_spaces(buf); + return 1; +} + +/* + * load a "patch" firmware file and parse it + */ +int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf) +{ + char buf[128]; + struct hda_codec *codec; + int line_mode; + + line_mode = LINE_MODE_NONE; + codec = NULL; + while (get_line_from_fw(buf, sizeof(buf) - 1, &fw_size, &fw_buf)) { + if (!*buf || *buf == '#' || *buf == '\n') + continue; + if (*buf == '[') + line_mode = parse_line_mode(buf, bus); + else if (patch_items[line_mode].parser && + (codec || line_mode <= LINE_MODE_CODEC)) + patch_items[line_mode].parser(buf, bus, &codec); + } + return 0; +} +EXPORT_SYMBOL_GPL(snd_hda_load_patch); +#endif /* CONFIG_SND_HDA_PATCH_LOADER */ + +/* + * sysfs entries + */ +static struct attribute *hda_dev_attrs[] = { + &dev_attr_vendor_id.attr, + &dev_attr_subsystem_id.attr, + &dev_attr_revision_id.attr, + &dev_attr_afg.attr, + &dev_attr_mfg.attr, + &dev_attr_vendor_name.attr, + &dev_attr_chip_name.attr, + &dev_attr_modelname.attr, + &dev_attr_init_pin_configs.attr, + &dev_attr_driver_pin_configs.attr, +#ifdef CONFIG_PM + &dev_attr_power_on_acct.attr, + &dev_attr_power_off_acct.attr, +#endif +#ifdef CONFIG_SND_HDA_RECONFIG + &dev_attr_init_verbs.attr, + &dev_attr_hints.attr, + &dev_attr_user_pin_configs.attr, + &dev_attr_reconfig.attr, + &dev_attr_clear.attr, +#endif + NULL +}; + +static struct attribute_group hda_dev_attr_group = { + .attrs = hda_dev_attrs, +}; + +const struct attribute_group *snd_hda_dev_attr_groups[] = { + &hda_dev_attr_group, + NULL +}; + +void snd_hda_sysfs_init(struct hda_codec *codec) +{ + mutex_init(&codec->user_mutex); +#ifdef CONFIG_SND_HDA_RECONFIG + snd_array_init(&codec->init_verbs, sizeof(struct hda_verb), 32); + snd_array_init(&codec->hints, sizeof(struct hda_hint), 32); + snd_array_init(&codec->user_pins, sizeof(struct hda_pincfg), 16); +#endif +} + +void snd_hda_sysfs_clear(struct hda_codec *codec) +{ +#ifdef CONFIG_SND_HDA_RECONFIG + int i; + + /* clear init verbs */ + snd_array_free(&codec->init_verbs); + /* clear hints */ + for (i = 0; i < codec->hints.used; i++) { + struct hda_hint *hint = snd_array_elem(&codec->hints, i); + kfree(hint->key); /* we don't need to free hint->val */ + } + snd_array_free(&codec->hints); + snd_array_free(&codec->user_pins); +#endif +} diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c new file mode 100644 index 00000000000..358414da641 --- /dev/null +++ b/sound/pci/hda/hda_tegra.c @@ -0,0 +1,588 @@ +/* + * + * Implementation of primary ALSA driver code base for NVIDIA Tegra HDA. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/clk.h> +#include <linux/clocksource.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/mutex.h> +#include <linux/of_device.h> +#include <linux/reboot.h> +#include <linux/slab.h> +#include <linux/time.h> + +#include <sound/core.h> +#include <sound/initval.h> + +#include "hda_codec.h" +#include "hda_controller.h" +#include "hda_priv.h" + +/* Defines for Nvidia Tegra HDA support */ +#define HDA_BAR0 0x8000 + +#define HDA_CFG_CMD 0x1004 +#define HDA_CFG_BAR0 0x1010 + +#define HDA_ENABLE_IO_SPACE (1 << 0) +#define HDA_ENABLE_MEM_SPACE (1 << 1) +#define HDA_ENABLE_BUS_MASTER (1 << 2) +#define HDA_ENABLE_SERR (1 << 8) +#define HDA_DISABLE_INTR (1 << 10) +#define HDA_BAR0_INIT_PROGRAM 0xFFFFFFFF +#define HDA_BAR0_FINAL_PROGRAM (1 << 14) + +/* IPFS */ +#define HDA_IPFS_CONFIG 0x180 +#define HDA_IPFS_EN_FPCI 0x1 + +#define HDA_IPFS_FPCI_BAR0 0x80 +#define HDA_FPCI_BAR0_START 0x40 + +#define HDA_IPFS_INTR_MASK 0x188 +#define HDA_IPFS_EN_INTR (1 << 16) + +/* max number of SDs */ +#define NUM_CAPTURE_SD 1 +#define NUM_PLAYBACK_SD 1 + +struct hda_tegra { + struct azx chip; + struct device *dev; + struct clk *hda_clk; + struct clk *hda2codec_2x_clk; + struct clk *hda2hdmi_clk; + void __iomem *regs; +}; + +#ifdef CONFIG_PM +static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; +module_param(power_save, bint, 0644); +MODULE_PARM_DESC(power_save, + "Automatic power-saving timeout (in seconds, 0 = disable)."); +#else +static int power_save = 0; +#endif + +/* + * DMA page allocation ops. + */ +static int dma_alloc_pages(struct azx *chip, int type, size_t size, + struct snd_dma_buffer *buf) +{ + return snd_dma_alloc_pages(type, chip->card->dev, size, buf); +} + +static void dma_free_pages(struct azx *chip, struct snd_dma_buffer *buf) +{ + snd_dma_free_pages(buf); +} + +static int substream_alloc_pages(struct azx *chip, + struct snd_pcm_substream *substream, + size_t size) +{ + struct azx_dev *azx_dev = get_azx_dev(substream); + + azx_dev->bufsize = 0; + azx_dev->period_bytes = 0; + azx_dev->format_val = 0; + return snd_pcm_lib_malloc_pages(substream, size); +} + +static int substream_free_pages(struct azx *chip, + struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +/* + * Register access ops. Tegra HDA register access is DWORD only. + */ +static void hda_tegra_writel(u32 value, u32 *addr) +{ + writel(value, addr); +} + +static u32 hda_tegra_readl(u32 *addr) +{ + return readl(addr); +} + +static void hda_tegra_writew(u16 value, u16 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + v &= ~(0xffff << shift); + v |= value << shift; + writel(v, dword_addr); +} + +static u16 hda_tegra_readw(u16 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + return (v >> shift) & 0xffff; +} + +static void hda_tegra_writeb(u8 value, u8 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + v &= ~(0xff << shift); + v |= value << shift; + writel(v, dword_addr); +} + +static u8 hda_tegra_readb(u8 *addr) +{ + unsigned int shift = ((unsigned long)(addr) & 0x3) << 3; + void *dword_addr = (void *)((unsigned long)(addr) & ~0x3); + u32 v; + + v = readl(dword_addr); + return (v >> shift) & 0xff; +} + +static const struct hda_controller_ops hda_tegra_ops = { + .reg_writel = hda_tegra_writel, + .reg_readl = hda_tegra_readl, + .reg_writew = hda_tegra_writew, + .reg_readw = hda_tegra_readw, + .reg_writeb = hda_tegra_writeb, + .reg_readb = hda_tegra_readb, + .dma_alloc_pages = dma_alloc_pages, + .dma_free_pages = dma_free_pages, + .substream_alloc_pages = substream_alloc_pages, + .substream_free_pages = substream_free_pages, +}; + +static void hda_tegra_init(struct hda_tegra *hda) +{ + u32 v; + + /* Enable PCI access */ + v = readl(hda->regs + HDA_IPFS_CONFIG); + v |= HDA_IPFS_EN_FPCI; + writel(v, hda->regs + HDA_IPFS_CONFIG); + + /* Enable MEM/IO space and bus master */ + v = readl(hda->regs + HDA_CFG_CMD); + v &= ~HDA_DISABLE_INTR; + v |= HDA_ENABLE_MEM_SPACE | HDA_ENABLE_IO_SPACE | + HDA_ENABLE_BUS_MASTER | HDA_ENABLE_SERR; + writel(v, hda->regs + HDA_CFG_CMD); + + writel(HDA_BAR0_INIT_PROGRAM, hda->regs + HDA_CFG_BAR0); + writel(HDA_BAR0_FINAL_PROGRAM, hda->regs + HDA_CFG_BAR0); + writel(HDA_FPCI_BAR0_START, hda->regs + HDA_IPFS_FPCI_BAR0); + + v = readl(hda->regs + HDA_IPFS_INTR_MASK); + v |= HDA_IPFS_EN_INTR; + writel(v, hda->regs + HDA_IPFS_INTR_MASK); +} + +static int hda_tegra_enable_clocks(struct hda_tegra *data) +{ + int rc; + + rc = clk_prepare_enable(data->hda_clk); + if (rc) + return rc; + rc = clk_prepare_enable(data->hda2codec_2x_clk); + if (rc) + goto disable_hda; + rc = clk_prepare_enable(data->hda2hdmi_clk); + if (rc) + goto disable_codec_2x; + + return 0; + +disable_codec_2x: + clk_disable_unprepare(data->hda2codec_2x_clk); +disable_hda: + clk_disable_unprepare(data->hda_clk); + return rc; +} + +#ifdef CONFIG_PM_SLEEP +static void hda_tegra_disable_clocks(struct hda_tegra *data) +{ + clk_disable_unprepare(data->hda2hdmi_clk); + clk_disable_unprepare(data->hda2codec_2x_clk); + clk_disable_unprepare(data->hda_clk); +} + +/* + * power management + */ +static int hda_tegra_suspend(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct azx_pcm *p; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + list_for_each_entry(p, &chip->pcm_list, list) + snd_pcm_suspend_all(p->pcm); + if (chip->initialized) + snd_hda_suspend(chip->bus); + + azx_stop_chip(chip); + azx_enter_link_reset(chip); + hda_tegra_disable_clocks(hda); + + return 0; +} + +static int hda_tegra_resume(struct device *dev) +{ + struct snd_card *card = dev_get_drvdata(dev); + struct azx *chip = card->private_data; + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + int status; + + hda_tegra_enable_clocks(hda); + + /* Read STATESTS before controller reset */ + status = azx_readw(chip, STATESTS); + + hda_tegra_init(hda); + + azx_init_chip(chip, 1); + + snd_hda_resume(chip->bus); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} +#endif /* CONFIG_PM_SLEEP */ + +static const struct dev_pm_ops hda_tegra_pm = { + SET_SYSTEM_SLEEP_PM_OPS(hda_tegra_suspend, hda_tegra_resume) +}; + +/* + * reboot notifier for hang-up problem at power-down + */ +static int hda_tegra_halt(struct notifier_block *nb, unsigned long event, + void *buf) +{ + struct azx *chip = container_of(nb, struct azx, reboot_notifier); + snd_hda_bus_reboot_notify(chip->bus); + azx_stop_chip(chip); + return NOTIFY_OK; +} + +static void hda_tegra_notifier_register(struct azx *chip) +{ + chip->reboot_notifier.notifier_call = hda_tegra_halt; + register_reboot_notifier(&chip->reboot_notifier); +} + +static void hda_tegra_notifier_unregister(struct azx *chip) +{ + if (chip->reboot_notifier.notifier_call) + unregister_reboot_notifier(&chip->reboot_notifier); +} + +/* + * destructor + */ +static int hda_tegra_dev_free(struct snd_device *device) +{ + int i; + struct azx *chip = device->device_data; + + hda_tegra_notifier_unregister(chip); + + if (chip->initialized) { + for (i = 0; i < chip->num_streams; i++) + azx_stream_stop(chip, &chip->azx_dev[i]); + azx_stop_chip(chip); + } + + azx_free_stream_pages(chip); + + return 0; +} + +static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev) +{ + struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip); + struct device *dev = hda->dev; + struct resource *res; + int err; + + hda->hda_clk = devm_clk_get(dev, "hda"); + if (IS_ERR(hda->hda_clk)) + return PTR_ERR(hda->hda_clk); + hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x"); + if (IS_ERR(hda->hda2codec_2x_clk)) + return PTR_ERR(hda->hda2codec_2x_clk); + hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi"); + if (IS_ERR(hda->hda2hdmi_clk)) + return PTR_ERR(hda->hda2hdmi_clk); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + hda->regs = devm_ioremap_resource(dev, res); + if (IS_ERR(chip->remap_addr)) + return PTR_ERR(chip->remap_addr); + + chip->remap_addr = hda->regs + HDA_BAR0; + chip->addr = res->start + HDA_BAR0; + + err = hda_tegra_enable_clocks(hda); + if (err) + return err; + + hda_tegra_init(hda); + + return 0; +} + +/* + * The codecs were powered up in snd_hda_codec_new(). + * Now all initialization done, so turn them down if possible + */ +static void power_down_all_codecs(struct azx *chip) +{ + struct hda_codec *codec; + list_for_each_entry(codec, &chip->bus->codec_list, list) + snd_hda_power_down(codec); +} + +static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev) +{ + struct snd_card *card = chip->card; + int err; + unsigned short gcap; + int irq_id = platform_get_irq(pdev, 0); + + err = hda_tegra_init_chip(chip, pdev); + if (err) + return err; + + err = devm_request_irq(chip->card->dev, irq_id, azx_interrupt, + IRQF_SHARED, KBUILD_MODNAME, chip); + if (err) { + dev_err(chip->card->dev, + "unable to request IRQ %d, disabling device\n", + irq_id); + return err; + } + chip->irq = irq_id; + + synchronize_irq(chip->irq); + + gcap = azx_readw(chip, GCAP); + dev_dbg(card->dev, "chipset global capabilities = 0x%x\n", gcap); + + /* read number of streams from GCAP register instead of using + * hardcoded value + */ + chip->capture_streams = (gcap >> 8) & 0x0f; + chip->playback_streams = (gcap >> 12) & 0x0f; + if (!chip->playback_streams && !chip->capture_streams) { + /* gcap didn't give any info, switching to old method */ + chip->playback_streams = NUM_PLAYBACK_SD; + chip->capture_streams = NUM_CAPTURE_SD; + } + chip->capture_index_offset = 0; + chip->playback_index_offset = chip->capture_streams; + chip->num_streams = chip->playback_streams + chip->capture_streams; + chip->azx_dev = devm_kcalloc(card->dev, chip->num_streams, + sizeof(*chip->azx_dev), GFP_KERNEL); + if (!chip->azx_dev) + return -ENOMEM; + + err = azx_alloc_stream_pages(chip); + if (err < 0) + return err; + + /* initialize streams */ + azx_init_stream(chip); + + /* initialize chip */ + azx_init_chip(chip, 1); + + /* codec detection */ + if (!chip->codec_mask) { + dev_err(card->dev, "no codecs found!\n"); + return -ENODEV; + } + + strcpy(card->driver, "tegra-hda"); + strcpy(card->shortname, "tegra-hda"); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx irq %i", + card->shortname, chip->addr, chip->irq); + + return 0; +} + +/* + * constructor + */ +static int hda_tegra_create(struct snd_card *card, + unsigned int driver_caps, + const struct hda_controller_ops *hda_ops, + struct hda_tegra *hda) +{ + static struct snd_device_ops ops = { + .dev_free = hda_tegra_dev_free, + }; + struct azx *chip; + int err; + + chip = &hda->chip; + + spin_lock_init(&chip->reg_lock); + mutex_init(&chip->open_mutex); + chip->card = card; + chip->ops = hda_ops; + chip->irq = -1; + chip->driver_caps = driver_caps; + chip->driver_type = driver_caps & 0xff; + chip->dev_index = 0; + INIT_LIST_HEAD(&chip->pcm_list); + INIT_LIST_HEAD(&chip->list); + + chip->position_fix[0] = POS_FIX_AUTO; + chip->position_fix[1] = POS_FIX_AUTO; + chip->codec_probe_mask = -1; + + chip->single_cmd = false; + chip->snoop = true; + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + dev_err(card->dev, "Error creating device\n"); + return err; + } + + return 0; +} + +static const struct of_device_id hda_tegra_match[] = { + { .compatible = "nvidia,tegra30-hda" }, + {}, +}; +MODULE_DEVICE_TABLE(of, hda_tegra_match); + +static int hda_tegra_probe(struct platform_device *pdev) +{ + struct snd_card *card; + struct azx *chip; + struct hda_tegra *hda; + int err; + const unsigned int driver_flags = AZX_DCAPS_RIRB_DELAY; + + hda = devm_kzalloc(&pdev->dev, sizeof(*hda), GFP_KERNEL); + if (!hda) + return -ENOMEM; + hda->dev = &pdev->dev; + chip = &hda->chip; + + err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, + THIS_MODULE, 0, &card); + if (err < 0) { + dev_err(&pdev->dev, "Error creating card!\n"); + return err; + } + + err = hda_tegra_create(card, driver_flags, &hda_tegra_ops, hda); + if (err < 0) + goto out_free; + card->private_data = chip; + + dev_set_drvdata(&pdev->dev, card); + + err = hda_tegra_first_init(chip, pdev); + if (err < 0) + goto out_free; + + /* create codec instances */ + err = azx_codec_create(chip, NULL, 0, &power_save); + if (err < 0) + goto out_free; + + err = azx_codec_configure(chip); + if (err < 0) + goto out_free; + + /* create PCM streams */ + err = snd_hda_build_pcms(chip->bus); + if (err < 0) + goto out_free; + + /* create mixer controls */ + err = azx_mixer_create(chip); + if (err < 0) + goto out_free; + + err = snd_card_register(chip->card); + if (err < 0) + goto out_free; + + chip->running = 1; + power_down_all_codecs(chip); + hda_tegra_notifier_register(chip); + + return 0; + +out_free: + snd_card_free(card); + return err; +} + +static int hda_tegra_remove(struct platform_device *pdev) +{ + return snd_card_free(dev_get_drvdata(&pdev->dev)); +} + +static struct platform_driver tegra_platform_hda = { + .driver = { + .name = "tegra-hda", + .pm = &hda_tegra_pm, + .of_match_table = hda_tegra_match, + }, + .probe = hda_tegra_probe, + .remove = hda_tegra_remove, +}; +module_platform_driver(tegra_platform_hda); + +MODULE_DESCRIPTION("Tegra HDA bus driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index cdd43eadbc6..06275f8807a 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -20,9 +20,7 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> @@ -31,126 +29,20 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" -struct ad198x_spec { - const struct snd_kcontrol_new *mixers[6]; - int num_mixers; - unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - const struct hda_verb *init_verbs[6]; /* initialization verbs - * don't forget NULL termination! - */ - unsigned int num_init_verbs; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - unsigned int cur_eapd; - unsigned int need_dac_fix; - - const hda_nid_t *alt_dac_nid; - const struct hda_pcm_stream *stream_analog_alt_playback; - int independent_hp; - int num_active_streams; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - - /* capture source */ - const struct hda_input_mux *input_mux; - const hda_nid_t *capsrc_nids; - unsigned int cur_mux[3]; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - - unsigned int spdif_route; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - struct hda_input_mux private_imux; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - - unsigned int jack_present: 1; - unsigned int inv_jack_detect: 1;/* inverted jack-detection */ - unsigned int inv_eapd: 1; /* inverted EAPD implementation */ - unsigned int analog_beep: 1; /* analog beep input present */ - unsigned int avoid_init_slave_vol:1; - -#ifdef CONFIG_PM - struct hda_loopback_check loopback; -#endif - /* for virtual master */ - hda_nid_t vmaster_nid; - const char * const *slave_vols; - const char * const *slave_sws; -}; - -/* - * input MUX handling (common part) - */ -static int ad198x_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - - return snd_hda_input_mux_info(spec->input_mux, uinfo); -} - -static int ad198x_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} -static int ad198x_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, - spec->capsrc_nids[adc_idx], - &spec->cur_mux[adc_idx]); -} - -/* - * initialization (common callbacks) - */ -static int ad198x_init(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_init_verbs; i++) - snd_hda_sequence_write(codec, spec->init_verbs[i]); - return 0; -} +struct ad198x_spec { + struct hda_gen_spec gen; -static const char * const ad_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Mono", "Speaker", "IEC958", - NULL -}; + /* for auto parser */ + int smux_paths[4]; + unsigned int cur_smux; + hda_nid_t eapd_nid; -static const char * const ad1988_6stack_fp_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", "IEC958", - NULL + unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ }; -static void ad198x_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ @@ -160,438 +52,48 @@ static const struct snd_kcontrol_new ad_beep_mixer[] = { { } /* end */ }; -static const struct snd_kcontrol_new ad_beep2_mixer[] = { - HDA_CODEC_VOLUME("Digital Beep Playback Volume", 0, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP("Digital Beep Playback Switch", 0, 0, HDA_OUTPUT), - { } /* end */ -}; - #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) /* mono */ #else #define set_beep_amp(spec, nid, idx, dir) /* NOP */ #endif -static int ad198x_build_controls(struct hda_codec *codec) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static int create_beep_ctls(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - struct snd_kcontrol *kctl; - unsigned int i; - int err; + const struct snd_kcontrol_new *knew; - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* create beep controls if needed */ -#ifdef CONFIG_SND_HDA_INPUT_BEEP - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - knew = spec->analog_beep ? ad_beep2_mixer : ad_beep_mixer; - for ( ; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif - - /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = __snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, - (spec->slave_vols ? - spec->slave_vols : ad_slave_pfxs), - "Playback Volume", - !spec->avoid_init_slave_vol, NULL); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, - (spec->slave_sws ? - spec->slave_sws : ad_slave_pfxs), - "Playback Switch"); - if (err < 0) - return err; - } - - ad198x_free_kctls(codec); /* no longer needed */ - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); - if (err < 0) - return err; - } + if (!spec->beep_amp) + return 0; - /* assign IEC958 enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, - SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); - if (kctl) { - err = snd_hda_add_nid(codec, kctl, 0, - spec->multiout.dig_out_nid); + for (knew = ad_beep_mixer ; knew->name; knew++) { + int err; + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } - return 0; } - -#ifdef CONFIG_PM -static int ad198x_check_power_status(struct hda_codec *codec, hda_nid_t nid) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} +#else +#define create_beep_ctls(codec) 0 #endif -static void activate_ctl(struct hda_codec *codec, const char *name, int active) -{ - struct snd_kcontrol *ctl = snd_hda_find_mixer_ctl(codec, name); - if (ctl) { - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access |= active ? 0 : - SNDRV_CTL_ELEM_ACCESS_INACTIVE; - ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_WRITE; - ctl->vd[0].access |= active ? - SNDRV_CTL_ELEM_ACCESS_WRITE : 0; - snd_ctl_notify(codec->bus->card, - SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); - } -} - -static void set_stream_active(struct hda_codec *codec, bool active) -{ - struct ad198x_spec *spec = codec->spec; - if (active) - spec->num_active_streams++; - else - spec->num_active_streams--; - activate_ctl(codec, "Independent HP", spec->num_active_streams == 0); -} - -static int ad1988_independent_hp_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "OFF", "ON", NULL}; - int index; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - index = uinfo->value.enumerated.item; - if (index >= 2) - index = 1; - strcpy(uinfo->value.enumerated.name, texts[index]); - return 0; -} - -static int ad1988_independent_hp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->independent_hp; - return 0; -} - -static int ad1988_independent_hp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - unsigned int select = ucontrol->value.enumerated.item[0]; - if (spec->independent_hp != select) { - spec->independent_hp = select; - if (spec->independent_hp) - spec->multiout.hp_nid = 0; - else - spec->multiout.hp_nid = spec->alt_dac_nid[0]; - return 1; - } - return 0; -} - -/* - * Analog playback callbacks - */ -static int ad198x_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - int err; - set_stream_active(codec, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); - if (err < 0) { - set_stream_active(codec, false); - return err; - } - return 0; -} - -static int ad198x_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int ad198x_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_analog_cleanup(codec, &spec->multiout); -} - -static int ad198x_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - -static int ad1988_alt_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - if (!spec->independent_hp) - return -EBUSY; - set_stream_active(codec, true); - return 0; -} - -static int ad1988_alt_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_active(codec, false); - return 0; -} - -static const struct hda_pcm_stream ad198x_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ad1988_alt_playback_pcm_open, - .close = ad1988_alt_playback_pcm_close - }, -}; - -/* - * Digital out - */ -static int ad198x_dig_playback_pcm_open(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_open(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_close(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_close(codec, &spec->multiout); -} - -static int ad198x_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - 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 - */ -static int ad198x_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ad198x_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ad198x_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - -/* - */ -static const struct hda_pcm_stream ad198x_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 6, /* changed later */ - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_playback_pcm_open, - .prepare = ad198x_playback_pcm_prepare, - .cleanup = ad198x_playback_pcm_cleanup, - .close = ad198x_playback_pcm_close - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = ad198x_capture_pcm_prepare, - .cleanup = ad198x_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .open = ad198x_dig_playback_pcm_open, - .close = ad198x_dig_playback_pcm_close, - .prepare = ad198x_dig_playback_pcm_prepare, - .cleanup = ad198x_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ad198x_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static int ad198x_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - info->name = "AD198x Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_adc_nids; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - - if (spec->multiout.dig_out_nid) { - info++; - codec->num_pcms++; - info->name = "AD198x Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ad198x_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad198x_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - if (spec->alt_dac_nid && spec->stream_analog_alt_playback) { - codec->num_pcms++; - info = spec->pcm_rec + 2; - info->name = "AD198x Headphone"; - info->pcm_type = HDA_PCM_TYPE_AUDIO; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid[0]; - } - - return 0; -} - -static void ad198x_free_kctls(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, hda_nid_t hp) { - struct ad198x_spec *spec = codec->spec; if (snd_hda_query_pin_caps(codec, front) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, - !spec->inv_eapd ? 0x00 : 0x02); + !codec->inv_eapd ? 0x00 : 0x02); if (snd_hda_query_pin_caps(codec, hp) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, - !spec->inv_eapd ? 0x00 : 0x02); + !codec->inv_eapd ? 0x00 : 0x02); } static void ad198x_power_eapd(struct hda_codec *codec) @@ -628,19 +130,6 @@ static void ad198x_shutup(struct hda_codec *codec) ad198x_power_eapd(codec); } -static void ad198x_free(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - - if (!spec) - return; - - ad198x_shutup(codec); - ad198x_free_kctls(codec); - kfree(spec); - snd_hda_detach_beep_device(codec); -} - #ifdef CONFIG_PM static int ad198x_suspend(struct hda_codec *codec) { @@ -649,942 +138,387 @@ static int ad198x_suspend(struct hda_codec *codec) } #endif -static const struct hda_codec_ops ad198x_patch_ops = { - .build_controls = ad198x_build_controls, - .build_pcms = ad198x_build_pcms, - .init = ad198x_init, - .free = ad198x_free, -#ifdef CONFIG_PM - .check_power_status = ad198x_check_power_status, - .suspend = ad198x_suspend, -#endif - .reboot_notify = ad198x_shutup, -}; - - -/* - * EAPD control - * the private value = nid - */ -#define ad198x_eapd_info snd_ctl_boolean_mono_info - -static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* follow EAPD via vmaster hook */ +static void ad_vmaster_eapd_hook(void *private_data, int enabled) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct hda_codec *codec = private_data; struct ad198x_spec *spec = codec->spec; - if (spec->inv_eapd) - ucontrol->value.integer.value[0] = ! spec->cur_eapd; - else - ucontrol->value.integer.value[0] = spec->cur_eapd; - return 0; -} -static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct ad198x_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int eapd; - eapd = !!ucontrol->value.integer.value[0]; - if (spec->inv_eapd) - eapd = !eapd; - if (eapd == spec->cur_eapd) - return 0; - spec->cur_eapd = eapd; - snd_hda_codec_write_cache(codec, nid, - 0, AC_VERB_SET_EAPD_BTLENABLE, - eapd ? 0x02 : 0x00); - return 1; + if (!spec->eapd_nid) + return; + if (codec->inv_eapd) + enabled = !enabled; + snd_hda_codec_update_cache(codec, spec->eapd_nid, 0, + AC_VERB_SET_EAPD_BTLENABLE, + enabled ? 0x02 : 0x00); } -static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo); -static int ad198x_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); -static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - - -/* - * AD1986A specific - */ - -#define AD1986A_SPDIF_OUT 0x02 -#define AD1986A_FRONT_DAC 0x03 -#define AD1986A_SURR_DAC 0x04 -#define AD1986A_CLFE_DAC 0x05 -#define AD1986A_ADC 0x06 - -static const hda_nid_t ad1986a_dac_nids[3] = { - AD1986A_FRONT_DAC, AD1986A_SURR_DAC, AD1986A_CLFE_DAC -}; -static const hda_nid_t ad1986a_adc_nids[1] = { AD1986A_ADC }; -static const hda_nid_t ad1986a_capsrc_nids[1] = { 0x12 }; - -static const struct hda_input_mux ad1986a_capture_source = { - .num_items = 7, - .items = { - { "Mic", 0x0 }, - { "CD", 0x1 }, - { "Aux", 0x3 }, - { "Line", 0x4 }, - { "Mix", 0x5 }, - { "Mono", 0x6 }, - { "Phone", 0x7 }, - }, -}; - - -static const struct hda_bind_ctls ad1986a_bind_pcm_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -static const struct hda_bind_ctls ad1986a_bind_pcm_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(AD1986A_FRONT_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_SURR_DAC, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(AD1986A_CLFE_DAC, 3, 0, HDA_OUTPUT), - 0 - }, -}; - /* - * mixers + * Automatic parse of I/O pins from the BIOS configuration */ -static const struct snd_kcontrol_new ad1986a_mixers[] = { - /* - * bind volumes/mutes of 3 DACs as a single PCM control for simplicity - */ - HDA_BIND_VOL("PCM Playback Volume", &ad1986a_bind_pcm_vol), - HDA_BIND_SW("PCM Playback Switch", &ad1986a_bind_pcm_sw), - HDA_CODEC_VOLUME("Front Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Surround Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x1d, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x1d, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - HDA_CODEC_MUTE("Stereo Downmix Switch", 0x09, 0x0, HDA_OUTPUT), - { } /* end */ -}; -/* additional mixers for 3stack mode */ -static const struct snd_kcontrol_new ad1986a_3st_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - { } /* end */ -}; - -/* laptop model - 2ch only */ -static const hda_nid_t ad1986a_laptop_dac_nids[1] = { AD1986A_FRONT_DAC }; - -/* master controls both pins 0x1a and 0x1b */ -static const struct hda_bind_ctls ad1986a_laptop_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; +static int ad198x_auto_build_controls(struct hda_codec *codec) +{ + int err; -static const struct hda_bind_ctls ad1986a_laptop_master_sw = { - .ops = &snd_hda_bind_sw, - .values = { - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - 0, - }, -}; + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + err = create_beep_ctls(codec); + if (err < 0) + return err; + return 0; +} -static const struct snd_kcontrol_new ad1986a_laptop_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), - HDA_CODEC_VOLUME("CD Playback Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x17, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - /* - HDA_CODEC_VOLUME("Mono Playback Volume", 0x1e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mono Playback Switch", 0x1e, 0x0, HDA_OUTPUT), */ - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ +static const struct hda_codec_ops ad198x_auto_patch_ops = { + .build_controls = ad198x_auto_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM + .check_power_status = snd_hda_gen_check_power_status, + .suspend = ad198x_suspend, +#endif + .reboot_notify = ad198x_shutup, }; -/* laptop-eapd model - 2ch only */ -static const struct hda_input_mux ad1986a_laptop_eapd_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x4 }, - { "Mix", 0x5 }, - }, -}; +static int ad198x_parse_auto_config(struct hda_codec *codec, bool indep_hp) +{ + struct ad198x_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int err; -static const struct hda_input_mux ad1986a_automic_capture_source = { - .num_items = 2, - .items = { - { "Mic", 0x0 }, - { "Mix", 0x5 }, - }, -}; + codec->spdif_status_reset = 1; + codec->no_trigger_sense = 1; + codec->no_sticky_stream = 1; -static const struct snd_kcontrol_new ad1986a_laptop_master_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - HDA_BIND_SW("Master Playback Switch", &ad1986a_laptop_master_sw), - { } /* end */ -}; + spec->gen.indep_hp = indep_hp; + spec->gen.add_stereo_mix_input = 1; -static const struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0f, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x12, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x1b, /* port-D */ - }, - { } /* end */ -}; + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + return err; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; -static const struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0, HDA_OUTPUT), - { } /* end */ -}; + codec->patch_ops = ad198x_auto_patch_ops; -/* re-connect the mic boost input according to the jack sensing */ -static void ad1986a_automic(struct hda_codec *codec) -{ - unsigned int present; - present = snd_hda_jack_detect(codec, 0x1f); - /* 0 = 0x1f, 2 = 0x1d, 4 = mixed */ - snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 2); + return 0; } -#define AD1986A_MIC_EVENT 0x36 +/* + * AD1986A specific + */ -static void ad1986a_automic_unsol_event(struct hda_codec *codec, - unsigned int res) +static int alloc_ad_spec(struct hda_codec *codec) { - if ((res >> 26) != AD1986A_MIC_EVENT) - return; - ad1986a_automic(codec); -} + struct ad198x_spec *spec; -static int ad1986a_automic_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_automic(codec); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + codec->spec = spec; + snd_hda_gen_spec_init(&spec->gen); return 0; } -/* laptop-automute - 2ch only */ +/* + * AD1986A fixup codes + */ -static void ad1986a_update_hp(struct hda_codec *codec) +/* Lenovo N100 seems to report the reversed bit for HP jack-sensing */ +static void ad_fixup_inv_jack_detect(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct ad198x_spec *spec = codec->spec; - unsigned int mute; - if (spec->jack_present) - mute = HDA_AMP_MUTE; /* mute internal speaker */ - else - /* unmute internal speaker if necessary */ - mute = snd_hda_codec_amp_read(codec, 0x1a, 0, HDA_OUTPUT, 0); - snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + codec->inv_jack_detect = 1; + spec->gen.keep_eapd_on = 1; + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + spec->eapd_nid = 0x1b; + } } -static void ad1986a_hp_automute(struct hda_codec *codec) +/* Toshiba Satellite L40 implements EAPD in a standard way unlike others */ +static void ad1986a_fixup_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct ad198x_spec *spec = codec->spec; - spec->jack_present = snd_hda_jack_detect(codec, 0x1a); - if (spec->inv_jack_detect) - spec->jack_present = !spec->jack_present; - ad1986a_update_hp(codec); -} - -#define AD1986A_HP_EVENT 0x37 - -static void ad1986a_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != AD1986A_HP_EVENT) - return; - ad1986a_hp_automute(codec); -} - -static int ad1986a_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_hp_automute(codec); - return 0; -} - -/* bind hp and internal speaker mute (with plug check) */ -static int ad1986a_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - long *valp = ucontrol->value.integer.value; - int change; - - change = snd_hda_codec_amp_update(codec, 0x1a, 0, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[0] ? 0 : HDA_AMP_MUTE); - change |= snd_hda_codec_amp_update(codec, 0x1a, 1, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - valp[1] ? 0 : HDA_AMP_MUTE); - if (change) - ad1986a_update_hp(codec); - return change; -} - -static const struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1986a_laptop_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1986a_hp_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_OUTPUT), - }, - { } /* end */ -}; - - -/* - * initialization verbs - */ -static const struct hda_verb ad1986a_init_verbs[] = { - /* Front, Surround, CLFE DAC; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Downmix - off */ - {0x09, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP, Line-Out, Surround, CLFE selectors */ - {0x0a, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic selector: Mic 1/2 pin */ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x10, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic 1/2 swap */ - {0x11, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Record selector: mic */ - {0x12, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic, Phone, CD, Aux, Line-In amp; mute as default */ - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* PC beep */ - {0x18, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* HP, Line-Out, Surround, CLFE, Mono pins; mute as default */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* HP Pin */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Front, Surround, CLFE Pins */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mono Pin */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line, Aux, CD, Beep-In Pin */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch2_init[] = { - /* Surround out -> Line In */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* Line-in selectors */ - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x1 }, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - /* Mic selector, mix C/LFE (backmic) and Mic (frontmic) */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch4_init[] = { - /* Surround out -> Surround */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* CLFE -> Mic in */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x4 }, - { } /* end */ -}; - -static const struct hda_verb ad1986a_ch6_init[] = { - /* Surround out -> Surround out */ - { 0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x10, AC_VERB_SET_CONNECT_SEL, 0x0 }, - /* CLFE -> CLFE */ - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x0 }, - { } /* end */ -}; - -static const struct hda_channel_mode ad1986a_modes[3] = { - { 2, ad1986a_ch2_init }, - { 4, ad1986a_ch4_init }, - { 6, ad1986a_ch6_init }, -}; - -/* eapd initialization */ -static const struct hda_verb ad1986a_eapd_init_verbs[] = { - {0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - {} -}; - -static const struct hda_verb ad1986a_automic_verbs[] = { - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /*{0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80},*/ - {0x0f, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x1f, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_MIC_EVENT}, - {} -}; - -/* Ultra initialization */ -static const struct hda_verb ad1986a_ultra_init[] = { - /* eapd initialization */ - { 0x1b, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, - /* CLFE -> Mic in */ - { 0x0f, AC_VERB_SET_CONNECT_SEL, 0x2 }, - { 0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - { 0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080 }, - { } /* end */ -}; - -/* pin sensing on HP jack */ -static const struct hda_verb ad1986a_hp_init_verbs[] = { - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1986A_HP_EVENT}, - {} -}; - -static void ad1986a_samsung_p50_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1986A_HP_EVENT: - ad1986a_hp_automute(codec); - break; - case AD1986A_MIC_EVENT: - ad1986a_automic(codec); - break; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + codec->inv_eapd = 0; + spec->gen.keep_eapd_on = 1; + spec->eapd_nid = 0x1b; } } -static int ad1986a_samsung_p50_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1986a_hp_automute(codec); - ad1986a_automic(codec); - return 0; -} - - -/* models */ enum { - AD1986A_6STACK, - AD1986A_3STACK, - AD1986A_LAPTOP, - AD1986A_LAPTOP_EAPD, - AD1986A_LAPTOP_AUTOMUTE, - AD1986A_ULTRA, - AD1986A_SAMSUNG, - AD1986A_SAMSUNG_P50, - AD1986A_MODELS -}; - -static const char * const ad1986a_models[AD1986A_MODELS] = { - [AD1986A_6STACK] = "6stack", - [AD1986A_3STACK] = "3stack", - [AD1986A_LAPTOP] = "laptop", - [AD1986A_LAPTOP_EAPD] = "laptop-eapd", - [AD1986A_LAPTOP_AUTOMUTE] = "laptop-automute", - [AD1986A_ULTRA] = "ultra", - [AD1986A_SAMSUNG] = "samsung", - [AD1986A_SAMSUNG_P50] = "samsung-p50", + AD1986A_FIXUP_INV_JACK_DETECT, + AD1986A_FIXUP_ULTRA, + AD1986A_FIXUP_SAMSUNG, + AD1986A_FIXUP_3STACK, + AD1986A_FIXUP_LAPTOP, + AD1986A_FIXUP_LAPTOP_IMIC, + AD1986A_FIXUP_EAPD, +}; + +static const struct hda_fixup ad1986a_fixups[] = { + [AD1986A_FIXUP_INV_JACK_DETECT] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad_fixup_inv_jack_detect, + }, + [AD1986A_FIXUP_ULTRA] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1d, 0x90a7013e }, /* int mic */ + {} + }, + }, + [AD1986A_FIXUP_SAMSUNG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1d, 0x90a7013e }, /* int mic */ + { 0x20, 0x411111f0 }, /* N/A */ + { 0x24, 0x411111f0 }, /* N/A */ + {} + }, + }, + [AD1986A_FIXUP_3STACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02214021 }, /* headphone */ + { 0x1b, 0x01014011 }, /* front */ + { 0x1c, 0x01813030 }, /* line-in */ + { 0x1d, 0x01a19020 }, /* rear mic */ + { 0x1e, 0x411111f0 }, /* N/A */ + { 0x1f, 0x02a190f0 }, /* mic */ + { 0x20, 0x411111f0 }, /* N/A */ + {} + }, + }, + [AD1986A_FIXUP_LAPTOP] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x02214021 }, /* headphone */ + { 0x1b, 0x90170110 }, /* speaker */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0x411111f0 }, /* N/A */ + { 0x1f, 0x02a191f0 }, /* mic */ + { 0x20, 0x411111f0 }, /* N/A */ + {} + }, + }, + [AD1986A_FIXUP_LAPTOP_IMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1d, 0x90a7013e }, /* int mic */ + {} + }, + .chained_before = 1, + .chain_id = AD1986A_FIXUP_LAPTOP, + }, + [AD1986A_FIXUP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1986a_fixup_eapd, + }, }; -static const struct snd_pci_quirk ad1986a_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1153, "ASUS M9", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x11f7, "ASUS U5A", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1213, "ASUS A6J", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1263, "ASUS U5F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1297, "ASUS Z62F", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS V1j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1302, "ASUS W3j", AD1986A_LAPTOP_EAPD), - SND_PCI_QUIRK(0x1043, 0x1443, "ASUS VX1", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8J", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x817f, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x818f, "ASUS P5", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS P5", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x81cb, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x1043, 0x8234, "ASUS M2N", AD1986A_3STACK), - SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_3STACK), - SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40-10Q", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xb03c, "Samsung R55", AD1986A_3STACK), - SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x144d, 0xc024, "Samsung P50", AD1986A_SAMSUNG_P50), - SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_ULTRA), - SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_SAMSUNG), - SND_PCI_QUIRK(0x144d, 0xc504, "Samsung Q35", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_LAPTOP), - SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_3STACK), - SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_LAPTOP_AUTOMUTE), - SND_PCI_QUIRK(0x17c0, 0x2017, "Samsung M50", AD1986A_LAPTOP), +static const struct snd_pci_quirk ad1986a_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC), + SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD), + SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x10de, 0xcb84, "ASUS A8N-VM", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x1179, 0xff40, "Toshiba Satellite L40", AD1986A_FIXUP_EAPD), + SND_PCI_QUIRK(0x144d, 0xc01e, "FSC V2060", AD1986A_FIXUP_LAPTOP), + SND_PCI_QUIRK_MASK(0x144d, 0xff00, 0xc000, "Samsung", AD1986A_FIXUP_SAMSUNG), + SND_PCI_QUIRK(0x144d, 0xc027, "Samsung Q1", AD1986A_FIXUP_ULTRA), + SND_PCI_QUIRK(0x17aa, 0x2066, "Lenovo N100", AD1986A_FIXUP_INV_JACK_DETECT), + SND_PCI_QUIRK(0x17aa, 0x1011, "Lenovo M55", AD1986A_FIXUP_3STACK), + SND_PCI_QUIRK(0x17aa, 0x1017, "Lenovo A60", AD1986A_FIXUP_3STACK), {} }; -#ifdef CONFIG_PM -static const struct hda_amp_list ad1986a_loopbacks[] = { - { 0x13, HDA_OUTPUT, 0 }, /* Mic */ - { 0x14, HDA_OUTPUT, 0 }, /* Phone */ - { 0x15, HDA_OUTPUT, 0 }, /* CD */ - { 0x16, HDA_OUTPUT, 0 }, /* Aux */ - { 0x17, HDA_OUTPUT, 0 }, /* Line */ - { } /* end */ +static const struct hda_model_fixup ad1986a_fixup_models[] = { + { .id = AD1986A_FIXUP_3STACK, .name = "3stack" }, + { .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" }, + { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" }, + { .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */ + {} }; -#endif - -static int is_jack_available(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int conf = snd_hda_codec_get_pincfg(codec, nid); - return get_defcfg_connect(conf) != AC_JACK_PORT_NONE; -} +/* + */ static int patch_ad1986a(struct hda_codec *codec) { + int err; struct ad198x_spec *spec; - int err, board_config; + static hda_nid_t preferred_pairs[] = { + 0x1a, 0x03, + 0x1b, 0x03, + 0x1c, 0x04, + 0x1d, 0x05, + 0x1e, 0x03, + 0 + }; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_ad_spec(codec); + if (err < 0) + return err; + spec = codec->spec; - codec->spec = spec; + /* AD1986A has the inverted EAPD implementation */ + codec->inv_eapd = 1; - err = snd_hda_attach_beep_device(codec, 0x19); - if (err < 0) { - ad198x_free(codec); - return err; - } + spec->gen.mixer_nid = 0x07; + spec->gen.beep_nid = 0x19; set_beep_amp(spec, 0x18, 0, HDA_OUTPUT); - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = ARRAY_SIZE(ad1986a_dac_nids); - spec->multiout.dac_nids = ad1986a_dac_nids; - spec->multiout.dig_out_nid = AD1986A_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1986a_adc_nids; - spec->capsrc_nids = ad1986a_capsrc_nids; - spec->input_mux = &ad1986a_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1986a_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1986a_init_verbs; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1986a_loopbacks; -#endif - spec->vmaster_nid = 0x1b; - spec->inv_eapd = 1; /* AD1986A has the inverted EAPD implementation */ - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1986A_MODELS, - ad1986a_models, - ad1986a_cfg_tbl); - switch (board_config) { - case AD1986A_3STACK: - spec->num_mixers = 2; - spec->mixers[1] = ad1986a_3st_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_ch2_init; - spec->channel_mode = ad1986a_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1986a_modes); - spec->need_dac_fix = 1; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - break; - case AD1986A_LAPTOP: - spec->mixers[0] = ad1986a_laptop_mixers; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - break; - case AD1986A_LAPTOP_EAPD: - spec->num_mixers = 3; - spec->mixers[0] = ad1986a_laptop_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->mixers[2] = ad1986a_laptop_intmic_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - break; - case AD1986A_SAMSUNG: - spec->num_mixers = 2; - spec->mixers[0] = ad1986a_laptop_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 3; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_automic_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_automic_capture_source; - codec->patch_ops.unsol_event = ad1986a_automic_unsol_event; - codec->patch_ops.init = ad1986a_automic_init; - break; - case AD1986A_SAMSUNG_P50: - spec->num_mixers = 2; - spec->mixers[0] = ad1986a_automute_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 4; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_automic_verbs; - spec->init_verbs[3] = ad1986a_hp_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_automic_capture_source; - codec->patch_ops.unsol_event = ad1986a_samsung_p50_unsol_event; - codec->patch_ops.init = ad1986a_samsung_p50_init; - break; - case AD1986A_LAPTOP_AUTOMUTE: - spec->num_mixers = 3; - spec->mixers[0] = ad1986a_automute_master_mixers; - spec->mixers[1] = ad1986a_laptop_eapd_mixers; - spec->mixers[2] = ad1986a_laptop_intmic_mixers; - spec->num_init_verbs = 3; - spec->init_verbs[1] = ad1986a_eapd_init_verbs; - spec->init_verbs[2] = ad1986a_hp_init_verbs; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - if (!is_jack_available(codec, 0x25)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1986a_laptop_eapd_capture_source; - codec->patch_ops.unsol_event = ad1986a_hp_unsol_event; - codec->patch_ops.init = ad1986a_hp_init; - /* Lenovo N100 seems to report the reversed bit - * for HP jack-sensing - */ - spec->inv_jack_detect = 1; - break; - case AD1986A_ULTRA: - spec->mixers[0] = ad1986a_laptop_eapd_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1986a_ultra_init; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1986a_laptop_dac_nids; - spec->multiout.dig_out_nid = 0; - break; - } - /* AD1986A has a hardware problem that it can't share a stream * with multiple output pins. The copy of front to surrounds * causes noisy or silent outputs at a certain timing, e.g. * changing the volume. * So, let's disable the shared stream. */ - spec->multiout.no_share_stream = 1; + spec->gen.multiout.no_share_stream = 1; + /* give fixed DAC/pin pairs */ + spec->gen.preferred_dacs = preferred_pairs; - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + /* AD1986A can't manage the dynamic pin on/off smoothly */ + spec->gen.auto_mute_via_amp = 1; + + snd_hda_pick_fixup(codec, ad1986a_fixup_models, ad1986a_fixup_tbl, + ad1986a_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = ad198x_parse_auto_config(codec, false); + if (err < 0) { + snd_hda_gen_free(codec); + return err; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } + /* * AD1983 specific */ -#define AD1983_SPDIF_OUT 0x02 -#define AD1983_DAC 0x03 -#define AD1983_ADC 0x04 - -static const hda_nid_t ad1983_dac_nids[1] = { AD1983_DAC }; -static const hda_nid_t ad1983_adc_nids[1] = { AD1983_ADC }; -static const hda_nid_t ad1983_capsrc_nids[1] = { 0x15 }; - -static const struct hda_input_mux ad1983_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - }, -}; - /* - * SPDIF playback route + * SPDIF mux control for AD1983 auto-parser */ -static int ad1983_spdif_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +static int ad1983_auto_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { "PCM", "ADC" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item > 1) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ad198x_spec *spec = codec->spec; + static const char * const texts2[] = { "PCM", "ADC" }; + static const char * const texts3[] = { "PCM", "ADC1", "ADC2" }; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns = snd_hda_get_num_conns(codec, dig_out); + + if (num_conns == 2) + return snd_hda_enum_helper_info(kcontrol, uinfo, 2, texts2); + else if (num_conns == 3) + return snd_hda_enum_helper_info(kcontrol, uinfo, 3, texts3); + else + return -EINVAL; } -static int ad1983_spdif_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ad1983_auto_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->spdif_route; + ucontrol->value.enumerated.item[0] = spec->cur_smux; return 0; } -static int ad1983_spdif_route_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int ad1983_auto_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; + unsigned int val = ucontrol->value.enumerated.item[0]; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns = snd_hda_get_num_conns(codec, dig_out); - if (ucontrol->value.enumerated.item[0] > 1) + if (val >= num_conns) return -EINVAL; - if (spec->spdif_route != ucontrol->value.enumerated.item[0]) { - spec->spdif_route = ucontrol->value.enumerated.item[0]; - snd_hda_codec_write_cache(codec, spec->multiout.dig_out_nid, 0, - AC_VERB_SET_CONNECT_SEL, - spec->spdif_route); - return 1; - } - return 0; + if (spec->cur_smux == val) + return 0; + spec->cur_smux = val; + snd_hda_codec_write_cache(codec, dig_out, 0, + AC_VERB_SET_CONNECT_SEL, val); + return 1; } -static const struct snd_kcontrol_new ad1983_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ +static struct snd_kcontrol_new ad1983_auto_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + .info = ad1983_auto_smux_enum_info, + .get = ad1983_auto_smux_enum_get, + .put = ad1983_auto_smux_enum_put, }; -static const struct hda_verb ad1983_init_verbs[] = { - /* Front, HP, Mono; mute as default */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Mic, Line-In: mute */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic selector; Mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Line-in selector: Line-in */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Mic boost: 0dB */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* Record selector: mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Mic Pin */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - { } /* end */ -}; +static int ad1983_add_spdif_mux_ctl(struct hda_codec *codec) +{ + struct ad198x_spec *spec = codec->spec; + hda_nid_t dig_out = spec->gen.multiout.dig_out_nid; + int num_conns; -#ifdef CONFIG_PM -static const struct hda_amp_list ad1983_loopbacks[] = { - { 0x12, HDA_OUTPUT, 0 }, /* Mic */ - { 0x13, HDA_OUTPUT, 0 }, /* Line */ - { } /* end */ -}; -#endif + if (!dig_out) + return 0; + num_conns = snd_hda_get_num_conns(codec, dig_out); + if (num_conns != 2 && num_conns != 3) + return 0; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1983_auto_smux_mixer)) + return -ENOMEM; + return 0; +} static int patch_ad1983(struct hda_codec *codec) { struct ad198x_spec *spec; + static hda_nid_t conn_0c[] = { 0x08 }; + static hda_nid_t conn_0d[] = { 0x09 }; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); + err = alloc_ad_spec(codec); + if (err < 0) return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1983_dac_nids); - spec->multiout.dac_nids = ad1983_dac_nids; - spec->multiout.dig_out_nid = AD1983_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1983_adc_nids; - spec->capsrc_nids = ad1983_capsrc_nids; - spec->input_mux = &ad1983_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1983_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1983_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1983_loopbacks; -#endif - spec->vmaster_nid = 0x05; + spec = codec->spec; - codec->patch_ops = ad198x_patch_ops; + spec->gen.mixer_nid = 0x0e; + spec->gen.beep_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + /* limit the loopback routes not to confuse the parser */ + snd_hda_override_conn_list(codec, 0x0c, ARRAY_SIZE(conn_0c), conn_0c); + snd_hda_override_conn_list(codec, 0x0d, ARRAY_SIZE(conn_0d), conn_0d); + err = ad198x_parse_auto_config(codec, false); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; return 0; + + error: + snd_hda_gen_free(codec); + return err; } @@ -1592,453 +526,89 @@ static int patch_ad1983(struct hda_codec *codec) * AD1981 HD specific */ -#define AD1981_SPDIF_OUT 0x02 -#define AD1981_DAC 0x03 -#define AD1981_ADC 0x04 - -static const hda_nid_t ad1981_dac_nids[1] = { AD1981_DAC }; -static const hda_nid_t ad1981_adc_nids[1] = { AD1981_ADC }; -static const hda_nid_t ad1981_capsrc_nids[1] = { 0x15 }; - -/* 0x0c, 0x09, 0x0e, 0x0f, 0x19, 0x05, 0x18, 0x17 */ -static const struct hda_input_mux ad1981_capture_source = { - .num_items = 7, - .items = { - { "Front Mic", 0x0 }, - { "Line", 0x1 }, - { "Mix", 0x2 }, - { "Mix Mono", 0x3 }, - { "CD", 0x4 }, - { "Mic", 0x6 }, - { "Aux", 0x7 }, - }, -}; - -static const struct snd_kcontrol_new ad1981_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x07, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Aux Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Aux Playback Switch", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct hda_verb ad1981_init_verbs[] = { - /* Front, HP, Mono; mute as default */ - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Beep, PCM, Front Mic, Line, Rear Mic, Aux, CD-In: mute */ - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Front, HP selectors; from Mix */ - {0x05, AC_VERB_SET_CONNECT_SEL, 0x01}, - {0x06, AC_VERB_SET_CONNECT_SEL, 0x01}, - /* Mono selector; from Mix */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x03}, - /* Mic Mixer; select Front Mic */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* Mic boost: 0dB */ - {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Record selector: Front mic */ - {0x15, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - /* SPDIF route: PCM */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Front Pin */ - {0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* HP Pin */ - {0x06, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc0 }, - /* Mono Pin */ - {0x07, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40 }, - /* Front & Rear Mic Pins */ - {0x08, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24 }, - /* Line Pin */ - {0x09, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20 }, - /* Digital Beep */ - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x00}, - /* Line-Out as Input: disabled */ - {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1981_loopbacks[] = { - { 0x12, HDA_OUTPUT, 0 }, /* Front Mic */ - { 0x13, HDA_OUTPUT, 0 }, /* Line */ - { 0x1b, HDA_OUTPUT, 0 }, /* Aux */ - { 0x1c, HDA_OUTPUT, 0 }, /* Mic */ - { 0x1d, HDA_OUTPUT, 0 }, /* CD */ - { } /* end */ -}; -#endif - -/* - * Patch for HP nx6320 - * - * nx6320 uses EAPD in the reverse way - EAPD-on means the internal - * speaker output enabled _and_ mute-LED off. - */ - -#define AD1981_HP_EVENT 0x37 -#define AD1981_MIC_EVENT 0x38 - -static const struct hda_verb ad1981_hp_init_verbs[] = { - {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x00 }, /* default off */ - /* pin sensing on HP and Mic jacks */ - {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -/* turn on/off EAPD (+ mute HP) as a master switch */ -static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void ad1981_fixup_hp_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - if (! ad198x_eapd_put(kcontrol, ucontrol)) - return 0; - /* change speaker pin appropriately */ - snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); - /* toggle HP mute appropriately */ - snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, - HDA_AMP_MUTE, - spec->cur_eapd ? 0 : HDA_AMP_MUTE); - return 1; -} - -/* bind volumes of both NID 0x05 and 0x06 */ -static const struct hda_bind_ctls ad1981_hp_bind_master_vol = { - .ops = &snd_hda_bind_vol, - .values = { - HDA_COMPOSE_AMP_VAL(0x05, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x06, 3, 0, HDA_OUTPUT), - 0 - }, -}; - -/* mute internal speaker if HP is plugged */ -static void ad1981_hp_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x06); - snd_hda_codec_amp_stereo(codec, 0x05, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* toggle input of built-in and mic jack appropriately */ -static void ad1981_hp_automic(struct hda_codec *codec) -{ - static const struct hda_verb mic_jack_on[] = { - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - static const struct hda_verb mic_jack_off[] = { - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, 0xb080}, - {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - {} - }; - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x08); - if (present) - snd_hda_sequence_write(codec, mic_jack_on); - else - snd_hda_sequence_write(codec, mic_jack_off); -} - -/* unsolicited event for HP jack sensing */ -static void ad1981_hp_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - res >>= 26; - switch (res) { - case AD1981_HP_EVENT: - ad1981_hp_automute(codec); - break; - case AD1981_MIC_EVENT: - ad1981_hp_automic(codec); - break; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + spec->eapd_nid = 0x05; } } -static const struct hda_input_mux ad1981_hp_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Dock Mic", 0x1 }, - { "Mix", 0x2 }, - }, -}; - -static const struct snd_kcontrol_new ad1981_hp_mixers[] = { - HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, - .name = "Master Playback Switch", - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad1981_hp_master_sw_put, - .private_value = 0x05, - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), -#if 0 - /* FIXME: analog mic/line loopback doesn't work with my tests... - * (although recording is OK) - */ - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x1c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x1c, 0x0, HDA_OUTPUT), - /* FIXME: does this laptop have analog CD connection? */ - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), -#endif - HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x18, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* initialize jack-sensing, too */ -static int ad1981_hp_init(struct hda_codec *codec) +/* set the upper-limit for mixer amp to 0dB for avoiding the possible + * damage by overloading + */ +static void ad1981_fixup_amp_override(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - ad198x_init(codec); - ad1981_hp_automute(codec); - ad1981_hp_automic(codec); - return 0; + if (action == HDA_FIXUP_ACT_PRE_PROBE) + snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); } -/* configuration for Toshiba Laptops */ -static const struct hda_verb ad1981_toshiba_init_verbs[] = { - {0x05, AC_VERB_SET_EAPD_BTLENABLE, 0x01 }, /* default on */ - /* pin sensing on HP and Mic jacks */ - {0x06, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_HP_EVENT}, - {0x08, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1981_MIC_EVENT}, - {} -}; - -static const struct snd_kcontrol_new ad1981_toshiba_mixers[] = { - HDA_CODEC_VOLUME("Amp Volume", 0x1a, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Amp Switch", 0x1a, 0x0, HDA_OUTPUT), - { } +enum { + AD1981_FIXUP_AMP_OVERRIDE, + AD1981_FIXUP_HP_EAPD, }; -/* configuration for Lenovo Thinkpad T60 */ -static const struct snd_kcontrol_new ad1981_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x1d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x08, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x15, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, +static const struct hda_fixup ad1981_fixups[] = { + [AD1981_FIXUP_AMP_OVERRIDE] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1981_fixup_amp_override, }, - /* identical with AD1983 */ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, + [AD1981_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1981_fixup_hp_eapd, + .chained = true, + .chain_id = AD1981_FIXUP_AMP_OVERRIDE, }, - { } /* end */ }; -static const struct hda_input_mux ad1981_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Mix", 0x2 }, - { "CD", 0x4 }, - }, -}; - -/* models */ -enum { - AD1981_BASIC, - AD1981_HP, - AD1981_THINKPAD, - AD1981_TOSHIBA, - AD1981_MODELS -}; - -static const char * const ad1981_models[AD1981_MODELS] = { - [AD1981_HP] = "hp", - [AD1981_THINKPAD] = "thinkpad", - [AD1981_BASIC] = "basic", - [AD1981_TOSHIBA] = "toshiba" -}; - -static const 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_VENDOR(0x103c, "HP nx", AD1981_HP), - SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba U205", AD1981_TOSHIBA), - /* Lenovo Thinkpad T60/X60/Z6xx */ - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1981_THINKPAD), +static const struct snd_pci_quirk ad1981_fixup_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x1014, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1981_FIXUP_HP_EAPD), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", AD1981_FIXUP_AMP_OVERRIDE), /* HP nx6320 (reversed SSID, H/W bug) */ - SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_HP), + SND_PCI_QUIRK(0x30b0, 0x103c, "HP nx6320", AD1981_FIXUP_HP_EAPD), {} }; static int patch_ad1981(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; + int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) + err = alloc_ad_spec(codec); + if (err < 0) return -ENOMEM; + spec = codec->spec; - codec->spec = spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } + spec->gen.mixer_nid = 0x0e; + spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x0d, 0, HDA_OUTPUT); - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1981_dac_nids); - spec->multiout.dac_nids = ad1981_dac_nids; - spec->multiout.dig_out_nid = AD1981_SPDIF_OUT; - spec->num_adc_nids = 1; - spec->adc_nids = ad1981_adc_nids; - spec->capsrc_nids = ad1981_capsrc_nids; - spec->input_mux = &ad1981_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1981_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1981_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1981_loopbacks; -#endif - spec->vmaster_nid = 0x05; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1981_MODELS, - ad1981_models, - ad1981_cfg_tbl); - switch (board_config) { - case AD1981_HP: - spec->mixers[0] = ad1981_hp_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_hp_init_verbs; - if (!is_jack_available(codec, 0x0a)) - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1981_THINKPAD: - spec->mixers[0] = ad1981_thinkpad_mixers; - spec->input_mux = &ad1981_thinkpad_capture_source; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x11, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1981_TOSHIBA: - spec->mixers[0] = ad1981_hp_mixers; - spec->mixers[1] = ad1981_toshiba_mixers; - spec->num_init_verbs = 2; - spec->init_verbs[1] = ad1981_toshiba_init_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1981_hp_capture_source; - codec->patch_ops.init = ad1981_hp_init; - codec->patch_ops.unsol_event = ad1981_hp_unsol_event; - break; - } + snd_hda_pick_fixup(codec, NULL, ad1981_fixup_tbl, ad1981_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + err = ad198x_parse_auto_config(codec, false); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; + + error: + snd_hda_gen_free(codec); + return err; } @@ -2127,89 +697,7 @@ static int patch_ad1981(struct hda_codec *codec) * E/F quad mic array */ - -/* models */ -enum { - AD1988_6STACK, - AD1988_6STACK_DIG, - AD1988_3STACK, - AD1988_3STACK_DIG, - AD1988_LAPTOP, - AD1988_LAPTOP_DIG, - AD1988_AUTO, - AD1988_MODEL_LAST, -}; - -/* reivision id to check workarounds */ -#define AD1988A_REV2 0x100200 - -#define is_rev2(codec) \ - ((codec)->vendor_id == 0x11d41988 && \ - (codec)->revision_id == AD1988A_REV2) - -/* - * mixers - */ - -static const hda_nid_t ad1988_6stack_dac_nids[4] = { - 0x04, 0x06, 0x05, 0x0a -}; - -static const hda_nid_t ad1988_3stack_dac_nids[3] = { - 0x04, 0x05, 0x0a -}; - -/* for AD1988A revision-2, DAC2-4 are swapped */ -static const hda_nid_t ad1988_6stack_dac_nids_rev2[4] = { - 0x04, 0x05, 0x0a, 0x06 -}; - -static const hda_nid_t ad1988_alt_dac_nid[1] = { - 0x03 -}; - -static const hda_nid_t ad1988_3stack_dac_nids_rev2[3] = { - 0x04, 0x0a, 0x06 -}; - -static const hda_nid_t ad1988_adc_nids[3] = { - 0x08, 0x09, 0x0f -}; - -static const hda_nid_t ad1988_capsrc_nids[3] = { - 0x0c, 0x0d, 0x0e -}; - -#define AD1988_SPDIF_OUT 0x02 -#define AD1988_SPDIF_OUT_HDMI 0x0b -#define AD1988_SPDIF_IN 0x07 - -static const hda_nid_t ad1989b_slave_dig_outs[] = { - AD1988_SPDIF_OUT, AD1988_SPDIF_OUT_HDMI, 0 -}; - -static const struct hda_input_mux ad1988_6stack_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, /* port-B */ - { "Line", 0x2 }, /* port-C */ - { "Mic", 0x4 }, /* port-E */ - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -static const struct hda_input_mux ad1988_laptop_capture_source = { - .num_items = 3, - .items = { - { "Mic/Line", 0x1 }, /* port-B */ - { "CD", 0x5 }, - { "Mix", 0x9 }, - }, -}; - -/* - */ +#ifdef ENABLE_AD_STATIC_QUIRKS static int ad198x_ch_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -2240,1172 +728,213 @@ static int ad198x_ch_mode_put(struct snd_kcontrol *kcontrol, spec->multiout.num_dacs = spec->multiout.max_channels / 2; return err; } +#endif /* ENABLE_AD_STATIC_QUIRKS */ -static const struct snd_kcontrol_new ad1988_hp_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = ad1988_independent_hp_info, - .get = ad1988_independent_hp_get, - .put = ad1988_independent_hp_put, - }, - { } /* end */ -}; - -/* 6-stack mode */ -static const struct snd_kcontrol_new ad1988_6stack_mixers1[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x06, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_6stack_mixers1_rev2[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x05, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0a, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0a, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Side Playback Volume", 0x06, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_6stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2a, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x27, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x27, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Side Playback Switch", 0x28, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* 3-stack mode */ -static const struct snd_kcontrol_new ad1988_3stack_mixers1[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_3stack_mixers1_rev2[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x0a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x06, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x06, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_3stack_mixers2[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_BIND_MUTE("Front Playback Switch", 0x29, 2, HDA_INPUT), - HDA_BIND_MUTE("Surround Playback Switch", 0x2c, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("Center Playback Switch", 0x26, 1, 2, HDA_INPUT), - HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x26, 2, 2, HDA_INPUT), - HDA_BIND_MUTE("Headphone Playback Switch", 0x22, 2, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x4, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - - { } /* end */ -}; - -/* laptop mode */ -static const struct snd_kcontrol_new ad1988_laptop_mixers[] = { - HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x29, 0x0, HDA_INPUT), - HDA_BIND_MUTE("Mono Playback Switch", 0x1e, 2, HDA_INPUT), - - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x6, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x1, HDA_INPUT), - - HDA_CODEC_VOLUME("Analog Mix Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Analog Mix Playback Switch", 0x21, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "External Amplifier", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, - .info = ad198x_eapd_info, - .get = ad198x_eapd_get, - .put = ad198x_eapd_put, - .private_value = 0x12, /* port-D */ - }, - - { } /* end */ -}; - -/* capture */ -static const struct snd_kcontrol_new ad1988_capture_mixers[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 2, 0x0e, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 2, 0x0e, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 3, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -static int ad1988_spdif_playback_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int ad1988_auto_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); static const char * const texts[] = { - "PCM", "ADC1", "ADC2", "ADC3" + "PCM", "ADC1", "ADC2", "ADC3", }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= 4) - uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); - return 0; + int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; + if (num_conns > 4) + num_conns = 4; + return snd_hda_enum_helper_info(kcontrol, uinfo, num_conns, texts); } -static int ad1988_spdif_playback_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ad1988_auto_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int sel; - - sel = snd_hda_codec_read(codec, 0x1d, 0, AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - if (!(sel & 0x80)) - ucontrol->value.enumerated.item[0] = 0; - else { - sel = snd_hda_codec_read(codec, 0x0b, 0, - AC_VERB_GET_CONNECT_SEL, 0); - if (sel < 3) - sel++; - else - sel = 0; - ucontrol->value.enumerated.item[0] = sel; - } + struct ad198x_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->cur_smux; return 0; } -static int ad1988_spdif_playback_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int ad1988_auto_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int val, sel; - int change; + struct ad198x_spec *spec = codec->spec; + unsigned int val = ucontrol->value.enumerated.item[0]; + struct nid_path *path; + int num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; - val = ucontrol->value.enumerated.item[0]; - if (val > 3) + if (val >= num_conns) return -EINVAL; - if (!val) { - sel = snd_hda_codec_read(codec, 0x1d, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT); - change = sel & 0x80; - if (change) { - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(1)); - } - } else { - sel = snd_hda_codec_read(codec, 0x1d, 0, - AC_VERB_GET_AMP_GAIN_MUTE, - AC_AMP_GET_INPUT | 0x01); - change = sel & 0x80; - if (change) { - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - snd_hda_codec_write_cache(codec, 0x1d, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - sel = snd_hda_codec_read(codec, 0x0b, 0, - AC_VERB_GET_CONNECT_SEL, 0) + 1; - change |= sel != val; - if (change) - snd_hda_codec_write_cache(codec, 0x0b, 0, - AC_VERB_SET_CONNECT_SEL, - val - 1); - } - return change; -} - -static const struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "IEC958 Playback Source", - .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, - .info = ad1988_spdif_playback_source_info, - .get = ad1988_spdif_playback_source_get, - .put = ad1988_spdif_playback_source_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1988_spdif_in_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Capture Volume", 0x1c, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1989_spdif_out_mixers[] = { - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("HDMI Playback Volume", 0x1d, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* - * initialization verbs - */ - -/* - * for 6-stack (+dig) - */ -static const struct hda_verb ad1988_6stack_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-F surround path */ - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-G CLFE path */ - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-H side path */ - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x28, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in path */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in path */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Analog CD Input */ - {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - - { } -}; - -static const struct hda_verb ad1988_6stack_fp_init_verbs[] = { - /* Headphone; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - - { } -}; - -static const struct hda_verb ad1988_capture_init_verbs[] = { - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - - { } -}; - -static const struct hda_verb ad1988_spdif_init_verbs[] = { - /* SPDIF out sel */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x0b, AC_VERB_SET_CONNECT_SEL, 0x0}, /* ADC1 */ - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* SPDIF out pin */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - - { } -}; - -static const struct hda_verb ad1988_spdif_in_init_verbs[] = { - /* unmute SPDIF input pin */ - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - { } -}; - -/* AD1989 has no ADC -> SPDIF route */ -static const struct hda_verb ad1989_spdif_init_verbs[] = { - /* SPDIF-1 out pin */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - /* SPDIF-2/HDMI out pin */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } -}; - -/* - * verbs for 3stack (+dig) - */ -static const struct hda_verb ad1988_3stack_ch2_init[] = { - /* set port-C to line-in */ - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, - /* set port-E to mic-in */ - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, - { } /* end */ -}; - -static const struct hda_verb ad1988_3stack_ch6_init[] = { - /* set port-C to surround out */ - { 0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - /* set port-E to CLFE out */ - { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, - { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -static const struct hda_channel_mode ad1988_3stack_modes[2] = { - { 2, ad1988_3stack_ch2_init }, - { 6, ad1988_3stack_ch6_init }, -}; - -static const struct hda_verb ad1988_3stack_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-D line-out path */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B front mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C line-in/surround path - 6ch mode as default */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x31, AC_VERB_SET_CONNECT_SEL, 0x0}, /* output sel: DAC 0x05 */ - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* Port-E mic-in/CLFE path - 6ch mode as default */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x32, AC_VERB_SET_CONNECT_SEL, 0x1}, /* output sel: DAC 0x0a */ - {0x34, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - front-mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - { } -}; - -/* - * verbs for laptop mode (+dig) - */ -static const struct hda_verb ad1988_laptop_hp_on[] = { - /* unmute port-A and mute port-D */ - { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { } /* end */ -}; -static const struct hda_verb ad1988_laptop_hp_off[] = { - /* mute port-A and unmute port-D */ - { 0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - { 0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, - { } /* end */ -}; - -#define AD1988_HP_EVENT 0x01 - -static const struct hda_verb ad1988_laptop_init_verbs[] = { - /* Front, Surround, CLFE, side DAC; unmute as default */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x06, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-A front headphon path */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC0:03h */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1988_HP_EVENT }, - /* Port-D line-out path + EAPD */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x00}, /* EAPD-off */ - /* Mono out path */ - {0x36, AC_VERB_SET_CONNECT_SEL, 0x1}, /* DAC1:04h */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, 0xb01f}, /* unmute, 0dB */ - /* Port-B mic-in path */ - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-C docking station - try to output */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x33, AC_VERB_SET_CONNECT_SEL, 0x0}, - /* mute analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* select ADCs - mic */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - { } -}; - -static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) -{ - if ((res >> 26) != AD1988_HP_EVENT) - return; - if (snd_hda_jack_detect(codec, 0x11)) - snd_hda_sequence_write(codec, ad1988_laptop_hp_on); - else - snd_hda_sequence_write(codec, ad1988_laptop_hp_off); -} - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1988_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Line */ - { 0x20, HDA_INPUT, 4 }, /* Mic */ - { 0x20, HDA_INPUT, 6 }, /* CD */ - { } /* end */ -}; -#endif - -/* - * Automatic parse of I/O pins from the BIOS configuration - */ - -enum { - AD_CTL_WIDGET_VOL, - AD_CTL_WIDGET_MUTE, - AD_CTL_BIND_MUTE, -}; -static const struct snd_kcontrol_new ad1988_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), -}; - -/* add dynamic controls */ -static int add_control(struct ad198x_spec *spec, int type, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return -ENOMEM; - *knew = ad1988_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (! knew->name) - return -ENOMEM; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -#define AD1988_PIN_CD_NID 0x18 -#define AD1988_PIN_BEEP_NID 0x10 - -static const hda_nid_t ad1988_mixer_nids[8] = { - /* A B C D E F G H */ - 0x22, 0x2b, 0x2c, 0x29, 0x26, 0x2a, 0x27, 0x28 -}; + if (spec->cur_smux == val) + return 0; -static inline hda_nid_t ad1988_idx_to_dac(struct hda_codec *codec, int idx) -{ - static const hda_nid_t idx_to_dac[8] = { - /* A B C D E F G H */ - 0x03, 0x06, 0x05, 0x04, 0x0a, 0x06, 0x05, 0x0a - }; - static const hda_nid_t idx_to_dac_rev2[8] = { - /* A B C D E F G H */ - 0x03, 0x05, 0x0a, 0x04, 0x06, 0x05, 0x0a, 0x06 - }; - if (is_rev2(codec)) - return idx_to_dac_rev2[idx]; - else - return idx_to_dac[idx]; + mutex_lock(&codec->control_mutex); + codec->cached_write = 1; + path = snd_hda_get_path_from_idx(codec, + spec->smux_paths[spec->cur_smux]); + if (path) + snd_hda_activate_path(codec, path, false, true); + path = snd_hda_get_path_from_idx(codec, spec->smux_paths[val]); + if (path) + snd_hda_activate_path(codec, path, true, true); + spec->cur_smux = val; + codec->cached_write = 0; + mutex_unlock(&codec->control_mutex); + snd_hda_codec_flush_cache(codec); /* flush the updates */ + return 1; } -static const hda_nid_t ad1988_boost_nids[8] = { - 0x38, 0x39, 0x3a, 0x3d, 0x3c, 0x3b, 0, 0 +static struct snd_kcontrol_new ad1988_auto_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + .info = ad1988_auto_smux_enum_info, + .get = ad1988_auto_smux_enum_get, + .put = ad1988_auto_smux_enum_put, }; -static int ad1988_pin_idx(hda_nid_t nid) -{ - static const hda_nid_t ad1988_io_pins[8] = { - 0x11, 0x14, 0x15, 0x12, 0x17, 0x16, 0x24, 0x25 - }; - int i; - for (i = 0; i < ARRAY_SIZE(ad1988_io_pins); i++) - if (ad1988_io_pins[i] == nid) - return i; - return 0; /* should be -1 */ -} - -static int ad1988_pin_to_loopback_idx(hda_nid_t nid) -{ - static const int loopback_idx[8] = { - 2, 0, 1, 3, 4, 5, 1, 4 - }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 6; - default: - return loopback_idx[ad1988_pin_idx(nid)]; - } -} - -static int ad1988_pin_to_adc_idx(hda_nid_t nid) -{ - static const int adc_idx[8] = { - 0, 1, 2, 8, 4, 3, 6, 7 - }; - switch (nid) { - case AD1988_PIN_CD_NID: - return 5; - default: - return adc_idx[ad1988_pin_idx(nid)]; - } -} - -/* fill in the dac_nids table from the parsed pin configuration */ -static int ad1988_auto_fill_dac_nids(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) +static int ad1988_auto_init(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - int i, idx; - - spec->multiout.dac_nids = spec->private_dac_nids; - - /* check the pins hardwired to audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - idx = ad1988_pin_idx(cfg->line_out_pins[i]); - spec->private_dac_nids[i] = ad1988_idx_to_dac(codec, idx); - } - spec->multiout.num_dacs = cfg->line_outs; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int ad1988_auto_create_multi_out_ctls(struct ad198x_spec *spec, - const struct auto_pin_cfg *cfg) -{ - char name[32]; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; int i, err; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = spec->multiout.dac_nids[i]; - if (! dac) - continue; - nid = ad1988_mixer_nids[ad1988_pin_idx(cfg->line_out_pins[i])]; - if (i == 2) { - /* Center/LFE */ - err = add_control(spec, AD_CTL_WIDGET_VOL, - "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_WIDGET_VOL, - "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(dac, 2, 0, HDA_OUTPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT)); - if (err < 0) - return err; - err = add_control(spec, AD_CTL_BIND_MUTE, - "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT)); - if (err < 0) - return err; - } else { - sprintf(name, "%s Playback Volume", chname[i]); - err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", chname[i]); - err = add_control(spec, AD_CTL_BIND_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* add playback controls for speaker and HP outputs */ -static int ad1988_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - const char *pfx) -{ - struct ad198x_spec *spec = codec->spec; - hda_nid_t nid; - int i, idx, err; - char name[32]; - - if (! pin) - return 0; - - idx = ad1988_pin_idx(pin); - nid = ad1988_idx_to_dac(codec, idx); - /* 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, - HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT))) < 0) - return err; - return 0; -} - -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct ad198x_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, int boost) -{ - char name[32]; - int err, idx; - - sprintf(name, "%s Playback Volume", ctlname); - idx = ad1988_pin_to_loopback_idx(pin); - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x20, 3, idx, HDA_INPUT))) < 0) + err = snd_hda_gen_init(codec); + if (err < 0) return err; - if (boost) { - hda_nid_t bnid; - idx = ad1988_pin_idx(pin); - bnid = ad1988_boost_nids[idx]; - if (bnid) { - sprintf(name, "%s Boost Volume", ctlname); - return add_control(spec, AD_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(bnid, 3, idx, HDA_OUTPUT)); - - } - } - return 0; -} + if (!spec->gen.autocfg.dig_outs) + return 0; -/* create playback/capture controls for input pins */ -static int ad1988_auto_create_analog_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - int i, err, type, type_idx; - - for (i = 0; i < cfg->num_inputs; i++) { - const char *label; - type = cfg->inputs[i].type; - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, - ad1988_pin_to_adc_idx(cfg->inputs[i].pin), - &type_idx); - err = new_analog_input(spec, cfg->inputs[i].pin, - label, type_idx, - type == AUTO_PIN_MIC); - if (err < 0) - return err; + for (i = 0; i < 4; i++) { + struct nid_path *path; + path = snd_hda_get_path_from_idx(codec, spec->smux_paths[i]); + if (path) + snd_hda_activate_path(codec, path, path->active, false); } - snd_hda_add_imux_item(imux, "Mix", 9, NULL); - - if ((err = add_control(spec, AD_CTL_WIDGET_VOL, - "Analog Mix Playback Volume", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; - if ((err = add_control(spec, AD_CTL_WIDGET_MUTE, - "Analog Mix Playback Switch", - HDA_COMPOSE_AMP_VAL(0x21, 3, 0x0, HDA_OUTPUT))) < 0) - return err; return 0; } -static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t nid, int pin_type, - int dac_idx) -{ - /* set as output */ - snd_hda_set_pin_ctl(codec, nid, pin_type); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - switch (nid) { - case 0x11: /* port-A - DAC 03 */ - snd_hda_codec_write(codec, 0x37, 0, AC_VERB_SET_CONNECT_SEL, 0x00); - break; - case 0x14: /* port-B - DAC 06 */ - snd_hda_codec_write(codec, 0x30, 0, AC_VERB_SET_CONNECT_SEL, 0x02); - break; - case 0x15: /* port-C - DAC 05 */ - snd_hda_codec_write(codec, 0x31, 0, AC_VERB_SET_CONNECT_SEL, 0x00); - break; - case 0x17: /* port-E - DAC 0a */ - snd_hda_codec_write(codec, 0x32, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - case 0x13: /* mono - DAC 04 */ - snd_hda_codec_write(codec, 0x36, 0, AC_VERB_SET_CONNECT_SEL, 0x01); - break; - } -} - -static void ad1988_auto_init_multi_out(struct hda_codec *codec) +static int ad1988_add_spdif_mux_ctl(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - int i; + int i, num_conns; + /* we create four static faked paths, since AD codecs have odd + * widget connections regarding the SPDIF out source + */ + static struct nid_path fake_paths[4] = { + { + .depth = 3, + .path = { 0x02, 0x1d, 0x1b }, + .idx = { 0, 0, 0 }, + .multi = { 0, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x08, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 0, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x09, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 1, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + { + .depth = 4, + .path = { 0x0f, 0x0b, 0x1d, 0x1b }, + .idx = { 0, 2, 1, 0 }, + .multi = { 0, 1, 0, 0 }, + }, + }; - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - ad1988_auto_set_output_and_unmute(codec, nid, PIN_OUT, i); - } -} + /* SPDIF source mux appears to be present only on AD1988A */ + if (!spec->gen.autocfg.dig_outs || + get_wcaps_type(get_wcaps(codec, 0x1d)) != AC_WID_AUD_MIX) + return 0; -static void ad1988_auto_init_extra_out(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - hda_nid_t pin; - - pin = spec->autocfg.speaker_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_OUT, 0); - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - ad1988_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); -} + num_conns = snd_hda_get_num_conns(codec, 0x0b) + 1; + if (num_conns != 3 && num_conns != 4) + return 0; -static void ad1988_auto_init_analog_input(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, idx; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int type = cfg->inputs[i].type; - int val; - switch (nid) { - case 0x15: /* port-C */ - snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - case 0x17: /* port-E */ - snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0); - break; - } - val = PIN_IN; - if (type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); - if (nid != AD1988_PIN_CD_NID) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - idx = ad1988_pin_idx(nid); - if (ad1988_boost_nids[idx]) - snd_hda_codec_write(codec, ad1988_boost_nids[idx], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); + for (i = 0; i < num_conns; i++) { + struct nid_path *path = snd_array_new(&spec->gen.paths); + if (!path) + return -ENOMEM; + *path = fake_paths[i]; + if (!i) + path->active = 1; + spec->smux_paths[i] = snd_hda_get_path_idx(codec, path); } -} - -/* parse the BIOS configuration and set up the alc_spec */ -/* return 1 if successful, 0 if the proper config is not found, or a negative error code */ -static int ad1988_parse_auto_config(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - if ((err = ad1988_auto_fill_dac_nids(codec, &spec->autocfg)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid BIOS pin config */ - if ((err = ad1988_auto_create_multi_out_ctls(spec, &spec->autocfg)) < 0 || - (err = ad1988_auto_create_extra_out(codec, - spec->autocfg.speaker_pins[0], - "Speaker")) < 0 || - (err = ad1988_auto_create_extra_out(codec, spec->autocfg.hp_pins[0], - "Headphone")) < 0 || - (err = ad1988_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = AD1988_SPDIF_IN; - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->init_verbs[spec->num_init_verbs++] = ad1988_6stack_init_verbs; - - spec->input_mux = &spec->private_imux; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &ad1988_auto_smux_mixer)) + return -ENOMEM; - return 1; -} + codec->patch_ops.init = ad1988_auto_init; -/* init callback for auto-configuration model -- overriding the default init */ -static int ad1988_auto_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1988_auto_init_multi_out(codec); - ad1988_auto_init_extra_out(codec); - ad1988_auto_init_analog_input(codec); return 0; } /* */ -static const char * const ad1988_models[AD1988_MODEL_LAST] = { - [AD1988_6STACK] = "6stack", - [AD1988_6STACK_DIG] = "6stack-dig", - [AD1988_3STACK] = "3stack", - [AD1988_3STACK_DIG] = "3stack-dig", - [AD1988_LAPTOP] = "laptop", - [AD1988_LAPTOP_DIG] = "laptop-dig", - [AD1988_AUTO] = "auto", +enum { + AD1988_FIXUP_6STACK_DIG, +}; + +static const struct hda_fixup ad1988_fixups[] = { + [AD1988_FIXUP_6STACK_DIG] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x11, 0x02214130 }, /* front-hp */ + { 0x12, 0x01014010 }, /* line-out */ + { 0x14, 0x02a19122 }, /* front-mic */ + { 0x15, 0x01813021 }, /* line-in */ + { 0x16, 0x01011012 }, /* line-out */ + { 0x17, 0x01a19020 }, /* mic */ + { 0x1b, 0x0145f1f0 }, /* SPDIF */ + { 0x24, 0x01016011 }, /* line-out */ + { 0x25, 0x01012013 }, /* line-out */ + { } + } + }, }; -static const struct snd_pci_quirk ad1988_cfg_tbl[] = { - SND_PCI_QUIRK(0x1043, 0x81ec, "Asus P5B-DLX", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x81f6, "Asus M2N-SLI", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x8277, "Asus P5K-E/WIFI-AP", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x82c0, "Asus M3N-HT Deluxe", AD1988_6STACK_DIG), - SND_PCI_QUIRK(0x1043, 0x8311, "Asus P5Q-Premium/Pro", AD1988_6STACK_DIG), +static const struct hda_model_fixup ad1988_fixup_models[] = { + { .id = AD1988_FIXUP_6STACK_DIG, .name = "6stack-dig" }, {} }; static int patch_ad1988(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - if (is_rev2(codec)) - snd_printk(KERN_INFO "patch_analog: AD1988A rev.2 is detected, enable workarounds\n"); - - board_config = snd_hda_check_board_config(codec, AD1988_MODEL_LAST, - ad1988_models, ad1988_cfg_tbl); - if (board_config < 0) { - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - board_config = AD1988_AUTO; - } - - if (board_config == AD1988_AUTO) { - /* automatic parse from the BIOS config */ - err = ad1988_parse_auto_config(codec); - if (err < 0) { - ad198x_free(codec); - return err; - } else if (! err) { - printk(KERN_INFO "hda_codec: Cannot set up configuration from BIOS. Using 6-stack mode...\n"); - board_config = AD1988_6STACK; - } - } + int err; - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); + err = alloc_ad_spec(codec); + if (err < 0) return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = ad1988_alt_dac_nid[0]; - switch (board_config) { - case AD1988_6STACK: - case AD1988_6STACK_DIG: - spec->multiout.max_channels = 8; - spec->multiout.num_dacs = 4; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_6stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_6stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_6stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_6stack_mixers1; - spec->mixers[1] = ad1988_6stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_6stack_init_verbs; - if (board_config == AD1988_6STACK_DIG) { - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - spec->dig_in_nid = AD1988_SPDIF_IN; - } - break; - case AD1988_3STACK: - case AD1988_3STACK_DIG: - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = 3; - if (is_rev2(codec)) - spec->multiout.dac_nids = ad1988_3stack_dac_nids_rev2; - else - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_6stack_capture_source; - spec->channel_mode = ad1988_3stack_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1988_3stack_modes); - spec->num_mixers = 2; - if (is_rev2(codec)) - spec->mixers[0] = ad1988_3stack_mixers1_rev2; - else - spec->mixers[0] = ad1988_3stack_mixers1; - spec->mixers[1] = ad1988_3stack_mixers2; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_3stack_init_verbs; - if (board_config == AD1988_3STACK_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = ad1988_3stack_dac_nids; - spec->input_mux = &ad1988_laptop_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1988_laptop_mixers; - spec->inv_eapd = 1; /* inverted EAPD */ - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1988_laptop_init_verbs; - if (board_config == AD1988_LAPTOP_DIG) - spec->multiout.dig_out_nid = AD1988_SPDIF_OUT; - break; - } + spec = codec->spec; - if (spec->autocfg.hp_pins[0]) { - spec->mixers[spec->num_mixers++] = ad1988_hp_mixers; - spec->slave_vols = ad1988_6stack_fp_slave_pfxs; - spec->slave_sws = ad1988_6stack_fp_slave_pfxs; - spec->alt_dac_nid = ad1988_alt_dac_nid; - spec->stream_analog_alt_playback = - &ad198x_pcm_analog_alt_playback; - } + spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; + spec->gen.beep_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - spec->num_adc_nids = ARRAY_SIZE(ad1988_adc_nids); - spec->adc_nids = ad1988_adc_nids; - spec->capsrc_nids = ad1988_capsrc_nids; - spec->mixers[spec->num_mixers++] = ad1988_capture_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1988_capture_init_verbs; - if (spec->multiout.dig_out_nid) { - if (codec->vendor_id >= 0x11d4989a) { - spec->mixers[spec->num_mixers++] = - ad1989_spdif_out_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1989_spdif_init_verbs; - codec->slave_dig_outs = ad1989b_slave_dig_outs; - } else { - spec->mixers[spec->num_mixers++] = - ad1988_spdif_out_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1988_spdif_init_verbs; - } - } - if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { - spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1988_spdif_in_init_verbs; - } + snd_hda_pick_fixup(codec, ad1988_fixup_models, NULL, ad1988_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - codec->patch_ops = ad198x_patch_ops; - switch (board_config) { - case AD1988_AUTO: - codec->patch_ops.init = ad1988_auto_init; - break; - case AD1988_LAPTOP: - case AD1988_LAPTOP_DIG: - codec->patch_ops.unsol_event = ad1988_laptop_unsol_event; - break; - } -#ifdef CONFIG_PM - spec->loopback.amplist = ad1988_loopbacks; -#endif - spec->vmaster_nid = 0x04; + err = ad198x_parse_auto_config(codec, true); + if (err < 0) + goto error; + err = ad1988_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; + + error: + snd_hda_gen_free(codec); + return err; } @@ -3421,434 +950,6 @@ static int patch_ad1988(struct hda_codec *codec) * * AD1984 = AD1884 + two digital mic-ins * - * FIXME: - * For simplicity, we share the single DAC for both HP and line-outs - * right now. The inidividual playbacks could be easily implemented, - * but no build-up framework is given, so far. - */ - -static const hda_nid_t ad1884_dac_nids[1] = { - 0x04, -}; - -static const hda_nid_t ad1884_adc_nids[2] = { - 0x08, 0x09, -}; - -static const hda_nid_t ad1884_capsrc_nids[2] = { - 0x0c, 0x0d, -}; - -#define AD1884_SPDIF_OUT 0x02 - -static const struct hda_input_mux ad1884_capture_source = { - .num_items = 4, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x1 }, - { "CD", 0x2 }, - { "Mix", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new ad1884_base_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984_dmic_mixers[] = { - HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Digital Mic Capture Switch", 0x05, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME_IDX("Digital Mic Capture Volume", 1, 0x06, 0x0, - HDA_INPUT), - HDA_CODEC_MUTE_IDX("Digital Mic Capture Switch", 1, 0x06, 0x0, - HDA_INPUT), - { } /* end */ -}; - -/* - * initialization verbs - */ -static const struct hda_verb ad1884_init_verbs[] = { - /* DACs; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-A (HP) mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* HP selector - select DAC2 */ - {0x22, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-D (Line-out) mixer */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono selector */ - {0x0e, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-C (rear mic) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - /* SPDIF output selector */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1884_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 2 }, /* CD */ - { 0x20, HDA_INPUT, 4 }, /* Docking */ - { } /* end */ -}; -#endif - -static const char * const ad1884_slave_vols[] = { - "PCM", "Mic", "Mono", "Front Mic", "Mic", "CD", - "Internal Mic", "Dock Mic", /* "Beep", */ "IEC958", - NULL -}; - -static int patch_ad1884(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; - - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); - return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1884_dac_nids); - spec->multiout.dac_nids = ad1884_dac_nids; - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1884_adc_nids); - spec->adc_nids = ad1884_adc_nids; - spec->capsrc_nids = ad1884_capsrc_nids; - spec->input_mux = &ad1884_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1884_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1884_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1884_loopbacks; -#endif - spec->vmaster_nid = 0x04; - /* we need to cover all playback volumes */ - spec->slave_vols = ad1884_slave_vols; - /* slaves may contain input volumes, so we can't raise to 0dB blindly */ - spec->avoid_init_slave_vol = 1; - - codec->patch_ops = ad198x_patch_ops; - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; - - return 0; -} - -/* - * Lenovo Thinkpad T61/X61 - */ -static const struct hda_input_mux ad1984_thinkpad_capture_source = { - .num_items = 4, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x1 }, - { "Mix", 0x3 }, - { "Dock Mic", 0x4 }, - }, -}; - - -/* - * Dell Precision T3400 - */ -static const struct hda_input_mux ad1984_dell_desktop_capture_source = { - .num_items = 3, - .items = { - { "Front Mic", 0x0 }, - { "Line-In", 0x1 }, - { "Mix", 0x3 }, - }, -}; - - -static const struct snd_kcontrol_new ad1984_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - /* HDA_CODEC_VOLUME_IDX("PCM Playback Volume", 1, 0x03, 0x0, HDA_OUTPUT), */ - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Beep Playback Volume", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0x20, 0x03, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -/* additional verbs */ -static const struct hda_verb ad1984_thinkpad_init_verbs[] = { - /* Port-E (docking station mic) pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* docking mic boost */ - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Analog PC Beeper - allow firmware/ACPI beeps */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(3) | 0x1a}, - /* Analog mixer - docking mic; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* enable EAPD bit */ - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - { } /* end */ -}; - -/* - * Dell Precision T3400 - */ -static const struct snd_kcontrol_new ad1984_dell_desktop_mixers[] = { - HDA_CODEC_VOLUME("PCM Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Speaker Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line-In Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line-In Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line-In Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ -}; - -/* Digial MIC ADC NID 0x05 + 0x06 */ -static int ad1984_pcm_dmic_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_setup_stream(codec, 0x05 + substream->number, - stream_tag, 0, format); - return 0; -} - -static int ad1984_pcm_dmic_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - snd_hda_codec_cleanup_stream(codec, 0x05 + substream->number); - return 0; -} - -static const struct hda_pcm_stream ad1984_pcm_dmic_capture = { - .substreams = 2, - .channels_min = 2, - .channels_max = 2, - .nid = 0x05, - .ops = { - .prepare = ad1984_pcm_dmic_prepare, - .cleanup = ad1984_pcm_dmic_cleanup - }, -}; - -static int ad1984_build_pcms(struct hda_codec *codec) -{ - struct ad198x_spec *spec = codec->spec; - struct hda_pcm *info; - int err; - - err = ad198x_build_pcms(codec); - if (err < 0) - return err; - - info = spec->pcm_rec + codec->num_pcms; - codec->num_pcms++; - info->name = "AD1984 Digital Mic"; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ad1984_pcm_dmic_capture; - return 0; -} - -/* models */ -enum { - AD1984_BASIC, - AD1984_THINKPAD, - AD1984_DELL_DESKTOP, - AD1984_MODELS -}; - -static const char * const ad1984_models[AD1984_MODELS] = { - [AD1984_BASIC] = "basic", - [AD1984_THINKPAD] = "thinkpad", - [AD1984_DELL_DESKTOP] = "dell_desktop", -}; - -static const struct snd_pci_quirk ad1984_cfg_tbl[] = { - /* Lenovo Thinkpad T61/X61 */ - SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1984_THINKPAD), - SND_PCI_QUIRK(0x1028, 0x0214, "Dell T3400", AD1984_DELL_DESKTOP), - SND_PCI_QUIRK(0x1028, 0x0233, "Dell Latitude E6400", AD1984_DELL_DESKTOP), - {} -}; - -static int patch_ad1984(struct hda_codec *codec) -{ - struct ad198x_spec *spec; - int board_config, err; - - err = patch_ad1884(codec); - if (err < 0) - return err; - spec = codec->spec; - board_config = snd_hda_check_board_config(codec, AD1984_MODELS, - ad1984_models, ad1984_cfg_tbl); - switch (board_config) { - case AD1984_BASIC: - /* additional digital mics */ - spec->mixers[spec->num_mixers++] = ad1984_dmic_mixers; - codec->patch_ops.build_pcms = ad1984_build_pcms; - break; - case AD1984_THINKPAD: - if (codec->subsystem_id == 0x17aa20fb) { - /* Thinpad X300 does not have the ability to do SPDIF, - or attach to docking station to use SPDIF */ - spec->multiout.dig_out_nid = 0; - } else - spec->multiout.dig_out_nid = AD1884_SPDIF_OUT; - spec->input_mux = &ad1984_thinkpad_capture_source; - spec->mixers[0] = ad1984_thinkpad_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1984_thinkpad_init_verbs; - spec->analog_beep = 1; - break; - case AD1984_DELL_DESKTOP: - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1984_dell_desktop_capture_source; - spec->mixers[0] = ad1984_dell_desktop_mixers; - break; - } - return 0; -} - - -/* * AD1883 / AD1884A / AD1984A / AD1984B * * port-B (0x14) - front mic-in @@ -3861,825 +962,161 @@ static int patch_ad1984(struct hda_codec *codec) * AD1984A = AD1884A + digital-mic * AD1883 = equivalent with AD1984A * AD1984B = AD1984A + extra SPDIF-out - * - * FIXME: - * We share the single DAC for both HP and line-outs (see AD1884/1984). - */ - -static const hda_nid_t ad1884a_dac_nids[1] = { - 0x03, -}; - -#define ad1884a_adc_nids ad1884_adc_nids -#define ad1884a_capsrc_nids ad1884_capsrc_nids - -#define AD1884A_SPDIF_OUT 0x02 - -static const struct hda_input_mux ad1884a_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x0 }, - { "Mic", 0x4 }, - { "Line", 0x1 }, - { "CD", 0x2 }, - { "Mix", 0x3 }, - }, -}; - -static const struct snd_kcontrol_new ad1884a_base_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x02, HDA_INPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Line Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -/* - * initialization verbs */ -static const struct hda_verb ad1884a_init_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-D (Line-out) mixer - route only from analog mixer */ - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer - route only from analog mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-C (rear line-in) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - /* Port-E (rear mic) pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* no boost */ - /* Port-F (CD) pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(4)}, /* aux */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* SPDIF output amp */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; -#ifdef CONFIG_PM -static const struct hda_amp_list ad1884a_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 2 }, /* CD */ - { 0x20, HDA_INPUT, 4 }, /* Docking */ - { } /* end */ -}; -#endif - -/* - * Laptop model - * - * Port A: Headphone jack - * Port B: MIC jack - * Port C: Internal MIC - * Port D: Dock Line Out (if enabled) - * Port E: Dock Line In (if enabled) - * Port F: Internal speakers +/* set the upper-limit for mixer amp to 0dB for avoiding the possible + * damage by overloading */ - -static int ad1884a_mobile_master_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void ad1884_fixup_amp_override(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - int ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - int mute = (!ucontrol->value.integer.value[0] && - !ucontrol->value.integer.value[1]); - /* toggle GPIO1 according to the mute state */ - snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - mute ? 0x02 : 0x0); - return ret; + if (action == HDA_FIXUP_ACT_PRE_PROBE) + snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); } -static const struct snd_kcontrol_new ad1884a_laptop_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_MUTE("Dock Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Dock Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Dock Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1884a_mobile_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - /*HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), - }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Capture Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Capture Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -/* mute internal speaker if HP is plugged */ -static void ad1884a_hp_automute(struct hda_codec *codec) +/* toggle GPIO1 according to the mute state */ +static void ad1884_vmaster_hp_gpio_hook(void *private_data, int enabled) { - unsigned int present; + struct hda_codec *codec = private_data; + struct ad198x_spec *spec = codec->spec; - present = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, - present ? 0x00 : 0x02); + if (spec->eapd_nid) + ad_vmaster_eapd_hook(private_data, enabled); + snd_hda_codec_update_cache(codec, 0x01, 0, + AC_VERB_SET_GPIO_DATA, + enabled ? 0x00 : 0x02); } -/* switch to external mic if plugged */ -static void ad1884a_hp_automic(struct hda_codec *codec) +static void ad1884_fixup_hp_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x14); - snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 1); -} - -#define AD1884A_HP_EVENT 0x37 -#define AD1884A_MIC_EVENT 0x36 + struct ad198x_spec *spec = codec->spec; + static const struct hda_verb gpio_init_verbs[] = { + {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, + {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, + {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, + {}, + }; -/* unsolicited event for HP jack sensing */ -static void ad1884a_hp_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_hp_automute(codec); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->gen.vmaster_mute.hook = ad1884_vmaster_hp_gpio_hook; + spec->gen.own_eapd_ctl = 1; + snd_hda_sequence_write_cache(codec, gpio_init_verbs); break; - case AD1884A_MIC_EVENT: - ad1884a_hp_automic(codec); + case HDA_FIXUP_ACT_PROBE: + if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) + spec->eapd_nid = spec->gen.autocfg.line_out_pins[0]; + else + spec->eapd_nid = spec->gen.autocfg.speaker_pins[0]; break; } } -/* initialize jack-sensing, too */ -static int ad1884a_hp_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_hp_automute(codec); - ad1884a_hp_automic(codec); - return 0; -} - -/* mute internal speaker if HP or docking HP is plugged */ -static void ad1884a_laptop_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x11); - if (!present) - present = snd_hda_jack_detect(codec, 0x12); - snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); - snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_EAPD_BTLENABLE, - present ? 0x00 : 0x02); -} - -/* switch to external mic if plugged */ -static void ad1884a_laptop_automic(struct hda_codec *codec) +static void ad1884_fixup_thinkpad(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - unsigned int idx; - - if (snd_hda_jack_detect(codec, 0x14)) - idx = 0; - else if (snd_hda_jack_detect(codec, 0x1c)) - idx = 4; - else - idx = 1; - snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, idx); -} + struct ad198x_spec *spec = codec->spec; -/* unsolicited event for HP jack sensing */ -static void ad1884a_laptop_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_laptop_automute(codec); - break; - case AD1884A_MIC_EVENT: - ad1884a_laptop_automic(codec); - break; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.keep_eapd_on = 1; + spec->gen.vmaster_mute.hook = ad_vmaster_eapd_hook; + spec->eapd_nid = 0x12; + /* Analog PC Beeper - allow firmware/ACPI beeps */ + spec->beep_amp = HDA_COMPOSE_AMP_VAL(0x20, 3, 3, HDA_INPUT); + spec->gen.beep_nid = 0; /* no digital beep */ } } -/* initialize jack-sensing, too */ -static int ad1884a_laptop_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_laptop_automute(codec); - ad1884a_laptop_automic(codec); - return 0; -} - -/* additional verbs for laptop model */ -static const struct hda_verb ad1884a_laptop_verbs[] = { - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F (int speaker) pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* required for compaq 6530s/6531s speaker output */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - /* Port-C pin - internal mic-in */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-D (docking line-out) pin - default unmuted */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - { } /* end */ -}; - -static const struct hda_verb ad1884a_mobile_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-B (mic jack) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-C (int mic) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - { } /* end */ -}; - -/* - * Thinkpad X300 - * 0x11 - HP - * 0x12 - speaker - * 0x14 - mic-in - * 0x17 - built-in mic - */ - -static const struct hda_verb ad1984a_thinkpad_verbs[] = { - /* HP unmute */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* analog mix */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* turn on EAPD */ - {0x12, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - /* internal mic - dmic */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* set magic COEFs for dmic */ +/* set magic COEFs for dmic */ +static const struct hda_verb ad1884_dmic_init_verbs[] = { {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, {0x01, AC_VERB_SET_PROC_COEF, 0x08}, - { } /* end */ + {} }; -static const struct snd_kcontrol_new ad1984a_thinkpad_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x14, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - { } /* end */ +enum { + AD1884_FIXUP_AMP_OVERRIDE, + AD1884_FIXUP_HP_EAPD, + AD1884_FIXUP_DMIC_COEF, + AD1884_FIXUP_THINKPAD, + AD1884_FIXUP_HP_TOUCHSMART, }; -static const struct hda_input_mux ad1984a_thinkpad_capture_source = { - .num_items = 3, - .items = { - { "Mic", 0x0 }, - { "Internal Mic", 0x5 }, - { "Mix", 0x3 }, +static const struct hda_fixup ad1884_fixups[] = { + [AD1884_FIXUP_AMP_OVERRIDE] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1884_fixup_amp_override, }, -}; - -/* mute internal speaker if HP is plugged */ -static void ad1984a_thinkpad_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_amp_stereo(codec, 0x12, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - -/* unsolicited event for HP jack sensing */ -static void ad1984a_thinkpad_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != AD1884A_HP_EVENT) - return; - ad1984a_thinkpad_automute(codec); -} - -/* initialize jack-sensing, too */ -static int ad1984a_thinkpad_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1984a_thinkpad_automute(codec); - return 0; -} - -/* - * Precision R5500 - * 0x12 - HP/line-out - * 0x13 - speaker (mono) - * 0x15 - mic-in - */ - -static const struct hda_verb ad1984a_precision_verbs[] = { - /* Unmute main output path */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x1f}, /* 0dB */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(5) + 0x17}, /* 0dB */ - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - /* Select mic as input */ - {0x0c, AC_VERB_SET_CONNECT_SEL, 0x1}, - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE + 0x27}, /* 0dB */ - /* Configure as mic */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, 0x7002}, /* raise mic as default */ - /* HP unmute */ - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* turn on EAPD */ - {0x13, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - /* unsolicited event for pin-sense */ - {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984a_precision_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x15, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Speaker Playback Volume", 0x13, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - { } /* end */ -}; - - -/* mute internal speaker if HP is plugged */ -static void ad1984a_precision_automute(struct hda_codec *codec) -{ - unsigned int present; - - present = snd_hda_jack_detect(codec, 0x12); - snd_hda_codec_amp_stereo(codec, 0x13, HDA_OUTPUT, 0, - HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); -} - - -/* unsolicited event for HP jack sensing */ -static void ad1984a_precision_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - if ((res >> 26) != AD1884A_HP_EVENT) - return; - ad1984a_precision_automute(codec); -} - -/* initialize jack-sensing, too */ -static int ad1984a_precision_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1984a_precision_automute(codec); - return 0; -} - - -/* - * HP Touchsmart - * port-A (0x11) - front hp-out - * port-B (0x14) - unused - * port-C (0x15) - unused - * port-D (0x12) - rear line out - * port-E (0x1c) - front mic-in - * port-F (0x16) - Internal speakers - * digital-mic (0x17) - Internal mic - */ - -static const struct hda_verb ad1984a_touchsmart_verbs[] = { - /* DACs; unmute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, 0x27}, /* 0dB */ - /* Port-A (HP) mixer - route only from analog mixer */ - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - /* Port-A (HP) pin - always unmuted */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - /* Port-E (int speaker) mixer - route only from analog mixer */ - {0x25, AC_VERB_SET_AMP_GAIN_MUTE, 0x03}, - /* Port-E pin */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - /* Port-F (int speaker) mixer - route only from analog mixer */ - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x0b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-F pin */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* capture sources */ - /* {0x0c, AC_VERB_SET_CONNECT_SEL, 0x0}, */ /* set via unsol */ - {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x0d, AC_VERB_SET_CONNECT_SEL, 0x0}, - {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* unsolicited event for pin-sense */ - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_HP_EVENT}, - {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1884A_MIC_EVENT}, - /* allow to touch GPIO1 (for mute control) */ - {0x01, AC_VERB_SET_GPIO_MASK, 0x02}, - {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x02}, - {0x01, AC_VERB_SET_GPIO_DATA, 0x02}, /* first muted */ - /* internal mic - dmic */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - /* set magic COEFs for dmic */ - {0x01, AC_VERB_SET_COEF_INDEX, 0x13f7}, - {0x01, AC_VERB_SET_PROC_COEF, 0x08}, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { - HDA_CODEC_VOLUME("Master Playback Volume", 0x21, 0x0, HDA_OUTPUT), -/* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .subdevice = HDA_SUBDEV_AMP_FLAG, - .name = "Master Playback Switch", - .info = snd_hda_mixer_amp_switch_info, - .get = snd_hda_mixer_amp_switch_get, - .put = ad1884a_mobile_master_sw_put, - .private_value = HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + [AD1884_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1884_fixup_hp_eapd, + .chained = true, + .chain_id = AD1884_FIXUP_AMP_OVERRIDE, + }, + [AD1884_FIXUP_DMIC_COEF] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = ad1884_dmic_init_verbs, + }, + [AD1884_FIXUP_THINKPAD] = { + .type = HDA_FIXUP_FUNC, + .v.func = ad1884_fixup_thinkpad, + .chained = true, + .chain_id = AD1884_FIXUP_DMIC_COEF, + }, + [AD1884_FIXUP_HP_TOUCHSMART] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = ad1884_dmic_init_verbs, + .chained = true, + .chain_id = AD1884_FIXUP_HP_EAPD, }, - HDA_CODEC_VOLUME("PCM Playback Volume", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x20, 0x5, HDA_INPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Mic Boost Volume", 0x25, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Internal Mic Boost Volume", 0x17, 0x0, HDA_INPUT), - { } /* end */ -}; - -/* switch to external mic if plugged */ -static void ad1984a_touchsmart_automic(struct hda_codec *codec) -{ - if (snd_hda_jack_detect(codec, 0x1c)) - snd_hda_codec_write(codec, 0x0c, 0, - AC_VERB_SET_CONNECT_SEL, 0x4); - else - snd_hda_codec_write(codec, 0x0c, 0, - AC_VERB_SET_CONNECT_SEL, 0x5); -} - - -/* unsolicited event for HP jack sensing */ -static void ad1984a_touchsmart_unsol_event(struct hda_codec *codec, - unsigned int res) -{ - switch (res >> 26) { - case AD1884A_HP_EVENT: - ad1884a_hp_automute(codec); - break; - case AD1884A_MIC_EVENT: - ad1984a_touchsmart_automic(codec); - break; - } -} - -/* initialize jack-sensing, too */ -static int ad1984a_touchsmart_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1884a_hp_automute(codec); - ad1984a_touchsmart_automic(codec); - return 0; -} - - -/* - */ - -enum { - AD1884A_DESKTOP, - AD1884A_LAPTOP, - AD1884A_MOBILE, - AD1884A_THINKPAD, - AD1984A_TOUCHSMART, - AD1984A_PRECISION, - AD1884A_MODELS -}; - -static const char * const ad1884a_models[AD1884A_MODELS] = { - [AD1884A_DESKTOP] = "desktop", - [AD1884A_LAPTOP] = "laptop", - [AD1884A_MOBILE] = "mobile", - [AD1884A_THINKPAD] = "thinkpad", - [AD1984A_TOUCHSMART] = "touchsmart", - [AD1984A_PRECISION] = "precision", }; -static const struct snd_pci_quirk ad1884a_cfg_tbl[] = { - SND_PCI_QUIRK(0x1028, 0x04ac, "Precision R5500", AD1984A_PRECISION), - 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_MASK(0x103c, 0xfff0, 0x3070, "HP", AD1884A_MOBILE), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30d0, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x30e0, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3600, "HP laptop", AD1884A_LAPTOP), - SND_PCI_QUIRK_MASK(0x103c, 0xfff0, 0x7010, "HP laptop", AD1884A_MOBILE), - SND_PCI_QUIRK(0x17aa, 0x20ac, "Thinkpad X300", AD1884A_THINKPAD), - SND_PCI_QUIRK(0x103c, 0x2a82, "Touchsmart", AD1984A_TOUCHSMART), +static const struct snd_pci_quirk ad1884_fixup_tbl[] = { + SND_PCI_QUIRK(0x103c, 0x2a82, "HP Touchsmart", AD1884_FIXUP_HP_TOUCHSMART), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", AD1884_FIXUP_HP_EAPD), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo Thinkpad", AD1884_FIXUP_THINKPAD), {} }; -static int patch_ad1884a(struct hda_codec *codec) + +static int patch_ad1884(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + int err; - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); + err = alloc_ad_spec(codec); + if (err < 0) return err; - } + spec = codec->spec; + + spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; + spec->gen.beep_nid = 0x10; set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = ARRAY_SIZE(ad1884a_dac_nids); - spec->multiout.dac_nids = ad1884a_dac_nids; - spec->multiout.dig_out_nid = AD1884A_SPDIF_OUT; - spec->num_adc_nids = ARRAY_SIZE(ad1884a_adc_nids); - spec->adc_nids = ad1884a_adc_nids; - spec->capsrc_nids = ad1884a_capsrc_nids; - spec->input_mux = &ad1884a_capture_source; - spec->num_mixers = 1; - spec->mixers[0] = ad1884a_base_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1884a_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1884a_loopbacks; -#endif - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1884A_MODELS, - ad1884a_models, - ad1884a_cfg_tbl); - switch (board_config) { - case AD1884A_LAPTOP: - spec->mixers[0] = ad1884a_laptop_mixers; - spec->init_verbs[spec->num_init_verbs++] = ad1884a_laptop_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1884a_laptop_unsol_event; - codec->patch_ops.init = ad1884a_laptop_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1884A_MOBILE: - spec->mixers[0] = ad1884a_mobile_mixers; - spec->init_verbs[0] = ad1884a_mobile_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1884a_hp_unsol_event; - codec->patch_ops.init = ad1884a_hp_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - case AD1884A_THINKPAD: - spec->mixers[0] = ad1984a_thinkpad_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1984a_thinkpad_verbs; - spec->multiout.dig_out_nid = 0; - spec->input_mux = &ad1984a_thinkpad_capture_source; - codec->patch_ops.unsol_event = ad1984a_thinkpad_unsol_event; - codec->patch_ops.init = ad1984a_thinkpad_init; - break; - case AD1984A_PRECISION: - spec->mixers[0] = ad1984a_precision_mixers; - spec->init_verbs[spec->num_init_verbs++] = - ad1984a_precision_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1984a_precision_unsol_event; - codec->patch_ops.init = ad1984a_precision_init; - break; - case AD1984A_TOUCHSMART: - spec->mixers[0] = ad1984a_touchsmart_mixers; - spec->init_verbs[0] = ad1984a_touchsmart_verbs; - spec->multiout.dig_out_nid = 0; - codec->patch_ops.unsol_event = ad1984a_touchsmart_unsol_event; - codec->patch_ops.init = ad1984a_touchsmart_init; - /* set the upper-limit for mixer amp to 0dB for avoiding the - * possible damage by overloading - */ - snd_hda_override_amp_caps(codec, 0x20, HDA_INPUT, - (0x17 << AC_AMPCAP_OFFSET_SHIFT) | - (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | - (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | - (1 << AC_AMPCAP_MUTE_SHIFT)); - break; - } + snd_hda_pick_fixup(codec, NULL, ad1884_fixup_tbl, ad1884_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + err = ad198x_parse_auto_config(codec, true); + if (err < 0) + goto error; + err = ad1983_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; -} + error: + snd_hda_gen_free(codec); + return err; +} /* * AD1882 / AD1882A @@ -4693,371 +1130,31 @@ static int patch_ad1884a(struct hda_codec *codec) * port-G - rear clfe-out (6stack) */ -static const hda_nid_t ad1882_dac_nids[3] = { - 0x04, 0x03, 0x05 -}; - -static const hda_nid_t ad1882_adc_nids[2] = { - 0x08, 0x09, -}; - -static const hda_nid_t ad1882_capsrc_nids[2] = { - 0x0c, 0x0d, -}; - -#define AD1882_SPDIF_OUT 0x02 - -/* list: 0x11, 0x39, 0x3a, 0x18, 0x3c, 0x3b, 0x12, 0x20 */ -static const struct hda_input_mux ad1882_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, - { "Mic", 0x4 }, - { "Line", 0x2 }, - { "CD", 0x3 }, - { "Mix", 0x7 }, - }, -}; - -/* list: 0x11, 0x39, 0x3a, 0x3c, 0x18, 0x1f, 0x12, 0x20 */ -static const struct hda_input_mux ad1882a_capture_source = { - .num_items = 5, - .items = { - { "Front Mic", 0x1 }, - { "Mic", 0x4}, - { "Line", 0x2 }, - { "Digital Mic", 0x06 }, - { "Mix", 0x7 }, - }, -}; - -static const struct snd_kcontrol_new ad1882_base_mixers[] = { - HDA_CODEC_VOLUME("Front Playback Volume", 0x04, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x05, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x05, 2, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Headphone Playback Switch", 0x11, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Front Playback Switch", 0x12, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_MONO("Mono Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Mono Playback Switch", 0x13, 1, 0x0, HDA_OUTPUT), - - HDA_CODEC_VOLUME("Mic Boost Volume", 0x3c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Front Mic Boost Volume", 0x39, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Line-In Boost Volume", 0x3a, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0c, 0x0, HDA_OUTPUT), - HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x0d, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x0d, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .count = 2, - .info = ad198x_mux_enum_info, - .get = ad198x_mux_enum_get, - .put = ad198x_mux_enum_put, - }, - /* SPDIF controls */ - HDA_CODEC_VOLUME("IEC958 Playback Volume", 0x1b, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source", - /* identical with ad1983 */ - .info = ad1983_spdif_route_info, - .get = ad1983_spdif_route_get, - .put = ad1983_spdif_route_put, - }, - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882_loopback_mixers[] = { - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882a_loopback_mixers[] = { - HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Front Mic Playback Switch", 0x20, 0x00, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x20, 0x04, HDA_INPUT), - HDA_CODEC_VOLUME("Line Playback Volume", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_MUTE("Line Playback Switch", 0x20, 0x01, HDA_INPUT), - HDA_CODEC_VOLUME("CD Playback Volume", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_MUTE("CD Playback Switch", 0x20, 0x06, HDA_INPUT), - HDA_CODEC_VOLUME("Digital Mic Boost Volume", 0x1f, 0x0, HDA_INPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new ad1882_3stack_mixers[] = { - HDA_CODEC_MUTE("Surround Playback Switch", 0x15, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x17, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x17, 2, 0x0, HDA_OUTPUT), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = ad198x_ch_mode_info, - .get = ad198x_ch_mode_get, - .put = ad198x_ch_mode_put, - }, - { } /* end */ -}; - -/* simple auto-mute control for AD1882 3-stack board */ -#define AD1882_HP_EVENT 0x01 - -static void ad1882_3stack_automute(struct hda_codec *codec) -{ - bool mute = snd_hda_jack_detect(codec, 0x11); - snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, - mute ? 0 : PIN_OUT); -} - -static int ad1882_3stack_automute_init(struct hda_codec *codec) -{ - ad198x_init(codec); - ad1882_3stack_automute(codec); - return 0; -} - -static void ad1882_3stack_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch (res >> 26) { - case AD1882_HP_EVENT: - ad1882_3stack_automute(codec); - break; - } -} - -static const struct snd_kcontrol_new ad1882_6stack_mixers[] = { - HDA_CODEC_MUTE("Surround Playback Switch", 0x16, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x24, 1, 0x0, HDA_OUTPUT), - HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x24, 2, 0x0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct hda_verb ad1882_ch2_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -static const struct hda_verb ad1882_ch4_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - { } /* end */ -}; - -static const struct hda_verb ad1882_ch6_init[] = { - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - { } /* end */ -}; - -static const struct hda_channel_mode ad1882_modes[3] = { - { 2, ad1882_ch2_init }, - { 4, ad1882_ch4_init }, - { 6, ad1882_ch6_init }, -}; - -/* - * initialization verbs - */ -static const struct hda_verb ad1882_init_verbs[] = { - /* DACs; mute as default */ - {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Port-A (HP) mixer */ - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-A pin */ - {0x11, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* HP selector - select DAC2 */ - {0x37, AC_VERB_SET_CONNECT_SEL, 0x1}, - /* Port-D (Line-out) mixer */ - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Port-D pin */ - {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x12, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Mono-out mixer */ - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, - {0x1e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, - /* Mono-out pin */ - {0x13, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-B (front mic) pin */ - {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x39, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-C (line-in) pin */ - {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x3a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-C mixer - mute as input */ - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x2c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Port-E (mic-in) pin */ - {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - {0x3c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* boost */ - /* Port-E mixer - mute as input */ - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x26, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - /* Port-F (surround) */ - {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Port-G (CLFE) */ - {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - /* Analog mixer; mute as default */ - /* list: 0x39, 0x3a, 0x11, 0x12, 0x3c, 0x3b, 0x18, 0x1a */ - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(6)}, - {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(7)}, - /* Analog Mix output amp */ - {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x1f}, /* 0dB */ - /* SPDIF output selector */ - {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - {0x02, AC_VERB_SET_CONNECT_SEL, 0x0}, /* PCM */ - {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x27}, /* 0dB */ - { } /* end */ -}; - -static const struct hda_verb ad1882_3stack_automute_verbs[] = { - {0x11, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | AD1882_HP_EVENT}, - { } /* end */ -}; - -#ifdef CONFIG_PM -static const struct hda_amp_list ad1882_loopbacks[] = { - { 0x20, HDA_INPUT, 0 }, /* Front Mic */ - { 0x20, HDA_INPUT, 1 }, /* Mic */ - { 0x20, HDA_INPUT, 4 }, /* Line */ - { 0x20, HDA_INPUT, 6 }, /* CD */ - { } /* end */ -}; -#endif - -/* models */ -enum { - AD1882_3STACK, - AD1882_6STACK, - AD1882_3STACK_AUTOMUTE, - AD1882_MODELS -}; - -static const char * const ad1882_models[AD1986A_MODELS] = { - [AD1882_3STACK] = "3stack", - [AD1882_6STACK] = "6stack", - [AD1882_3STACK_AUTOMUTE] = "3stack-automute", -}; - - static int patch_ad1882(struct hda_codec *codec) { struct ad198x_spec *spec; - int err, board_config; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - codec->spec = spec; + int err; - err = snd_hda_attach_beep_device(codec, 0x10); - if (err < 0) { - ad198x_free(codec); + err = alloc_ad_spec(codec); + if (err < 0) return err; - } - set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); - - spec->multiout.max_channels = 6; - spec->multiout.num_dacs = 3; - spec->multiout.dac_nids = ad1882_dac_nids; - spec->multiout.dig_out_nid = AD1882_SPDIF_OUT; - 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 == 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 == 0x11d41882) - spec->mixers[1] = ad1882_loopback_mixers; - else - spec->mixers[1] = ad1882a_loopback_mixers; - spec->num_init_verbs = 1; - spec->init_verbs[0] = ad1882_init_verbs; - spec->spdif_route = 0; -#ifdef CONFIG_PM - spec->loopback.amplist = ad1882_loopbacks; -#endif - spec->vmaster_nid = 0x04; - - codec->patch_ops = ad198x_patch_ops; - - /* override some parameters */ - board_config = snd_hda_check_board_config(codec, AD1882_MODELS, - ad1882_models, NULL); - switch (board_config) { - default: - case AD1882_3STACK: - case AD1882_3STACK_AUTOMUTE: - spec->num_mixers = 3; - spec->mixers[2] = ad1882_3stack_mixers; - spec->channel_mode = ad1882_modes; - spec->num_channel_mode = ARRAY_SIZE(ad1882_modes); - spec->need_dac_fix = 1; - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - if (board_config != AD1882_3STACK) { - spec->init_verbs[spec->num_init_verbs++] = - ad1882_3stack_automute_verbs; - codec->patch_ops.unsol_event = ad1882_3stack_unsol_event; - codec->patch_ops.init = ad1882_3stack_automute_init; - } - break; - case AD1882_6STACK: - spec->num_mixers = 3; - spec->mixers[2] = ad1882_6stack_mixers; - break; - } - - codec->no_trigger_sense = 1; - codec->no_sticky_stream = 1; + spec = codec->spec; + spec->gen.mixer_nid = 0x20; + spec->gen.mixer_merge_nid = 0x21; + spec->gen.beep_nid = 0x10; + set_beep_amp(spec, 0x10, 0, HDA_OUTPUT); + err = ad198x_parse_auto_config(codec, true); + if (err < 0) + goto error; + err = ad1988_add_spdif_mux_ctl(codec); + if (err < 0) + goto error; return 0; + + error: + snd_hda_gen_free(codec); + return err; } @@ -5065,15 +1162,15 @@ static int patch_ad1882(struct hda_codec *codec) * patch entries */ static const struct hda_codec_preset snd_hda_preset_analog[] = { - { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884a }, + { .id = 0x11d4184a, .name = "AD1884A", .patch = patch_ad1884 }, { .id = 0x11d41882, .name = "AD1882", .patch = patch_ad1882 }, - { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884a }, + { .id = 0x11d41883, .name = "AD1883", .patch = patch_ad1884 }, { .id = 0x11d41884, .name = "AD1884", .patch = patch_ad1884 }, - { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884a }, - { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884a }, + { .id = 0x11d4194a, .name = "AD1984A", .patch = patch_ad1884 }, + { .id = 0x11d4194b, .name = "AD1984B", .patch = patch_ad1884 }, { .id = 0x11d41981, .name = "AD1981", .patch = patch_ad1981 }, { .id = 0x11d41983, .name = "AD1983", .patch = patch_ad1983 }, - { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1984 }, + { .id = 0x11d41984, .name = "AD1984", .patch = patch_ad1884 }, { .id = 0x11d41986, .name = "AD1986A", .patch = patch_ad1986a }, { .id = 0x11d41988, .name = "AD1988", .patch = patch_ad1988 }, { .id = 0x11d4198b, .name = "AD1988B", .patch = patch_ad1988 }, diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index 19ae14f739c..5e65999e0d8 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -19,510 +19,52 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_generic.h" -/* - */ - -struct ca0110_spec { - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; - hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; - hda_nid_t input_pins[AUTO_PIN_LAST]; - hda_nid_t adcs[AUTO_PIN_LAST]; - hda_nid_t dig_out; - hda_nid_t dig_in; - unsigned int num_inputs; - char input_labels[AUTO_PIN_LAST][32]; - struct hda_pcm pcm_rec[2]; /* PCM information */ -}; - -/* - * PCM callbacks - */ -static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -/* - * Analog capture - */ -static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], - stream_tag, 0, format); - return 0; -} - -static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct ca0110_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); - return 0; -} - -/* - */ - -static const char * const dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) - -static int ca0110_build_controls(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - static const char * const prefix[AUTO_CFG_MAX_OUTS] = { - "Front", "Surround", NULL, "Side", "Multi" - }; - hda_nid_t mutenid; - int i, err; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) - mutenid = spec->out_pins[i]; - else - mutenid = spec->multiout.dac_nids[i]; - if (!prefix[i]) { - err = add_mono_switch(codec, mutenid, - "Center", 1); - if (err < 0) - return err; - err = add_mono_switch(codec, mutenid, - "LFE", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "Center", 1); - if (err < 0) - return err; - err = add_mono_volume(codec, spec->multiout.dac_nids[i], - "LFE", 1); - if (err < 0) - return err; - } else { - err = add_out_switch(codec, mutenid, - prefix[i]); - if (err < 0) - return err; - err = add_out_volume(codec, spec->multiout.dac_nids[i], - prefix[i]); - if (err < 0) - return err; - } - } - if (cfg->hp_outs) { - if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) - mutenid = cfg->hp_pins[0]; - else - mutenid = spec->multiout.dac_nids[i]; - - err = add_out_switch(codec, mutenid, "Headphone"); - if (err < 0) - return err; - if (spec->hp_dac) { - err = add_out_volume(codec, spec->hp_dac, "Headphone"); - if (err < 0) - return err; - } - } - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; - if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) - mutenid = spec->input_pins[i]; - else - mutenid = spec->adcs[i]; - err = add_in_switch(codec, mutenid, label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - } - - if (spec->dig_out) { - err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, - spec->dig_out); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - if (err < 0) - return err; - err = add_in_volume(codec, spec->dig_in, "IEC958"); - } - return 0; -} - -/* - */ -static const struct hda_pcm_stream ca0110_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .ops = { - .open = ca0110_playback_pcm_open, - .prepare = ca0110_playback_pcm_prepare, - .cleanup = ca0110_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = ca0110_capture_pcm_prepare, - .cleanup = ca0110_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0110_dig_playback_pcm_open, - .close = ca0110_dig_playback_pcm_close, - .prepare = ca0110_dig_playback_pcm_prepare - }, -}; - -static const struct hda_pcm_stream ca0110_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int ca0110_build_pcms(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "CA0110 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; - - if (!spec->dig_out && !spec->dig_in) - return 0; - - info++; - info->name = "CA0110 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0110_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0110_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_IN | - snd_hda_get_default_vref(codec, pin)); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static int ca0110_init(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - init_output(codec, cfg->hp_pins[0], spec->hp_dac); - init_output(codec, cfg->dig_out_pins[0], spec->dig_out); - - for (i = 0; i < spec->num_inputs; i++) - init_input(codec, spec->input_pins[i], spec->adcs[i]); - init_input(codec, cfg->dig_in_pin, spec->dig_in); - return 0; -} - -static void ca0110_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} static const struct hda_codec_ops ca0110_patch_ops = { - .build_controls = ca0110_build_controls, - .build_pcms = ca0110_build_pcms, - .init = ca0110_init, - .free = ca0110_free, + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, }; - -static void parse_line_outs(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, n; - unsigned int def_conf; - hda_nid_t nid; - - n = 0; - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) - continue; /* invalid pin */ - if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) - continue; - spec->out_pins[n++] = nid; - } - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = n; - spec->multiout.max_channels = n * 2; -} - -static void parse_hp_out(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - unsigned int def_conf; - hda_nid_t nid, dac; - - if (!cfg->hp_outs) - return; - nid = cfg->hp_pins[0]; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!def_conf) { - cfg->hp_outs = 0; - return; - } - if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) - return; - - for (i = 0; i < cfg->line_outs; i++) - if (dac == spec->dacs[i]) - break; - if (i >= cfg->line_outs) { - spec->hp_dac = dac; - spec->multiout.hp_nid = dac; - } -} - -static void parse_input(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid, pin; - int n, i, j; - - n = 0; - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type != AC_WID_AUD_IN) - continue; - if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) - continue; - if (pin == cfg->dig_in_pin) { - spec->dig_in = nid; - continue; - } - for (j = 0; j < cfg->num_inputs; j++) - if (cfg->inputs[j].pin == pin) - break; - if (j >= cfg->num_inputs) - continue; - spec->input_pins[n] = pin; - snd_hda_get_pin_label(codec, pin, cfg, - spec->input_labels[n], - sizeof(spec->input_labels[n]), NULL); - spec->adcs[n] = nid; - n++; - } - spec->num_inputs = n; -} - -static void parse_digital(struct hda_codec *codec) -{ - struct ca0110_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], - &spec->dig_out, 1) == 1) - spec->multiout.dig_out_nid = spec->dig_out; -} - static int ca0110_parse_auto_config(struct hda_codec *codec) { - struct ca0110_spec *spec = codec->spec; + struct hda_gen_spec *spec = codec->spec; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_defcfg(codec, &spec->autocfg, NULL, 0); + if (err < 0) + return err; + err = snd_hda_gen_parse_auto_config(codec, &spec->autocfg); if (err < 0) return err; - parse_line_outs(codec); - parse_hp_out(codec); - parse_digital(codec); - parse_input(codec); return 0; } static int patch_ca0110(struct hda_codec *codec) { - struct ca0110_spec *spec; + struct hda_gen_spec *spec; int err; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + snd_hda_gen_spec_init(spec); codec->spec = spec; + spec->multi_cap_vol = 1; codec->bus->needs_damn_long_delay = 1; err = ca0110_parse_auto_config(codec); @@ -534,8 +76,7 @@ static int patch_ca0110(struct hda_codec *codec) return 0; error: - kfree(codec->spec); - codec->spec = NULL; + snd_hda_gen_free(codec); return err; } diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 49750a96d64..092f2bd030b 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c @@ -24,19 +24,454 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/mutex.h> #include <linux/module.h> +#include <linux/firmware.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_jack.h" + +#include "ca0132_regs.h" + +/* Enable this to see controls for tuning purpose. */ +/*#define ENABLE_TUNING_CONTROLS*/ + +#define FLOAT_ZERO 0x00000000 +#define FLOAT_ONE 0x3f800000 +#define FLOAT_TWO 0x40000000 +#define FLOAT_MINUS_5 0xc0a00000 + +#define UNSOL_TAG_HP 0x10 +#define UNSOL_TAG_AMIC1 0x12 +#define UNSOL_TAG_DSP 0x16 + +#define DSP_DMA_WRITE_BUFLEN_INIT (1UL<<18) +#define DSP_DMA_WRITE_BUFLEN_OVLY (1UL<<15) + +#define DMA_TRANSFER_FRAME_SIZE_NWORDS 8 +#define DMA_TRANSFER_MAX_FRAME_SIZE_NWORDS 32 +#define DMA_OVERLAY_FRAME_SIZE_NWORDS 2 + +#define MASTERCONTROL 0x80 +#define MASTERCONTROL_ALLOC_DMA_CHAN 10 +#define MASTERCONTROL_QUERY_SPEAKER_EQ_ADDRESS 60 #define WIDGET_CHIP_CTRL 0x15 #define WIDGET_DSP_CTRL 0x16 -#define WUH_MEM_CONNID 10 -#define DSP_MEM_CONNID 16 +#define MEM_CONNID_MICIN1 3 +#define MEM_CONNID_MICIN2 5 +#define MEM_CONNID_MICOUT1 12 +#define MEM_CONNID_MICOUT2 14 +#define MEM_CONNID_WUH 10 +#define MEM_CONNID_DSP 16 +#define MEM_CONNID_DMIC 100 + +#define SCP_SET 0 +#define SCP_GET 1 + +#define EFX_FILE "ctefx.bin" + +#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP +MODULE_FIRMWARE(EFX_FILE); +#endif + +static char *dirstr[2] = { "Playback", "Capture" }; + +enum { + SPEAKER_OUT, + HEADPHONE_OUT +}; + +enum { + DIGITAL_MIC, + LINE_MIC_IN +}; + +enum { +#define VNODE_START_NID 0x80 + VNID_SPK = VNODE_START_NID, /* Speaker vnid */ + VNID_MIC, + VNID_HP_SEL, + VNID_AMIC1_SEL, + VNID_HP_ASEL, + VNID_AMIC1_ASEL, + VNODE_END_NID, +#define VNODES_COUNT (VNODE_END_NID - VNODE_START_NID) + +#define EFFECT_START_NID 0x90 +#define OUT_EFFECT_START_NID EFFECT_START_NID + SURROUND = OUT_EFFECT_START_NID, + CRYSTALIZER, + DIALOG_PLUS, + SMART_VOLUME, + X_BASS, + EQUALIZER, + OUT_EFFECT_END_NID, +#define OUT_EFFECTS_COUNT (OUT_EFFECT_END_NID - OUT_EFFECT_START_NID) + +#define IN_EFFECT_START_NID OUT_EFFECT_END_NID + ECHO_CANCELLATION = IN_EFFECT_START_NID, + VOICE_FOCUS, + MIC_SVM, + NOISE_REDUCTION, + IN_EFFECT_END_NID, +#define IN_EFFECTS_COUNT (IN_EFFECT_END_NID - IN_EFFECT_START_NID) + + VOICEFX = IN_EFFECT_END_NID, + PLAY_ENHANCEMENT, + CRYSTAL_VOICE, + EFFECT_END_NID +#define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) +}; + +/* Effects values size*/ +#define EFFECT_VALS_MAX_COUNT 12 + +/* Latency introduced by DSP blocks in milliseconds. */ +#define DSP_CAPTURE_INIT_LATENCY 0 +#define DSP_CRYSTAL_VOICE_LATENCY 124 +#define DSP_PLAYBACK_INIT_LATENCY 13 +#define DSP_PLAY_ENHANCEMENT_LATENCY 30 +#define DSP_SPEAKER_OUT_LATENCY 7 + +struct ct_effect { + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + hda_nid_t nid; + int mid; /*effect module ID*/ + int reqs[EFFECT_VALS_MAX_COUNT]; /*effect module request*/ + int direct; /* 0:output; 1:input*/ + int params; /* number of default non-on/off params */ + /*effect default values, 1st is on/off. */ + unsigned int def_vals[EFFECT_VALS_MAX_COUNT]; +}; + +#define EFX_DIR_OUT 0 +#define EFX_DIR_IN 1 + +static struct ct_effect ca0132_effects[EFFECTS_COUNT] = { + { .name = "Surround", + .nid = SURROUND, + .mid = 0x96, + .reqs = {0, 1}, + .direct = EFX_DIR_OUT, + .params = 1, + .def_vals = {0x3F800000, 0x3F2B851F} + }, + { .name = "Crystalizer", + .nid = CRYSTALIZER, + .mid = 0x96, + .reqs = {7, 8}, + .direct = EFX_DIR_OUT, + .params = 1, + .def_vals = {0x3F800000, 0x3F266666} + }, + { .name = "Dialog Plus", + .nid = DIALOG_PLUS, + .mid = 0x96, + .reqs = {2, 3}, + .direct = EFX_DIR_OUT, + .params = 1, + .def_vals = {0x00000000, 0x3F000000} + }, + { .name = "Smart Volume", + .nid = SMART_VOLUME, + .mid = 0x96, + .reqs = {4, 5, 6}, + .direct = EFX_DIR_OUT, + .params = 2, + .def_vals = {0x3F800000, 0x3F3D70A4, 0x00000000} + }, + { .name = "X-Bass", + .nid = X_BASS, + .mid = 0x96, + .reqs = {24, 23, 25}, + .direct = EFX_DIR_OUT, + .params = 2, + .def_vals = {0x3F800000, 0x42A00000, 0x3F000000} + }, + { .name = "Equalizer", + .nid = EQUALIZER, + .mid = 0x96, + .reqs = {9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20}, + .direct = EFX_DIR_OUT, + .params = 11, + .def_vals = {0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000} + }, + { .name = "Echo Cancellation", + .nid = ECHO_CANCELLATION, + .mid = 0x95, + .reqs = {0, 1, 2, 3}, + .direct = EFX_DIR_IN, + .params = 3, + .def_vals = {0x00000000, 0x3F3A9692, 0x00000000, 0x00000000} + }, + { .name = "Voice Focus", + .nid = VOICE_FOCUS, + .mid = 0x95, + .reqs = {6, 7, 8, 9}, + .direct = EFX_DIR_IN, + .params = 3, + .def_vals = {0x3F800000, 0x3D7DF3B6, 0x41F00000, 0x41F00000} + }, + { .name = "Mic SVM", + .nid = MIC_SVM, + .mid = 0x95, + .reqs = {44, 45}, + .direct = EFX_DIR_IN, + .params = 1, + .def_vals = {0x00000000, 0x3F3D70A4} + }, + { .name = "Noise Reduction", + .nid = NOISE_REDUCTION, + .mid = 0x95, + .reqs = {4, 5}, + .direct = EFX_DIR_IN, + .params = 1, + .def_vals = {0x3F800000, 0x3F000000} + }, + { .name = "VoiceFX", + .nid = VOICEFX, + .mid = 0x95, + .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18}, + .direct = EFX_DIR_IN, + .params = 8, + .def_vals = {0x00000000, 0x43C80000, 0x44AF0000, 0x44FA0000, + 0x3F800000, 0x3F800000, 0x3F800000, 0x00000000, + 0x00000000} + } +}; + +/* Tuning controls */ +#ifdef ENABLE_TUNING_CONTROLS + +enum { +#define TUNING_CTL_START_NID 0xC0 + WEDGE_ANGLE = TUNING_CTL_START_NID, + SVM_LEVEL, + EQUALIZER_BAND_0, + EQUALIZER_BAND_1, + EQUALIZER_BAND_2, + EQUALIZER_BAND_3, + EQUALIZER_BAND_4, + EQUALIZER_BAND_5, + EQUALIZER_BAND_6, + EQUALIZER_BAND_7, + EQUALIZER_BAND_8, + EQUALIZER_BAND_9, + TUNING_CTL_END_NID +#define TUNING_CTLS_COUNT (TUNING_CTL_END_NID - TUNING_CTL_START_NID) +}; + +struct ct_tuning_ctl { + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + hda_nid_t parent_nid; + hda_nid_t nid; + int mid; /*effect module ID*/ + int req; /*effect module request*/ + int direct; /* 0:output; 1:input*/ + unsigned int def_val;/*effect default values*/ +}; + +static struct ct_tuning_ctl ca0132_tuning_ctls[] = { + { .name = "Wedge Angle", + .parent_nid = VOICE_FOCUS, + .nid = WEDGE_ANGLE, + .mid = 0x95, + .req = 8, + .direct = EFX_DIR_IN, + .def_val = 0x41F00000 + }, + { .name = "SVM Level", + .parent_nid = MIC_SVM, + .nid = SVM_LEVEL, + .mid = 0x95, + .req = 45, + .direct = EFX_DIR_IN, + .def_val = 0x3F3D70A4 + }, + { .name = "EQ Band0", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_0, + .mid = 0x96, + .req = 11, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band1", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_1, + .mid = 0x96, + .req = 12, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band2", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_2, + .mid = 0x96, + .req = 13, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band3", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_3, + .mid = 0x96, + .req = 14, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band4", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_4, + .mid = 0x96, + .req = 15, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band5", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_5, + .mid = 0x96, + .req = 16, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band6", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_6, + .mid = 0x96, + .req = 17, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band7", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_7, + .mid = 0x96, + .req = 18, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band8", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_8, + .mid = 0x96, + .req = 19, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + }, + { .name = "EQ Band9", + .parent_nid = EQUALIZER, + .nid = EQUALIZER_BAND_9, + .mid = 0x96, + .req = 20, + .direct = EFX_DIR_OUT, + .def_val = 0x00000000 + } +}; +#endif + +/* Voice FX Presets */ +#define VOICEFX_MAX_PARAM_COUNT 9 + +struct ct_voicefx { + char *name; + hda_nid_t nid; + int mid; + int reqs[VOICEFX_MAX_PARAM_COUNT]; /*effect module request*/ +}; + +struct ct_voicefx_preset { + char *name; /*preset name*/ + unsigned int vals[VOICEFX_MAX_PARAM_COUNT]; +}; + +static struct ct_voicefx ca0132_voicefx = { + .name = "VoiceFX Capture Switch", + .nid = VOICEFX, + .mid = 0x95, + .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18} +}; + +static struct ct_voicefx_preset ca0132_voicefx_presets[] = { + { .name = "Neutral", + .vals = { 0x00000000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x3F800000, 0x3F800000, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Female2Male", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x3F19999A, 0x3F866666, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Male2Female", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x450AC000, 0x4017AE14, 0x3F6B851F, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "ScrappyKid", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x40400000, 0x3F28F5C3, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Elderly", + .vals = { 0x3F800000, 0x44324000, 0x44BB8000, + 0x44E10000, 0x3FB33333, 0x3FB9999A, + 0x3F800000, 0x3E3A2E43, 0x00000000 } + }, + { .name = "Orc", + .vals = { 0x3F800000, 0x43EA0000, 0x44A52000, + 0x45098000, 0x3F266666, 0x3FC00000, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Elf", + .vals = { 0x3F800000, 0x43C70000, 0x44AE6000, + 0x45193000, 0x3F8E147B, 0x3F75C28F, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Dwarf", + .vals = { 0x3F800000, 0x43930000, 0x44BEE000, + 0x45007000, 0x3F451EB8, 0x3F7851EC, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "AlienBrute", + .vals = { 0x3F800000, 0x43BFC5AC, 0x44B28FDF, + 0x451F6000, 0x3F266666, 0x3FA7D945, + 0x3F800000, 0x3CF5C28F, 0x00000000 } + }, + { .name = "Robot", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x3FB2718B, 0x3F800000, + 0xBC07010E, 0x00000000, 0x00000000 } + }, + { .name = "Marine", + .vals = { 0x3F800000, 0x43C20000, 0x44906000, + 0x44E70000, 0x3F4CCCCD, 0x3F8A3D71, + 0x3F0A3D71, 0x00000000, 0x00000000 } + }, + { .name = "Emo", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x3F800000, 0x3F800000, + 0x3E4CCCCD, 0x00000000, 0x00000000 } + }, + { .name = "DeepVoice", + .vals = { 0x3F800000, 0x43A9C5AC, 0x44AA4FDF, + 0x44FFC000, 0x3EDBB56F, 0x3F99C4CA, + 0x3F800000, 0x00000000, 0x00000000 } + }, + { .name = "Munchkin", + .vals = { 0x3F800000, 0x43C80000, 0x44AF0000, + 0x44FA0000, 0x3F800000, 0x3F1A043C, + 0x3F800000, 0x00000000, 0x00000000 } + } +}; enum hda_cmd_vendor_io { /* for DspIO node */ @@ -62,7 +497,11 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_HIC_POST_READ = 0x702, VENDOR_CHIPIO_HIC_READ_DATA = 0xF03, + VENDOR_CHIPIO_8051_DATA_WRITE = 0x707, + VENDOR_CHIPIO_8051_DATA_READ = 0xF07, + VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE = 0x70A, + VENDOR_CHIPIO_CT_EXTENSIONS_GET = 0xF0A, VENDOR_CHIPIO_PLL_PMU_WRITE = 0x70C, VENDOR_CHIPIO_PLL_PMU_READ = 0xF0C, @@ -70,18 +509,27 @@ enum hda_cmd_vendor_io { VENDOR_CHIPIO_8051_ADDRESS_HIGH = 0x70E, VENDOR_CHIPIO_FLAG_SET = 0x70F, VENDOR_CHIPIO_FLAGS_GET = 0xF0F, - VENDOR_CHIPIO_PARAMETER_SET = 0x710, - VENDOR_CHIPIO_PARAMETER_GET = 0xF10, + VENDOR_CHIPIO_PARAM_SET = 0x710, + VENDOR_CHIPIO_PARAM_GET = 0xF10, VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET = 0x711, VENDOR_CHIPIO_PORT_ALLOC_SET = 0x712, VENDOR_CHIPIO_PORT_ALLOC_GET = 0xF12, VENDOR_CHIPIO_PORT_FREE_SET = 0x713, - VENDOR_CHIPIO_PARAMETER_EX_ID_GET = 0xF17, - VENDOR_CHIPIO_PARAMETER_EX_ID_SET = 0x717, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_GET = 0xF18, - VENDOR_CHIPIO_PARAMETER_EX_VALUE_SET = 0x718 + VENDOR_CHIPIO_PARAM_EX_ID_GET = 0xF17, + VENDOR_CHIPIO_PARAM_EX_ID_SET = 0x717, + VENDOR_CHIPIO_PARAM_EX_VALUE_GET = 0xF18, + VENDOR_CHIPIO_PARAM_EX_VALUE_SET = 0x718, + + VENDOR_CHIPIO_DMIC_CTL_SET = 0x788, + VENDOR_CHIPIO_DMIC_CTL_GET = 0xF88, + VENDOR_CHIPIO_DMIC_PIN_SET = 0x789, + VENDOR_CHIPIO_DMIC_PIN_GET = 0xF89, + VENDOR_CHIPIO_DMIC_MCLK_SET = 0x78A, + VENDOR_CHIPIO_DMIC_MCLK_GET = 0xF8A, + + VENDOR_CHIPIO_EAPD_SEL_SET = 0x78D }; /* @@ -131,7 +579,7 @@ enum control_flag_id { /* Impedance for ramp generator on Port_A 16 Ohm/10K Ohm */ CONTROL_FLAG_PORT_A_10KOHM_LOAD = 20, /* Impedance for ramp generator on Port_D, 16 Ohm/10K Ohm */ - CONTROL_FLAG_PORT_D_10K0HM_LOAD = 21, + CONTROL_FLAG_PORT_D_10KOHM_LOAD = 21, /* ASI rate is 48kHz/96kHz */ CONTROL_FLAG_ASI_96KHZ = 22, /* DAC power settings able to control attached ports no/yes */ @@ -145,9 +593,17 @@ enum control_flag_id { /* * Control parameter IDs */ -enum control_parameter_id { +enum control_param_id { + /* 0: None, 1: Mic1In*/ + CONTROL_PARAM_VIP_SOURCE = 1, /* 0: force HDA, 1: allow DSP if HDA Spdif1Out stream is idle */ CONTROL_PARAM_SPDIF1_SOURCE = 2, + /* Port A output stage gain setting to use when 16 Ohm output + * impedance is selected*/ + CONTROL_PARAM_PORTA_160OHM_GAIN = 8, + /* Port D output stage gain setting to use when 16 Ohm output + * impedance is selected*/ + CONTROL_PARAM_PORTD_160OHM_GAIN = 10, /* Stream Control */ @@ -225,123 +681,118 @@ enum ca0132_sample_rate { SR_RATE_UNKNOWN = 0x1F }; -/* - * Scp Helper function - */ -enum get_set { - IS_SET = 0, - IS_GET = 1, +enum dsp_download_state { + DSP_DOWNLOAD_FAILED = -1, + DSP_DOWNLOAD_INIT = 0, + DSP_DOWNLOADING = 1, + DSP_DOWNLOADED = 2 }; -/* - * Duplicated from ca0110 codec - */ - -static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_HP); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - if (dac && (get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); -} - -static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) -{ - if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_IN | - snd_hda_get_default_vref(codec, pin)); - if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP)) - snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); -} - -static char *dirstr[2] = { "Playback", "Capture" }; - -static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); - if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_MUTE) == 0) { - snd_printdd("Skipping '%s %s Switch' (no mute on node 0x%x)\n", pfx, dirstr[dir], nid); - return 0; - } - sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, - int chan, int dir) -{ - char namestr[44]; - int type = dir ? HDA_INPUT : HDA_OUTPUT; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); - if ((query_amp_caps(codec, nid, type) & AC_AMPCAP_NUM_STEPS) == 0) { - snd_printdd("Skipping '%s %s Volume' (no amp on node 0x%x)\n", pfx, dirstr[dir], nid); - return 0; - } - sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); -} - -#define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) -#define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) -#define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) -#define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) -#define add_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 0) -#define add_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 0) -#define add_in_mono_switch(codec, nid, pfx, chan) \ - _add_switch(codec, nid, pfx, chan, 1) -#define add_in_mono_volume(codec, nid, pfx, chan) \ - _add_volume(codec, nid, pfx, chan, 1) - +/* retrieve parameters from hda format */ +#define get_hdafmt_chs(fmt) (fmt & 0xf) +#define get_hdafmt_bits(fmt) ((fmt >> 4) & 0x7) +#define get_hdafmt_rate(fmt) ((fmt >> 8) & 0x7f) +#define get_hdafmt_type(fmt) ((fmt >> 15) & 0x1) /* * CA0132 specific */ struct ca0132_spec { + struct snd_kcontrol_new *mixers[5]; + unsigned int num_mixers; + const struct hda_verb *base_init_verbs; + const struct hda_verb *base_exit_verbs; + const struct hda_verb *init_verbs[5]; + unsigned int num_init_verbs; /* exclude base init verbs */ struct auto_pin_cfg autocfg; + + /* Nodes configurations */ struct hda_multi_out multiout; hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; - hda_nid_t hp_dac; + unsigned int num_outputs; hda_nid_t input_pins[AUTO_PIN_LAST]; hda_nid_t adcs[AUTO_PIN_LAST]; hda_nid_t dig_out; hda_nid_t dig_in; unsigned int num_inputs; - long curr_hp_switch; - long curr_hp_volume[2]; - long curr_speaker_switch; - struct mutex chipio_mutex; - const char *input_labels[AUTO_PIN_LAST]; - struct hda_pcm pcm_rec[2]; /* PCM information */ + hda_nid_t shared_mic_nid; + hda_nid_t shared_out_nid; + struct hda_pcm pcm_rec[5]; /* PCM information */ + + /* chip access */ + struct mutex chipio_mutex; /* chip access mutex */ + u32 curr_chip_addx; + + /* DSP download related */ + enum dsp_download_state dsp_state; + unsigned int dsp_stream_id; + unsigned int wait_scp; + unsigned int wait_scp_header; + unsigned int wait_num_data; + unsigned int scp_resp_header; + unsigned int scp_resp_data[4]; + unsigned int scp_resp_count; + + /* mixer and effects related */ + unsigned char dmic_ctl; + int cur_out_type; + int cur_mic_type; + long vnode_lvol[VNODES_COUNT]; + long vnode_rvol[VNODES_COUNT]; + long vnode_lswitch[VNODES_COUNT]; + long vnode_rswitch[VNODES_COUNT]; + long effects_switch[EFFECTS_COUNT]; + long voicefx_val; + long cur_mic_boost; + + struct hda_codec *codec; + struct delayed_work unsol_hp_work; + +#ifdef ENABLE_TUNING_CONTROLS + long cur_ctl_vals[TUNING_CTLS_COUNT]; +#endif }; +/* + * CA0132 codec access + */ +static unsigned int codec_send_command(struct hda_codec *codec, hda_nid_t nid, + unsigned int verb, unsigned int parm, unsigned int *res) +{ + unsigned int response; + response = snd_hda_codec_read(codec, nid, 0, verb, parm); + *res = response; + + return ((response == -1) ? -1 : 0); +} + +static int codec_set_converter_format(struct hda_codec *codec, hda_nid_t nid, + unsigned short converter_format, unsigned int *res) +{ + return codec_send_command(codec, nid, VENDOR_CHIPIO_STREAM_FORMAT, + converter_format & 0xffff, res); +} + +static int codec_set_converter_stream_channel(struct hda_codec *codec, + hda_nid_t nid, unsigned char stream, + unsigned char channel, unsigned int *res) +{ + unsigned char converter_stream_channel = 0; + + converter_stream_channel = (stream << 4) | (channel & 0x0f); + return codec_send_command(codec, nid, AC_VERB_SET_CHANNEL_STREAMID, + converter_stream_channel, res); +} + /* Chip access helper function */ static int chipio_send(struct hda_codec *codec, unsigned int reg, unsigned int data) { unsigned int res; - int retry = 50; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); /* send bits of data specified by reg */ do { @@ -349,7 +800,9 @@ static int chipio_send(struct hda_codec *codec, reg, data); if (res == VENDOR_STATUS_CHIPIO_OK) return 0; - } while (--retry); + msleep(20); + } while (time_before(jiffies, timeout)); + return -EIO; } @@ -359,8 +812,12 @@ static int chipio_send(struct hda_codec *codec, static int chipio_write_address(struct hda_codec *codec, unsigned int chip_addx) { + struct ca0132_spec *spec = codec->spec; int res; + if (spec->curr_chip_addx == chip_addx) + return 0; + /* send low 16 bits of the address */ res = chipio_send(codec, VENDOR_CHIPIO_ADDRESS_LOW, chip_addx & 0xffff); @@ -371,15 +828,17 @@ static int chipio_write_address(struct hda_codec *codec, chip_addx >> 16); } + spec->curr_chip_addx = (res < 0) ? ~0UL : chip_addx; + return res; } /* * Write data through the vendor widget -- NOT protected by the Mutex! */ - static int chipio_write_data(struct hda_codec *codec, unsigned int data) { + struct ca0132_spec *spec = codec->spec; int res; /* send low 16 bits of the data */ @@ -391,14 +850,40 @@ static int chipio_write_data(struct hda_codec *codec, unsigned int data) data >> 16); } + /*If no error encountered, automatically increment the address + as per chip behaviour*/ + spec->curr_chip_addx = (res != -EIO) ? + (spec->curr_chip_addx + 4) : ~0UL; return res; } /* + * Write multiple data through the vendor widget -- NOT protected by the Mutex! + */ +static int chipio_write_data_multiple(struct hda_codec *codec, + const u32 *data, + unsigned int count) +{ + int status = 0; + + if (data == NULL) { + codec_dbg(codec, "chipio_write_data null ptr\n"); + return -EINVAL; + } + + while ((count-- != 0) && (status == 0)) + status = chipio_write_data(codec, *data++); + + return status; +} + + +/* * Read data through the vendor widget -- NOT protected by the Mutex! */ static int chipio_read_data(struct hda_codec *codec, unsigned int *data) { + struct ca0132_spec *spec = codec->spec; int res; /* post read */ @@ -416,6 +901,10 @@ static int chipio_read_data(struct hda_codec *codec, unsigned int *data) 0); } + /*If no error encountered, automatically increment the address + as per chip behaviour*/ + spec->curr_chip_addx = (res != -EIO) ? + (spec->curr_chip_addx + 4) : ~0UL; return res; } @@ -446,6 +935,30 @@ exit: } /* + * Write multiple values to the given address through the chip I/O widget. + * protected by the Mutex + */ +static int chipio_write_multiple(struct hda_codec *codec, + u32 chip_addx, + const u32 *data, + unsigned int count) +{ + struct ca0132_spec *spec = codec->spec; + int status; + + mutex_lock(&spec->chipio_mutex); + status = chipio_write_address(codec, chip_addx); + if (status < 0) + goto error; + + status = chipio_write_data_multiple(codec, data, count); +error: + mutex_unlock(&spec->chipio_mutex); + + return status; +} + +/* * Read the given address through the chip I/O widget * protected by the Mutex */ @@ -472,17 +985,1682 @@ exit: } /* - * PCM callbacks + * Set chip control flags through the chip I/O widget. */ -static int ca0132_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static void chipio_set_control_flag(struct hda_codec *codec, + enum control_flag_id flag_id, + bool flag_state) +{ + unsigned int val; + unsigned int flag_bit; + + flag_bit = (flag_state ? 1 : 0); + val = (flag_bit << 7) | (flag_id); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_FLAG_SET, val); +} + +/* + * Set chip parameters through the chip I/O widget. + */ +static void chipio_set_control_param(struct hda_codec *codec, + enum control_param_id param_id, int param_val) +{ + struct ca0132_spec *spec = codec->spec; + int val; + + if ((param_id < 32) && (param_val < 8)) { + val = (param_val << 5) | (param_id); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_SET, val); + } else { + mutex_lock(&spec->chipio_mutex); + if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) { + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_EX_ID_SET, + param_id); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PARAM_EX_VALUE_SET, + param_val); + } + mutex_unlock(&spec->chipio_mutex); + } +} + +/* + * Set sampling rate of the connection point. + */ +static void chipio_set_conn_rate(struct hda_codec *codec, + int connid, enum ca0132_sample_rate rate) +{ + chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_ID, connid); + chipio_set_control_param(codec, CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, + rate); +} + +/* + * Enable clocks. + */ +static void chipio_enable_clocks(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 5); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0x0b); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 6); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PLL_PMU_WRITE, 0xff); + mutex_unlock(&spec->chipio_mutex); +} + +/* + * CA0132 DSP IO stuffs + */ +static int dspio_send(struct hda_codec *codec, unsigned int reg, + unsigned int data) +{ + int res; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + /* send bits of data specified by reg to dsp */ + do { + res = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, reg, data); + if ((res >= 0) && (res != VENDOR_STATUS_DSPIO_BUSY)) + return res; + msleep(20); + } while (time_before(jiffies, timeout)); + + return -EIO; +} + +/* + * Wait for DSP to be ready for commands + */ +static void dspio_write_wait(struct hda_codec *codec) +{ + int status; + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + + do { + status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, + VENDOR_DSPIO_STATUS, 0); + if ((status == VENDOR_STATUS_DSPIO_OK) || + (status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY)) + break; + msleep(1); + } while (time_before(jiffies, timeout)); +} + +/* + * Write SCP data to DSP + */ +static int dspio_write(struct hda_codec *codec, unsigned int scp_data) +{ + struct ca0132_spec *spec = codec->spec; + int status; + + dspio_write_wait(codec); + + mutex_lock(&spec->chipio_mutex); + status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_LOW, + scp_data & 0xffff); + if (status < 0) + goto error; + + status = dspio_send(codec, VENDOR_DSPIO_SCP_WRITE_DATA_HIGH, + scp_data >> 16); + if (status < 0) + goto error; + + /* OK, now check if the write itself has executed*/ + status = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, + VENDOR_DSPIO_STATUS, 0); +error: + mutex_unlock(&spec->chipio_mutex); + + return (status == VENDOR_STATUS_DSPIO_SCP_COMMAND_QUEUE_FULL) ? + -EIO : 0; +} + +/* + * Write multiple SCP data to DSP + */ +static int dspio_write_multiple(struct hda_codec *codec, + unsigned int *buffer, unsigned int size) +{ + int status = 0; + unsigned int count; + + if ((buffer == NULL)) + return -EINVAL; + + count = 0; + while (count < size) { + status = dspio_write(codec, *buffer++); + if (status != 0) + break; + count++; + } + + return status; +} + +static int dspio_read(struct hda_codec *codec, unsigned int *data) +{ + int status; + + status = dspio_send(codec, VENDOR_DSPIO_SCP_POST_READ_DATA, 0); + if (status == -EIO) + return status; + + status = dspio_send(codec, VENDOR_DSPIO_STATUS, 0); + if (status == -EIO || + status == VENDOR_STATUS_DSPIO_SCP_RESPONSE_QUEUE_EMPTY) + return -EIO; + + *data = snd_hda_codec_read(codec, WIDGET_DSP_CTRL, 0, + VENDOR_DSPIO_SCP_READ_DATA, 0); + + return 0; +} + +static int dspio_read_multiple(struct hda_codec *codec, unsigned int *buffer, + unsigned int *buf_size, unsigned int size_count) +{ + int status = 0; + unsigned int size = *buf_size; + unsigned int count; + unsigned int skip_count; + unsigned int dummy; + + if ((buffer == NULL)) + return -1; + + count = 0; + while (count < size && count < size_count) { + status = dspio_read(codec, buffer++); + if (status != 0) + break; + count++; + } + + skip_count = count; + if (status == 0) { + while (skip_count < size) { + status = dspio_read(codec, &dummy); + if (status != 0) + break; + skip_count++; + } + } + *buf_size = count; + + return status; +} + +/* + * Construct the SCP header using corresponding fields + */ +static inline unsigned int +make_scp_header(unsigned int target_id, unsigned int source_id, + unsigned int get_flag, unsigned int req, + unsigned int device_flag, unsigned int resp_flag, + unsigned int error_flag, unsigned int data_size) +{ + unsigned int header = 0; + + header = (data_size & 0x1f) << 27; + header |= (error_flag & 0x01) << 26; + header |= (resp_flag & 0x01) << 25; + header |= (device_flag & 0x01) << 24; + header |= (req & 0x7f) << 17; + header |= (get_flag & 0x01) << 16; + header |= (source_id & 0xff) << 8; + header |= target_id & 0xff; + + return header; +} + +/* + * Extract corresponding fields from SCP header + */ +static inline void +extract_scp_header(unsigned int header, + unsigned int *target_id, unsigned int *source_id, + unsigned int *get_flag, unsigned int *req, + unsigned int *device_flag, unsigned int *resp_flag, + unsigned int *error_flag, unsigned int *data_size) +{ + if (data_size) + *data_size = (header >> 27) & 0x1f; + if (error_flag) + *error_flag = (header >> 26) & 0x01; + if (resp_flag) + *resp_flag = (header >> 25) & 0x01; + if (device_flag) + *device_flag = (header >> 24) & 0x01; + if (req) + *req = (header >> 17) & 0x7f; + if (get_flag) + *get_flag = (header >> 16) & 0x01; + if (source_id) + *source_id = (header >> 8) & 0xff; + if (target_id) + *target_id = header & 0xff; +} + +#define SCP_MAX_DATA_WORDS (16) + +/* Structure to contain any SCP message */ +struct scp_msg { + unsigned int hdr; + unsigned int data[SCP_MAX_DATA_WORDS]; +}; + +static void dspio_clear_response_queue(struct hda_codec *codec) +{ + unsigned int dummy = 0; + int status = -1; + + /* clear all from the response queue */ + do { + status = dspio_read(codec, &dummy); + } while (status == 0); +} + +static int dspio_get_response_data(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); + unsigned int data = 0; + unsigned int count; + + if (dspio_read(codec, &data) < 0) + return -EIO; + + if ((data & 0x00ffffff) == spec->wait_scp_header) { + spec->scp_resp_header = data; + spec->scp_resp_count = data >> 27; + count = spec->wait_num_data; + dspio_read_multiple(codec, spec->scp_resp_data, + &spec->scp_resp_count, count); + return 0; + } + + return -EIO; } +/* + * Send SCP message to DSP + */ +static int dspio_send_scp_message(struct hda_codec *codec, + unsigned char *send_buf, + unsigned int send_buf_size, + unsigned char *return_buf, + unsigned int return_buf_size, + unsigned int *bytes_returned) +{ + struct ca0132_spec *spec = codec->spec; + int status = -1; + unsigned int scp_send_size = 0; + unsigned int total_size; + bool waiting_for_resp = false; + unsigned int header; + struct scp_msg *ret_msg; + unsigned int resp_src_id, resp_target_id; + unsigned int data_size, src_id, target_id, get_flag, device_flag; + + if (bytes_returned) + *bytes_returned = 0; + + /* get scp header from buffer */ + header = *((unsigned int *)send_buf); + extract_scp_header(header, &target_id, &src_id, &get_flag, NULL, + &device_flag, NULL, NULL, &data_size); + scp_send_size = data_size + 1; + total_size = (scp_send_size * 4); + + if (send_buf_size < total_size) + return -EINVAL; + + if (get_flag || device_flag) { + if (!return_buf || return_buf_size < 4 || !bytes_returned) + return -EINVAL; + + spec->wait_scp_header = *((unsigned int *)send_buf); + + /* swap source id with target id */ + resp_target_id = src_id; + resp_src_id = target_id; + spec->wait_scp_header &= 0xffff0000; + spec->wait_scp_header |= (resp_src_id << 8) | (resp_target_id); + spec->wait_num_data = return_buf_size/sizeof(unsigned int) - 1; + spec->wait_scp = 1; + waiting_for_resp = true; + } + + status = dspio_write_multiple(codec, (unsigned int *)send_buf, + scp_send_size); + if (status < 0) { + spec->wait_scp = 0; + return status; + } + + if (waiting_for_resp) { + unsigned long timeout = jiffies + msecs_to_jiffies(1000); + memset(return_buf, 0, return_buf_size); + do { + msleep(20); + } while (spec->wait_scp && time_before(jiffies, timeout)); + waiting_for_resp = false; + if (!spec->wait_scp) { + ret_msg = (struct scp_msg *)return_buf; + memcpy(&ret_msg->hdr, &spec->scp_resp_header, 4); + memcpy(&ret_msg->data, spec->scp_resp_data, + spec->wait_num_data); + *bytes_returned = (spec->scp_resp_count + 1) * 4; + status = 0; + } else { + status = -EIO; + } + spec->wait_scp = 0; + } + + return status; +} + +/** + * Prepare and send the SCP message to DSP + * @codec: the HDA codec + * @mod_id: ID of the DSP module to send the command + * @req: ID of request to send to the DSP module + * @dir: SET or GET + * @data: pointer to the data to send with the request, request specific + * @len: length of the data, in bytes + * @reply: point to the buffer to hold data returned for a reply + * @reply_len: length of the reply buffer returned from GET + * + * Returns zero or a negative error code. + */ +static int dspio_scp(struct hda_codec *codec, + int mod_id, int req, int dir, void *data, unsigned int len, + void *reply, unsigned int *reply_len) +{ + int status = 0; + struct scp_msg scp_send, scp_reply; + unsigned int ret_bytes, send_size, ret_size; + unsigned int send_get_flag, reply_resp_flag, reply_error_flag; + unsigned int reply_data_size; + + memset(&scp_send, 0, sizeof(scp_send)); + memset(&scp_reply, 0, sizeof(scp_reply)); + + if ((len != 0 && data == NULL) || (len > SCP_MAX_DATA_WORDS)) + return -EINVAL; + + if (dir == SCP_GET && reply == NULL) { + codec_dbg(codec, "dspio_scp get but has no buffer\n"); + return -EINVAL; + } + + if (reply != NULL && (reply_len == NULL || (*reply_len == 0))) { + codec_dbg(codec, "dspio_scp bad resp buf len parms\n"); + return -EINVAL; + } + + scp_send.hdr = make_scp_header(mod_id, 0x20, (dir == SCP_GET), req, + 0, 0, 0, len/sizeof(unsigned int)); + if (data != NULL && len > 0) { + len = min((unsigned int)(sizeof(scp_send.data)), len); + memcpy(scp_send.data, data, len); + } + + ret_bytes = 0; + send_size = sizeof(unsigned int) + len; + status = dspio_send_scp_message(codec, (unsigned char *)&scp_send, + send_size, (unsigned char *)&scp_reply, + sizeof(scp_reply), &ret_bytes); + + if (status < 0) { + codec_dbg(codec, "dspio_scp: send scp msg failed\n"); + return status; + } + + /* extract send and reply headers members */ + extract_scp_header(scp_send.hdr, NULL, NULL, &send_get_flag, + NULL, NULL, NULL, NULL, NULL); + extract_scp_header(scp_reply.hdr, NULL, NULL, NULL, NULL, NULL, + &reply_resp_flag, &reply_error_flag, + &reply_data_size); + + if (!send_get_flag) + return 0; + + if (reply_resp_flag && !reply_error_flag) { + ret_size = (ret_bytes - sizeof(scp_reply.hdr)) + / sizeof(unsigned int); + + if (*reply_len < ret_size*sizeof(unsigned int)) { + codec_dbg(codec, "reply too long for buf\n"); + return -EINVAL; + } else if (ret_size != reply_data_size) { + codec_dbg(codec, "RetLen and HdrLen .NE.\n"); + return -EINVAL; + } else { + *reply_len = ret_size*sizeof(unsigned int); + memcpy(reply, scp_reply.data, *reply_len); + } + } else { + codec_dbg(codec, "reply ill-formed or errflag set\n"); + return -EIO; + } + + return status; +} + +/* + * Set DSP parameters + */ +static int dspio_set_param(struct hda_codec *codec, int mod_id, + int req, void *data, unsigned int len) +{ + return dspio_scp(codec, mod_id, req, SCP_SET, data, len, NULL, NULL); +} + +static int dspio_set_uint_param(struct hda_codec *codec, int mod_id, + int req, unsigned int data) +{ + return dspio_set_param(codec, mod_id, req, &data, sizeof(unsigned int)); +} + +/* + * Allocate a DSP DMA channel via an SCP message + */ +static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan) +{ + int status = 0; + unsigned int size = sizeof(dma_chan); + + codec_dbg(codec, " dspio_alloc_dma_chan() -- begin\n"); + status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN, + SCP_GET, NULL, 0, dma_chan, &size); + + if (status < 0) { + codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n"); + return status; + } + + if ((*dma_chan + 1) == 0) { + codec_dbg(codec, "no free dma channels to allocate\n"); + return -EBUSY; + } + + codec_dbg(codec, "dspio_alloc_dma_chan: chan=%d\n", *dma_chan); + codec_dbg(codec, " dspio_alloc_dma_chan() -- complete\n"); + + return status; +} + +/* + * Free a DSP DMA via an SCP message + */ +static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan) +{ + int status = 0; + unsigned int dummy = 0; + + codec_dbg(codec, " dspio_free_dma_chan() -- begin\n"); + codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan); + + status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN, + SCP_SET, &dma_chan, sizeof(dma_chan), NULL, &dummy); + + if (status < 0) { + codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n"); + return status; + } + + codec_dbg(codec, " dspio_free_dma_chan() -- complete\n"); + + return status; +} + +/* + * (Re)start the DSP + */ +static int dsp_set_run_state(struct hda_codec *codec) +{ + unsigned int dbg_ctrl_reg; + unsigned int halt_state; + int err; + + err = chipio_read(codec, DSP_DBGCNTL_INST_OFFSET, &dbg_ctrl_reg); + if (err < 0) + return err; + + halt_state = (dbg_ctrl_reg & DSP_DBGCNTL_STATE_MASK) >> + DSP_DBGCNTL_STATE_LOBIT; + + if (halt_state != 0) { + dbg_ctrl_reg &= ~((halt_state << DSP_DBGCNTL_SS_LOBIT) & + DSP_DBGCNTL_SS_MASK); + err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET, + dbg_ctrl_reg); + if (err < 0) + return err; + + dbg_ctrl_reg |= (halt_state << DSP_DBGCNTL_EXEC_LOBIT) & + DSP_DBGCNTL_EXEC_MASK; + err = chipio_write(codec, DSP_DBGCNTL_INST_OFFSET, + dbg_ctrl_reg); + if (err < 0) + return err; + } + + return 0; +} + +/* + * Reset the DSP + */ +static int dsp_reset(struct hda_codec *codec) +{ + unsigned int res; + int retry = 20; + + codec_dbg(codec, "dsp_reset\n"); + do { + res = dspio_send(codec, VENDOR_DSPIO_DSP_INIT, 0); + retry--; + } while (res == -EIO && retry); + + if (!retry) { + codec_dbg(codec, "dsp_reset timeout\n"); + return -EIO; + } + + return 0; +} + +/* + * Convert chip address to DSP address + */ +static unsigned int dsp_chip_to_dsp_addx(unsigned int chip_addx, + bool *code, bool *yram) +{ + *code = *yram = false; + + if (UC_RANGE(chip_addx, 1)) { + *code = true; + return UC_OFF(chip_addx); + } else if (X_RANGE_ALL(chip_addx, 1)) { + return X_OFF(chip_addx); + } else if (Y_RANGE_ALL(chip_addx, 1)) { + *yram = true; + return Y_OFF(chip_addx); + } + + return INVALID_CHIP_ADDRESS; +} + +/* + * Check if the DSP DMA is active + */ +static bool dsp_is_dma_active(struct hda_codec *codec, unsigned int dma_chan) +{ + unsigned int dma_chnlstart_reg; + + chipio_read(codec, DSPDMAC_CHNLSTART_INST_OFFSET, &dma_chnlstart_reg); + + return ((dma_chnlstart_reg & (1 << + (DSPDMAC_CHNLSTART_EN_LOBIT + dma_chan))) != 0); +} + +static int dsp_dma_setup_common(struct hda_codec *codec, + unsigned int chip_addx, + unsigned int dma_chan, + unsigned int port_map_mask, + bool ovly) +{ + int status = 0; + unsigned int chnl_prop; + unsigned int dsp_addx; + unsigned int active; + bool code, yram; + + codec_dbg(codec, "-- dsp_dma_setup_common() -- Begin ---------\n"); + + if (dma_chan >= DSPDMAC_DMA_CFG_CHANNEL_COUNT) { + codec_dbg(codec, "dma chan num invalid\n"); + return -EINVAL; + } + + if (dsp_is_dma_active(codec, dma_chan)) { + codec_dbg(codec, "dma already active\n"); + return -EBUSY; + } + + dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram); + + if (dsp_addx == INVALID_CHIP_ADDRESS) { + codec_dbg(codec, "invalid chip addr\n"); + return -ENXIO; + } + + chnl_prop = DSPDMAC_CHNLPROP_AC_MASK; + active = 0; + + codec_dbg(codec, " dsp_dma_setup_common() start reg pgm\n"); + + if (ovly) { + status = chipio_read(codec, DSPDMAC_CHNLPROP_INST_OFFSET, + &chnl_prop); + + if (status < 0) { + codec_dbg(codec, "read CHNLPROP Reg fail\n"); + return status; + } + codec_dbg(codec, "dsp_dma_setup_common() Read CHNLPROP\n"); + } + + if (!code) + chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan)); + else + chnl_prop |= (1 << (DSPDMAC_CHNLPROP_MSPCE_LOBIT + dma_chan)); + + chnl_prop &= ~(1 << (DSPDMAC_CHNLPROP_DCON_LOBIT + dma_chan)); + + status = chipio_write(codec, DSPDMAC_CHNLPROP_INST_OFFSET, chnl_prop); + if (status < 0) { + codec_dbg(codec, "write CHNLPROP Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup_common() Write CHNLPROP\n"); + + if (ovly) { + status = chipio_read(codec, DSPDMAC_ACTIVE_INST_OFFSET, + &active); + + if (status < 0) { + codec_dbg(codec, "read ACTIVE Reg fail\n"); + return status; + } + codec_dbg(codec, "dsp_dma_setup_common() Read ACTIVE\n"); + } + + active &= (~(1 << (DSPDMAC_ACTIVE_AAR_LOBIT + dma_chan))) & + DSPDMAC_ACTIVE_AAR_MASK; + + status = chipio_write(codec, DSPDMAC_ACTIVE_INST_OFFSET, active); + if (status < 0) { + codec_dbg(codec, "write ACTIVE Reg fail\n"); + return status; + } + + codec_dbg(codec, " dsp_dma_setup_common() Write ACTIVE\n"); + + status = chipio_write(codec, DSPDMAC_AUDCHSEL_INST_OFFSET(dma_chan), + port_map_mask); + if (status < 0) { + codec_dbg(codec, "write AUDCHSEL Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup_common() Write AUDCHSEL\n"); + + status = chipio_write(codec, DSPDMAC_IRQCNT_INST_OFFSET(dma_chan), + DSPDMAC_IRQCNT_BICNT_MASK | DSPDMAC_IRQCNT_CICNT_MASK); + if (status < 0) { + codec_dbg(codec, "write IRQCNT Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup_common() Write IRQCNT\n"); + + codec_dbg(codec, + "ChipA=0x%x,DspA=0x%x,dmaCh=%u, " + "CHSEL=0x%x,CHPROP=0x%x,Active=0x%x\n", + chip_addx, dsp_addx, dma_chan, + port_map_mask, chnl_prop, active); + + codec_dbg(codec, "-- dsp_dma_setup_common() -- Complete ------\n"); + + return 0; +} + +/* + * Setup the DSP DMA per-transfer-specific registers + */ +static int dsp_dma_setup(struct hda_codec *codec, + unsigned int chip_addx, + unsigned int count, + unsigned int dma_chan) +{ + int status = 0; + bool code, yram; + unsigned int dsp_addx; + unsigned int addr_field; + unsigned int incr_field; + unsigned int base_cnt; + unsigned int cur_cnt; + unsigned int dma_cfg = 0; + unsigned int adr_ofs = 0; + unsigned int xfr_cnt = 0; + const unsigned int max_dma_count = 1 << (DSPDMAC_XFRCNT_BCNT_HIBIT - + DSPDMAC_XFRCNT_BCNT_LOBIT + 1); + + codec_dbg(codec, "-- dsp_dma_setup() -- Begin ---------\n"); + + if (count > max_dma_count) { + codec_dbg(codec, "count too big\n"); + return -EINVAL; + } + + dsp_addx = dsp_chip_to_dsp_addx(chip_addx, &code, &yram); + if (dsp_addx == INVALID_CHIP_ADDRESS) { + codec_dbg(codec, "invalid chip addr\n"); + return -ENXIO; + } + + codec_dbg(codec, " dsp_dma_setup() start reg pgm\n"); + + addr_field = dsp_addx << DSPDMAC_DMACFG_DBADR_LOBIT; + incr_field = 0; + + if (!code) { + addr_field <<= 1; + if (yram) + addr_field |= (1 << DSPDMAC_DMACFG_DBADR_LOBIT); + + incr_field = (1 << DSPDMAC_DMACFG_AINCR_LOBIT); + } + + dma_cfg = addr_field + incr_field; + status = chipio_write(codec, DSPDMAC_DMACFG_INST_OFFSET(dma_chan), + dma_cfg); + if (status < 0) { + codec_dbg(codec, "write DMACFG Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup() Write DMACFG\n"); + + adr_ofs = (count - 1) << (DSPDMAC_DSPADROFS_BOFS_LOBIT + + (code ? 0 : 1)); + + status = chipio_write(codec, DSPDMAC_DSPADROFS_INST_OFFSET(dma_chan), + adr_ofs); + if (status < 0) { + codec_dbg(codec, "write DSPADROFS Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup() Write DSPADROFS\n"); + + base_cnt = (count - 1) << DSPDMAC_XFRCNT_BCNT_LOBIT; + + cur_cnt = (count - 1) << DSPDMAC_XFRCNT_CCNT_LOBIT; + + xfr_cnt = base_cnt | cur_cnt; + + status = chipio_write(codec, + DSPDMAC_XFRCNT_INST_OFFSET(dma_chan), xfr_cnt); + if (status < 0) { + codec_dbg(codec, "write XFRCNT Reg fail\n"); + return status; + } + codec_dbg(codec, " dsp_dma_setup() Write XFRCNT\n"); + + codec_dbg(codec, + "ChipA=0x%x, cnt=0x%x, DMACFG=0x%x, " + "ADROFS=0x%x, XFRCNT=0x%x\n", + chip_addx, count, dma_cfg, adr_ofs, xfr_cnt); + + codec_dbg(codec, "-- dsp_dma_setup() -- Complete ---------\n"); + + return 0; +} + +/* + * Start the DSP DMA + */ +static int dsp_dma_start(struct hda_codec *codec, + unsigned int dma_chan, bool ovly) +{ + unsigned int reg = 0; + int status = 0; + + codec_dbg(codec, "-- dsp_dma_start() -- Begin ---------\n"); + + if (ovly) { + status = chipio_read(codec, + DSPDMAC_CHNLSTART_INST_OFFSET, ®); + + if (status < 0) { + codec_dbg(codec, "read CHNLSTART reg fail\n"); + return status; + } + codec_dbg(codec, "-- dsp_dma_start() Read CHNLSTART\n"); + + reg &= ~(DSPDMAC_CHNLSTART_EN_MASK | + DSPDMAC_CHNLSTART_DIS_MASK); + } + + status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET, + reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_EN_LOBIT))); + if (status < 0) { + codec_dbg(codec, "write CHNLSTART reg fail\n"); + return status; + } + codec_dbg(codec, "-- dsp_dma_start() -- Complete ---------\n"); + + return status; +} + +/* + * Stop the DSP DMA + */ +static int dsp_dma_stop(struct hda_codec *codec, + unsigned int dma_chan, bool ovly) +{ + unsigned int reg = 0; + int status = 0; + + codec_dbg(codec, "-- dsp_dma_stop() -- Begin ---------\n"); + + if (ovly) { + status = chipio_read(codec, + DSPDMAC_CHNLSTART_INST_OFFSET, ®); + + if (status < 0) { + codec_dbg(codec, "read CHNLSTART reg fail\n"); + return status; + } + codec_dbg(codec, "-- dsp_dma_stop() Read CHNLSTART\n"); + reg &= ~(DSPDMAC_CHNLSTART_EN_MASK | + DSPDMAC_CHNLSTART_DIS_MASK); + } + + status = chipio_write(codec, DSPDMAC_CHNLSTART_INST_OFFSET, + reg | (1 << (dma_chan + DSPDMAC_CHNLSTART_DIS_LOBIT))); + if (status < 0) { + codec_dbg(codec, "write CHNLSTART reg fail\n"); + return status; + } + codec_dbg(codec, "-- dsp_dma_stop() -- Complete ---------\n"); + + return status; +} + +/** + * Allocate router ports + * + * @codec: the HDA codec + * @num_chans: number of channels in the stream + * @ports_per_channel: number of ports per channel + * @start_device: start device + * @port_map: pointer to the port list to hold the allocated ports + * + * Returns zero or a negative error code. + */ +static int dsp_allocate_router_ports(struct hda_codec *codec, + unsigned int num_chans, + unsigned int ports_per_channel, + unsigned int start_device, + unsigned int *port_map) +{ + int status = 0; + int res; + u8 val; + + status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); + if (status < 0) + return status; + + val = start_device << 6; + val |= (ports_per_channel - 1) << 4; + val |= num_chans - 1; + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PORT_ALLOC_CONFIG_SET, + val); + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PORT_ALLOC_SET, + MEM_CONNID_DSP); + + status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); + if (status < 0) + return status; + + res = snd_hda_codec_read(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PORT_ALLOC_GET, 0); + + *port_map = res; + + return (res < 0) ? res : 0; +} + +/* + * Free router ports + */ +static int dsp_free_router_ports(struct hda_codec *codec) +{ + int status = 0; + + status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); + if (status < 0) + return status; + + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_PORT_FREE_SET, + MEM_CONNID_DSP); + + status = chipio_send(codec, VENDOR_CHIPIO_STATUS, 0); + + return status; +} + +/* + * Allocate DSP ports for the download stream + */ +static int dsp_allocate_ports(struct hda_codec *codec, + unsigned int num_chans, + unsigned int rate_multi, unsigned int *port_map) +{ + int status; + + codec_dbg(codec, " dsp_allocate_ports() -- begin\n"); + + if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) { + codec_dbg(codec, "bad rate multiple\n"); + return -EINVAL; + } + + status = dsp_allocate_router_ports(codec, num_chans, + rate_multi, 0, port_map); + + codec_dbg(codec, " dsp_allocate_ports() -- complete\n"); + + return status; +} + +static int dsp_allocate_ports_format(struct hda_codec *codec, + const unsigned short fmt, + unsigned int *port_map) +{ + int status; + unsigned int num_chans; + + unsigned int sample_rate_div = ((get_hdafmt_rate(fmt) >> 0) & 3) + 1; + unsigned int sample_rate_mul = ((get_hdafmt_rate(fmt) >> 3) & 3) + 1; + unsigned int rate_multi = sample_rate_mul / sample_rate_div; + + if ((rate_multi != 1) && (rate_multi != 2) && (rate_multi != 4)) { + codec_dbg(codec, "bad rate multiple\n"); + return -EINVAL; + } + + num_chans = get_hdafmt_chs(fmt) + 1; + + status = dsp_allocate_ports(codec, num_chans, rate_multi, port_map); + + return status; +} + +/* + * free DSP ports + */ +static int dsp_free_ports(struct hda_codec *codec) +{ + int status; + + codec_dbg(codec, " dsp_free_ports() -- begin\n"); + + status = dsp_free_router_ports(codec); + if (status < 0) { + codec_dbg(codec, "free router ports fail\n"); + return status; + } + codec_dbg(codec, " dsp_free_ports() -- complete\n"); + + return status; +} + +/* + * HDA DMA engine stuffs for DSP code download + */ +struct dma_engine { + struct hda_codec *codec; + unsigned short m_converter_format; + struct snd_dma_buffer *dmab; + unsigned int buf_size; +}; + + +enum dma_state { + DMA_STATE_STOP = 0, + DMA_STATE_RUN = 1 +}; + +static int dma_convert_to_hda_format( + unsigned int sample_rate, + unsigned short channels, + unsigned short *hda_format) +{ + unsigned int format_val; + + format_val = snd_hda_calc_stream_format( + sample_rate, + channels, + SNDRV_PCM_FORMAT_S32_LE, + 32, 0); + + if (hda_format) + *hda_format = (unsigned short)format_val; + + return 0; +} + +/* + * Reset DMA for DSP download + */ +static int dma_reset(struct dma_engine *dma) +{ + struct hda_codec *codec = dma->codec; + struct ca0132_spec *spec = codec->spec; + int status; + + if (dma->dmab->area) + snd_hda_codec_load_dsp_cleanup(codec, dma->dmab); + + status = snd_hda_codec_load_dsp_prepare(codec, + dma->m_converter_format, + dma->buf_size, + dma->dmab); + if (status < 0) + return status; + spec->dsp_stream_id = status; + return 0; +} + +static int dma_set_state(struct dma_engine *dma, enum dma_state state) +{ + bool cmd; + + switch (state) { + case DMA_STATE_STOP: + cmd = false; + break; + case DMA_STATE_RUN: + cmd = true; + break; + default: + return 0; + } + + snd_hda_codec_load_dsp_trigger(dma->codec, cmd); + return 0; +} + +static unsigned int dma_get_buffer_size(struct dma_engine *dma) +{ + return dma->dmab->bytes; +} + +static unsigned char *dma_get_buffer_addr(struct dma_engine *dma) +{ + return dma->dmab->area; +} + +static int dma_xfer(struct dma_engine *dma, + const unsigned int *data, + unsigned int count) +{ + memcpy(dma->dmab->area, data, count); + return 0; +} + +static void dma_get_converter_format( + struct dma_engine *dma, + unsigned short *format) +{ + if (format) + *format = dma->m_converter_format; +} + +static unsigned int dma_get_stream_id(struct dma_engine *dma) +{ + struct ca0132_spec *spec = dma->codec->spec; + + return spec->dsp_stream_id; +} + +struct dsp_image_seg { + u32 magic; + u32 chip_addr; + u32 count; + u32 data[0]; +}; + +static const u32 g_magic_value = 0x4c46584d; +static const u32 g_chip_addr_magic_value = 0xFFFFFF01; + +static bool is_valid(const struct dsp_image_seg *p) +{ + return p->magic == g_magic_value; +} + +static bool is_hci_prog_list_seg(const struct dsp_image_seg *p) +{ + return g_chip_addr_magic_value == p->chip_addr; +} + +static bool is_last(const struct dsp_image_seg *p) +{ + return p->count == 0; +} + +static size_t dsp_sizeof(const struct dsp_image_seg *p) +{ + return sizeof(*p) + p->count*sizeof(u32); +} + +static const struct dsp_image_seg *get_next_seg_ptr( + const struct dsp_image_seg *p) +{ + return (struct dsp_image_seg *)((unsigned char *)(p) + dsp_sizeof(p)); +} + +/* + * CA0132 chip DSP transfer stuffs. For DSP download. + */ +#define INVALID_DMA_CHANNEL (~0U) + +/* + * Program a list of address/data pairs via the ChipIO widget. + * The segment data is in the format of successive pairs of words. + * These are repeated as indicated by the segment's count field. + */ +static int dspxfr_hci_write(struct hda_codec *codec, + const struct dsp_image_seg *fls) +{ + int status; + const u32 *data; + unsigned int count; + + if (fls == NULL || fls->chip_addr != g_chip_addr_magic_value) { + codec_dbg(codec, "hci_write invalid params\n"); + return -EINVAL; + } + + count = fls->count; + data = (u32 *)(fls->data); + while (count >= 2) { + status = chipio_write(codec, data[0], data[1]); + if (status < 0) { + codec_dbg(codec, "hci_write chipio failed\n"); + return status; + } + count -= 2; + data += 2; + } + return 0; +} + +/** + * Write a block of data into DSP code or data RAM using pre-allocated + * DMA engine. + * + * @codec: the HDA codec + * @fls: pointer to a fast load image + * @reloc: Relocation address for loading single-segment overlays, or 0 for + * no relocation + * @dma_engine: pointer to DMA engine to be used for DSP download + * @dma_chan: The number of DMA channels used for DSP download + * @port_map_mask: port mapping + * @ovly: TRUE if overlay format is required + * + * Returns zero or a negative error code. + */ +static int dspxfr_one_seg(struct hda_codec *codec, + const struct dsp_image_seg *fls, + unsigned int reloc, + struct dma_engine *dma_engine, + unsigned int dma_chan, + unsigned int port_map_mask, + bool ovly) +{ + int status = 0; + bool comm_dma_setup_done = false; + const unsigned int *data; + unsigned int chip_addx; + unsigned int words_to_write; + unsigned int buffer_size_words; + unsigned char *buffer_addx; + unsigned short hda_format; + unsigned int sample_rate_div; + unsigned int sample_rate_mul; + unsigned int num_chans; + unsigned int hda_frame_size_words; + unsigned int remainder_words; + const u32 *data_remainder; + u32 chip_addx_remainder; + unsigned int run_size_words; + const struct dsp_image_seg *hci_write = NULL; + unsigned long timeout; + bool dma_active; + + if (fls == NULL) + return -EINVAL; + if (is_hci_prog_list_seg(fls)) { + hci_write = fls; + fls = get_next_seg_ptr(fls); + } + + if (hci_write && (!fls || is_last(fls))) { + codec_dbg(codec, "hci_write\n"); + return dspxfr_hci_write(codec, hci_write); + } + + if (fls == NULL || dma_engine == NULL || port_map_mask == 0) { + codec_dbg(codec, "Invalid Params\n"); + return -EINVAL; + } + + data = fls->data; + chip_addx = fls->chip_addr, + words_to_write = fls->count; + + if (!words_to_write) + return hci_write ? dspxfr_hci_write(codec, hci_write) : 0; + if (reloc) + chip_addx = (chip_addx & (0xFFFF0000 << 2)) + (reloc << 2); + + if (!UC_RANGE(chip_addx, words_to_write) && + !X_RANGE_ALL(chip_addx, words_to_write) && + !Y_RANGE_ALL(chip_addx, words_to_write)) { + codec_dbg(codec, "Invalid chip_addx Params\n"); + return -EINVAL; + } + + buffer_size_words = (unsigned int)dma_get_buffer_size(dma_engine) / + sizeof(u32); + + buffer_addx = dma_get_buffer_addr(dma_engine); + + if (buffer_addx == NULL) { + codec_dbg(codec, "dma_engine buffer NULL\n"); + return -EINVAL; + } + + dma_get_converter_format(dma_engine, &hda_format); + sample_rate_div = ((get_hdafmt_rate(hda_format) >> 0) & 3) + 1; + sample_rate_mul = ((get_hdafmt_rate(hda_format) >> 3) & 3) + 1; + num_chans = get_hdafmt_chs(hda_format) + 1; + + hda_frame_size_words = ((sample_rate_div == 0) ? 0 : + (num_chans * sample_rate_mul / sample_rate_div)); + + if (hda_frame_size_words == 0) { + codec_dbg(codec, "frmsz zero\n"); + return -EINVAL; + } + + buffer_size_words = min(buffer_size_words, + (unsigned int)(UC_RANGE(chip_addx, 1) ? + 65536 : 32768)); + buffer_size_words -= buffer_size_words % hda_frame_size_words; + codec_dbg(codec, + "chpadr=0x%08x frmsz=%u nchan=%u " + "rate_mul=%u div=%u bufsz=%u\n", + chip_addx, hda_frame_size_words, num_chans, + sample_rate_mul, sample_rate_div, buffer_size_words); + + if (buffer_size_words < hda_frame_size_words) { + codec_dbg(codec, "dspxfr_one_seg:failed\n"); + return -EINVAL; + } + + remainder_words = words_to_write % hda_frame_size_words; + data_remainder = data; + chip_addx_remainder = chip_addx; + + data += remainder_words; + chip_addx += remainder_words*sizeof(u32); + words_to_write -= remainder_words; + + while (words_to_write != 0) { + run_size_words = min(buffer_size_words, words_to_write); + codec_dbg(codec, "dspxfr (seg loop)cnt=%u rs=%u remainder=%u\n", + words_to_write, run_size_words, remainder_words); + dma_xfer(dma_engine, data, run_size_words*sizeof(u32)); + if (!comm_dma_setup_done) { + status = dsp_dma_stop(codec, dma_chan, ovly); + if (status < 0) + return status; + status = dsp_dma_setup_common(codec, chip_addx, + dma_chan, port_map_mask, ovly); + if (status < 0) + return status; + comm_dma_setup_done = true; + } + + status = dsp_dma_setup(codec, chip_addx, + run_size_words, dma_chan); + if (status < 0) + return status; + status = dsp_dma_start(codec, dma_chan, ovly); + if (status < 0) + return status; + if (!dsp_is_dma_active(codec, dma_chan)) { + codec_dbg(codec, "dspxfr:DMA did not start\n"); + return -EIO; + } + status = dma_set_state(dma_engine, DMA_STATE_RUN); + if (status < 0) + return status; + if (remainder_words != 0) { + status = chipio_write_multiple(codec, + chip_addx_remainder, + data_remainder, + remainder_words); + if (status < 0) + return status; + remainder_words = 0; + } + if (hci_write) { + status = dspxfr_hci_write(codec, hci_write); + if (status < 0) + return status; + hci_write = NULL; + } + + timeout = jiffies + msecs_to_jiffies(2000); + do { + dma_active = dsp_is_dma_active(codec, dma_chan); + if (!dma_active) + break; + msleep(20); + } while (time_before(jiffies, timeout)); + if (dma_active) + break; + + codec_dbg(codec, "+++++ DMA complete\n"); + dma_set_state(dma_engine, DMA_STATE_STOP); + status = dma_reset(dma_engine); + + if (status < 0) + return status; + + data += run_size_words; + chip_addx += run_size_words*sizeof(u32); + words_to_write -= run_size_words; + } + + if (remainder_words != 0) { + status = chipio_write_multiple(codec, chip_addx_remainder, + data_remainder, remainder_words); + } + + return status; +} + +/** + * Write the entire DSP image of a DSP code/data overlay to DSP memories + * + * @codec: the HDA codec + * @fls_data: pointer to a fast load image + * @reloc: Relocation address for loading single-segment overlays, or 0 for + * no relocation + * @sample_rate: sampling rate of the stream used for DSP download + * @number_channels: channels of the stream used for DSP download + * @ovly: TRUE if overlay format is required + * + * Returns zero or a negative error code. + */ +static int dspxfr_image(struct hda_codec *codec, + const struct dsp_image_seg *fls_data, + unsigned int reloc, + unsigned int sample_rate, + unsigned short channels, + bool ovly) +{ + struct ca0132_spec *spec = codec->spec; + int status; + unsigned short hda_format = 0; + unsigned int response; + unsigned char stream_id = 0; + struct dma_engine *dma_engine; + unsigned int dma_chan; + unsigned int port_map_mask; + + if (fls_data == NULL) + return -EINVAL; + + dma_engine = kzalloc(sizeof(*dma_engine), GFP_KERNEL); + if (!dma_engine) + return -ENOMEM; + + dma_engine->dmab = kzalloc(sizeof(*dma_engine->dmab), GFP_KERNEL); + if (!dma_engine->dmab) { + kfree(dma_engine); + return -ENOMEM; + } + + dma_engine->codec = codec; + dma_convert_to_hda_format(sample_rate, channels, &hda_format); + dma_engine->m_converter_format = hda_format; + dma_engine->buf_size = (ovly ? DSP_DMA_WRITE_BUFLEN_OVLY : + DSP_DMA_WRITE_BUFLEN_INIT) * 2; + + dma_chan = ovly ? INVALID_DMA_CHANNEL : 0; + + status = codec_set_converter_format(codec, WIDGET_CHIP_CTRL, + hda_format, &response); + + if (status < 0) { + codec_dbg(codec, "set converter format fail\n"); + goto exit; + } + + status = snd_hda_codec_load_dsp_prepare(codec, + dma_engine->m_converter_format, + dma_engine->buf_size, + dma_engine->dmab); + if (status < 0) + goto exit; + spec->dsp_stream_id = status; + + if (ovly) { + status = dspio_alloc_dma_chan(codec, &dma_chan); + if (status < 0) { + codec_dbg(codec, "alloc dmachan fail\n"); + dma_chan = INVALID_DMA_CHANNEL; + goto exit; + } + } + + port_map_mask = 0; + status = dsp_allocate_ports_format(codec, hda_format, + &port_map_mask); + if (status < 0) { + codec_dbg(codec, "alloc ports fail\n"); + goto exit; + } + + stream_id = dma_get_stream_id(dma_engine); + status = codec_set_converter_stream_channel(codec, + WIDGET_CHIP_CTRL, stream_id, 0, &response); + if (status < 0) { + codec_dbg(codec, "set stream chan fail\n"); + goto exit; + } + + while ((fls_data != NULL) && !is_last(fls_data)) { + if (!is_valid(fls_data)) { + codec_dbg(codec, "FLS check fail\n"); + status = -EINVAL; + goto exit; + } + status = dspxfr_one_seg(codec, fls_data, reloc, + dma_engine, dma_chan, + port_map_mask, ovly); + if (status < 0) + break; + + if (is_hci_prog_list_seg(fls_data)) + fls_data = get_next_seg_ptr(fls_data); + + if ((fls_data != NULL) && !is_last(fls_data)) + fls_data = get_next_seg_ptr(fls_data); + } + + if (port_map_mask != 0) + status = dsp_free_ports(codec); + + if (status < 0) + goto exit; + + status = codec_set_converter_stream_channel(codec, + WIDGET_CHIP_CTRL, 0, 0, &response); + +exit: + if (ovly && (dma_chan != INVALID_DMA_CHANNEL)) + dspio_free_dma_chan(codec, dma_chan); + + if (dma_engine->dmab->area) + snd_hda_codec_load_dsp_cleanup(codec, dma_engine->dmab); + kfree(dma_engine->dmab); + kfree(dma_engine); + + return status; +} + +/* + * CA0132 DSP download stuffs. + */ +static void dspload_post_setup(struct hda_codec *codec) +{ + codec_dbg(codec, "---- dspload_post_setup ------\n"); + + /*set DSP speaker to 2.0 configuration*/ + chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080); + chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000); + + /*update write pointer*/ + chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x29), 0x00000002); +} + +/** + * Download DSP from a DSP Image Fast Load structure. This structure is a + * linear, non-constant sized element array of structures, each of which + * contain the count of the data to be loaded, the data itself, and the + * corresponding starting chip address of the starting data location. + * + * @codec: the HDA codec + * @fls: pointer to a fast load image + * @ovly: TRUE if overlay format is required + * @reloc: Relocation address for loading single-segment overlays, or 0 for + * no relocation + * @autostart: TRUE if DSP starts after loading; ignored if ovly is TRUE + * @router_chans: number of audio router channels to be allocated (0 means use + * internal defaults; max is 32) + * + * Returns zero or a negative error code. + */ +static int dspload_image(struct hda_codec *codec, + const struct dsp_image_seg *fls, + bool ovly, + unsigned int reloc, + bool autostart, + int router_chans) +{ + int status = 0; + unsigned int sample_rate; + unsigned short channels; + + codec_dbg(codec, "---- dspload_image begin ------\n"); + if (router_chans == 0) { + if (!ovly) + router_chans = DMA_TRANSFER_FRAME_SIZE_NWORDS; + else + router_chans = DMA_OVERLAY_FRAME_SIZE_NWORDS; + } + + sample_rate = 48000; + channels = (unsigned short)router_chans; + + while (channels > 16) { + sample_rate *= 2; + channels /= 2; + } + + do { + codec_dbg(codec, "Ready to program DMA\n"); + if (!ovly) + status = dsp_reset(codec); + + if (status < 0) + break; + + codec_dbg(codec, "dsp_reset() complete\n"); + status = dspxfr_image(codec, fls, reloc, sample_rate, channels, + ovly); + + if (status < 0) + break; + + codec_dbg(codec, "dspxfr_image() complete\n"); + if (autostart && !ovly) { + dspload_post_setup(codec); + status = dsp_set_run_state(codec); + } + + codec_dbg(codec, "LOAD FINISHED\n"); + } while (0); + + return status; +} + +#ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP +static bool dspload_is_loaded(struct hda_codec *codec) +{ + unsigned int data = 0; + int status = 0; + + status = chipio_read(codec, 0x40004, &data); + if ((status < 0) || (data != 1)) + return false; + + return true; +} +#else +#define dspload_is_loaded(codec) false +#endif + +static bool dspload_wait_loaded(struct hda_codec *codec) +{ + unsigned long timeout = jiffies + msecs_to_jiffies(2000); + + do { + if (dspload_is_loaded(codec)) { + pr_info("ca0132 DOWNLOAD OK :-) DSP IS RUNNING.\n"); + return true; + } + msleep(20); + } while (time_before(jiffies, timeout)); + + pr_err("ca0132 DOWNLOAD FAILED!!! DSP IS NOT RUNNING.\n"); + return false; +} + +/* + * PCM callbacks + */ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -490,8 +2668,10 @@ static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct ca0132_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); + + snd_hda_codec_setup_stream(codec, spec->dacs[0], stream_tag, 0, format); + + return 0; } static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, @@ -499,7 +2679,43 @@ static int ca0132_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct ca0132_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); + + if (spec->dsp_state == DSP_DOWNLOADING) + return 0; + + /*If Playback effects are on, allow stream some time to flush + *effects tail*/ + if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) + msleep(50); + + snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); + + return 0; +} + +static unsigned int ca0132_playback_pcm_delay(struct hda_pcm_stream *info, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int latency = DSP_PLAYBACK_INIT_LATENCY; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (spec->dsp_state != DSP_DOWNLOADED) + return 0; + + /* Add latency if playback enhancement and either effect is enabled. */ + if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) { + if ((spec->effects_switch[SURROUND - EFFECT_START_NID]) || + (spec->effects_switch[DIALOG_PLUS - EFFECT_START_NID])) + latency += DSP_PLAY_ENHANCEMENT_LATENCY; + } + + /* Applying Speaker EQ adds latency as well. */ + if (spec->cur_out_type == SPEAKER_OUT) + latency += DSP_SPEAKER_OUT_LATENCY; + + return (latency * runtime->rate) / 1000; } /* @@ -541,308 +2757,1212 @@ static int ca0132_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, } /* + * Analog capture */ -static struct hda_pcm_stream ca0132_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0132_playback_pcm_open, - .prepare = ca0132_playback_pcm_prepare, - .cleanup = ca0132_playback_pcm_cleanup - }, -}; +static int ca0132_capture_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + snd_hda_codec_setup_stream(codec, hinfo->nid, + stream_tag, 0, format); -static struct hda_pcm_stream ca0132_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, + return 0; +} + +static int ca0132_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0132_spec *spec = codec->spec; + + if (spec->dsp_state == DSP_DOWNLOADING) + return 0; + + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + return 0; +} + +static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int latency = DSP_CAPTURE_INIT_LATENCY; + struct snd_pcm_runtime *runtime = substream->runtime; + + if (spec->dsp_state != DSP_DOWNLOADED) + return 0; + + if (spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) + latency += DSP_CRYSTAL_VOICE_LATENCY; + + return (latency * runtime->rate) / 1000; +} + +/* + * Controls stuffs. + */ + +/* + * Mixer controls helpers. + */ +#define CA0132_CODEC_VOL_MONO(xname, nid, channel, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ + .info = ca0132_volume_info, \ + .get = ca0132_volume_get, \ + .put = ca0132_volume_put, \ + .tlv = { .c = ca0132_volume_tlv }, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } + +#define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .subdevice = HDA_SUBDEV_AMP_FLAG, \ + .info = snd_hda_mixer_amp_switch_info, \ + .get = ca0132_switch_get, \ + .put = ca0132_switch_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } + +/* stereo */ +#define CA0132_CODEC_VOL(xname, nid, dir) \ + CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) +#define CA0132_CODEC_MUTE(xname, nid, dir) \ + CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) + +/* The followings are for tuning of products */ +#ifdef ENABLE_TUNING_CONTROLS + +static unsigned int voice_focus_vals_lookup[] = { +0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000, 0x41C00000, 0x41C80000, +0x41D00000, 0x41D80000, 0x41E00000, 0x41E80000, 0x41F00000, 0x41F80000, +0x42000000, 0x42040000, 0x42080000, 0x420C0000, 0x42100000, 0x42140000, +0x42180000, 0x421C0000, 0x42200000, 0x42240000, 0x42280000, 0x422C0000, +0x42300000, 0x42340000, 0x42380000, 0x423C0000, 0x42400000, 0x42440000, +0x42480000, 0x424C0000, 0x42500000, 0x42540000, 0x42580000, 0x425C0000, +0x42600000, 0x42640000, 0x42680000, 0x426C0000, 0x42700000, 0x42740000, +0x42780000, 0x427C0000, 0x42800000, 0x42820000, 0x42840000, 0x42860000, +0x42880000, 0x428A0000, 0x428C0000, 0x428E0000, 0x42900000, 0x42920000, +0x42940000, 0x42960000, 0x42980000, 0x429A0000, 0x429C0000, 0x429E0000, +0x42A00000, 0x42A20000, 0x42A40000, 0x42A60000, 0x42A80000, 0x42AA0000, +0x42AC0000, 0x42AE0000, 0x42B00000, 0x42B20000, 0x42B40000, 0x42B60000, +0x42B80000, 0x42BA0000, 0x42BC0000, 0x42BE0000, 0x42C00000, 0x42C20000, +0x42C40000, 0x42C60000, 0x42C80000, 0x42CA0000, 0x42CC0000, 0x42CE0000, +0x42D00000, 0x42D20000, 0x42D40000, 0x42D60000, 0x42D80000, 0x42DA0000, +0x42DC0000, 0x42DE0000, 0x42E00000, 0x42E20000, 0x42E40000, 0x42E60000, +0x42E80000, 0x42EA0000, 0x42EC0000, 0x42EE0000, 0x42F00000, 0x42F20000, +0x42F40000, 0x42F60000, 0x42F80000, 0x42FA0000, 0x42FC0000, 0x42FE0000, +0x43000000, 0x43010000, 0x43020000, 0x43030000, 0x43040000, 0x43050000, +0x43060000, 0x43070000, 0x43080000, 0x43090000, 0x430A0000, 0x430B0000, +0x430C0000, 0x430D0000, 0x430E0000, 0x430F0000, 0x43100000, 0x43110000, +0x43120000, 0x43130000, 0x43140000, 0x43150000, 0x43160000, 0x43170000, +0x43180000, 0x43190000, 0x431A0000, 0x431B0000, 0x431C0000, 0x431D0000, +0x431E0000, 0x431F0000, 0x43200000, 0x43210000, 0x43220000, 0x43230000, +0x43240000, 0x43250000, 0x43260000, 0x43270000, 0x43280000, 0x43290000, +0x432A0000, 0x432B0000, 0x432C0000, 0x432D0000, 0x432E0000, 0x432F0000, +0x43300000, 0x43310000, 0x43320000, 0x43330000, 0x43340000 }; -static struct hda_pcm_stream ca0132_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = ca0132_dig_playback_pcm_open, - .close = ca0132_dig_playback_pcm_close, - .prepare = ca0132_dig_playback_pcm_prepare, - .cleanup = ca0132_dig_playback_pcm_cleanup - }, +static unsigned int mic_svm_vals_lookup[] = { +0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD, +0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE, +0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B, +0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F, +0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1, +0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333, +0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85, +0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7, +0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14, +0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D, +0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666, +0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F, +0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8, +0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1, +0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A, +0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333, +0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000 }; -static struct hda_pcm_stream ca0132_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, +static unsigned int equalizer_vals_lookup[] = { +0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000, +0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000, +0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000, +0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000, +0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000, +0x40C00000, 0x40E00000, 0x41000000, 0x41100000, 0x41200000, 0x41300000, +0x41400000, 0x41500000, 0x41600000, 0x41700000, 0x41800000, 0x41880000, +0x41900000, 0x41980000, 0x41A00000, 0x41A80000, 0x41B00000, 0x41B80000, +0x41C00000 }; -static int ca0132_build_pcms(struct hda_codec *codec) +static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid, + unsigned int *lookup, int idx) { - struct ca0132_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + int i = 0; - codec->pcm_info = info; - codec->num_pcms = 0; + for (i = 0; i < TUNING_CTLS_COUNT; i++) + if (nid == ca0132_tuning_ctls[i].nid) + break; - info->name = "CA0132 Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; - codec->num_pcms++; + snd_hda_power_up(codec); + dspio_set_param(codec, ca0132_tuning_ctls[i].mid, + ca0132_tuning_ctls[i].req, + &(lookup[idx]), sizeof(unsigned int)); + snd_hda_power_down(codec); - if (!spec->dig_out && !spec->dig_in) - return 0; + return 1; +} - info++; - info->name = "CA0132 Digital"; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->dig_out) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - ca0132_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - ca0132_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; +static int tuning_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + long *valp = ucontrol->value.integer.value; + int idx = nid - TUNING_CTL_START_NID; + *valp = spec->cur_ctl_vals[idx]; return 0; } -#define REG_CODEC_MUTE 0x18b014 -#define REG_CODEC_HP_VOL_L 0x18b070 -#define REG_CODEC_HP_VOL_R 0x18b074 +static int voice_focus_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int chs = get_amp_channels(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 20; + uinfo->value.integer.max = 180; + uinfo->value.integer.step = 1; + + return 0; +} -static int ca0132_hp_switch_get(struct snd_kcontrol *kcontrol, +static int voice_focus_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); long *valp = ucontrol->value.integer.value; + int idx; + + idx = nid - TUNING_CTL_START_NID; + /* any change? */ + if (spec->cur_ctl_vals[idx] == *valp) + return 0; + + spec->cur_ctl_vals[idx] = *valp; + + idx = *valp - 20; + tuning_ctl_set(codec, nid, voice_focus_vals_lookup, idx); + + return 1; +} + +static int mic_svm_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int chs = get_amp_channels(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 100; + uinfo->value.integer.step = 1; - *valp = spec->curr_hp_switch; return 0; } -static int ca0132_hp_switch_put(struct snd_kcontrol *kcontrol, +static int mic_svm_ctl_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); long *valp = ucontrol->value.integer.value; - unsigned int data; - int err; + int idx; + idx = nid - TUNING_CTL_START_NID; /* any change? */ - if (spec->curr_hp_switch == *valp) + if (spec->cur_ctl_vals[idx] == *valp) return 0; - snd_hda_power_up(codec); + spec->cur_ctl_vals[idx] = *valp; - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - goto exit; + idx = *valp; + tuning_ctl_set(codec, nid, mic_svm_vals_lookup, idx); - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0x7f) | (*valp ? 0 : 0x80); - err = chipio_write(codec, REG_CODEC_MUTE, data); - if (err < 0) - goto exit; + return 0; +} - spec->curr_hp_switch = *valp; +static int equalizer_ctl_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + int chs = get_amp_channels(kcontrol); + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = chs == 3 ? 2 : 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 48; + uinfo->value.integer.step = 1; - exit: - snd_hda_power_down(codec); - return err < 0 ? err : 1; + return 0; } -static int ca0132_speaker_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int equalizer_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); long *valp = ucontrol->value.integer.value; + int idx; + + idx = nid - TUNING_CTL_START_NID; + /* any change? */ + if (spec->cur_ctl_vals[idx] == *valp) + return 0; + + spec->cur_ctl_vals[idx] = *valp; + + idx = *valp; + tuning_ctl_set(codec, nid, equalizer_vals_lookup, idx); + + return 1; +} + +static const DECLARE_TLV_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); +static const DECLARE_TLV_DB_SCALE(eq_db_scale, -2400, 100, 0); + +static int add_tuning_control(struct hda_codec *codec, + hda_nid_t pnid, hda_nid_t nid, + const char *name, int dir) +{ + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + int type = dir ? HDA_INPUT : HDA_OUTPUT; + struct snd_kcontrol_new knew = + HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type); + + knew.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ; + knew.tlv.c = 0; + knew.tlv.p = 0; + switch (pnid) { + case VOICE_FOCUS: + knew.info = voice_focus_ctl_info; + knew.get = tuning_ctl_get; + knew.put = voice_focus_ctl_put; + knew.tlv.p = voice_focus_db_scale; + break; + case MIC_SVM: + knew.info = mic_svm_ctl_info; + knew.get = tuning_ctl_get; + knew.put = mic_svm_ctl_put; + break; + case EQUALIZER: + knew.info = equalizer_ctl_info; + knew.get = tuning_ctl_get; + knew.put = equalizer_ctl_put; + knew.tlv.p = eq_db_scale; + break; + default: + return 0; + } + knew.private_value = + HDA_COMPOSE_AMP_VAL(nid, 1, 0, type); + sprintf(namestr, "%s %s Volume", name, dirstr[dir]); + return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); +} + +static int add_tuning_ctls(struct hda_codec *codec) +{ + int i; + int err; + + for (i = 0; i < TUNING_CTLS_COUNT; i++) { + err = add_tuning_control(codec, + ca0132_tuning_ctls[i].parent_nid, + ca0132_tuning_ctls[i].nid, + ca0132_tuning_ctls[i].name, + ca0132_tuning_ctls[i].direct); + if (err < 0) + return err; + } - *valp = spec->curr_speaker_switch; return 0; } -static int ca0132_speaker_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void ca0132_init_tuning_defaults(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; - unsigned int data; + int i; + + /* Wedge Angle defaults to 30. 10 below is 30 - 20. 20 is min. */ + spec->cur_ctl_vals[WEDGE_ANGLE - TUNING_CTL_START_NID] = 10; + /* SVM level defaults to 0.74. */ + spec->cur_ctl_vals[SVM_LEVEL - TUNING_CTL_START_NID] = 74; + + /* EQ defaults to 0dB. */ + for (i = 2; i < TUNING_CTLS_COUNT; i++) + spec->cur_ctl_vals[i] = 24; +} +#endif /*ENABLE_TUNING_CONTROLS*/ + +/* + * Select the active output. + * If autodetect is enabled, output will be selected based on jack detection. + * If jack inserted, headphone will be selected, else built-in speakers + * If autodetect is disabled, output will be selected based on selection. + */ +static int ca0132_select_out(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int pin_ctl; + int jack_present; + int auto_jack; + unsigned int tmp; int err; - /* any change? */ - if (spec->curr_speaker_switch == *valp) + codec_dbg(codec, "ca0132_select_out\n"); + + snd_hda_power_up(codec); + + auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; + + if (auto_jack) + jack_present = snd_hda_jack_detect(codec, spec->out_pins[1]); + else + jack_present = + spec->vnode_lswitch[VNID_HP_SEL - VNODE_START_NID]; + + if (jack_present) + spec->cur_out_type = HEADPHONE_OUT; + else + spec->cur_out_type = SPEAKER_OUT; + + if (spec->cur_out_type == SPEAKER_OUT) { + codec_dbg(codec, "ca0132_select_out speaker\n"); + /*speaker out config*/ + tmp = FLOAT_ONE; + err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); + if (err < 0) + goto exit; + /*enable speaker EQ*/ + tmp = FLOAT_ONE; + err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp); + if (err < 0) + goto exit; + + /* Setup EAPD */ + snd_hda_codec_write(codec, spec->out_pins[1], 0, + VENDOR_CHIPIO_EAPD_SEL_SET, 0x02); + snd_hda_codec_write(codec, spec->out_pins[0], 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + snd_hda_codec_write(codec, spec->out_pins[0], 0, + VENDOR_CHIPIO_EAPD_SEL_SET, 0x00); + snd_hda_codec_write(codec, spec->out_pins[0], 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x02); + + /* disable headphone node */ + pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_set_pin_ctl(codec, spec->out_pins[1], + pin_ctl & ~PIN_HP); + /* enable speaker node */ + pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_set_pin_ctl(codec, spec->out_pins[0], + pin_ctl | PIN_OUT); + } else { + codec_dbg(codec, "ca0132_select_out hp\n"); + /*headphone out config*/ + tmp = FLOAT_ZERO; + err = dspio_set_uint_param(codec, 0x80, 0x04, tmp); + if (err < 0) + goto exit; + /*disable speaker EQ*/ + tmp = FLOAT_ZERO; + err = dspio_set_uint_param(codec, 0x8f, 0x00, tmp); + if (err < 0) + goto exit; + + /* Setup EAPD */ + snd_hda_codec_write(codec, spec->out_pins[0], 0, + VENDOR_CHIPIO_EAPD_SEL_SET, 0x00); + snd_hda_codec_write(codec, spec->out_pins[0], 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x00); + snd_hda_codec_write(codec, spec->out_pins[1], 0, + VENDOR_CHIPIO_EAPD_SEL_SET, 0x02); + snd_hda_codec_write(codec, spec->out_pins[0], 0, + AC_VERB_SET_EAPD_BTLENABLE, 0x02); + + /* disable speaker*/ + pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_set_pin_ctl(codec, spec->out_pins[0], + pin_ctl & ~PIN_HP); + /* enable headphone*/ + pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_set_pin_ctl(codec, spec->out_pins[1], + pin_ctl | PIN_HP); + } + +exit: + snd_hda_power_down(codec); + + return err < 0 ? err : 0; +} + +static void ca0132_unsol_hp_delayed(struct work_struct *work) +{ + struct ca0132_spec *spec = container_of( + to_delayed_work(work), struct ca0132_spec, unsol_hp_work); + ca0132_select_out(spec->codec); + snd_hda_jack_report_sync(spec->codec); +} + +static void ca0132_set_dmic(struct hda_codec *codec, int enable); +static int ca0132_mic_boost_set(struct hda_codec *codec, long val); +static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); + +/* + * Select the active VIP source + */ +static int ca0132_set_vipsource(struct hda_codec *codec, int val) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + + if (spec->dsp_state != DSP_DOWNLOADED) return 0; + /* if CrystalVoice if off, vipsource should be 0 */ + if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] || + (val == 0)) { + chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0); + chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); + chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); + if (spec->cur_mic_type == DIGITAL_MIC) + tmp = FLOAT_TWO; + else + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x00, tmp); + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x80, 0x05, tmp); + } else { + chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000); + chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000); + if (spec->cur_mic_type == DIGITAL_MIC) + tmp = FLOAT_TWO; + else + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x00, tmp); + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x05, tmp); + msleep(20); + chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val); + } + + return 1; +} + +/* + * Select the active microphone. + * If autodetect is enabled, mic will be selected based on jack detection. + * If jack inserted, ext.mic will be selected, else built-in mic + * If autodetect is disabled, mic will be selected based on selection. + */ +static int ca0132_select_mic(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + int jack_present; + int auto_jack; + + codec_dbg(codec, "ca0132_select_mic\n"); + snd_hda_power_up(codec); - err = chipio_read(codec, REG_CODEC_MUTE, &data); - if (err < 0) - goto exit; + auto_jack = spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID]; + + if (auto_jack) + jack_present = snd_hda_jack_detect(codec, spec->input_pins[0]); + else + jack_present = + spec->vnode_lswitch[VNID_AMIC1_SEL - VNODE_START_NID]; + + if (jack_present) + spec->cur_mic_type = LINE_MIC_IN; + else + spec->cur_mic_type = DIGITAL_MIC; + + if (spec->cur_mic_type == DIGITAL_MIC) { + /* enable digital Mic */ + chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_32_000); + ca0132_set_dmic(codec, 1); + ca0132_mic_boost_set(codec, 0); + /* set voice focus */ + ca0132_effects_set(codec, VOICE_FOCUS, + spec->effects_switch + [VOICE_FOCUS - EFFECT_START_NID]); + } else { + /* disable digital Mic */ + chipio_set_conn_rate(codec, MEM_CONNID_DMIC, SR_96_000); + ca0132_set_dmic(codec, 0); + ca0132_mic_boost_set(codec, spec->cur_mic_boost); + /* disable voice focus */ + ca0132_effects_set(codec, VOICE_FOCUS, 0); + } + + snd_hda_power_down(codec); + + return 0; +} + +/* + * Check if VNODE settings take effect immediately. + */ +static bool ca0132_is_vnode_effective(struct hda_codec *codec, + hda_nid_t vnid, + hda_nid_t *shared_nid) +{ + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid; + + switch (vnid) { + case VNID_SPK: + nid = spec->shared_out_nid; + break; + case VNID_MIC: + nid = spec->shared_mic_nid; + break; + default: + return false; + } + + if (shared_nid) + *shared_nid = nid; + + return true; +} + +/* +* The following functions are control change helpers. +* They return 0 if no changed. Return 1 if changed. +*/ +static int ca0132_voicefx_set(struct hda_codec *codec, int enable) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + + /* based on CrystalVoice state to enable VoiceFX. */ + if (enable) { + tmp = spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] ? + FLOAT_ONE : FLOAT_ZERO; + } else { + tmp = FLOAT_ZERO; + } + + dspio_set_uint_param(codec, ca0132_voicefx.mid, + ca0132_voicefx.reqs[0], tmp); + + return 1; +} + +/* + * Set the effects parameters + */ +static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int on; + int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; + int err = 0; + int idx = nid - EFFECT_START_NID; + + if ((idx < 0) || (idx >= num_fx)) + return 0; /* no changed */ + + /* for out effect, qualify with PE */ + if ((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) { + /* if PE if off, turn off out effects. */ + if (!spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) + val = 0; + } + + /* for in effect, qualify with CrystalVoice */ + if ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID)) { + /* if CrystalVoice if off, turn off in effects. */ + if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]) + val = 0; + + /* Voice Focus applies to 2-ch Mic, Digital Mic */ + if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC)) + val = 0; + } + + codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n", + nid, val); + + on = (val == 0) ? FLOAT_ZERO : FLOAT_ONE; + err = dspio_set_uint_param(codec, ca0132_effects[idx].mid, + ca0132_effects[idx].reqs[0], on); - /* *valp 0 is mute, 1 is unmute */ - data = (data & 0xef) | (*valp ? 0 : 0x10); - err = chipio_write(codec, REG_CODEC_MUTE, data); if (err < 0) - goto exit; + return 0; /* no changed */ - spec->curr_speaker_switch = *valp; + return 1; +} - exit: - snd_hda_power_down(codec); - return err < 0 ? err : 1; +/* + * Turn on/off Playback Enhancements + */ +static int ca0132_pe_switch_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid; + int i, ret = 0; + + codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n", + spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]); + + i = OUT_EFFECT_START_NID - EFFECT_START_NID; + nid = OUT_EFFECT_START_NID; + /* PE affects all out effects */ + for (; nid < OUT_EFFECT_END_NID; nid++, i++) + ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]); + + return ret; } -static int ca0132_hp_volume_get(struct snd_kcontrol *kcontrol, +/* Check if Mic1 is streaming, if so, stop streaming */ +static int stop_mic1(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int oldval = snd_hda_codec_read(codec, spec->adcs[0], 0, + AC_VERB_GET_CONV, 0); + if (oldval != 0) + snd_hda_codec_write(codec, spec->adcs[0], 0, + AC_VERB_SET_CHANNEL_STREAMID, + 0); + return oldval; +} + +/* Resume Mic1 streaming if it was stopped. */ +static void resume_mic1(struct hda_codec *codec, unsigned int oldval) +{ + struct ca0132_spec *spec = codec->spec; + /* Restore the previous stream and channel */ + if (oldval != 0) + snd_hda_codec_write(codec, spec->adcs[0], 0, + AC_VERB_SET_CHANNEL_STREAMID, + oldval); +} + +/* + * Turn on/off CrystalVoice + */ +static int ca0132_cvoice_switch_set(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid; + int i, ret = 0; + unsigned int oldval; + + codec_dbg(codec, "ca0132_cvoice_switch_set: val=%ld\n", + spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID]); + + i = IN_EFFECT_START_NID - EFFECT_START_NID; + nid = IN_EFFECT_START_NID; + /* CrystalVoice affects all in effects */ + for (; nid < IN_EFFECT_END_NID; nid++, i++) + ret |= ca0132_effects_set(codec, nid, spec->effects_switch[i]); + + /* including VoiceFX */ + ret |= ca0132_voicefx_set(codec, (spec->voicefx_val ? 1 : 0)); + + /* set correct vipsource */ + oldval = stop_mic1(codec); + ret |= ca0132_set_vipsource(codec, 1); + resume_mic1(codec, oldval); + return ret; +} + +static int ca0132_mic_boost_set(struct hda_codec *codec, long val) +{ + struct ca0132_spec *spec = codec->spec; + int ret = 0; + + if (val) /* on */ + ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0, + HDA_INPUT, 0, HDA_AMP_VOLMASK, 3); + else /* off */ + ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0, + HDA_INPUT, 0, HDA_AMP_VOLMASK, 0); + + return ret; +} + +static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + hda_nid_t nid = get_amp_nid(kcontrol); + hda_nid_t shared_nid = 0; + bool effective; + int ret = 0; struct ca0132_spec *spec = codec->spec; - long *valp = ucontrol->value.integer.value; + int auto_jack; + + if (nid == VNID_HP_SEL) { + auto_jack = + spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; + if (!auto_jack) + ca0132_select_out(codec); + return 1; + } + + if (nid == VNID_AMIC1_SEL) { + auto_jack = + spec->vnode_lswitch[VNID_AMIC1_ASEL - VNODE_START_NID]; + if (!auto_jack) + ca0132_select_mic(codec); + return 1; + } - *valp++ = spec->curr_hp_volume[0]; - *valp = spec->curr_hp_volume[1]; + if (nid == VNID_HP_ASEL) { + ca0132_select_out(codec); + return 1; + } + + if (nid == VNID_AMIC1_ASEL) { + ca0132_select_mic(codec); + return 1; + } + + /* if effective conditions, then update hw immediately. */ + effective = ca0132_is_vnode_effective(codec, nid, &shared_nid); + if (effective) { + int dir = get_amp_direction(kcontrol); + int ch = get_amp_channels(kcontrol); + unsigned long pval; + + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch, + 0, dir); + ret = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + } + + return ret; +} +/* End of control change helpers. */ + +static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + unsigned int items = sizeof(ca0132_voicefx_presets) + / sizeof(struct ct_voicefx_preset); + + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = items; + if (uinfo->value.enumerated.item >= items) + uinfo->value.enumerated.item = items - 1; + strcpy(uinfo->value.enumerated.name, + ca0132_voicefx_presets[uinfo->value.enumerated.item].name); return 0; } -static int ca0132_hp_volume_put(struct snd_kcontrol *kcontrol, +static int ca0132_voicefx_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; + + ucontrol->value.enumerated.item[0] = spec->voicefx_val; + return 0; +} + +static int ca0132_voicefx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + int i, err = 0; + int sel = ucontrol->value.enumerated.item[0]; + unsigned int items = sizeof(ca0132_voicefx_presets) + / sizeof(struct ct_voicefx_preset); + + if (sel >= items) + return 0; + + codec_dbg(codec, "ca0132_voicefx_put: sel=%d, preset=%s\n", + sel, ca0132_voicefx_presets[sel].name); + + /* + * Idx 0 is default. + * Default needs to qualify with CrystalVoice state. + */ + for (i = 0; i < VOICEFX_MAX_PARAM_COUNT; i++) { + err = dspio_set_uint_param(codec, ca0132_voicefx.mid, + ca0132_voicefx.reqs[i], + ca0132_voicefx_presets[sel].vals[i]); + if (err < 0) + break; + } + + if (err >= 0) { + spec->voicefx_val = sel; + /* enable voice fx */ + ca0132_voicefx_set(codec, (sel ? 1 : 0)); + } + + return 1; +} + +static int ca0132_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); long *valp = ucontrol->value.integer.value; - long left_vol, right_vol; - unsigned int data; - int val; - int err; - left_vol = *valp++; - right_vol = *valp; + /* vnode */ + if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) { + if (ch & 1) { + *valp = spec->vnode_lswitch[nid - VNODE_START_NID]; + valp++; + } + if (ch & 2) { + *valp = spec->vnode_rswitch[nid - VNODE_START_NID]; + valp++; + } + return 0; + } - /* any change? */ - if ((spec->curr_hp_volume[0] == left_vol) && - (spec->curr_hp_volume[1] == right_vol)) + /* effects, include PE and CrystalVoice */ + if ((nid >= EFFECT_START_NID) && (nid < EFFECT_END_NID)) { + *valp = spec->effects_switch[nid - EFFECT_START_NID]; return 0; + } + + /* mic boost */ + if (nid == spec->input_pins[0]) { + *valp = spec->cur_mic_boost; + return 0; + } + + return 0; +} + +static int ca0132_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + int changed = 1; + + codec_dbg(codec, "ca0132_switch_put: nid=0x%x, val=%ld\n", + nid, *valp); snd_hda_power_up(codec); + /* vnode */ + if ((nid >= VNODE_START_NID) && (nid < VNODE_END_NID)) { + if (ch & 1) { + spec->vnode_lswitch[nid - VNODE_START_NID] = *valp; + valp++; + } + if (ch & 2) { + spec->vnode_rswitch[nid - VNODE_START_NID] = *valp; + valp++; + } + changed = ca0132_vnode_switch_set(kcontrol, ucontrol); + goto exit; + } - err = chipio_read(codec, REG_CODEC_HP_VOL_L, &data); - if (err < 0) + /* PE */ + if (nid == PLAY_ENHANCEMENT) { + spec->effects_switch[nid - EFFECT_START_NID] = *valp; + changed = ca0132_pe_switch_set(codec); goto exit; + } - val = 31 - left_vol; - data = (data & 0xe0) | val; - err = chipio_write(codec, REG_CODEC_HP_VOL_L, data); - if (err < 0) + /* CrystalVoice */ + if (nid == CRYSTAL_VOICE) { + spec->effects_switch[nid - EFFECT_START_NID] = *valp; + changed = ca0132_cvoice_switch_set(codec); goto exit; + } - val = 31 - right_vol; - data = (data & 0xe0) | val; - err = chipio_write(codec, REG_CODEC_HP_VOL_R, data); - if (err < 0) + /* out and in effects */ + if (((nid >= OUT_EFFECT_START_NID) && (nid < OUT_EFFECT_END_NID)) || + ((nid >= IN_EFFECT_START_NID) && (nid < IN_EFFECT_END_NID))) { + spec->effects_switch[nid - EFFECT_START_NID] = *valp; + changed = ca0132_effects_set(codec, nid, *valp); goto exit; + } - spec->curr_hp_volume[0] = left_vol; - spec->curr_hp_volume[1] = right_vol; + /* mic boost */ + if (nid == spec->input_pins[0]) { + spec->cur_mic_boost = *valp; - exit: + /* Mic boost does not apply to Digital Mic */ + if (spec->cur_mic_type != DIGITAL_MIC) + changed = ca0132_mic_boost_set(codec, *valp); + goto exit; + } + +exit: snd_hda_power_down(codec); - return err < 0 ? err : 1; + return changed; } -static int add_hp_switch(struct hda_codec *codec, hda_nid_t nid) +/* + * Volume related + */ +static int ca0132_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Headphone Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_hp_switch_get; - knew.put = ca0132_hp_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + int dir = get_amp_direction(kcontrol); + unsigned long pval; + int err; + + switch (nid) { + case VNID_SPK: + /* follow shared_out info */ + nid = spec->shared_out_nid; + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + break; + case VNID_MIC: + /* follow shared_mic info */ + nid = spec->shared_mic_nid; + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + break; + default: + err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); + } + return err; } -static int add_hp_volume(struct hda_codec *codec, hda_nid_t nid) +static int ca0132_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_MONO("Headphone Playback Volume", - nid, 3, 0, HDA_OUTPUT); - knew.get = ca0132_hp_volume_get; - knew.put = ca0132_hp_volume_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + + /* store the left and right volume */ + if (ch & 1) { + *valp = spec->vnode_lvol[nid - VNODE_START_NID]; + valp++; + } + if (ch & 2) { + *valp = spec->vnode_rvol[nid - VNODE_START_NID]; + valp++; + } + return 0; } -static int add_speaker_switch(struct hda_codec *codec, hda_nid_t nid) +static int ca0132_volume_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_MONO("Speaker Playback Switch", - nid, 1, 0, HDA_OUTPUT); - knew.get = ca0132_speaker_switch_get; - knew.put = ca0132_speaker_switch_put; - return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct ca0132_spec *spec = codec->spec; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + long *valp = ucontrol->value.integer.value; + hda_nid_t shared_nid = 0; + bool effective; + int changed = 1; + + /* store the left and right volume */ + if (ch & 1) { + spec->vnode_lvol[nid - VNODE_START_NID] = *valp; + valp++; + } + if (ch & 2) { + spec->vnode_rvol[nid - VNODE_START_NID] = *valp; + valp++; + } + + /* if effective conditions, then update hw immediately. */ + effective = ca0132_is_vnode_effective(codec, nid, &shared_nid); + if (effective) { + int dir = get_amp_direction(kcontrol); + unsigned long pval; + + snd_hda_power_up(codec); + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(shared_nid, ch, + 0, dir); + changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + snd_hda_power_down(codec); + } + + return changed; } -static void ca0132_fix_hp_caps(struct hda_codec *codec) +static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, + unsigned int size, unsigned int __user *tlv) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps; + hda_nid_t nid = get_amp_nid(kcontrol); + int ch = get_amp_channels(kcontrol); + int dir = get_amp_direction(kcontrol); + unsigned long pval; + int err; - /* set mute-capable, 1db step, 32 steps, ofs 6 */ - caps = 0x80031f06; - snd_hda_override_amp_caps(codec, cfg->hp_pins[0], HDA_OUTPUT, caps); + switch (nid) { + case VNID_SPK: + /* follow shared_out tlv */ + nid = spec->shared_out_nid; + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + break; + case VNID_MIC: + /* follow shared_mic tlv */ + nid = spec->shared_mic_nid; + mutex_lock(&codec->control_mutex); + pval = kcontrol->private_value; + kcontrol->private_value = HDA_COMPOSE_AMP_VAL(nid, ch, 0, dir); + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + kcontrol->private_value = pval; + mutex_unlock(&codec->control_mutex); + break; + default: + err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); + } + return err; +} + +static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid, + const char *pfx, int dir) +{ + char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + int type = dir ? HDA_INPUT : HDA_OUTPUT; + struct snd_kcontrol_new knew = + CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type); + sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); + return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); +} + +static int add_voicefx(struct hda_codec *codec) +{ + struct snd_kcontrol_new knew = + HDA_CODEC_MUTE_MONO(ca0132_voicefx.name, + VOICEFX, 1, 0, HDA_INPUT); + knew.info = ca0132_voicefx_info; + knew.get = ca0132_voicefx_get; + knew.put = ca0132_voicefx_put; + return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec)); } +/* + * When changing Node IDs for Mixer Controls below, make sure to update + * Node IDs in ca0132_config() as well. + */ +static struct snd_kcontrol_new ca0132_mixer[] = { + CA0132_CODEC_VOL("Master Playback Volume", VNID_SPK, HDA_OUTPUT), + CA0132_CODEC_MUTE("Master Playback Switch", VNID_SPK, HDA_OUTPUT), + CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT), + CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT), + HDA_CODEC_VOLUME("Analog-Mic2 Capture Volume", 0x08, 0, HDA_INPUT), + HDA_CODEC_MUTE("Analog-Mic2 Capture Switch", 0x08, 0, HDA_INPUT), + HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT), + HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT), + CA0132_CODEC_MUTE_MONO("Mic1-Boost (30dB) Capture Switch", + 0x12, 1, HDA_INPUT), + CA0132_CODEC_MUTE_MONO("HP/Speaker Playback Switch", + VNID_HP_SEL, 1, HDA_OUTPUT), + CA0132_CODEC_MUTE_MONO("AMic1/DMic Capture Switch", + VNID_AMIC1_SEL, 1, HDA_INPUT), + CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch", + VNID_HP_ASEL, 1, HDA_OUTPUT), + CA0132_CODEC_MUTE_MONO("AMic1/DMic Auto Detect Capture Switch", + VNID_AMIC1_ASEL, 1, HDA_INPUT), + { } /* end */ +}; + static int ca0132_build_controls(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; + int i, num_fx; + int err = 0; - if (spec->multiout.num_dacs) { - err = add_speaker_switch(codec, spec->out_pins[0]); + /* Add Mixer controls */ + for (i = 0; i < spec->num_mixers; i++) { + err = snd_hda_add_new_ctls(codec, spec->mixers[i]); if (err < 0) return err; } - if (cfg->hp_outs) { - ca0132_fix_hp_caps(codec); - err = add_hp_switch(codec, cfg->hp_pins[0]); - if (err < 0) - return err; - err = add_hp_volume(codec, cfg->hp_pins[0]); + /* Add in and out effects controls. + * VoiceFX, PE and CrystalVoice are added separately. + */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; + for (i = 0; i < num_fx; i++) { + err = add_fx_switch(codec, ca0132_effects[i].nid, + ca0132_effects[i].name, + ca0132_effects[i].direct); if (err < 0) return err; } - for (i = 0; i < spec->num_inputs; i++) { - const char *label = spec->input_labels[i]; + err = add_fx_switch(codec, PLAY_ENHANCEMENT, "PlayEnhancement", 0); + if (err < 0) + return err; - err = add_in_switch(codec, spec->adcs[i], label); - if (err < 0) - return err; - err = add_in_volume(codec, spec->adcs[i], label); - if (err < 0) - return err; - if (cfg->inputs[i].type == AUTO_PIN_MIC) { - /* add Mic-Boost */ - err = add_in_mono_volume(codec, spec->input_pins[i], - "Mic Boost", 1); - if (err < 0) - return err; - } - } + err = add_fx_switch(codec, CRYSTAL_VOICE, "CrystalVoice", 1); + if (err < 0) + return err; + + add_voicefx(codec); + +#ifdef ENABLE_TUNING_CONTROLS + add_tuning_ctls(codec); +#endif + + err = snd_hda_jack_add_kctls(codec, &spec->autocfg); + if (err < 0) + return err; if (spec->dig_out) { err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out, @@ -863,83 +3983,567 @@ static int ca0132_build_controls(struct hda_codec *codec) return 0; } +/* + * PCM + */ +static struct hda_pcm_stream ca0132_pcm_analog_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 6, + .ops = { + .prepare = ca0132_playback_pcm_prepare, + .cleanup = ca0132_playback_pcm_cleanup, + .get_delay = ca0132_playback_pcm_delay, + }, +}; + +static struct hda_pcm_stream ca0132_pcm_analog_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .prepare = ca0132_capture_pcm_prepare, + .cleanup = ca0132_capture_pcm_cleanup, + .get_delay = ca0132_capture_pcm_delay, + }, +}; + +static struct hda_pcm_stream ca0132_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .ops = { + .open = ca0132_dig_playback_pcm_open, + .close = ca0132_dig_playback_pcm_close, + .prepare = ca0132_dig_playback_pcm_prepare, + .cleanup = ca0132_dig_playback_pcm_cleanup + }, +}; + +static struct hda_pcm_stream ca0132_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +static int ca0132_build_pcms(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + + codec->pcm_info = info; + codec->num_pcms = 0; + + info->name = "CA0132 Analog"; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = + spec->multiout.max_channels; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; + codec->num_pcms++; + + info++; + info->name = "CA0132 Analog Mic-In2"; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1]; + codec->num_pcms++; + + info++; + info->name = "CA0132 What U Hear"; + info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[2]; + codec->num_pcms++; + + if (!spec->dig_out && !spec->dig_in) + return 0; + + info++; + info->name = "CA0132 Digital"; + info->pcm_type = HDA_PCM_TYPE_SPDIF; + if (spec->dig_out) { + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + ca0132_pcm_digital_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; + } + if (spec->dig_in) { + info->stream[SNDRV_PCM_STREAM_CAPTURE] = + ca0132_pcm_digital_capture; + info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; + } + codec->num_pcms++; + + return 0; +} + +static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) +{ + if (pin) { + snd_hda_set_pin_ctl(codec, pin, PIN_HP); + if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + } + if (dac && (get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) + snd_hda_codec_write(codec, dac, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); +} + +static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) +{ + if (pin) { + snd_hda_set_pin_ctl(codec, pin, PIN_VREF80); + if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + } + if (adc && (get_wcaps(codec, adc) & AC_WCAP_IN_AMP)) { + snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, + AMP_IN_UNMUTE(0)); + + /* init to 0 dB and unmute. */ + snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0, + HDA_AMP_VOLMASK, 0x5a); + snd_hda_codec_amp_stereo(codec, adc, HDA_INPUT, 0, + HDA_AMP_MUTE, 0); + } +} + +static void ca0132_init_unsol(struct hda_codec *codec) +{ + snd_hda_jack_detect_enable(codec, UNSOL_TAG_HP, UNSOL_TAG_HP); + snd_hda_jack_detect_enable(codec, UNSOL_TAG_AMIC1, UNSOL_TAG_AMIC1); +} -static void ca0132_set_ct_ext(struct hda_codec *codec, int enable) +static void refresh_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir) { - /* Set Creative extension */ - snd_printdd("SET CREATIVE EXTENSION\n"); + unsigned int caps; + + caps = snd_hda_param_read(codec, nid, dir == HDA_OUTPUT ? + AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); + snd_hda_override_amp_caps(codec, nid, dir, caps); +} + +/* + * Switch between Digital built-in mic and analog mic. + */ +static void ca0132_set_dmic(struct hda_codec *codec, int enable) +{ + struct ca0132_spec *spec = codec->spec; + unsigned int tmp; + u8 val; + unsigned int oldval; + + codec_dbg(codec, "ca0132_set_dmic: enable=%d\n", enable); + + oldval = stop_mic1(codec); + ca0132_set_vipsource(codec, 0); + if (enable) { + /* set DMic input as 2-ch */ + tmp = FLOAT_TWO; + dspio_set_uint_param(codec, 0x80, 0x00, tmp); + + val = spec->dmic_ctl; + val |= 0x80; + snd_hda_codec_write(codec, spec->input_pins[0], 0, + VENDOR_CHIPIO_DMIC_CTL_SET, val); + + if (!(spec->dmic_ctl & 0x20)) + chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 1); + } else { + /* set AMic input as mono */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x00, tmp); + + val = spec->dmic_ctl; + /* clear bit7 and bit5 to disable dmic */ + val &= 0x5f; + snd_hda_codec_write(codec, spec->input_pins[0], 0, + VENDOR_CHIPIO_DMIC_CTL_SET, val); + + if (!(spec->dmic_ctl & 0x20)) + chipio_set_control_flag(codec, CONTROL_FLAG_DMIC, 0); + } + ca0132_set_vipsource(codec, 1); + resume_mic1(codec, oldval); +} + +/* + * Initialization for Digital Mic. + */ +static void ca0132_init_dmic(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + u8 val; + + /* Setup Digital Mic here, but don't enable. + * Enable based on jack detect. + */ + + /* MCLK uses MPIO1, set to enable. + * Bit 2-0: MPIO select + * Bit 3: set to disable + * Bit 7-4: reserved + */ + val = 0x01; + snd_hda_codec_write(codec, spec->input_pins[0], 0, + VENDOR_CHIPIO_DMIC_MCLK_SET, val); + + /* Data1 uses MPIO3. Data2 not use + * Bit 2-0: Data1 MPIO select + * Bit 3: set disable Data1 + * Bit 6-4: Data2 MPIO select + * Bit 7: set disable Data2 + */ + val = 0x83; + snd_hda_codec_write(codec, spec->input_pins[0], 0, + VENDOR_CHIPIO_DMIC_PIN_SET, val); + + /* Use Ch-0 and Ch-1. Rate is 48K, mode 1. Disable DMic first. + * Bit 3-0: Channel mask + * Bit 4: set for 48KHz, clear for 32KHz + * Bit 5: mode + * Bit 6: set to select Data2, clear for Data1 + * Bit 7: set to enable DMic, clear for AMic + */ + val = 0x23; + /* keep a copy of dmic ctl val for enable/disable dmic purpuse */ + spec->dmic_ctl = val; + snd_hda_codec_write(codec, spec->input_pins[0], 0, + VENDOR_CHIPIO_DMIC_CTL_SET, val); +} + +/* + * Initialization for Analog Mic 2 + */ +static void ca0132_init_analog_mic2(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + mutex_lock(&spec->chipio_mutex); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x2D); + snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, + VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, - VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, - enable); - msleep(20); + VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); + mutex_unlock(&spec->chipio_mutex); } +static void ca0132_refresh_widget_caps(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + int i; + hda_nid_t nid; -static void ca0132_config(struct hda_codec *codec) + codec_dbg(codec, "ca0132_refresh_widget_caps.\n"); + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) + codec->wcaps[i] = snd_hda_param_read(codec, nid, + AC_PAR_AUDIO_WIDGET_CAP); + + for (i = 0; i < spec->multiout.num_dacs; i++) + refresh_amp_caps(codec, spec->dacs[i], HDA_OUTPUT); + + for (i = 0; i < spec->num_outputs; i++) + refresh_amp_caps(codec, spec->out_pins[i], HDA_OUTPUT); + + for (i = 0; i < spec->num_inputs; i++) { + refresh_amp_caps(codec, spec->adcs[i], HDA_INPUT); + refresh_amp_caps(codec, spec->input_pins[i], HDA_INPUT); + } +} + +/* + * Setup default parameters for DSP + */ +static void ca0132_setup_defaults(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + unsigned int tmp; + int num_fx; + int idx, i; + + if (spec->dsp_state != DSP_DOWNLOADED) + return; + + /* out, in effects + voicefx */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; + for (idx = 0; idx < num_fx; idx++) { + for (i = 0; i <= ca0132_effects[idx].params; i++) { + dspio_set_uint_param(codec, ca0132_effects[idx].mid, + ca0132_effects[idx].reqs[i], + ca0132_effects[idx].def_vals[i]); + } + } - codec->pcm_format_first = 1; - codec->no_sticky_stream = 1; + /*remove DSP headroom*/ + tmp = FLOAT_ZERO; + dspio_set_uint_param(codec, 0x96, 0x3C, tmp); - /* line-outs */ - cfg->line_outs = 1; - cfg->line_out_pins[0] = 0x0b; /* front */ - cfg->line_out_type = AUTO_PIN_LINE_OUT; + /*set speaker EQ bypass attenuation*/ + dspio_set_uint_param(codec, 0x8f, 0x01, tmp); - spec->dacs[0] = 0x02; - spec->out_pins[0] = 0x0b; - spec->multiout.dac_nids = spec->dacs; - spec->multiout.num_dacs = 1; - spec->multiout.max_channels = 2; + /* set AMic1 and AMic2 as mono mic */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x00, tmp); + dspio_set_uint_param(codec, 0x80, 0x01, tmp); - /* headphone */ - cfg->hp_outs = 1; - cfg->hp_pins[0] = 0x0f; + /* set AMic1 as CrystalVoice input */ + tmp = FLOAT_ONE; + dspio_set_uint_param(codec, 0x80, 0x05, tmp); - spec->hp_dac = 0; - spec->multiout.hp_nid = 0; + /* set WUH source */ + tmp = FLOAT_TWO; + dspio_set_uint_param(codec, 0x31, 0x00, tmp); +} - /* inputs */ - cfg->num_inputs = 2; /* Mic-in and line-in */ - cfg->inputs[0].pin = 0x12; - cfg->inputs[0].type = AUTO_PIN_MIC; - cfg->inputs[1].pin = 0x11; - cfg->inputs[1].type = AUTO_PIN_LINE_IN; +/* + * Initialization of flags in chip + */ +static void ca0132_init_flags(struct hda_codec *codec) +{ + chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0); + chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_COMMON_MODE, 0); + chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_COMMON_MODE, 0); + chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0); + chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0); + chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1); +} - /* Mic-in */ - spec->input_pins[0] = 0x12; - spec->input_labels[0] = "Mic"; - spec->adcs[0] = 0x07; +/* + * Initialization of parameters in chip + */ +static void ca0132_init_params(struct hda_codec *codec) +{ + chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6); + chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6); +} - /* Line-In */ - spec->input_pins[1] = 0x11; - spec->input_labels[1] = "Line"; - spec->adcs[1] = 0x08; - spec->num_inputs = 2; +static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k) +{ + chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, is96k); + chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, is96k); + chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, is96k); + chipio_set_control_flag(codec, CONTROL_FLAG_SRC_CLOCK_196MHZ, is96k); + chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, is96k); + chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, is96k); + + chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); + chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); + chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); +} - /* SPDIF I/O */ - spec->dig_out = 0x05; - spec->multiout.dig_out_nid = spec->dig_out; - cfg->dig_out_pins[0] = 0x0c; - cfg->dig_outs = 1; - cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; - spec->dig_in = 0x09; - cfg->dig_in_pin = 0x0e; - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; +static bool ca0132_download_dsp_images(struct hda_codec *codec) +{ + bool dsp_loaded = false; + const struct dsp_image_seg *dsp_os_image; + const struct firmware *fw_entry; + + if (request_firmware(&fw_entry, EFX_FILE, codec->bus->card->dev) != 0) + return false; + + dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); + if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { + pr_err("ca0132 dspload_image failed.\n"); + goto exit_download; + } + + dsp_loaded = dspload_wait_loaded(codec); + +exit_download: + release_firmware(fw_entry); + + return dsp_loaded; +} + +static void ca0132_download_dsp(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + +#ifndef CONFIG_SND_HDA_CODEC_CA0132_DSP + return; /* NOP */ +#endif + + chipio_enable_clocks(codec); + spec->dsp_state = DSP_DOWNLOADING; + if (!ca0132_download_dsp_images(codec)) + spec->dsp_state = DSP_DOWNLOAD_FAILED; + else + spec->dsp_state = DSP_DOWNLOADED; + + if (spec->dsp_state == DSP_DOWNLOADED) + ca0132_set_dsp_msr(codec, true); } +static void ca0132_process_dsp_response(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + + codec_dbg(codec, "ca0132_process_dsp_response\n"); + if (spec->wait_scp) { + if (dspio_get_response_data(codec) >= 0) + spec->wait_scp = 0; + } + + dspio_clear_response_queue(codec); +} + +static void ca0132_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct ca0132_spec *spec = codec->spec; + + if (((res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f) == UNSOL_TAG_DSP) { + ca0132_process_dsp_response(codec); + } else { + res = snd_hda_jack_get_action(codec, + (res >> AC_UNSOL_RES_TAG_SHIFT) & 0x3f); + + codec_dbg(codec, "snd_hda_jack_get_action: 0x%x\n", res); + + switch (res) { + case UNSOL_TAG_HP: + /* Delay enabling the HP amp, to let the mic-detection + * state machine run. + */ + cancel_delayed_work_sync(&spec->unsol_hp_work); + queue_delayed_work(codec->bus->workq, + &spec->unsol_hp_work, + msecs_to_jiffies(500)); + break; + case UNSOL_TAG_AMIC1: + ca0132_select_mic(codec); + snd_hda_jack_report_sync(codec); + break; + default: + break; + } + } +} + +/* + * Verbs tables. + */ + +/* Sends before DSP download. */ +static struct hda_verb ca0132_base_init_verbs[] = { + /*enable ct extension*/ + {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x1}, + /*enable DSP node unsol, needed for DSP download*/ + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_DSP}, + {} +}; + +/* Send at exit. */ +static struct hda_verb ca0132_base_exit_verbs[] = { + /*set afg to D3*/ + {0x01, AC_VERB_SET_POWER_STATE, 0x03}, + /*disable ct extension*/ + {0x15, VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0}, + {} +}; + +/* Other verbs tables. Sends after DSP download. */ +static struct hda_verb ca0132_init_verbs0[] = { + /* chip init verbs */ + {0x15, 0x70D, 0xF0}, + {0x15, 0x70E, 0xFE}, + {0x15, 0x707, 0x75}, + {0x15, 0x707, 0xD3}, + {0x15, 0x707, 0x09}, + {0x15, 0x707, 0x53}, + {0x15, 0x707, 0xD4}, + {0x15, 0x707, 0xEF}, + {0x15, 0x707, 0x75}, + {0x15, 0x707, 0xD3}, + {0x15, 0x707, 0x09}, + {0x15, 0x707, 0x02}, + {0x15, 0x707, 0x37}, + {0x15, 0x707, 0x78}, + {0x15, 0x53C, 0xCE}, + {0x15, 0x575, 0xC9}, + {0x15, 0x53D, 0xCE}, + {0x15, 0x5B7, 0xC9}, + {0x15, 0x70D, 0xE8}, + {0x15, 0x70E, 0xFE}, + {0x15, 0x707, 0x02}, + {0x15, 0x707, 0x68}, + {0x15, 0x707, 0x62}, + {0x15, 0x53A, 0xCE}, + {0x15, 0x546, 0xC9}, + {0x15, 0x53B, 0xCE}, + {0x15, 0x5E8, 0xC9}, + {0x15, 0x717, 0x0D}, + {0x15, 0x718, 0x20}, + {} +}; + +static struct hda_verb ca0132_init_verbs1[] = { + {0x10, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_HP}, + {0x12, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | UNSOL_TAG_AMIC1}, + /* config EAPD */ + {0x0b, 0x78D, 0x00}, + /*{0x0b, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/ + /*{0x10, 0x78D, 0x02},*/ + /*{0x10, AC_VERB_SET_EAPD_BTLENABLE, 0x02},*/ + {} +}; + static void ca0132_init_chip(struct hda_codec *codec) { struct ca0132_spec *spec = codec->spec; + int num_fx; + int i; + unsigned int on; mutex_init(&spec->chipio_mutex); + + spec->cur_out_type = SPEAKER_OUT; + spec->cur_mic_type = DIGITAL_MIC; + spec->cur_mic_boost = 0; + + for (i = 0; i < VNODES_COUNT; i++) { + spec->vnode_lvol[i] = 0x5a; + spec->vnode_rvol[i] = 0x5a; + spec->vnode_lswitch[i] = 0; + spec->vnode_rswitch[i] = 0; + } + + /* + * Default states for effects are in ca0132_effects[]. + */ + num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; + for (i = 0; i < num_fx; i++) { + on = (unsigned int)ca0132_effects[i].reqs[0]; + spec->effects_switch[i] = on ? 1 : 0; + } + + spec->voicefx_val = 0; + spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1; + spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] = 0; + +#ifdef ENABLE_TUNING_CONTROLS + ca0132_init_tuning_defaults(codec); +#endif } static void ca0132_exit_chip(struct hda_codec *codec) { /* put any chip cleanup stuffs here. */ + + if (dspload_is_loaded(codec)) + dsp_reset(codec); } static int ca0132_init(struct hda_codec *codec) @@ -948,11 +4552,23 @@ static int ca0132_init(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; int i; - for (i = 0; i < spec->multiout.num_dacs; i++) { - init_output(codec, spec->out_pins[i], - spec->multiout.dac_nids[i]); - } - init_output(codec, cfg->hp_pins[0], spec->hp_dac); + spec->dsp_state = DSP_DOWNLOAD_INIT; + spec->curr_chip_addx = INVALID_CHIP_ADDRESS; + + snd_hda_power_up(codec); + + ca0132_init_params(codec); + ca0132_init_flags(codec); + snd_hda_sequence_write(codec, spec->base_init_verbs); + ca0132_download_dsp(codec); + ca0132_refresh_widget_caps(codec); + ca0132_setup_defaults(codec); + ca0132_init_analog_mic2(codec); + ca0132_init_dmic(codec); + + for (i = 0; i < spec->num_outputs; i++) + init_output(codec, spec->out_pins[i], spec->dacs[0]); + init_output(codec, cfg->dig_out_pins[0], spec->dig_out); for (i = 0; i < spec->num_inputs; i++) @@ -960,16 +4576,30 @@ static int ca0132_init(struct hda_codec *codec) init_input(codec, cfg->dig_in_pin, spec->dig_in); - ca0132_set_ct_ext(codec, 1); + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); + + ca0132_init_unsol(codec); + + ca0132_select_out(codec); + ca0132_select_mic(codec); + + snd_hda_jack_report_sync(codec); + + snd_hda_power_down(codec); return 0; } - static void ca0132_free(struct hda_codec *codec) { - ca0132_set_ct_ext(codec, 0); + struct ca0132_spec *spec = codec->spec; + + cancel_delayed_work_sync(&spec->unsol_hp_work); + snd_hda_power_up(codec); + snd_hda_sequence_write(codec, spec->base_exit_verbs); ca0132_exit_chip(codec); + snd_hda_power_down(codec); kfree(codec->spec); } @@ -978,26 +4608,83 @@ static struct hda_codec_ops ca0132_patch_ops = { .build_pcms = ca0132_build_pcms, .init = ca0132_init, .free = ca0132_free, + .unsol_event = ca0132_unsol_event, }; +static void ca0132_config(struct hda_codec *codec) +{ + struct ca0132_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->autocfg; + + spec->dacs[0] = 0x2; + spec->dacs[1] = 0x3; + spec->dacs[2] = 0x4; + + spec->multiout.dac_nids = spec->dacs; + spec->multiout.num_dacs = 3; + spec->multiout.max_channels = 2; + + spec->num_outputs = 2; + spec->out_pins[0] = 0x0b; /* speaker out */ + spec->out_pins[1] = 0x10; /* headphone out */ + spec->shared_out_nid = 0x2; + spec->num_inputs = 3; + spec->adcs[0] = 0x7; /* digital mic / analog mic1 */ + spec->adcs[1] = 0x8; /* analog mic2 */ + spec->adcs[2] = 0xa; /* what u hear */ + spec->shared_mic_nid = 0x7; + + spec->input_pins[0] = 0x12; + spec->input_pins[1] = 0x11; + spec->input_pins[2] = 0x13; + + /* SPDIF I/O */ + spec->dig_out = 0x05; + spec->multiout.dig_out_nid = spec->dig_out; + cfg->dig_out_pins[0] = 0x0c; + cfg->dig_outs = 1; + cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; + spec->dig_in = 0x09; + cfg->dig_in_pin = 0x0e; + cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; +} static int patch_ca0132(struct hda_codec *codec) { struct ca0132_spec *spec; + int err; - snd_printdd("patch_ca0132\n"); + codec_dbg(codec, "patch_ca0132\n"); spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; codec->spec = spec; + spec->codec = codec; + + spec->num_mixers = 1; + spec->mixers[0] = ca0132_mixer; + + spec->base_init_verbs = ca0132_base_init_verbs; + spec->base_exit_verbs = ca0132_base_exit_verbs; + spec->init_verbs[0] = ca0132_init_verbs0; + spec->init_verbs[1] = ca0132_init_verbs1; + spec->num_init_verbs = 2; + + INIT_DELAYED_WORK(&spec->unsol_hp_work, ca0132_unsol_hp_delayed); ca0132_init_chip(codec); ca0132_config(codec); + err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + if (err < 0) + return err; + codec->patch_ops = ca0132_patch_ops; + codec->pcm_format_first = 1; + codec->no_sticky_stream = 1; return 0; } @@ -1013,7 +4700,7 @@ static struct hda_codec_preset snd_hda_preset_ca0132[] = { MODULE_ALIAS("snd-hda-codec-id:11020011"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Creative CA0132, CA0132 HD-audio codec"); +MODULE_DESCRIPTION("Creative Sound Core3D codec"); static struct hda_codec_preset_list ca0132_list = { .preset = snd_hda_preset_ca0132, diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 61a71131711..387f0b55188 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -19,16 +19,15 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> +#include <sound/tlv.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" -#include <sound/tlv.h> +#include "hda_generic.h" /* */ @@ -36,44 +35,21 @@ struct cs_spec { struct hda_gen_spec gen; - struct auto_pin_cfg autocfg; - struct hda_multi_out multiout; - struct snd_kcontrol *vmaster_sw; - struct snd_kcontrol *vmaster_vol; - - hda_nid_t dac_nid[AUTO_CFG_MAX_OUTS]; - hda_nid_t slave_dig_outs[2]; - - unsigned int input_idx[AUTO_PIN_LAST]; - unsigned int capsrc_idx[AUTO_PIN_LAST]; - hda_nid_t adc_nid[AUTO_PIN_LAST]; - unsigned int adc_idx[AUTO_PIN_LAST]; - unsigned int num_inputs; - unsigned int cur_input; - unsigned int automic_idx; - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - hda_nid_t dig_in; - - const struct hda_bind_ctls *capture_bind[2]; - unsigned int gpio_mask; unsigned int gpio_dir; unsigned int gpio_data; unsigned int gpio_eapd_hp; /* EAPD GPIO bit for headphones */ unsigned int gpio_eapd_speaker; /* EAPD GPIO bit for speakers */ - struct hda_pcm pcm_rec[2]; /* PCM information */ - - unsigned int hp_detect:1; - unsigned int mic_detect:1; /* CS421x */ unsigned int spdif_detect:1; + unsigned int spdif_present:1; unsigned int sense_b:1; hda_nid_t vendor_nid; - struct hda_input_mux input_mux; - unsigned int last_input; + + /* for MBP SPDIF control */ + int (*spdif_sw_put)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); }; /* available models with CS420x */ @@ -84,7 +60,8 @@ enum { CS420X_GPIO_13, CS420X_GPIO_23, CS420X_MBP101, - CS420X_MBP101_COEF, + CS420X_MBP81, + CS420X_MBA42, CS420X_AUTO, /* aliases */ CS420X_IMAC27_122 = CS420X_GPIO_23, @@ -95,14 +72,15 @@ enum { enum { CS421X_CDB4210, CS421X_SENSE_B, + CS421X_STUMPY, }; /* Vendor-specific processing widget */ #define CS420X_VENDOR_NID 0x11 #define CS_DIG_OUT1_PIN_NID 0x10 #define CS_DIG_OUT2_PIN_NID 0x15 -#define CS_DMIC1_PIN_NID 0x12 -#define CS_DMIC2_PIN_NID 0x0e +#define CS_DMIC1_PIN_NID 0x0e +#define CS_DMIC2_PIN_NID 0x12 /* coef indices */ #define IDX_SPDIF_STAT 0x0000 @@ -136,6 +114,9 @@ enum { /* 0x0009 - 0x0014 -> 12 test regs */ /* 0x0015 - visibility reg */ +/* Cirrus Logic CS4208 */ +#define CS4208_VENDOR_NID 0x24 + /* * Cirrus Logic CS4210 * @@ -179,921 +160,53 @@ static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, AC_VERB_SET_PROC_COEF, coef); } - -#define HP_EVENT 1 -#define MIC_EVENT 2 - -/* - * PCM callbacks - */ -static int cs_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int cs_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int cs_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int cs_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int cs_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int cs_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); -} - -static int cs_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -static void cs_update_input_select(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - if (spec->cur_adc) - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); -} - -/* - * Analog capture - */ -static int cs_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nid[spec->cur_input]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - cs_update_input_select(codec); - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int cs_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct cs_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -/* - */ -static const struct hda_pcm_stream cs_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_playback_pcm_open, - .prepare = cs_playback_pcm_prepare, - .cleanup = cs_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .prepare = cs_capture_pcm_prepare, - .cleanup = cs_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .ops = { - .open = cs_dig_playback_pcm_open, - .close = cs_dig_playback_pcm_close, - .prepare = cs_dig_playback_pcm_prepare, - .cleanup = cs_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream cs_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -static int cs_build_pcms(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->pcm_info = info; - codec->num_pcms = 0; - - info->name = "Cirrus Analog"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = cs_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dac_nid[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = cs_pcm_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nid[spec->cur_input]; - codec->num_pcms++; - - if (!spec->multiout.dig_out_nid && !spec->dig_in) - return 0; - - info++; - info->name = "Cirrus Digital"; - info->pcm_type = spec->autocfg.dig_out_type[0]; - if (!info->pcm_type) - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - cs_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - cs_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; - } - codec->num_pcms++; - - return 0; -} - -/* - * parse codec topology - */ - -static hda_nid_t get_dac(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t dac; - if (!pin) - return 0; - if (snd_hda_get_connections(codec, pin, &dac, 1) != 1) - return 0; - return dac; -} - -static int is_ext_mic(struct hda_codec *codec, unsigned int idx) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t pin = cfg->inputs[idx].pin; - unsigned int val; - if (!is_jack_detectable(codec, pin)) - return 0; - val = snd_hda_codec_get_pincfg(codec, pin); - return (snd_hda_get_input_pin_attr(val) != INPUT_PIN_ATTR_INT); -} - -static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, - unsigned int *idxp) -{ - int i, idx; - hda_nid_t nid; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type != AC_WID_AUD_IN) - continue; - idx = snd_hda_get_conn_index(codec, nid, pin, false); - if (idx >= 0) { - *idxp = idx; - return nid; - } - } - return 0; -} - -static int is_active_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int val; - val = snd_hda_codec_get_pincfg(codec, nid); - return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); -} - -static int parse_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, extra_nids; - hda_nid_t dac; - - for (i = 0; i < cfg->line_outs; i++) { - dac = get_dac(codec, cfg->line_out_pins[i]); - if (!dac) - break; - spec->dac_nid[i] = dac; - } - spec->multiout.num_dacs = i; - spec->multiout.dac_nids = spec->dac_nid; - spec->multiout.max_channels = i * 2; - - /* add HP and speakers */ - extra_nids = 0; - for (i = 0; i < cfg->hp_outs; i++) { - dac = get_dac(codec, cfg->hp_pins[i]); - if (!dac) - break; - if (!i) - spec->multiout.hp_nid = dac; - else - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - for (i = 0; i < cfg->speaker_outs; i++) { - dac = get_dac(codec, cfg->speaker_pins[i]); - if (!dac) - break; - spec->multiout.extra_out_nid[extra_nids++] = dac; - } - - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = 0; - } - - return 0; -} - -static int parse_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - spec->input_idx[spec->num_inputs] = i; - spec->capsrc_idx[i] = spec->num_inputs++; - spec->cur_input = i; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - } - if (!spec->num_inputs) - return 0; - - /* check whether the automatic mic switch is available */ - if (spec->num_inputs == 2 && - cfg->inputs[0].type == AUTO_PIN_MIC && - cfg->inputs[1].type == AUTO_PIN_MIC) { - if (is_ext_mic(codec, cfg->inputs[0].pin)) { - if (!is_ext_mic(codec, cfg->inputs[1].pin)) { - spec->mic_detect = 1; - spec->automic_idx = 0; - } - } else { - if (is_ext_mic(codec, cfg->inputs[1].pin)) { - spec->mic_detect = 1; - spec->automic_idx = 1; - } - } - } - return 0; -} - - -static int parse_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - - if (!cfg->dig_outs) - return 0; - if (snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) < 1) - return 0; - spec->multiout.dig_out_nid = nid; - spec->multiout.share_spdif = 1; - if (cfg->dig_outs > 1 && - snd_hda_get_connections(codec, cfg->dig_out_pins[1], &nid, 1) > 0) { - spec->slave_dig_outs[0] = nid; - codec->slave_dig_outs = spec->slave_dig_outs; - } - return 0; -} - -static int parse_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int idx; - - if (cfg->dig_in_pin) - spec->dig_in = get_adc(codec, cfg->dig_in_pin, &idx); - return 0; -} - -/* - * create mixer controls - */ - -static const char * const dir_sfx[2] = { "Playback", "Capture" }; - -static int add_mute(struct hda_codec *codec, const char *name, int index, - unsigned int pval, int dir, struct snd_kcontrol **kctlp) -{ - char tmp[44]; - struct snd_kcontrol_new knew = - HDA_CODEC_MUTE_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, 0, *kctlp); -} - -static int add_volume(struct hda_codec *codec, const char *name, - int index, unsigned int pval, int dir, - struct snd_kcontrol **kctlp) -{ - char tmp[44]; - struct snd_kcontrol_new knew = - HDA_CODEC_VOLUME_IDX(tmp, index, 0, 0, HDA_OUTPUT); - knew.private_value = pval; - snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); - *kctlp = snd_ctl_new1(&knew, codec); - (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; - return snd_hda_ctl_add(codec, 0, *kctlp); -} - -static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) -{ - unsigned int caps; - - /* set the upper-limit for mixer amp to 0dB */ - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); - caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) - << AC_AMPCAP_NUM_STEPS_SHIFT; - snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); -} - -static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) -{ - struct cs_spec *spec = codec->spec; - unsigned int tlv[4]; - int err; - - spec->vmaster_sw = - snd_ctl_make_virtual_master("Master Playback Switch", NULL); - err = snd_hda_ctl_add(codec, dac, spec->vmaster_sw); - if (err < 0) - return err; - - snd_hda_set_vmaster_tlv(codec, dac, HDA_OUTPUT, tlv); - spec->vmaster_vol = - snd_ctl_make_virtual_master("Master Playback Volume", tlv); - err = snd_hda_ctl_add(codec, dac, spec->vmaster_vol); - if (err < 0) - return err; - return 0; -} - -static int add_output(struct hda_codec *codec, hda_nid_t dac, int idx, - int num_ctls, int type) -{ - struct cs_spec *spec = codec->spec; - const char *name; - int err, index; - struct snd_kcontrol *kctl; - static const char * const speakers[] = { - "Front Speaker", "Surround Speaker", "Bass Speaker" - }; - static const char * const line_outs[] = { - "Front Line Out", "Surround Line Out", "Bass Line Out" - }; - - fix_volume_caps(codec, dac); - if (!spec->vmaster_sw) { - err = add_vmaster(codec, dac); - if (err < 0) - return err; - } - - index = 0; - switch (type) { - case AUTO_PIN_HP_OUT: - name = "Headphone"; - index = idx; - break; - case AUTO_PIN_SPEAKER_OUT: - if (num_ctls > 1) - name = speakers[idx]; - else - name = "Speaker"; - break; - default: - if (num_ctls > 1) - name = line_outs[idx]; - else - name = "Line Out"; - break; - } - - err = add_mute(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_sw, kctl); - if (err < 0) - return err; - - err = add_volume(codec, name, index, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_vol, kctl); - if (err < 0) - return err; - - return 0; -} - -static int build_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - for (i = 0; i < cfg->line_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->line_out_pins[i]), - i, cfg->line_outs, cfg->line_out_type); - if (err < 0) - return err; - } - for (i = 0; i < cfg->hp_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->hp_pins[i]), - i, cfg->hp_outs, AUTO_PIN_HP_OUT); - if (err < 0) - return err; - } - for (i = 0; i < cfg->speaker_outs; i++) { - err = add_output(codec, get_dac(codec, cfg->speaker_pins[i]), - i, cfg->speaker_outs, AUTO_PIN_SPEAKER_OUT); - if (err < 0) - return err; - } - return 0; -} - -/* - */ - -static const struct snd_kcontrol_new cs_capture_ctls[] = { - HDA_BIND_SW("Capture Switch", 0), - HDA_BIND_VOL("Capture Volume", 0), -}; - -static int change_cur_input(struct hda_codec *codec, unsigned int idx, - int force) -{ - struct cs_spec *spec = codec->spec; - - if (spec->cur_input == idx && !force) - return 0; - if (spec->cur_adc && spec->cur_adc != spec->adc_nid[idx]) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = spec->adc_nid[idx]; - snd_hda_codec_setup_stream(codec, spec->cur_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - } - spec->cur_input = idx; - cs_update_input_select(codec); - return 1; -} - -static int cs_capture_source_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int idx; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - idx = spec->input_idx[uinfo->value.enumerated.item]; - snd_hda_get_pin_label(codec, cfg->inputs[idx].pin, cfg, - uinfo->value.enumerated.name, - sizeof(uinfo->value.enumerated.name), NULL); - return 0; -} - -static int cs_capture_source_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->capsrc_idx[spec->cur_input]; - return 0; -} - -static int cs_capture_source_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - unsigned int idx = ucontrol->value.enumerated.item[0]; - - if (idx >= spec->num_inputs) - return -EINVAL; - idx = spec->input_idx[idx]; - return change_cur_input(codec, idx, 0); -} - -static const struct snd_kcontrol_new cs_capture_source = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs_capture_source_info, - .get = cs_capture_source_get, - .put = cs_capture_source_put, -}; - -static const struct hda_bind_ctls *make_bind_capture(struct hda_codec *codec, - struct hda_ctl_ops *ops) -{ - struct cs_spec *spec = codec->spec; - struct hda_bind_ctls *bind; - int i, n; - - bind = kzalloc(sizeof(*bind) + sizeof(long) * (spec->num_inputs + 1), - GFP_KERNEL); - if (!bind) - return NULL; - bind->ops = ops; - n = 0; - for (i = 0; i < AUTO_PIN_LAST; i++) { - if (!spec->adc_nid[i]) - continue; - bind->values[n++] = - HDA_COMPOSE_AMP_VAL(spec->adc_nid[i], 3, - spec->adc_idx[i], HDA_INPUT); - } - return bind; -} - -/* add a (input-boost) volume control to the given input pin */ -static int add_input_volume_control(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - int item) -{ - hda_nid_t pin = cfg->inputs[item].pin; - u32 caps; - const char *label; - struct snd_kcontrol *kctl; - - if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) - return 0; - caps = query_amp_caps(codec, pin, HDA_INPUT); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (caps <= 1) - return 0; - label = hda_get_autocfg_input_label(codec, cfg, item); - return add_volume(codec, label, 0, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); -} - -static int build_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int i, err; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - int n; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - for (n = 0; n < AUTO_PIN_LAST; n++) { - if (!spec->adc_nid[n]) - continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); - if (err < 0) - return err; - } - } - - if (spec->num_inputs > 1 && !spec->mic_detect) { - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs_capture_source, codec)); - if (err < 0) - return err; - } - - for (i = 0; i < spec->num_inputs; i++) { - err = add_input_volume_control(codec, &spec->autocfg, i); - if (err < 0) - return err; - } - - return 0; -} - -/* - */ - -static int build_digital_output(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - if (!spec->multiout.dig_out_nid) - return 0; - - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); - if (err < 0) - return err; - return 0; -} - -static int build_digital_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - if (spec->dig_in) - return snd_hda_create_spdif_in_ctls(codec, spec->dig_in); - return 0; -} - /* * auto-mute and auto-mic switching * CS421x auto-output redirecting * HP/SPK/SPDIF */ -static void cs_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int hp_present; - unsigned int spdif_present; - hda_nid_t nid; - int i; - spdif_present = 0; - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - if (is_jack_detectable(codec, nid)) { - /* - TODO: SPDIF output redirect when SENSE_B is enabled. - Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) - assumed. - */ - if (snd_hda_jack_detect(codec, nid) - /* && spec->sense_b */) - spdif_present = 1; - } - } - - hp_present = 0; - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - hp_present = snd_hda_jack_detect(codec, nid); - if (hp_present) - break; - } + /* mute HPs if spdif jack (SENSE_B) is present */ + spec->gen.master_mute = !!(spec->spdif_present && spec->sense_b); - /* mute speakers if spdif or hp jack is plugged in */ - for (i = 0; i < cfg->speaker_outs; i++) { - int pin_ctl = hp_present ? 0 : PIN_OUT; - /* detect on spdif is specific to CS4210 */ - if (spdif_present && (spec->vendor_nid == CS4210_VENDOR_NID)) - pin_ctl = 0; + snd_hda_gen_update_outputs(codec); - nid = cfg->speaker_pins[i]; - snd_hda_set_pin_ctl(codec, nid, pin_ctl); - } - if (spec->gpio_eapd_hp) { - unsigned int gpio = hp_present ? + if (spec->gpio_eapd_hp || spec->gpio_eapd_speaker) { + spec->gpio_data = spec->gen.hp_jack_present ? spec->gpio_eapd_hp : spec->gpio_eapd_speaker; snd_hda_codec_write(codec, 0x01, 0, - AC_VERB_SET_GPIO_DATA, gpio); - } - - /* specific to CS4210 */ - if (spec->vendor_nid == CS4210_VENDOR_NID) { - /* mute HPs if spdif jack (SENSE_B) is present */ - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, - (spdif_present && spec->sense_b) ? 0 : PIN_HP); - } - - /* SPDIF TX on/off */ - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - snd_hda_set_pin_ctl(codec, nid, - spdif_present ? PIN_OUT : 0); - - } - /* Update board GPIOs if neccessary ... */ - } -} - -/* - * Auto-input redirect for CS421x - * Switch max 3 inputs of a single ADC (nid 3) -*/ - -static void cs_automic(struct hda_codec *codec, struct hda_jack_tbl *tbl) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - unsigned int present; - - nid = cfg->inputs[spec->automic_idx].pin; - present = snd_hda_jack_detect(codec, nid); - - /* specific to CS421x, single ADC */ - if (spec->vendor_nid == CS420X_VENDOR_NID) { - if (present) - change_cur_input(codec, spec->automic_idx, 0); - else - change_cur_input(codec, !spec->automic_idx, 0); - } else { - if (present) { - if (spec->cur_input != spec->automic_idx) { - spec->last_input = spec->cur_input; - spec->cur_input = spec->automic_idx; - } - } else { - spec->cur_input = spec->last_input; - } - cs_update_input_select(codec); + AC_VERB_SET_GPIO_DATA, spec->gpio_data); } } -/* - */ - -static void init_output(struct hda_codec *codec) +static bool is_active_pin(struct hda_codec *codec, hda_nid_t nid) { - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - /* mute first */ - for (i = 0; i < spec->multiout.num_dacs; i++) - snd_hda_codec_write(codec, spec->multiout.dac_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - if (spec->multiout.hp_nid) - snd_hda_codec_write(codec, spec->multiout.hp_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { - if (!spec->multiout.extra_out_nid[i]) - break; - snd_hda_codec_write(codec, spec->multiout.extra_out_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); - } - - /* set appropriate pin controls */ - for (i = 0; i < cfg->line_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT); - /* HP */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, PIN_HP); - if (!cfg->speaker_outs) - continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable_callback(codec, nid, HP_EVENT, cs_automute); - spec->hp_detect = 1; - } - } - - /* Speaker */ - for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT); - - /* SPDIF is enabled on presence detect for CS421x */ - if (spec->hp_detect || spec->spdif_detect) - cs_automute(codec, NULL); + unsigned int val; + val = snd_hda_codec_get_pincfg(codec, nid); + return (get_defcfg_connect(val) != AC_JACK_PORT_NONE); } -static void init_input(struct hda_codec *codec) +static void init_input_coef(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int coef; - int i; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int ctl; - hda_nid_t pin = cfg->inputs[i].pin; - if (!spec->adc_nid[i]) - continue; - /* set appropriate pin control and mute first */ - ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, ctl); - snd_hda_codec_write(codec, spec->adc_nid[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(spec->adc_idx[i])); - if (spec->mic_detect && spec->automic_idx == i) - snd_hda_jack_detect_enable_callback(codec, pin, MIC_EVENT, cs_automic); - } /* CS420x has multiple ADC, CS421x has single ADC */ if (spec->vendor_nid == CS420X_VENDOR_NID) { - change_cur_input(codec, spec->cur_input, 1); - if (spec->mic_detect) - cs_automic(codec, NULL); - - coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ + coef = cs_vendor_coef_get(codec, IDX_BEEP_CFG); if (is_active_pin(codec, CS_DMIC2_PIN_NID)) - coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */ + coef |= 1 << 4; /* DMIC2 2 chan on, GPIO1 off */ if (is_active_pin(codec, CS_DMIC1_PIN_NID)) - coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off + coef |= 1 << 3; /* DMIC1 2 chan on, GPIO0 off * No effect if SPDIF_OUT2 is * selected in IDX_SPDIF_CTL. */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); - } else { - if (spec->mic_detect) - cs_automic(codec, NULL); - else { - spec->cur_adc = spec->adc_nid[spec->cur_input]; - cs_update_input_select(codec); - } + + cs_vendor_coef_set(codec, IDX_BEEP_CFG, coef); } } @@ -1106,13 +219,26 @@ static const struct hda_verb cs_coef_init_verbs[] = { | 0x1000 /* Enable DACs High Pass Filter */ | 0x0400 /* Disable Coefficient Auto increment */ )}, + /* ADC1/2 - Digital and Analog Soft Ramp */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x000a}, /* Beep */ - {0x11, AC_VERB_SET_COEF_INDEX, IDX_DAC_CFG}, + {0x11, AC_VERB_SET_COEF_INDEX, IDX_BEEP_CFG}, {0x11, AC_VERB_SET_PROC_COEF, 0x0007}, /* Enable Beep thru DAC1/2/3 */ {} /* terminator */ }; +static const struct hda_verb cs4208_coef_init_verbs[] = { + {0x01, AC_VERB_SET_POWER_STATE, 0x00}, /* AFG: D0 */ + {0x24, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ + {0x24, AC_VERB_SET_COEF_INDEX, 0x0033}, + {0x24, AC_VERB_SET_PROC_COEF, 0x0001}, /* A1 ICS */ + {0x24, AC_VERB_SET_COEF_INDEX, 0x0034}, + {0x24, AC_VERB_SET_PROC_COEF, 0x1C01}, /* A1 Enable, A Thresh = 300mV */ + {} /* terminator */ +}; + /* Errata: CS4207 rev C0/C1/C2 Silicon * * http://www.cirrus.com/en/pubs/errata/ER880C3.pdf @@ -1162,16 +288,8 @@ static const struct hda_verb cs_errata_init_verbs[] = { {} /* terminator */ }; -static const struct hda_verb mbp101_init_verbs[] = { - {0x11, AC_VERB_SET_COEF_INDEX, 0x0002}, - {0x11, AC_VERB_SET_PROC_COEF, 0x100a}, - {0x11, AC_VERB_SET_COEF_INDEX, 0x0004}, - {0x11, AC_VERB_SET_PROC_COEF, 0x000f}, - {} -}; - /* SPDIF setup */ -static void init_digital(struct hda_codec *codec) +static void init_digital_coef(struct hda_codec *codec) { unsigned int coef; @@ -1189,10 +307,15 @@ static int cs_init(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; - /* init_verb sequence for C0/C1/C2 errata*/ - snd_hda_sequence_write(codec, cs_errata_init_verbs); + if (spec->vendor_nid == CS420X_VENDOR_NID) { + /* init_verb sequence for C0/C1/C2 errata*/ + snd_hda_sequence_write(codec, cs_errata_init_verbs); + snd_hda_sequence_write(codec, cs_coef_init_verbs); + } else if (spec->vendor_nid == CS4208_VENDOR_NID) { + snd_hda_sequence_write(codec, cs4208_coef_init_verbs); + } - snd_hda_sequence_write(codec, cs_coef_init_verbs); + snd_hda_gen_init(codec); if (spec->gpio_mask) { snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, @@ -1203,53 +326,30 @@ static int cs_init(struct hda_codec *codec) spec->gpio_data); } - init_output(codec); - init_input(codec); - init_digital(codec); + if (spec->vendor_nid == CS420X_VENDOR_NID) { + init_input_coef(codec); + init_digital_coef(codec); + } return 0; } static int cs_build_controls(struct hda_codec *codec) { - struct cs_spec *spec = codec->spec; int err; - err = build_output(codec); + err = snd_hda_gen_build_controls(codec); if (err < 0) return err; - err = build_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - err = build_digital_input(codec); - if (err < 0) - return err; - err = cs_init(codec); - if (err < 0) - return err; - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); return 0; } -static void cs_free(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - kfree(spec->capture_bind[0]); - kfree(spec->capture_bind[1]); - snd_hda_gen_free(&spec->gen); - kfree(codec->spec); -} +#define cs_free snd_hda_gen_free static const struct hda_codec_ops cs_patch_ops = { .build_controls = cs_build_controls, - .build_pcms = cs_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = cs_init, .free = cs_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1260,22 +360,14 @@ static int cs_parse_auto_config(struct hda_codec *codec) struct cs_spec *spec = codec->spec; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) return err; - err = parse_output(codec); - if (err < 0) - return err; - err = parse_input(codec); - if (err < 0) - return err; - err = parse_digital_output(codec); - if (err < 0) - return err; - err = parse_digital_input(codec); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; + return 0; } @@ -1286,6 +378,8 @@ static const struct hda_model_fixup cs420x_models[] = { { .id = CS420X_IMAC27_122, .name = "imac27_122" }, { .id = CS420X_APPLE, .name = "apple" }, { .id = CS420X_MBP101, .name = "mbp101" }, + { .id = CS420X_MBP81, .name = "mbp81" }, + { .id = CS420X_MBA42, .name = "mba42" }, {} }; @@ -1298,8 +392,10 @@ static const struct snd_pci_quirk cs420x_fixup_tbl[] = { /*SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27),*/ /* codec SSID */ + SND_PCI_QUIRK(0x106b, 0x1c00, "MacBookPro 8,1", CS420X_MBP81), SND_PCI_QUIRK(0x106b, 0x2000, "iMac 12,2", CS420X_IMAC27_122), SND_PCI_QUIRK(0x106b, 0x2800, "MacBookPro 10,1", CS420X_MBP101), + SND_PCI_QUIRK(0x106b, 0x5b00, "MacBookAir 4,2", CS420X_MBA42), SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS420X_APPLE), {} /* terminator */ }; @@ -1353,6 +449,43 @@ static const struct hda_pintbl mbp101_pincfgs[] = { {} /* terminator */ }; +static const struct hda_pintbl mba42_pincfgs[] = { + { 0x09, 0x012b4030 }, /* HP */ + { 0x0a, 0x400000f0 }, + { 0x0b, 0x90100120 }, /* speaker */ + { 0x0c, 0x400000f0 }, + { 0x0d, 0x90a00110 }, /* mic */ + { 0x0e, 0x400000f0 }, + { 0x0f, 0x400000f0 }, + { 0x10, 0x400000f0 }, + { 0x12, 0x400000f0 }, + { 0x15, 0x400000f0 }, + {} /* terminator */ +}; + +static const struct hda_pintbl mba6_pincfgs[] = { + { 0x10, 0x032120f0 }, /* HP */ + { 0x11, 0x500000f0 }, + { 0x12, 0x90100010 }, /* Speaker */ + { 0x13, 0x500000f0 }, + { 0x14, 0x500000f0 }, + { 0x15, 0x770000f0 }, + { 0x16, 0x770000f0 }, + { 0x17, 0x430000f0 }, + { 0x18, 0x43ab9030 }, /* Mic */ + { 0x19, 0x770000f0 }, + { 0x1a, 0x770000f0 }, + { 0x1b, 0x770000f0 }, + { 0x1c, 0x90a00090 }, + { 0x1d, 0x500000f0 }, + { 0x1e, 0x500000f0 }, + { 0x1f, 0x500000f0 }, + { 0x20, 0x500000f0 }, + { 0x21, 0x430000f0 }, + { 0x22, 0x430000f0 }, + {} /* terminator */ +}; + static void cs420x_fixup_gpio_13(struct hda_codec *codec, const struct hda_fixup *fix, int action) { @@ -1408,28 +541,51 @@ static const struct hda_fixup cs420x_fixups[] = { .type = HDA_FIXUP_PINS, .v.pins = mbp101_pincfgs, .chained = true, - .chain_id = CS420X_MBP101_COEF, + .chain_id = CS420X_GPIO_13, }, - [CS420X_MBP101_COEF] = { + [CS420X_MBP81] = { .type = HDA_FIXUP_VERBS, - .v.verbs = mbp101_init_verbs, + .v.verbs = (const struct hda_verb[]) { + /* internal mic ADC2: right only, single ended */ + {0x11, AC_VERB_SET_COEF_INDEX, IDX_ADC_CFG}, + {0x11, AC_VERB_SET_PROC_COEF, 0x102a}, + {} + }, + .chained = true, + .chain_id = CS420X_GPIO_13, + }, + [CS420X_MBA42] = { + .type = HDA_FIXUP_PINS, + .v.pins = mba42_pincfgs, .chained = true, .chain_id = CS420X_GPIO_13, }, }; +static struct cs_spec *cs_alloc_spec(struct hda_codec *codec, int vendor_nid) +{ + struct cs_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return NULL; + codec->spec = spec; + spec->vendor_nid = vendor_nid; + snd_hda_gen_spec_init(&spec->gen); + + return spec; +} + static int patch_cs420x(struct hda_codec *codec) { struct cs_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = cs_alloc_spec(codec, CS420X_VENDOR_NID); if (!spec) return -ENOMEM; - codec->spec = spec; - snd_hda_gen_init(&spec->gen); - spec->vendor_nid = CS420X_VENDOR_NID; + spec->gen.automute_hook = cs_automute; snd_hda_pick_fixup(codec, cs420x_models, cs420x_fixup_tbl, cs420x_fixups); @@ -1447,7 +603,165 @@ static int patch_cs420x(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; + return err; +} + +/* + * CS4208 support: + * Its layout is no longer compatible with CS4206/CS4207 + */ +enum { + CS4208_MAC_AUTO, + CS4208_MBA6, + CS4208_MBP11, + CS4208_GPIO0, +}; + +static const struct hda_model_fixup cs4208_models[] = { + { .id = CS4208_GPIO0, .name = "gpio0" }, + { .id = CS4208_MBA6, .name = "mba6" }, + { .id = CS4208_MBP11, .name = "mbp11" }, + {} +}; + +static const struct snd_pci_quirk cs4208_fixup_tbl[] = { + SND_PCI_QUIRK_VENDOR(0x106b, "Apple", CS4208_MAC_AUTO), + {} /* terminator */ +}; + +/* codec SSID matching */ +static const struct snd_pci_quirk cs4208_mac_fixup_tbl[] = { + SND_PCI_QUIRK(0x106b, 0x5e00, "MacBookPro 11,2", CS4208_MBP11), + SND_PCI_QUIRK(0x106b, 0x7100, "MacBookAir 6,1", CS4208_MBA6), + SND_PCI_QUIRK(0x106b, 0x7200, "MacBookAir 6,2", CS4208_MBA6), + {} /* terminator */ +}; + +static void cs4208_fixup_gpio0(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct cs_spec *spec = codec->spec; + spec->gpio_eapd_hp = 0; + spec->gpio_eapd_speaker = 1; + spec->gpio_mask = spec->gpio_dir = + spec->gpio_eapd_hp | spec->gpio_eapd_speaker; + } +} + +static const struct hda_fixup cs4208_fixups[]; + +/* remap the fixup from codec SSID and apply it */ +static void cs4208_fixup_mac(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + snd_hda_pick_fixup(codec, NULL, cs4208_mac_fixup_tbl, cs4208_fixups); + if (codec->fixup_id < 0 || codec->fixup_id == CS4208_MAC_AUTO) + codec->fixup_id = CS4208_GPIO0; /* default fixup */ + snd_hda_apply_fixup(codec, action); +} + +static int cs4208_spdif_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct cs_spec *spec = codec->spec; + hda_nid_t pin = spec->gen.autocfg.dig_out_pins[0]; + int pinctl = ucontrol->value.integer.value[0] ? PIN_OUT : 0; + + snd_hda_set_pin_ctl_cache(codec, pin, pinctl); + return spec->spdif_sw_put(kcontrol, ucontrol); +} + +/* hook the SPDIF switch */ +static void cs4208_fixup_spdif_switch(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_BUILD) { + struct cs_spec *spec = codec->spec; + struct snd_kcontrol *kctl; + + if (!spec->gen.autocfg.dig_out_pins[0]) + return; + kctl = snd_hda_find_mixer_ctl(codec, "IEC958 Playback Switch"); + if (!kctl) + return; + spec->spdif_sw_put = kctl->put; + kctl->put = cs4208_spdif_sw_put; + } +} + +static const struct hda_fixup cs4208_fixups[] = { + [CS4208_MBA6] = { + .type = HDA_FIXUP_PINS, + .v.pins = mba6_pincfgs, + .chained = true, + .chain_id = CS4208_GPIO0, + }, + [CS4208_MBP11] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs4208_fixup_spdif_switch, + .chained = true, + .chain_id = CS4208_GPIO0, + }, + [CS4208_GPIO0] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs4208_fixup_gpio0, + }, + [CS4208_MAC_AUTO] = { + .type = HDA_FIXUP_FUNC, + .v.func = cs4208_fixup_mac, + }, +}; + +/* correct the 0dB offset of input pins */ +static void cs4208_fix_amp_caps(struct hda_codec *codec, hda_nid_t adc) +{ + unsigned int caps; + + caps = query_amp_caps(codec, adc, HDA_INPUT); + caps &= ~(AC_AMPCAP_OFFSET); + caps |= 0x02; + snd_hda_override_amp_caps(codec, adc, HDA_INPUT, caps); +} + +static int patch_cs4208(struct hda_codec *codec) +{ + struct cs_spec *spec; + int err; + + spec = cs_alloc_spec(codec, CS4208_VENDOR_NID); + if (!spec) + return -ENOMEM; + + spec->gen.automute_hook = cs_automute; + /* exclude NID 0x10 (HP) from output volumes due to different steps */ + spec->gen.out_vol_mask = 1ULL << 0x10; + + snd_hda_pick_fixup(codec, cs4208_models, cs4208_fixup_tbl, + cs4208_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + snd_hda_override_wcaps(codec, 0x18, + get_wcaps(codec, 0x18) | AC_WCAP_STEREO); + cs4208_fix_amp_caps(codec, 0x18); + cs4208_fix_amp_caps(codec, 0x1b); + cs4208_fix_amp_caps(codec, 0x1c); + + err = cs_parse_auto_config(codec); + if (err < 0) + goto error; + + codec->patch_ops = cs_patch_ops; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + + return 0; + + error: + cs_free(codec); return err; } @@ -1462,6 +776,7 @@ static int patch_cs420x(struct hda_codec *codec) /* CS4210 board names */ static const struct hda_model_fixup cs421x_models[] = { { .id = CS421X_CDB4210, .name = "cdb4210" }, + { .id = CS421X_STUMPY, .name = "stumpy" }, {} }; @@ -1483,6 +798,17 @@ static const struct hda_pintbl cdb4210_pincfgs[] = { {} /* terminator */ }; +/* Stumpy ChromeBox */ +static const struct hda_pintbl stumpy_pincfgs[] = { + { 0x05, 0x022120f0 }, + { 0x06, 0x901700f0 }, + { 0x07, 0x02a120f0 }, + { 0x08, 0x77a70037 }, + { 0x09, 0x77a6003e }, + { 0x0a, 0x434510f0 }, + {} /* terminator */ +}; + /* Setup GPIO/SENSE for each board (if used) */ static void cs421x_fixup_sense_b(struct hda_codec *codec, const struct hda_fixup *fix, int action) @@ -1502,7 +828,11 @@ static const struct hda_fixup cs421x_fixups[] = { [CS421X_SENSE_B] = { .type = HDA_FIXUP_FUNC, .v.func = cs421x_fixup_sense_b, - } + }, + [CS421X_STUMPY] = { + .type = HDA_FIXUP_PINS, + .v.pins = stumpy_pincfgs, + }, }; static const struct hda_verb cs421x_coef_init_verbs[] = { @@ -1606,7 +936,7 @@ static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, } } -static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { +static const struct snd_kcontrol_new cs421x_speaker_boost_ctl = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1651,20 +981,44 @@ static void cs4210_pinmux_init(struct hda_codec *codec) } } -static void init_cs421x_digital(struct hda_codec *codec) +static void cs4210_spdif_automute(struct hda_codec *codec, + struct hda_jack_tbl *tbl) { struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + bool spdif_present = false; + hda_nid_t spdif_pin = spec->gen.autocfg.dig_out_pins[0]; + + /* detect on spdif is specific to CS4210 */ + if (!spec->spdif_detect || + spec->vendor_nid != CS4210_VENDOR_NID) + return; + + spdif_present = snd_hda_jack_detect(codec, spdif_pin); + if (spdif_present == spec->spdif_present) + return; + spec->spdif_present = spdif_present; + /* SPDIF TX on/off */ + if (spdif_present) + snd_hda_set_pin_ctl(codec, spdif_pin, + spdif_present ? PIN_OUT : 0); + + cs_automute(codec); +} + +static void parse_cs421x_digital(struct hda_codec *codec) +{ + struct cs_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int i; for (i = 0; i < cfg->dig_outs; i++) { hda_nid_t nid = cfg->dig_out_pins[i]; - if (!cfg->speaker_outs) - continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - snd_hda_jack_detect_enable_callback(codec, nid, SPDIF_EVENT, cs_automute); spec->spdif_detect = 1; + snd_hda_jack_detect_enable_callback(codec, nid, + SPDIF_EVENT, + cs4210_spdif_automute); } } } @@ -1679,6 +1033,8 @@ static int cs421x_init(struct hda_codec *codec) cs4210_pinmux_init(codec); } + snd_hda_gen_init(codec); + if (spec->gpio_mask) { snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, spec->gpio_mask); @@ -1688,234 +1044,61 @@ static int cs421x_init(struct hda_codec *codec) spec->gpio_data); } - init_output(codec); - init_input(codec); - init_cs421x_digital(codec); - - return 0; -} - -/* - * CS4210 Input MUX (1 ADC) - */ -static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_info(&spec->input_mux, uinfo); -} - -static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_input; - return 0; -} - -static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_nid[0], &spec->cur_input); - -} - -static struct snd_kcontrol_new cs421x_capture_source = { - - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs421x_mux_enum_info, - .get = cs421x_mux_enum_get, - .put = cs421x_mux_enum_put, -}; - -static int cs421x_add_input_volume_control(struct hda_codec *codec, int item) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - const struct hda_input_mux *imux = &spec->input_mux; - hda_nid_t pin = cfg->inputs[item].pin; - struct snd_kcontrol *kctl; - u32 caps; - - if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) - return 0; - - caps = query_amp_caps(codec, pin, HDA_INPUT); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (caps <= 1) - return 0; - - return add_volume(codec, imux->items[item].label, 0, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); -} - -/* add a (input-boost) volume control to the given input pin */ -static int build_cs421x_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux = &spec->input_mux; - int i, err, type_idx; - const char *label; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - int n; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - for (n = 0; n < AUTO_PIN_LAST; n++) { - if (!spec->adc_nid[n]) - continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); - if (err < 0) - return err; - } - } - - /* Add Input MUX Items + Capture Volume/Switch */ - for (i = 0; i < spec->num_inputs; i++) { - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx); - - err = cs421x_add_input_volume_control(codec, i); - if (err < 0) - return err; - } - - /* - Add 'Capture Source' Switch if - * 2 inputs and no mic detec - * 3 inputs - */ - if ((spec->num_inputs == 2 && !spec->mic_detect) || - (spec->num_inputs == 3)) { + init_input_coef(codec); - err = snd_hda_ctl_add(codec, spec->adc_nid[0], - snd_ctl_new1(&cs421x_capture_source, codec)); - if (err < 0) - return err; - } + cs4210_spdif_automute(codec, NULL); return 0; } -/* Single DAC (Mute/Gain) */ -static int build_cs421x_output(struct hda_codec *codec) +static int cs421x_build_controls(struct hda_codec *codec) { - hda_nid_t dac = CS4210_DAC_NID; struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct snd_kcontrol *kctl; int err; - char *name = "Master"; - - fix_volume_caps(codec, dac); - - err = add_mute(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = add_volume(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); + err = snd_hda_gen_build_controls(codec); if (err < 0) return err; - if (cfg->speaker_outs && (spec->vendor_nid == CS4210_VENDOR_NID)) { + if (spec->gen.autocfg.speaker_outs && + spec->vendor_nid == CS4210_VENDOR_NID) { err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); + snd_ctl_new1(&cs421x_speaker_boost_ctl, codec)); if (err < 0) return err; } - return err; -} - -static int cs421x_build_controls(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = build_cs421x_output(codec); - if (err < 0) - return err; - err = build_cs421x_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - err = cs421x_init(codec); - if (err < 0) - return err; - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - return 0; } -static int parse_cs421x_input(struct hda_codec *codec) +static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) { - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - spec->cur_input = spec->last_input = i; - spec->num_inputs++; + unsigned int caps; - /* check whether the automatic mic switch is available */ - if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) { - spec->mic_detect = 1; - spec->automic_idx = i; - } - } - return 0; + /* set the upper-limit for mixer amp to 0dB */ + caps = query_amp_caps(codec, dac, HDA_OUTPUT); + caps &= ~(0x7f << AC_AMPCAP_NUM_STEPS_SHIFT); + caps |= ((caps >> AC_AMPCAP_OFFSET_SHIFT) & 0x7f) + << AC_AMPCAP_NUM_STEPS_SHIFT; + snd_hda_override_amp_caps(codec, dac, HDA_OUTPUT, caps); } static int cs421x_parse_auto_config(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; + hda_nid_t dac = CS4210_DAC_NID; int err; - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - err = parse_output(codec); - if (err < 0) - return err; - err = parse_cs421x_input(codec); + fix_volume_caps(codec, dac); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); if (err < 0) return err; - err = parse_digital_output(codec); + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; + + parse_cs421x_digital(codec); return 0; } @@ -1946,9 +1129,9 @@ static int cs421x_suspend(struct hda_codec *codec) } #endif -static struct hda_codec_ops cs421x_patch_ops = { +static const struct hda_codec_ops cs421x_patch_ops = { .build_controls = cs421x_build_controls, - .build_pcms = cs_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = cs421x_init, .free = cs_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1962,13 +1145,11 @@ static int patch_cs4210(struct hda_codec *codec) struct cs_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = cs_alloc_spec(codec, CS4210_VENDOR_NID); if (!spec) return -ENOMEM; - codec->spec = spec; - snd_hda_gen_init(&spec->gen); - spec->vendor_nid = CS4210_VENDOR_NID; + spec->gen.automute_hook = cs_automute; snd_hda_pick_fixup(codec, cs421x_models, cs421x_fixup_tbl, cs421x_fixups); @@ -1993,7 +1174,6 @@ static int patch_cs4210(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; return err; } @@ -2002,13 +1182,9 @@ static int patch_cs4213(struct hda_codec *codec) struct cs_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); + spec = cs_alloc_spec(codec, CS4213_VENDOR_NID); if (!spec) return -ENOMEM; - codec->spec = spec; - snd_hda_gen_init(&spec->gen); - - spec->vendor_nid = CS4213_VENDOR_NID; err = cs421x_parse_auto_config(codec); if (err < 0) @@ -2019,7 +1195,6 @@ static int patch_cs4213(struct hda_codec *codec) error: cs_free(codec); - codec->spec = NULL; return err; } @@ -2030,6 +1205,7 @@ static int patch_cs4213(struct hda_codec *codec) static const struct hda_codec_preset snd_hda_preset_cirrus[] = { { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, + { .id = 0x10134208, .name = "CS4208", .patch = patch_cs4208 }, { .id = 0x10134210, .name = "CS4210", .patch = patch_cs4210 }, { .id = 0x10134213, .name = "CS4213", .patch = patch_cs4213 }, {} /* terminator */ @@ -2037,6 +1213,7 @@ static const struct hda_codec_preset snd_hda_preset_cirrus[] = { MODULE_ALIAS("snd-hda-codec-id:10134206"); MODULE_ALIAS("snd-hda-codec-id:10134207"); +MODULE_ALIAS("snd-hda-codec-id:10134208"); MODULE_ALIAS("snd-hda-codec-id:10134210"); MODULE_ALIAS("snd-hda-codec-id:10134213"); diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index c8fdaaefe70..061ea5965dd 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -22,14 +22,18 @@ */ #include <linux/init.h> -#include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" +#include "hda_jack.h" +#include "hda_generic.h" + +#undef ENABLE_CMI_STATIC_QUIRKS + +#ifdef ENABLE_CMI_STATIC_QUIRKS #define NUM_PINS 11 @@ -43,8 +47,14 @@ enum { CMI_AUTO, /* let driver guess it */ CMI_MODELS }; +#endif /* ENABLE_CMI_STATIC_QUIRKS */ struct cmi_spec { + struct hda_gen_spec gen; + +#ifdef ENABLE_CMI_STATIC_QUIRKS + /* below are only for static models */ + int board_config; unsigned int no_line_in: 1; /* no line-in (5-jack) */ unsigned int front_panel: 1; /* has front-panel 2-jack */ @@ -75,8 +85,10 @@ struct cmi_spec { /* multichannel pins */ struct hda_verb multi_init[9]; /* 2 verbs for each pin + terminator */ +#endif /* ENABLE_CMI_STATIC_QUIRKS */ }; +#ifdef ENABLE_CMI_STATIC_QUIRKS /* * input MUX */ @@ -356,77 +368,6 @@ static int cmi9880_build_controls(struct hda_codec *codec) return 0; } -/* fill in the multi_dac_nids table, which will decide - which audio widget to use for each channel */ -static int cmi9880_fill_multi_dac_nids(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int assigned[4]; - int i, j; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->dac_nids, 0, sizeof(spec->dac_nids)); - memset(assigned, 0, sizeof(assigned)); - /* check the pins we found */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - /* nid 0x0b~0x0e is hardwired to audio widget 0x3~0x6 */ - if (nid >= 0x0b && nid <= 0x0e) { - spec->dac_nids[i] = (nid - 0x0b) + 0x03; - assigned[nid - 0x0b] = 1; - } - } - /* left pin can be connect to any audio widget */ - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - if (nid <= 0x0e) - continue; - /* search for an empty channel */ - for (j = 0; j < cfg->line_outs; j++) { - if (! assigned[j]) { - spec->dac_nids[i] = j + 0x03; - assigned[j] = 1; - break; - } - } - } - spec->num_dacs = cfg->line_outs; - return 0; -} - -/* create multi_init table, which is used for multichannel initialization */ -static int cmi9880_fill_multi_init(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct cmi_spec *spec = codec->spec; - hda_nid_t nid; - int i, j, k; - - /* clear the table, only one c-media dac assumed here */ - memset(spec->multi_init, 0, sizeof(spec->multi_init)); - for (j = 0, i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - /* set as output */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_PIN_WIDGET_CONTROL; - spec->multi_init[j].param = PIN_OUT; - j++; - if (nid > 0x0e) { - /* set connection */ - spec->multi_init[j].nid = nid; - spec->multi_init[j].verb = AC_VERB_SET_CONNECT_SEL; - spec->multi_init[j].param = 0; - /* find the index in connect list */ - k = snd_hda_get_conn_index(codec, nid, - spec->dac_nids[i], 0); - if (k >= 0) - spec->multi_init[j].param = k; - j++; - } - } - return 0; -} - static int cmi9880_init(struct hda_codec *codec) { struct cmi_spec *spec = codec->spec; @@ -631,6 +572,42 @@ static const struct hda_codec_ops cmi9880_patch_ops = { .init = cmi9880_init, .free = cmi9880_free, }; +#endif /* ENABLE_CMI_STATIC_QUIRKS */ + +/* + * stuff for auto-parser + */ +static const struct hda_codec_ops cmi_auto_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = snd_hda_gen_init, + .free = snd_hda_gen_free, + .unsol_event = snd_hda_jack_unsol_event, +}; + +static int cmi_parse_auto_config(struct hda_codec *codec) +{ + struct cmi_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int err; + + snd_hda_gen_spec_init(&spec->gen); + + err = snd_hda_parse_pin_defcfg(codec, cfg, NULL, 0); + if (err < 0) + goto error; + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + goto error; + + codec->patch_ops = cmi_auto_patch_ops; + return 0; + + error: + snd_hda_gen_free(codec); + return err; +} + static int patch_cmi9880(struct hda_codec *codec) { @@ -641,15 +618,19 @@ static int patch_cmi9880(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; +#ifdef ENABLE_CMI_STATIC_QUIRKS spec->board_config = snd_hda_check_board_config(codec, CMI_MODELS, cmi9880_models, cmi9880_cfg_tbl); if (spec->board_config < 0) { - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", + codec_dbg(codec, "%s: BIOS auto-probing.\n", codec->chip_name); spec->board_config = CMI_AUTO; /* try everything */ } + if (spec->board_config == CMI_AUTO) + return cmi_parse_auto_config(codec); + /* copy default DAC NIDs */ memcpy(spec->dac_nids, cmi9880_dac_nids, sizeof(spec->dac_nids)); spec->num_dacs = 4; @@ -678,59 +659,13 @@ static int patch_cmi9880(struct hda_codec *codec) } break; case CMI_ALLOUT: + default: spec->front_panel = 1; spec->multiout.max_channels = 8; spec->no_line_in = 1; spec->input_mux = &cmi9880_no_line_mux; spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; break; - case CMI_AUTO: - { - unsigned int port_e, port_f, port_g, port_h; - unsigned int port_spdifi, port_spdifo; - struct auto_pin_cfg cfg; - - /* collect pin default configuration */ - port_e = snd_hda_codec_get_pincfg(codec, 0x0f); - port_f = snd_hda_codec_get_pincfg(codec, 0x10); - spec->front_panel = 1; - if (get_defcfg_connect(port_e) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_f) == AC_JACK_PORT_NONE) { - port_g = snd_hda_codec_get_pincfg(codec, 0x1f); - port_h = snd_hda_codec_get_pincfg(codec, 0x20); - spec->channel_modes = cmi9880_channel_modes; - /* no front panel */ - if (get_defcfg_connect(port_g) == AC_JACK_PORT_NONE || - get_defcfg_connect(port_h) == AC_JACK_PORT_NONE) { - /* no optional rear panel */ - spec->board_config = CMI_MINIMAL; - spec->front_panel = 0; - spec->num_channel_modes = 2; - } else { - spec->board_config = CMI_MIN_FP; - spec->num_channel_modes = 3; - } - spec->input_mux = &cmi9880_basic_mux; - spec->multiout.max_channels = cmi9880_channel_modes[0].channels; - } else { - spec->input_mux = &cmi9880_basic_mux; - port_spdifi = snd_hda_codec_get_pincfg(codec, 0x13); - port_spdifo = snd_hda_codec_get_pincfg(codec, 0x12); - if (get_defcfg_connect(port_spdifo) != AC_JACK_PORT_NONE) - spec->multiout.dig_out_nid = CMI_DIG_OUT_NID; - if (get_defcfg_connect(port_spdifi) != AC_JACK_PORT_NONE) - spec->dig_in_nid = CMI_DIG_IN_NID; - spec->multiout.max_channels = 8; - } - snd_hda_parse_pin_def_config(codec, &cfg, NULL); - if (cfg.line_outs) { - spec->multiout.max_channels = cfg.line_outs * 2; - cmi9880_fill_multi_dac_nids(codec, &cfg); - cmi9880_fill_multi_init(codec, &cfg); - } else - snd_printd("patch_cmedia: cannot detect association in defcfg\n"); - break; - } } spec->multiout.num_dacs = spec->num_dacs; @@ -741,6 +676,9 @@ static int patch_cmi9880(struct hda_codec *codec) codec->patch_ops = cmi9880_patch_ops; return 0; +#else + return cmi_parse_auto_config(codec); +#endif } /* diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 03b1dc317ff..1dc7e974f3b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -23,7 +23,6 @@ #include <linux/init.h> #include <linux/delay.h> #include <linux/slab.h> -#include <linux/pci.h> #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> @@ -33,6 +32,9 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" + +#undef ENABLE_CXT_STATIC_QUIRKS #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -53,27 +55,28 @@ #define AUTO_MIC_PORTB (1 << 1) #define AUTO_MIC_PORTC (1 << 2) -struct pin_dac_pair { - hda_nid_t pin; - hda_nid_t dac; - int type; -}; - -struct imux_info { - hda_nid_t pin; /* input pin NID */ - hda_nid_t adc; /* connected ADC NID */ - hda_nid_t boost; /* optional boost volume NID */ - int index; /* corresponding to autocfg.input */ -}; - struct conexant_spec { struct hda_gen_spec gen; + unsigned int beep_amp; + + /* extra EAPD pins */ + unsigned int num_eapds; + hda_nid_t eapds[4]; + bool dynamic_eapd; + + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + /* OPLC XO specific */ + bool recording; + bool dc_enable; + unsigned int dc_input_bias; /* offset into olpc_xo_dc_bias */ + struct nid_path *dc_mode_path; + +#ifdef ENABLE_CXT_STATIC_QUIRKS const struct snd_kcontrol_new *mixers[5]; int num_mixers; hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; - bool vmaster_mute_led; const struct hda_verb *init_verbs[5]; /* initialization verbs * don't forget NULL @@ -90,11 +93,6 @@ struct conexant_spec { unsigned int hp_present; unsigned int line_present; unsigned int auto_mic; - int auto_mic_ext; /* imux_pins[] index for ext mic */ - int auto_mic_dock; /* imux_pins[] index for dock mic */ - int auto_mic_int; /* imux_pins[] index for int mic */ - unsigned int need_dac_fix; - hda_nid_t slave_dig_outs[2]; /* capture */ unsigned int num_adc_nids; @@ -122,53 +120,61 @@ struct conexant_spec { unsigned int spdif_route; - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct hda_input_mux private_imux; - struct imux_info imux_info[HDA_MAX_NUM_INPUTS]; - hda_nid_t private_adc_nids[HDA_MAX_NUM_INPUTS]; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - struct pin_dac_pair dac_info[8]; - int dac_info_filled; - unsigned int port_d_mode; - unsigned int auto_mute:1; /* used in auto-parser */ - unsigned int detect_line:1; /* Line-out detection enabled */ - unsigned int automute_lines:1; /* automute line-out as well */ - unsigned int automute_hp_lo:1; /* both HP and LO available */ unsigned int dell_automute:1; unsigned int dell_vostro:1; unsigned int ideapad:1; unsigned int thinkpad:1; unsigned int hp_laptop:1; unsigned int asus:1; - unsigned int pin_eapd_ctrls:1; - unsigned int fixup_stereo_dmic:1; - - unsigned int adc_switching:1; - - unsigned int ext_mic_present; - unsigned int recording; - void (*capture_prepare)(struct hda_codec *codec); - void (*capture_cleanup)(struct hda_codec *codec); - - /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) - * through the microphone jack. - * When the user enables this through a mixer switch, both internal and - * external microphones are disabled. Gain is fixed at 0dB. In this mode, - * we also allow the bias to be configured through a separate mixer - * control. */ - unsigned int dc_enable; - unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ + unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ +#endif /* ENABLE_CXT_STATIC_QUIRKS */ +}; - unsigned int beep_amp; - /* extra EAPD pins */ - unsigned int num_eapds; - hda_nid_t eapds[4]; +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static inline void set_beep_amp(struct conexant_spec *spec, hda_nid_t nid, + int idx, int dir) +{ + spec->gen.beep_nid = nid; + spec->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir); +} +/* additional beep mixers; the actual parameters are overwritten at build */ +static const struct snd_kcontrol_new cxt_beep_mixer[] = { + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), + { } /* end */ }; +/* create beep controls if needed */ +static int add_beep_ctls(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + int err; + + if (spec->beep_amp) { + const struct snd_kcontrol_new *knew; + for (knew = cxt_beep_mixer; knew->name; knew++) { + struct snd_kcontrol *kctl; + kctl = snd_ctl_new1(knew, codec); + if (!kctl) + return -ENOMEM; + kctl->private_value = spec->beep_amp; + err = snd_hda_ctl_add(codec, 0, kctl); + if (err < 0) + return err; + } + } + return 0; +} +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#define add_beep_ctls(codec) 0 +#endif + + +#ifdef ENABLE_CXT_STATIC_QUIRKS static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) @@ -239,8 +245,6 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct conexant_spec *spec = codec->spec; - if (spec->capture_prepare) - spec->capture_prepare(codec); snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], stream_tag, 0, format); return 0; @@ -252,8 +256,6 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, { struct conexant_spec *spec = codec->spec; snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - if (spec->capture_cleanup) - spec->capture_cleanup(codec); return 0; } @@ -381,8 +383,6 @@ static int conexant_build_pcms(struct hda_codec *codec) info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; } - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; } return 0; @@ -430,7 +430,7 @@ static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, /* partial workaround for "azx_get_response timeout" */ if (power_state == AC_PWRST_D0) msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state, true); + snd_hda_codec_set_power_to_all(codec, fg, power_state); } static int conexant_init(struct hda_codec *codec) @@ -445,10 +445,7 @@ static int conexant_init(struct hda_codec *codec) static void conexant_free(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; - snd_hda_gen_free(&spec->gen); - snd_hda_detach_beep_device(codec); - kfree(spec); + kfree(codec->spec); } static const struct snd_kcontrol_new cxt_capture_mixers[] = { @@ -462,17 +459,8 @@ static const struct snd_kcontrol_new cxt_capture_mixers[] = { {} }; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -/* additional beep mixers; the actual parameters are overwritten at build */ -static const struct snd_kcontrol_new cxt_beep_mixer[] = { - HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0, 1, 0, HDA_OUTPUT), - HDA_CODEC_MUTE_BEEP_MONO("Beep Playback Switch", 0, 1, 0, HDA_OUTPUT), - { } /* end */ -}; -#endif - static const char * const slave_pfxs[] = { - "Headphone", "Speaker", "Front", "Surround", "CLFE", + "Headphone", "Speaker", "Bass Speaker", "Front", "Surround", "CLFE", NULL }; @@ -519,10 +507,9 @@ static int conexant_build_controls(struct hda_codec *codec) } if (spec->vmaster_nid && !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch", true, - &spec->vmaster_mute.sw_kctl); + err = snd_hda_add_vmaster(codec, "Master Playback Switch", + NULL, slave_pfxs, + "Playback Switch"); if (err < 0) return err; } @@ -533,33 +520,12 @@ static int conexant_build_controls(struct hda_codec *codec) return err; } -#ifdef CONFIG_SND_HDA_INPUT_BEEP - /* create beep controls if needed */ - if (spec->beep_amp) { - const struct snd_kcontrol_new *knew; - for (knew = cxt_beep_mixer; knew->name; knew++) { - struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(knew, codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - } - } -#endif - - return 0; -} + err = add_beep_ctls(codec); + if (err < 0) + return err; -#ifdef CONFIG_PM -static int conexant_suspend(struct hda_codec *codec) -{ - snd_hda_shutup_pins(codec); return 0; } -#endif static const struct hda_codec_ops conexant_patch_ops = { .build_controls = conexant_build_controls, @@ -567,19 +533,8 @@ static const struct hda_codec_ops conexant_patch_ops = { .init = conexant_init, .free = conexant_free, .set_power_state = conexant_set_power, -#ifdef CONFIG_PM - .suspend = conexant_suspend, -#endif - .reboot_notify = snd_hda_shutup_pins, }; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define set_beep_amp(spec, nid, idx, dir) \ - ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 1, idx, dir)) -#else -#define set_beep_amp(spec, nid, idx, dir) /* NOP */ -#endif - static int patch_conexant_auto(struct hda_codec *codec); /* * EAPD control @@ -663,8 +618,6 @@ static int conexant_ch_mode_put(struct snd_kcontrol *kcontrol, int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, spec->num_channel_mode, &spec->multiout.max_channels); - if (err >= 0 && spec->need_dac_fix) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; return err; } @@ -706,14 +659,6 @@ static const struct hda_input_mux cxt5045_capture_source_benq = { } }; -static const struct hda_input_mux cxt5045_capture_source_hp530 = { - .num_items = 2, - .items = { - { "Mic", 0x1 }, - { "Internal Mic", 0x2 }, - } -}; - /* turn on/off EAPD (+ mute HP) as a master switch */ static int cxt5045_hp_master_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -829,28 +774,6 @@ static const struct snd_kcontrol_new cxt5045_benq_mixers[] = { {} }; -static const struct snd_kcontrol_new cxt5045_mixers_hp530[] = { - HDA_CODEC_VOLUME("Capture Volume", 0x1a, 0x00, HDA_INPUT), - HDA_CODEC_MUTE("Capture Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("PCM Playback Volume", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x17, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Internal Mic Playback Volume", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Internal Mic Playback Switch", 0x17, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Mic Playback Volume", 0x17, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Mic Playback Switch", 0x17, 0x1, HDA_INPUT), - HDA_BIND_VOL("Master Playback Volume", &cxt5045_hp_bind_master_vol), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Switch", - .info = cxt_eapd_info, - .get = cxt_eapd_get, - .put = cxt5045_hp_master_sw_put, - .private_value = 0x10, - }, - - {} -}; - static const struct hda_verb cxt5045_init_verbs[] = { /* Line in, Mic */ {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN|AC_PINCTL_VREF_80 }, @@ -1033,7 +956,6 @@ enum { CXT5045_LAPTOP_MICSENSE, CXT5045_LAPTOP_HPMICSENSE, CXT5045_BENQ, - CXT5045_LAPTOP_HP530, #ifdef CONFIG_SND_DEBUG CXT5045_TEST, #endif @@ -1046,7 +968,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { [CXT5045_LAPTOP_MICSENSE] = "laptop-micsense", [CXT5045_LAPTOP_HPMICSENSE] = "laptop-hpmicsense", [CXT5045_BENQ] = "benq", - [CXT5045_LAPTOP_HP530] = "laptop-hp530", #ifdef CONFIG_SND_DEBUG [CXT5045_TEST] = "test", #endif @@ -1054,8 +975,6 @@ static const char * const cxt5045_models[CXT5045_MODELS] = { }; static const struct snd_pci_quirk cxt5045_cfg_tbl[] = { - SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT5045_LAPTOP_HP530), - SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x152d, 0x0753, "Benq R55E", CXT5045_BENQ), SND_PCI_QUIRK(0x1734, 0x10ad, "Fujitsu Si1520", CXT5045_LAPTOP_MICSENSE), SND_PCI_QUIRK(0x1734, 0x10cb, "Fujitsu Si3515", CXT5045_LAPTOP_HPMICSENSE), @@ -1146,14 +1065,6 @@ static int patch_cxt5045(struct hda_codec *codec) spec->num_mixers = 2; codec->patch_ops.init = cxt5045_init; break; - case CXT5045_LAPTOP_HP530: - codec->patch_ops.unsol_event = cxt5045_hp_unsol_event; - spec->input_mux = &cxt5045_capture_source_hp530; - spec->num_init_verbs = 2; - spec->init_verbs[1] = cxt5045_hp_sense_init_verbs; - spec->mixers[0] = cxt5045_mixers_hp530; - codec->patch_ops.init = cxt5045_init; - break; #ifdef CONFIG_SND_DEBUG case CXT5045_TEST: spec->input_mux = &cxt5045_test_capture_source; @@ -1182,7 +1093,7 @@ static int patch_cxt5045(struct hda_codec *codec) } if (spec->beep_amp) - snd_hda_attach_beep_device(codec, spec->beep_amp); + snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); return 0; } @@ -1961,7 +1872,7 @@ static int patch_cxt5051(struct hda_codec *codec) } if (spec->beep_amp) - snd_hda_attach_beep_device(codec, spec->beep_amp); + snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); return 0; } @@ -1973,11 +1884,6 @@ static const hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; static const hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; static const hda_nid_t cxt5066_digout_pin_nids[2] = { 0x20, 0x22 }; -/* OLPC's microphone port is DC coupled for use with external sensors, - * therefore we use a 50% mic bias in order to center the input signal with - * the DC input range of the codec. */ -#define CXT5066_OLPC_EXT_MIC_BIAS PIN_VREF50 - static const struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -1992,7 +1898,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int pinctl; - snd_printdd("CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", + codec_dbg(codec, + "CXT5066: update speaker, hp_present=%d, cur_eapd=%d\n", spec->hp_present, spec->cur_eapd); /* Port A (HP) */ @@ -2030,88 +1937,6 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct hda_input_mux cxt5066_olpc_dc_bias = { - .num_items = 3, - .items = { - { "Off", PIN_IN }, - { "50%", PIN_VREF50 }, - { "80%", PIN_VREF80 }, - }, -}; - -static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - /* Even though port F is the DC input, the bias is controlled on port B. - * we also leave that port as an active input (but unselected) in DC mode - * just in case that is necessary to make the bias setting take effect. */ - return snd_hda_set_pin_ctl_cache(codec, 0x1a, - cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); -} - -/* OLPC defers mic widget control until when capture is started because the - * microphone LED comes on as soon as these settings are put in place. if we - * did this before recording, it would give the false indication that recording - * is happening when it is not. */ -static void cxt5066_olpc_select_mic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - if (!spec->recording) - return; - - if (spec->dc_enable) { - /* in DC mode we ignore presence detection and just use the jack - * through our special DC port */ - const struct hda_verb enable_dc_mode[] = { - /* disble internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable DC capture, port F */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, - {}, - }; - - snd_hda_sequence_write(codec, enable_dc_mode); - /* port B input disabled (and bias set) through the following call */ - cxt5066_set_olpc_dc_bias(codec); - return; - } - - /* disable DC (port F) */ - snd_hda_set_pin_ctl(codec, 0x1e, 0); - - /* external mic, port B */ - snd_hda_set_pin_ctl(codec, 0x1a, - spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); - - /* internal mic, port C */ - snd_hda_set_pin_ctl(codec, 0x1b, - spec->ext_mic_present ? 0 : PIN_VREF80); -} - -/* toggle input of built-in and mic jack appropriately */ -static void cxt5066_olpc_automic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - unsigned int present; - - if (spec->dc_enable) /* don't do presence detection in DC mode */ - return; - - present = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - if (present) - snd_printdd("CXT5066: external microphone detected\n"); - else - snd_printdd("CXT5066: external microphone absent\n"); - - snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, - present ? 0 : 1); - spec->ext_mic_present = !!present; - - cxt5066_olpc_select_mic(codec); -} - /* toggle input of built-in digital mic and mic jack appropriately */ static void cxt5066_vostro_automic(struct hda_codec *codec) { @@ -2143,10 +1968,10 @@ static void cxt5066_vostro_automic(struct hda_codec *codec) present = snd_hda_jack_detect(codec, 0x1a); if (present) { - snd_printdd("CXT5066: external microphone detected\n"); + codec_dbg(codec, "CXT5066: external microphone detected\n"); snd_hda_sequence_write(codec, ext_mic_present); } else { - snd_printdd("CXT5066: external microphone absent\n"); + codec_dbg(codec, "CXT5066: external microphone absent\n"); snd_hda_sequence_write(codec, ext_mic_absent); } } @@ -2171,10 +1996,10 @@ static void cxt5066_ideapad_automic(struct hda_codec *codec) present = snd_hda_jack_detect(codec, 0x1b); if (present) { - snd_printdd("CXT5066: external microphone detected\n"); + codec_dbg(codec, "CXT5066: external microphone detected\n"); snd_hda_sequence_write(codec, ext_mic_present); } else { - snd_printdd("CXT5066: external microphone absent\n"); + codec_dbg(codec, "CXT5066: external microphone absent\n"); snd_hda_sequence_write(codec, ext_mic_absent); } } @@ -2186,7 +2011,7 @@ static void cxt5066_asus_automic(struct hda_codec *codec) unsigned int present; present = snd_hda_jack_detect(codec, 0x1b); - snd_printdd("CXT5066: external microphone present=%d\n", present); + codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, present ? 1 : 0); } @@ -2198,7 +2023,7 @@ static void cxt5066_hp_laptop_automic(struct hda_codec *codec) unsigned int present; present = snd_hda_jack_detect(codec, 0x1b); - snd_printdd("CXT5066: external microphone present=%d\n", present); + codec_dbg(codec, "CXT5066: external microphone present=%d\n", present); snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, present ? 1 : 3); } @@ -2237,13 +2062,13 @@ static void cxt5066_thinkpad_automic(struct hda_codec *codec) ext_present = snd_hda_jack_detect(codec, 0x1b); dock_present = snd_hda_jack_detect(codec, 0x1a); if (ext_present) { - snd_printdd("CXT5066: external microphone detected\n"); + codec_dbg(codec, "CXT5066: external microphone detected\n"); snd_hda_sequence_write(codec, ext_mic_present); } else if (dock_present) { - snd_printdd("CXT5066: dock microphone detected\n"); + codec_dbg(codec, "CXT5066: dock microphone detected\n"); snd_hda_sequence_write(codec, dock_mic_present); } else { - snd_printdd("CXT5066: external microphone absent\n"); + codec_dbg(codec, "CXT5066: external microphone absent\n"); snd_hda_sequence_write(codec, ext_mic_absent); } } @@ -2262,7 +2087,7 @@ static void cxt5066_hp_automute(struct hda_codec *codec) spec->hp_present = portA ? HP_PRESENT_PORT_A : 0; spec->hp_present |= portD ? HP_PRESENT_PORT_D : 0; - snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", + codec_dbg(codec, "CXT5066: hp automute portA=%x portD=%x present=%d\n", portA, portD, spec->hp_present); cxt5066_update_speaker(codec); } @@ -2285,26 +2110,9 @@ static void cxt5066_automic(struct hda_codec *codec) } /* unsolicited event for jack sensing */ -static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) -{ - struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); - switch (res >> 26) { - case CONEXANT_HP_EVENT: - cxt5066_hp_automute(codec); - break; - case CONEXANT_MIC_EVENT: - /* ignore mic events in DC mode; we're always using the jack */ - if (!spec->dc_enable) - cxt5066_olpc_automic(codec); - break; - } -} - -/* unsolicited event for jack sensing */ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) { - snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); + codec_dbg(codec, "CXT5066: unsol event %x (%x)\n", res, res >> 26); switch (res >> 26) { case CONEXANT_HP_EVENT: cxt5066_hp_automute(codec); @@ -2371,124 +2179,10 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, idx = imux->num_items - 1; spec->mic_boost = idx; - if (!spec->dc_enable) - cxt5066_set_mic_boost(codec); - return 1; -} - -static void cxt5066_enable_dc(struct hda_codec *codec) -{ - const struct hda_verb enable_dc_mode[] = { - /* disable gain */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* switch to DC input */ - {0x17, AC_VERB_SET_CONNECT_SEL, 3}, - {} - }; - - /* configure as input source */ - snd_hda_sequence_write(codec, enable_dc_mode); - cxt5066_olpc_select_mic(codec); /* also sets configured bias */ -} - -static void cxt5066_disable_dc(struct hda_codec *codec) -{ - /* reconfigure input source */ cxt5066_set_mic_boost(codec); - /* automic also selects the right mic if we're recording */ - cxt5066_olpc_automic(codec); -} - -static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.integer.value[0] = spec->dc_enable; - return 0; -} - -static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - int dc_enable = !!ucontrol->value.integer.value[0]; - - if (dc_enable == spec->dc_enable) - return 0; - - spec->dc_enable = dc_enable; - if (dc_enable) - cxt5066_enable_dc(codec); - else - cxt5066_disable_dc(codec); - - return 1; -} - -static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); -} - -static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->dc_input_bias; - return 0; -} - -static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; - unsigned int idx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - - spec->dc_input_bias = idx; - if (spec->dc_enable) - cxt5066_set_olpc_dc_bias(codec); return 1; } -static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - /* mark as recording and configure the microphone widget so that the - * recording LED comes on. */ - spec->recording = 1; - cxt5066_olpc_select_mic(codec); -} - -static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - const struct hda_verb disable_mics[] = { - /* disable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* disble internal mic, port C */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* disable DC capture, port F */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {}, - }; - - snd_hda_sequence_write(codec, disable_mics); - spec->recording = 0; -} - static void conexant_check_dig_outs(struct hda_codec *codec, const hda_nid_t *dig_pins, int num_pins) @@ -2503,10 +2197,6 @@ static void conexant_check_dig_outs(struct hda_codec *codec, continue; if (snd_hda_get_connections(codec, *dig_pins, nid_loc, 1) != 1) continue; - if (spec->slave_dig_outs[0]) - nid_loc++; - else - nid_loc = spec->slave_dig_outs; } } @@ -2543,43 +2233,6 @@ static const struct snd_kcontrol_new cxt5066_mixer_master[] = { {} }; -static const struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Master Playback Volume", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, - .subdevice = HDA_SUBDEV_AMP_FLAG, - .info = snd_hda_mixer_amp_volume_info, - .get = snd_hda_mixer_amp_volume_get, - .put = snd_hda_mixer_amp_volume_put, - .tlv = { .c = snd_hda_mixer_amp_tlv }, - /* offset by 28 volume steps to limit minimum gain to -46dB */ - .private_value = - HDA_COMPOSE_AMP_VAL_OFS(0x10, 3, 0, HDA_OUTPUT, 28), - }, - {} -}; - -static const struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DC Mode Enable Switch", - .info = snd_ctl_boolean_mono_info, - .get = cxt5066_olpc_dc_get, - .put = cxt5066_olpc_dc_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "DC Input Bias Enum", - .info = cxt5066_olpc_dc_bias_enum_info, - .get = cxt5066_olpc_dc_bias_enum_get, - .put = cxt5066_olpc_dc_bias_enum_put, - }, - {} -}; - static const struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -2670,67 +2323,6 @@ static const struct hda_verb cxt5066_init_verbs[] = { { } /* end */ }; -static const struct hda_verb cxt5066_init_verbs_olpc[] = { - /* Port A: headphones */ - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, - {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port C: internal microphone */ - {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port D: unused */ - {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port E: unused, but has primary EAPD */ - {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ - - /* Port F: external DC input through microphone port */ - {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Port G: internal speakers */ - {0x1f, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, - {0x1f, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ - - /* DAC1 */ - {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, - - /* DAC2: unused */ - {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, - - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x50}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, - {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, - - /* Disable digital microphone port */ - {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* Audio input selectors */ - {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE | 0x3}, - {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, - - /* Disable SPDIF */ - {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - {0x22, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, - - /* enable unsolicited events for Port A and B */ - {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_HP_EVENT}, - {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | CONEXANT_MIC_EVENT}, - { } /* end */ -}; - static const struct hda_verb cxt5066_init_verbs_vostro[] = { /* Port A: headphones */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, @@ -2916,7 +2508,7 @@ static const struct hda_verb cxt5066_init_verbs_hp_laptop[] = { /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { - snd_printdd("CXT5066: init\n"); + codec_dbg(codec, "CXT5066: init\n"); conexant_init(codec); if (codec->patch_ops.unsol_event) { cxt5066_hp_automute(codec); @@ -2926,25 +2518,9 @@ static int cxt5066_init(struct hda_codec *codec) return 0; } -static int cxt5066_olpc_init(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - snd_printdd("CXT5066: init\n"); - conexant_init(codec); - cxt5066_hp_automute(codec); - if (!spec->dc_enable) { - cxt5066_set_mic_boost(codec); - cxt5066_olpc_automic(codec); - } else { - cxt5066_enable_dc(codec); - } - return 0; -} - enum { CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ - CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ CXT5066_DELL_VOSTRO, /* Dell Vostro 1015i */ CXT5066_IDEAPAD, /* Lenovo IdeaPad U150 */ CXT5066_THINKPAD, /* Lenovo ThinkPad T410s, others? */ @@ -2957,7 +2533,6 @@ enum { static const char * const cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", - [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", [CXT5066_DELL_VOSTRO] = "dell-vostro", [CXT5066_IDEAPAD] = "ideapad", [CXT5066_THINKPAD] = "thinkpad", @@ -2973,21 +2548,16 @@ static const struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x0401, "Dell Vostro 1014", CXT5066_DELL_VOSTRO), SND_PCI_QUIRK(0x1028, 0x0408, "Dell Inspiron One 19T", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x1028, 0x050f, "Dell Inspiron", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1028, 0x0510, "Dell Vostro", CXT5066_IDEAPAD), SND_PCI_QUIRK(0x103c, 0x360b, "HP G60", CXT5066_HP_LAPTOP), SND_PCI_QUIRK(0x1043, 0x13f3, "Asus A52J", CXT5066_ASUS), SND_PCI_QUIRK(0x1043, 0x1643, "Asus K52JU", CXT5066_ASUS), SND_PCI_QUIRK(0x1043, 0x1993, "Asus U50F", CXT5066_ASUS), SND_PCI_QUIRK(0x1179, 0xff1e, "Toshiba Satellite C650D", CXT5066_IDEAPAD), - SND_PCI_QUIRK(0x1179, 0xff50, "Toshiba Satellite P500-PSPGSC-01800T", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", CXT5066_LAPTOP), - SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400s", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c5, "Thinkpad Edge 13", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x21c6, "Thinkpad Edge 13", CXT5066_ASUS), - SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT5066_THINKPAD), - SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT5066_THINKPAD), SND_PCI_QUIRK(0x17aa, 0x3a0d, "Lenovo U350", CXT5066_ASUS), SND_PCI_QUIRK(0x17aa, 0x38af, "Lenovo G560", CXT5066_ASUS), {} @@ -3070,32 +2640,11 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mic_boost = 3; /* default 30dB gain */ break; - case CXT5066_OLPC_XO_1_5: - codec->patch_ops.init = cxt5066_olpc_init; - codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; - spec->init_verbs[0] = cxt5066_init_verbs_olpc; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; - spec->mixers[spec->num_mixers++] = cxt5066_mixers; - spec->port_d_mode = 0; - spec->mic_boost = 3; /* default 30dB gain */ - - /* no S/PDIF out */ - spec->multiout.dig_out_nid = 0; - - /* input source automatically selected */ - spec->input_mux = NULL; - - /* our capture hooks which allow us to turn on the microphone LED - * at the right time */ - spec->capture_prepare = cxt5066_olpc_capture_prepare; - spec->capture_cleanup = cxt5066_olpc_capture_cleanup; - break; case CXT5066_DELL_VOSTRO: codec->patch_ops.init = cxt5066_init; codec->patch_ops.unsol_event = cxt5066_unsol_event; spec->init_verbs[0] = cxt5066_init_verbs_vostro; - spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; spec->port_d_mode = 0; @@ -3143,1276 +2692,501 @@ static int patch_cxt5066(struct hda_codec *codec) } if (spec->beep_amp) - snd_hda_attach_beep_device(codec, spec->beep_amp); + snd_hda_attach_beep_device(codec, get_amp_nid_(spec->beep_amp)); return 0; } +#endif /* ENABLE_CXT_STATIC_QUIRKS */ + + /* * Automatic parser for CX20641 & co */ -static int cx_auto_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t adc = spec->imux_info[spec->cur_mux[0]].adc; - if (spec->adc_switching) { - spec->cur_adc = adc; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - } - snd_hda_codec_setup_stream(codec, adc, stream_tag, 0, format); - return 0; -} - -static int cx_auto_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static void cx_auto_parse_beep(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream cx_auto_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = cx_auto_capture_pcm_prepare, - .cleanup = cx_auto_capture_pcm_cleanup - }, -}; - -static const hda_nid_t cx_auto_adc_nids[] = { 0x14 }; - -#define get_connection_index(codec, mux, nid)\ - snd_hda_get_conn_index(codec, mux, nid, 0) - -/* get an unassigned DAC from the given list. - * Return the nid if found and reduce the DAC list, or return zero if - * not found - */ -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t *dacs, int *num_dacs) -{ - int i, nums = *num_dacs; - hda_nid_t ret = 0; + hda_nid_t nid, end_nid; - for (i = 0; i < nums; i++) { - if (get_connection_index(codec, pin, dacs[i]) >= 0) { - ret = dacs[i]; + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) + if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { + set_beep_amp(spec, nid, 0, HDA_OUTPUT); break; } - } - if (!ret) - return 0; - if (--nums > 0) - memmove(dacs, dacs + 1, nums * sizeof(hda_nid_t)); - *num_dacs = nums; - return ret; } +#else +#define cx_auto_parse_beep(codec) +#endif -#define MAX_AUTO_DACS 5 - -#define DAC_SLAVE_FLAG 0x8000 /* filled dac is a slave */ - -/* fill analog DAC list from the widget tree */ -static int fill_cx_auto_dacs(struct hda_codec *codec, hda_nid_t *dacs) +/* parse EAPDs */ +static void cx_auto_parse_eapd(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; hda_nid_t nid, end_nid; - int nums = 0; end_nid = codec->start_nid + codec->num_nodes; for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type == AC_WID_AUD_OUT && !(wcaps & AC_WCAP_DIGITAL)) { - dacs[nums++] = nid; - if (nums >= MAX_AUTO_DACS) - break; - } - } - return nums; -} - -/* fill pin_dac_pair list from the pin and dac list */ -static int fill_dacs_for_pins(struct hda_codec *codec, hda_nid_t *pins, - int num_pins, hda_nid_t *dacs, int *rest, - struct pin_dac_pair *filled, int nums, - int type) -{ - int i, start = nums; - - for (i = 0; i < num_pins; i++, nums++) { - filled[nums].pin = pins[i]; - filled[nums].type = type; - filled[nums].dac = get_unassigned_dac(codec, pins[i], dacs, rest); - if (filled[nums].dac) - continue; - if (filled[start].dac && get_connection_index(codec, pins[i], filled[start].dac) >= 0) { - filled[nums].dac = filled[start].dac | DAC_SLAVE_FLAG; - continue; - } - if (filled[0].dac && get_connection_index(codec, pins[i], filled[0].dac) >= 0) { - filled[nums].dac = filled[0].dac | DAC_SLAVE_FLAG; + if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) continue; - } - snd_printdd("Failed to find a DAC for pin 0x%x", pins[i]); - } - return nums; -} - -/* parse analog output paths */ -static void cx_auto_parse_output(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t dacs[MAX_AUTO_DACS]; - int i, j, nums, rest; - - rest = fill_cx_auto_dacs(codec, dacs); - /* parse all analog output pins */ - nums = fill_dacs_for_pins(codec, cfg->line_out_pins, cfg->line_outs, - dacs, &rest, spec->dac_info, 0, - AUTO_PIN_LINE_OUT); - nums = fill_dacs_for_pins(codec, cfg->hp_pins, cfg->hp_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_HP_OUT); - nums = fill_dacs_for_pins(codec, cfg->speaker_pins, cfg->speaker_outs, - dacs, &rest, spec->dac_info, nums, - AUTO_PIN_SPEAKER_OUT); - spec->dac_info_filled = nums; - /* fill multiout struct */ - for (i = 0; i < nums; i++) { - hda_nid_t dac = spec->dac_info[i].dac; - if (!dac || (dac & DAC_SLAVE_FLAG)) + if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) continue; - switch (spec->dac_info[i].type) { - case AUTO_PIN_LINE_OUT: - spec->private_dac_nids[spec->multiout.num_dacs] = dac; - spec->multiout.num_dacs++; - break; - case AUTO_PIN_HP_OUT: - case AUTO_PIN_SPEAKER_OUT: - if (!spec->multiout.hp_nid) { - spec->multiout.hp_nid = dac; - break; - } - for (j = 0; j < ARRAY_SIZE(spec->multiout.extra_out_nid); j++) - if (!spec->multiout.extra_out_nid[j]) { - spec->multiout.extra_out_nid[j] = dac; - break; - } + spec->eapds[spec->num_eapds++] = nid; + if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) break; - } } - spec->multiout.dac_nids = spec->private_dac_nids; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - for (i = 0; i < cfg->hp_outs; i++) { - if (is_jack_detectable(codec, cfg->hp_pins[i])) { - spec->auto_mute = 1; - break; - } - } - if (spec->auto_mute && - cfg->line_out_pins[0] && - cfg->line_out_type != AUTO_PIN_SPEAKER_OUT && - cfg->line_out_pins[0] != cfg->hp_pins[0] && - cfg->line_out_pins[0] != cfg->speaker_pins[0]) { - for (i = 0; i < cfg->line_outs; i++) { - if (is_jack_detectable(codec, cfg->line_out_pins[i])) { - spec->detect_line = 1; - break; - } - } - spec->automute_lines = spec->detect_line; - } - - spec->vmaster_nid = spec->private_dac_nids[0]; + /* NOTE: below is a wild guess; if we have more than two EAPDs, + * it's a new chip, where EAPDs are supposed to be associated to + * pins, and we can control EAPD per pin. + * OTOH, if only one or two EAPDs are found, it's an old chip, + * thus it might control over all pins. + */ + if (spec->num_eapds > 2) + spec->dynamic_eapd = 1; } static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool on); - -static void do_automute(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool on) + hda_nid_t *pins, bool on) { - struct conexant_spec *spec = codec->spec; int i; - for (i = 0; i < num_pins; i++) - snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0); - if (spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, num_pins, pins, on); -} - -static int detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) -{ - int i, present = 0; - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - if (!nid || !is_jack_detectable(codec, nid)) - break; - present |= snd_hda_jack_detect(codec, nid); + if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_EAPD_BTLENABLE, + on ? 0x02 : 0); } - return present; } -/* auto-mute/unmute speaker and line outs according to headphone jack */ -static void cx_auto_update_speakers(struct hda_codec *codec) +/* turn on/off EAPD according to Master switch */ +static void cx_auto_vmaster_hook(void *private_data, int enabled) { + struct hda_codec *codec = private_data; struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int on = 1; - - /* turn on HP EAPD when HP jacks are present */ - if (spec->pin_eapd_ctrls) { - if (spec->auto_mute) - on = spec->hp_present; - cx_auto_turn_eapd(codec, cfg->hp_outs, cfg->hp_pins, on); - } - - /* mute speakers in auto-mode if HP or LO jacks are plugged */ - if (spec->auto_mute) - on = !(spec->hp_present || - (spec->detect_line && spec->line_present)); - do_automute(codec, cfg->speaker_outs, cfg->speaker_pins, on); - /* toggle line-out mutes if needed, too */ - /* if LO is a copy of either HP or Speaker, don't need to handle it */ - if (cfg->line_out_pins[0] == cfg->hp_pins[0] || - cfg->line_out_pins[0] == cfg->speaker_pins[0]) - return; - if (spec->auto_mute) { - /* mute LO in auto-mode when HP jack is present */ - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT || - spec->automute_lines) - on = !spec->hp_present; - else - on = 1; - } - do_automute(codec, cfg->line_outs, cfg->line_out_pins, on); + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); } -static void cx_auto_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) +static int cx_auto_build_controls(struct hda_codec *codec) { - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + int err; - if (!spec->auto_mute) - return; - spec->hp_present = detect_jacks(codec, cfg->hp_outs, cfg->hp_pins); - cx_auto_update_speakers(codec); -} + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; -static void cx_auto_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + err = add_beep_ctls(codec); + if (err < 0) + return err; - if (!spec->auto_mute || !spec->detect_line) - return; - spec->line_present = detect_jacks(codec, cfg->line_outs, - cfg->line_out_pins); - cx_auto_update_speakers(codec); + return 0; } -static int cx_automute_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int cx_auto_init(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; - static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" - }; - const char * const *texts; + snd_hda_gen_init(codec); + if (!spec->dynamic_eapd) + cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_hp_lo) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); -static int cx_automute_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; - unsigned int val; - if (!spec->auto_mute) - val = 0; - else if (!spec->automute_lines) - val = 1; - else - val = 2; - ucontrol->value.enumerated.item[0] = val; return 0; } -static int cx_automute_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; +#define cx_auto_free snd_hda_gen_free - switch (ucontrol->value.enumerated.item[0]) { - case 0: - if (!spec->auto_mute) - return 0; - spec->auto_mute = 0; - break; - case 1: - if (spec->auto_mute && !spec->automute_lines) - return 0; - spec->auto_mute = 1; - spec->automute_lines = 0; - break; - case 2: - if (!spec->automute_hp_lo) - return -EINVAL; - if (spec->auto_mute && spec->automute_lines) - return 0; - spec->auto_mute = 1; - spec->automute_lines = 1; - break; - default: - return -EINVAL; - } - cx_auto_update_speakers(codec); - return 1; -} +static const struct hda_codec_ops cx_auto_patch_ops = { + .build_controls = cx_auto_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = cx_auto_init, + .free = cx_auto_free, + .unsol_event = snd_hda_jack_unsol_event, +#ifdef CONFIG_PM + .check_power_status = snd_hda_gen_check_power_status, +#endif +}; -static const struct snd_kcontrol_new cx_automute_mode_enum[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Auto-Mute Mode", - .info = cx_automute_mode_info, - .get = cx_automute_mode_get, - .put = cx_automute_mode_put, - }, - { } +/* + * pin fix-up + */ +enum { + CXT_PINCFG_LENOVO_X200, + CXT_PINCFG_LENOVO_TP410, + CXT_PINCFG_LEMOTE_A1004, + CXT_PINCFG_LEMOTE_A1205, + CXT_FIXUP_STEREO_DMIC, + CXT_FIXUP_INC_MIC_BOOST, + CXT_FIXUP_HEADPHONE_MIC_PIN, + CXT_FIXUP_HEADPHONE_MIC, + CXT_FIXUP_GPIO1, + CXT_FIXUP_THINKPAD_ACPI, + CXT_FIXUP_OLPC_XO, + CXT_FIXUP_CAP_MIX_AMP, + CXT_FIXUP_TOSHIBA_P105, + CXT_FIXUP_HP_530, + CXT_FIXUP_CAP_MIX_AMP_5047, }; -static int cx_auto_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +/* for hda_fixup_thinkpad_acpi() */ +#include "thinkpad_helper.c" + +static void cxt_fixup_stereo_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - - return snd_hda_input_mux_info(&spec->private_imux, uinfo); + spec->gen.inv_dmic_split = 1; } -static int cx_auto_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void cxt5066_increase_mic_boost(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; - ucontrol->value.enumerated.item[0] = spec->cur_mux[0]; - return 0; + snd_hda_override_amp_caps(codec, 0x17, HDA_OUTPUT, + (0x3 << AC_AMPCAP_OFFSET_SHIFT) | + (0x4 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); } -/* look for the route the given pin from mux and return the index; - * if do_select is set, actually select the route. - */ -static int __select_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin, hda_nid_t *srcp, - bool do_select, int depth) +static void cxt_update_headset_mode(struct hda_codec *codec) { + /* The verbs used in this function were tested on a Conexant CX20751/2 codec. */ + int i; + bool mic_mode = false; struct conexant_spec *spec = codec->spec; - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int startidx, i, nums; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; - switch (get_wcaps_type(get_wcaps(codec, mux))) { - case AC_WID_AUD_IN: - case AC_WID_AUD_SEL: - case AC_WID_AUD_MIX: - break; - default: - return -1; - } + hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) - if (conn[i] == pin) { - if (do_select) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, i); - if (srcp) - *srcp = mux; - return i; - } - depth++; - if (depth == 2) - return -1; - - /* Try to rotate around connections to avoid one boost controlling - another input path as well */ - startidx = 0; - for (i = 0; i < spec->private_imux.num_items; i++) - if (spec->imux_info[i].pin == pin) { - startidx = i; + for (i = 0; i < cfg->num_inputs; i++) + if (cfg->inputs[i].pin == mux_pin) { + mic_mode = !!cfg->inputs[i].is_headphone_mic; break; } - for (i = 0; i < nums; i++) { - int j = (i + startidx) % nums; - int ret = __select_input_connection(codec, conn[j], pin, srcp, - do_select, depth); - if (ret >= 0) { - if (do_select) - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, j); - return j; - } + if (mic_mode) { + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x7c); /* enable merged mode for analog int-mic */ + spec->gen.hp_jack_present = false; + } else { + snd_hda_codec_write_cache(codec, 0x1c, 0, 0x410, 0x54); /* disable merged mode for analog int-mic */ + spec->gen.hp_jack_present = snd_hda_jack_detect(codec, spec->gen.autocfg.hp_pins[0]); } - return -1; -} -static void select_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin) -{ - __select_input_connection(codec, mux, pin, NULL, true, 0); + snd_hda_gen_update_outputs(codec); } -static int get_input_connection(struct hda_codec *codec, hda_nid_t mux, - hda_nid_t pin) +static void cxt_update_headset_mode_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - return __select_input_connection(codec, mux, pin, NULL, false, 0); + cxt_update_headset_mode(codec); } -static int cx_auto_mux_enum_update(struct hda_codec *codec, - const struct hda_input_mux *imux, - unsigned int idx) +static void cxt_fixup_headphone_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct conexant_spec *spec = codec->spec; - hda_nid_t adc; - int changed = 1; - if (!imux->num_items) - return 0; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[0] == idx) - changed = 0; - adc = spec->imux_info[idx].adc; - select_input_connection(codec, spec->imux_info[idx].adc, - spec->imux_info[idx].pin); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->parse_flags |= HDA_PINCFG_HEADPHONE_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + spec->gen.cap_sync_hook = cxt_update_headset_mode_hook; + spec->gen.automute_hook = cxt_update_headset_mode; + break; + case HDA_FIXUP_ACT_INIT: + cxt_update_headset_mode(codec); + break; } - spec->cur_mux[0] = idx; - return changed; } -static int cx_auto_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct conexant_spec *spec = codec->spec; +/* OPLC XO 1.5 fixup */ - return cx_auto_mux_enum_update(codec, &spec->private_imux, - ucontrol->value.enumerated.item[0]); -} +/* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) + * through the microphone jack. + * When the user enables this through a mixer switch, both internal and + * external microphones are disabled. Gain is fixed at 0dB. In this mode, + * we also allow the bias to be configured through a separate mixer + * control. */ -static const struct snd_kcontrol_new cx_auto_capture_mixers[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = cx_auto_mux_enum_info, - .get = cx_auto_mux_enum_get, - .put = cx_auto_mux_enum_put +#define update_mic_pin(codec, nid, val) \ + snd_hda_codec_update_cache(codec, nid, 0, \ + AC_VERB_SET_PIN_WIDGET_CONTROL, val) + +static const struct hda_input_mux olpc_xo_dc_bias = { + .num_items = 3, + .items = { + { "Off", PIN_IN }, + { "50%", PIN_VREF50 }, + { "80%", PIN_VREF80 }, }, - {} }; -static bool select_automic(struct hda_codec *codec, int idx, bool detect) -{ - struct conexant_spec *spec = codec->spec; - if (idx < 0) - return false; - if (detect && !snd_hda_jack_detect(codec, spec->imux_info[idx].pin)) - return false; - cx_auto_mux_enum_update(codec, &spec->private_imux, idx); - return true; -} - -/* automatic switch internal and external mic */ -static void cx_auto_automic(struct hda_codec *codec, struct hda_jack_tbl *jack) +static void olpc_xo_update_mic_boost(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; + int ch, val; - if (!spec->auto_mic) - return; - if (!select_automic(codec, spec->auto_mic_ext, true)) - if (!select_automic(codec, spec->auto_mic_dock, true)) - select_automic(codec, spec->auto_mic_int, false); -} - -/* check whether the pin config is suitable for auto-mic switching; - * auto-mic is enabled only when one int-mic and one ext- and/or - * one dock-mic exist - */ -static void cx_auto_check_auto_mic(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int pset[INPUT_PIN_ATTR_NORMAL + 1]; - int i; - - for (i = 0; i < ARRAY_SIZE(pset); i++) - pset[i] = -1; - for (i = 0; i < spec->private_imux.num_items; i++) { - hda_nid_t pin = spec->imux_info[i].pin; - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, pin); - int type, attr; - attr = snd_hda_get_input_pin_attr(def_conf); - if (attr == INPUT_PIN_ATTR_UNUSED) - return; /* invalid entry */ - if (attr > INPUT_PIN_ATTR_NORMAL) - attr = INPUT_PIN_ATTR_NORMAL; - if (attr != INPUT_PIN_ATTR_INT && - !is_jack_detectable(codec, pin)) - return; /* non-detectable pin */ - type = get_defcfg_device(def_conf); - if (type != AC_JACK_MIC_IN && - (attr != INPUT_PIN_ATTR_DOCK || type != AC_JACK_LINE_IN)) - return; /* no valid input type */ - if (pset[attr] >= 0) - return; /* already occupied */ - pset[attr] = i; - } - if (pset[INPUT_PIN_ATTR_INT] < 0 || - (pset[INPUT_PIN_ATTR_NORMAL] < 0 && pset[INPUT_PIN_ATTR_DOCK])) - return; /* no input to switch*/ - spec->auto_mic = 1; - spec->auto_mic_ext = pset[INPUT_PIN_ATTR_NORMAL]; - spec->auto_mic_dock = pset[INPUT_PIN_ATTR_DOCK]; - spec->auto_mic_int = pset[INPUT_PIN_ATTR_INT]; -} - -static void cx_auto_parse_input(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux; - int i, j; - - imux = &spec->private_imux; - for (i = 0; i < cfg->num_inputs; i++) { - for (j = 0; j < spec->num_adc_nids; j++) { - hda_nid_t adc = spec->adc_nids[j]; - int idx = get_input_connection(codec, adc, - cfg->inputs[i].pin); - if (idx >= 0) { - const char *label; - label = hda_get_autocfg_input_label(codec, cfg, i); - spec->imux_info[imux->num_items].index = i; - spec->imux_info[imux->num_items].boost = 0; - spec->imux_info[imux->num_items].adc = adc; - spec->imux_info[imux->num_items].pin = - cfg->inputs[i].pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } - } - if (imux->num_items >= 2 && cfg->num_inputs == imux->num_items) - cx_auto_check_auto_mic(codec); - if (imux->num_items > 1) { - for (i = 1; i < imux->num_items; i++) { - if (spec->imux_info[i].adc != spec->imux_info[0].adc) { - spec->adc_switching = 1; - break; - } - } - } -} - -/* get digital-input audio widget corresponding to the given pin */ -static hda_nid_t cx_auto_get_dig_in(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int type = get_wcaps_type(wcaps); - if (type == AC_WID_AUD_IN && (wcaps & AC_WCAP_DIGITAL)) { - if (get_connection_index(codec, nid, pin) >= 0) - return nid; - } + for (ch = 0; ch < 2; ch++) { + val = AC_AMP_SET_OUTPUT | + (ch ? AC_AMP_SET_RIGHT : AC_AMP_SET_LEFT); + if (!spec->dc_enable) + val |= snd_hda_codec_amp_read(codec, 0x17, ch, HDA_OUTPUT, 0); + snd_hda_codec_write(codec, 0x17, 0, + AC_VERB_SET_AMP_GAIN_MUTE, val); } - return 0; } -static void cx_auto_parse_digital(struct hda_codec *codec) +static void olpc_xo_update_mic_pins(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - - if (cfg->dig_outs && - snd_hda_get_connections(codec, cfg->dig_out_pins[0], &nid, 1) == 1) - spec->multiout.dig_out_nid = nid; - if (cfg->dig_in_pin) - spec->dig_in_nid = cx_auto_get_dig_in(codec, cfg->dig_in_pin); -} + int cur_input, val; + struct nid_path *path; -#ifdef CONFIG_SND_HDA_INPUT_BEEP -static void cx_auto_parse_beep(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t nid, end_nid; + cur_input = spec->gen.input_paths[0][spec->gen.cur_mux[0]]; - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_BEEP) { - set_beep_amp(spec, nid, 0, HDA_OUTPUT); - break; - } -} -#else -#define cx_auto_parse_beep(codec) -#endif - -/* parse EAPDs */ -static void cx_auto_parse_eapd(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - continue; - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) - continue; - spec->eapds[spec->num_eapds++] = nid; - if (spec->num_eapds >= ARRAY_SIZE(spec->eapds)) - break; - } - - /* NOTE: below is a wild guess; if we have more than two EAPDs, - * it's a new chip, where EAPDs are supposed to be associated to - * pins, and we can control EAPD per pin. - * OTOH, if only one or two EAPDs are found, it's an old chip, - * thus it might control over all pins. + /* Set up mic pins for port-B, C and F dynamically as the recording + * LED is turned on/off by these pin controls */ - spec->pin_eapd_ctrls = spec->num_eapds > 2; -} - -static int cx_auto_parse_auto_config(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - - cx_auto_parse_output(codec); - cx_auto_parse_input(codec); - cx_auto_parse_digital(codec); - cx_auto_parse_beep(codec); - cx_auto_parse_eapd(codec); - return 0; -} - -static void cx_auto_turn_eapd(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool on) -{ - int i; - for (i = 0; i < num_pins; i++) { - if (snd_hda_query_pin_caps(codec, pins[i]) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, pins[i], 0, - AC_VERB_SET_EAPD_BTLENABLE, - on ? 0x02 : 0); - } -} - -static void select_connection(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t src) -{ - int idx = get_connection_index(codec, pin, src); - if (idx >= 0) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, idx); -} - -static void mute_outputs(struct hda_codec *codec, int num_nids, - const hda_nid_t *nids) -{ - int i, val; - - for (i = 0; i < num_nids; i++) { - hda_nid_t nid = nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_OUT_AMP)) - continue; - if (query_amp_caps(codec, nid, HDA_OUTPUT) & AC_AMPCAP_MUTE) - val = AMP_OUT_MUTE; + if (!spec->dc_enable) { + /* disable DC bias path and pin for port F */ + update_mic_pin(codec, 0x1e, 0); + snd_hda_activate_path(codec, spec->dc_mode_path, false, false); + + /* update port B (ext mic) and C (int mic) */ + /* OLPC defers mic widget control until when capture is + * started because the microphone LED comes on as soon as + * these settings are put in place. if we did this before + * recording, it would give the false indication that + * recording is happening when it is not. + */ + update_mic_pin(codec, 0x1a, spec->recording ? + snd_hda_codec_get_pin_target(codec, 0x1a) : 0); + update_mic_pin(codec, 0x1b, spec->recording ? + snd_hda_codec_get_pin_target(codec, 0x1b) : 0); + /* enable normal mic path */ + path = snd_hda_get_path_from_idx(codec, cur_input); + if (path) + snd_hda_activate_path(codec, path, true, false); + } else { + /* disable normal mic path */ + path = snd_hda_get_path_from_idx(codec, cur_input); + if (path) + snd_hda_activate_path(codec, path, false, false); + + /* Even though port F is the DC input, the bias is controlled + * on port B. We also leave that port as an active input (but + * unselected) in DC mode just in case that is necessary to + * make the bias setting take effect. + */ + if (spec->recording) + val = olpc_xo_dc_bias.items[spec->dc_input_bias].index; else - val = AMP_OUT_ZERO; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); + val = 0; + update_mic_pin(codec, 0x1a, val); + update_mic_pin(codec, 0x1b, 0); + /* enable DC bias path and pin */ + update_mic_pin(codec, 0x1e, spec->recording ? PIN_IN : 0); + snd_hda_activate_path(codec, spec->dc_mode_path, true, false); } } -static void enable_unsol_pins(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, unsigned int action, - hda_jack_callback cb) -{ - int i; - for (i = 0; i < num_pins; i++) - snd_hda_jack_detect_enable_callback(codec, pins[i], action, cb); -} - -static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return true; - return false; -} - -/* is the given NID found in any of autocfg items? */ -static bool found_in_autocfg(struct auto_pin_cfg *cfg, hda_nid_t nid) -{ - int i; - - if (found_in_nid_list(nid, cfg->line_out_pins, cfg->line_outs) || - found_in_nid_list(nid, cfg->hp_pins, cfg->hp_outs) || - found_in_nid_list(nid, cfg->speaker_pins, cfg->speaker_outs) || - found_in_nid_list(nid, cfg->dig_out_pins, cfg->dig_outs)) - return true; - for (i = 0; i < cfg->num_inputs; i++) - if (cfg->inputs[i].pin == nid) - return true; - if (cfg->dig_in_pin == nid) - return true; - return false; -} - -/* clear unsol-event tags on unused pins; Conexant codecs seem to leave - * invalid unsol tags by some reason - */ -static void clear_unsol_on_unused_pins(struct hda_codec *codec) +/* mic_autoswitch hook */ +static void olpc_xo_automic(struct hda_codec *codec, struct hda_jack_tbl *jack) { struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; + int saved_cached_write = codec->cached_write; - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - if (!found_in_autocfg(cfg, pin->nid)) - snd_hda_codec_write(codec, pin->nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, 0); - } + codec->cached_write = 1; + /* in DC mode, we don't handle automic */ + if (!spec->dc_enable) + snd_hda_gen_mic_autoswitch(codec, jack); + olpc_xo_update_mic_pins(codec); + snd_hda_codec_flush_cache(codec); + codec->cached_write = saved_cached_write; + if (spec->dc_enable) + olpc_xo_update_mic_boost(codec); } -/* turn on/off EAPD according to Master switch */ -static void cx_auto_vmaster_hook(void *private_data, int enabled) +/* pcm_capture hook */ +static void olpc_xo_capture_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) { - struct hda_codec *codec = private_data; struct conexant_spec *spec = codec->spec; - if (enabled && spec->pin_eapd_ctrls) { - cx_auto_update_speakers(codec); - return; + /* toggle spec->recording flag and update mic pins accordingly + * for turning on/off LED + */ + switch (action) { + case HDA_GEN_PCM_ACT_PREPARE: + spec->recording = 1; + olpc_xo_update_mic_pins(codec); + break; + case HDA_GEN_PCM_ACT_CLEANUP: + spec->recording = 0; + olpc_xo_update_mic_pins(codec); + break; } - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, enabled); } -static void cx_auto_init_output(struct hda_codec *codec) +static int olpc_xo_dc_mode_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - int i; - - mute_outputs(codec, spec->multiout.num_dacs, spec->multiout.dac_nids); - for (i = 0; i < cfg->hp_outs; i++) { - unsigned int val = PIN_OUT; - if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) & - AC_PINCAP_HP_DRV) - val |= AC_PINCTL_HP_EN; - snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val); - } - mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); - mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); - mute_outputs(codec, cfg->speaker_outs, cfg->speaker_pins); - for (i = 0; i < spec->dac_info_filled; i++) { - nid = spec->dac_info[i].dac; - if (!nid) - nid = spec->multiout.dac_nids[0]; - else if (nid & DAC_SLAVE_FLAG) - nid &= ~DAC_SLAVE_FLAG; - select_connection(codec, spec->dac_info[i].pin, nid); - } - if (spec->auto_mute) { - enable_unsol_pins(codec, cfg->hp_outs, cfg->hp_pins, - CONEXANT_HP_EVENT, cx_auto_hp_automute); - spec->hp_present = detect_jacks(codec, cfg->hp_outs, - cfg->hp_pins); - if (spec->detect_line) { - enable_unsol_pins(codec, cfg->line_outs, - cfg->line_out_pins, - CONEXANT_LINE_EVENT, - cx_auto_line_automute); - spec->line_present = - detect_jacks(codec, cfg->line_outs, - cfg->line_out_pins); - } - } - cx_auto_update_speakers(codec); - /* turn on all EAPDs if no individual EAPD control is available */ - if (!spec->pin_eapd_ctrls) - cx_auto_turn_eapd(codec, spec->num_eapds, spec->eapds, true); - clear_unsol_on_unused_pins(codec); + ucontrol->value.integer.value[0] = spec->dc_enable; + return 0; } -static void cx_auto_init_input(struct hda_codec *codec) +static int olpc_xo_dc_mode_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, val; - - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t nid = spec->adc_nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP)) - continue; - if (query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE) - val = AMP_IN_MUTE(0); - else - val = AMP_IN_UNMUTE(0); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - val); - } - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int type = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - type |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, type); - } - - if (spec->auto_mic) { - if (spec->auto_mic_ext >= 0) { - snd_hda_jack_detect_enable_callback(codec, - cfg->inputs[spec->auto_mic_ext].pin, - CONEXANT_MIC_EVENT, cx_auto_automic); - } - if (spec->auto_mic_dock >= 0) { - snd_hda_jack_detect_enable_callback(codec, - cfg->inputs[spec->auto_mic_dock].pin, - CONEXANT_MIC_EVENT, cx_auto_automic); - } - cx_auto_automic(codec, NULL); - } else { - select_input_connection(codec, spec->imux_info[0].adc, - spec->imux_info[0].pin); - } -} + int dc_enable = !!ucontrol->value.integer.value[0]; -static void cx_auto_init_digital(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + if (dc_enable == spec->dc_enable) + return 0; - if (spec->multiout.dig_out_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT); - if (spec->dig_in_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN); + spec->dc_enable = dc_enable; + olpc_xo_update_mic_pins(codec); + olpc_xo_update_mic_boost(codec); + return 1; } -static int cx_auto_init(struct hda_codec *codec) +static int olpc_xo_dc_bias_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - snd_hda_gen_apply_verbs(codec); - cx_auto_init_output(codec); - cx_auto_init_input(codec); - cx_auto_init_digital(codec); - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - return 0; -} - -static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, - const char *dir, int cidx, - hda_nid_t nid, int hda_dir, int amp_idx, int chs) -{ - static char name[44]; - static struct snd_kcontrol_new knew[] = { - HDA_CODEC_VOLUME(name, 0, 0, 0), - HDA_CODEC_MUTE(name, 0, 0, 0), - }; - static const char * const sfx[2] = { "Volume", "Switch" }; - int i, err; - - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx, - hda_dir); - knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; - knew[i].index = cidx; - snprintf(name, sizeof(name), "%s%s %s", basename, dir, sfx[i]); - kctl = snd_ctl_new1(&knew[i], codec); - if (!kctl) - return -ENOMEM; - err = snd_hda_ctl_add(codec, nid, kctl); - if (err < 0) - return err; - if (!(query_amp_caps(codec, nid, hda_dir) & - (AC_AMPCAP_MUTE | AC_AMPCAP_MIN_MUTE))) - break; - } + ucontrol->value.enumerated.item[0] = spec->dc_input_bias; return 0; } -#define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ - cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3) - -#define cx_auto_add_pb_volume(codec, nid, str, idx) \ - cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) - -static int try_add_pb_volume(struct hda_codec *codec, hda_nid_t dac, - hda_nid_t pin, const char *name, int idx) +static int olpc_xo_dc_bias_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - unsigned int caps; - if (dac && !(dac & DAC_SLAVE_FLAG)) { - caps = query_amp_caps(codec, dac, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, dac, name, idx); - } - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - if (caps & AC_AMPCAP_NUM_STEPS) - return cx_auto_add_pb_volume(codec, pin, name, idx); - return 0; + return snd_hda_input_mux_info(&olpc_xo_dc_bias, uinfo); } -static int cx_auto_build_output_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int i, err; - int num_line = 0, num_hp = 0, num_spk = 0; - static const char * const texts[3] = { "Front", "Surround", "CLFE" }; - - if (spec->dac_info_filled == 1) - return try_add_pb_volume(codec, spec->dac_info[0].dac, - spec->dac_info[0].pin, - "Master", 0); - - for (i = 0; i < spec->dac_info_filled; i++) { - const char *label; - int idx, type; - hda_nid_t dac = spec->dac_info[i].dac; - type = spec->dac_info[i].type; - if (type == AUTO_PIN_LINE_OUT) - type = spec->autocfg.line_out_type; - switch (type) { - case AUTO_PIN_LINE_OUT: - default: - label = texts[num_line++]; - idx = 0; - break; - case AUTO_PIN_HP_OUT: - label = "Headphone"; - idx = num_hp++; - break; - case AUTO_PIN_SPEAKER_OUT: - label = "Speaker"; - idx = num_spk++; - break; - } - err = try_add_pb_volume(codec, dac, - spec->dac_info[i].pin, - label, idx); - if (err < 0) - return err; - } - - if (spec->auto_mute) { - err = snd_hda_add_new_ctls(codec, cx_automute_mode_enum); - if (err < 0) - return err; - } - - return 0; -} - -/* Returns zero if this is a normal stereo channel, and non-zero if it should - be split in two independent channels. - dest_label must be at least 44 characters. */ -static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label, - char *dest_label, int nid) +static int olpc_xo_dc_bias_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - int i; + const struct hda_input_mux *imux = &olpc_xo_dc_bias; + unsigned int idx; - if (!spec->fixup_stereo_dmic) + idx = ucontrol->value.enumerated.item[0]; + if (idx >= imux->num_items) + idx = imux->num_items - 1; + if (spec->dc_input_bias == idx) return 0; - for (i = 0; i < AUTO_CFG_MAX_INS; i++) { - int def_conf; - if (spec->autocfg.inputs[i].pin != nid) - continue; - - if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC) - return 0; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) - return 0; - - /* Finally found the inverted internal mic! */ - snprintf(dest_label, 44, "Inverted %s", label); - return 1; - } - return 0; + spec->dc_input_bias = idx; + if (spec->dc_enable) + olpc_xo_update_mic_pins(codec); + return 1; } -static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, - const char *label, const char *pfx, - int cidx) -{ - struct conexant_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_adc_nids; i++) { - char rightch_label[44]; - hda_nid_t adc_nid = spec->adc_nids[i]; - int idx = get_input_connection(codec, adc_nid, nid); - if (idx < 0) - continue; - if (codec->single_adc_amp) - idx = 0; - - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - /* Make two independent kcontrols for left and right */ - int err = cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 2); - } - return cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 3); - } - return 0; -} +static const struct snd_kcontrol_new olpc_xo_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Mode Enable Switch", + .info = snd_ctl_boolean_mono_info, + .get = olpc_xo_dc_mode_get, + .put = olpc_xo_dc_mode_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DC Input Bias Enum", + .info = olpc_xo_dc_bias_enum_info, + .get = olpc_xo_dc_bias_enum_get, + .put = olpc_xo_dc_bias_enum_put, + }, + {} +}; -static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, - const char *label, int cidx) +/* overriding mic boost put callback; update mic boost volume only when + * DC mode is disabled + */ +static int olpc_xo_mic_boost_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct conexant_spec *spec = codec->spec; - hda_nid_t mux, nid; - int i, con; - - nid = spec->imux_info[idx].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char rightch_label[44]; - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - int err = cx_auto_add_volume_idx(codec, label, " Boost", - cidx, nid, HDA_INPUT, 0, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, " Boost", - cidx, nid, HDA_INPUT, 0, 2); - } - return cx_auto_add_volume(codec, label, " Boost", cidx, - nid, HDA_INPUT); - } - con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, - &mux, false, 0); - if (con < 0) - return 0; - for (i = 0; i < idx; i++) { - if (spec->imux_info[i].boost == mux) - return 0; /* already present */ - } - - if (get_wcaps(codec, mux) & AC_WCAP_OUT_AMP) { - spec->imux_info[idx].boost = mux; - return cx_auto_add_volume(codec, label, " Boost", cidx, - mux, HDA_OUTPUT); - } - return 0; + int ret = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); + if (ret > 0 && spec->dc_enable) + olpc_xo_update_mic_boost(codec); + return ret; } -static int cx_auto_build_input_controls(struct hda_codec *codec) +static void cxt_fixup_olpc_xo(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct conexant_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - const char *prev_label; - int input_conn[HDA_MAX_NUM_INPUTS]; - int i, j, err, cidx; - int multi_connection; - - if (!imux->num_items) - return 0; - - multi_connection = 0; - for (i = 0; i < imux->num_items; i++) { - cidx = get_input_connection(codec, spec->imux_info[i].adc, - spec->imux_info[i].pin); - if (cidx < 0) - continue; - input_conn[i] = spec->imux_info[i].adc; - if (!codec->single_adc_amp) - input_conn[i] |= cidx << 8; - if (i > 0 && input_conn[i] != input_conn[0]) - multi_connection = 1; - } + int i; - prev_label = NULL; - cidx = 0; - for (i = 0; i < imux->num_items; i++) { - hda_nid_t nid = spec->imux_info[i].pin; - const char *label; + if (action != HDA_FIXUP_ACT_PROBE) + return; - label = hda_get_autocfg_input_label(codec, &spec->autocfg, - spec->imux_info[i].index); - if (label == prev_label) - cidx++; - else - cidx = 0; - prev_label = label; + spec->gen.mic_autoswitch_hook = olpc_xo_automic; + spec->gen.pcm_capture_hook = olpc_xo_capture_hook; + spec->dc_mode_path = snd_hda_add_new_path(codec, 0x1e, 0x14, 0); - err = cx_auto_add_boost_volume(codec, i, label, cidx); - if (err < 0) - return err; + snd_hda_add_new_ctls(codec, olpc_xo_mixers); - if (!multi_connection) { - if (i > 0) - continue; - err = cx_auto_add_capture_volume(codec, nid, - "Capture", "", cidx); - } else { - bool dup_found = false; - for (j = 0; j < i; j++) { - if (input_conn[j] == input_conn[i]) { - dup_found = true; - break; - } - } - if (dup_found) - continue; - err = cx_auto_add_capture_volume(codec, nid, - label, " Capture", cidx); + /* OLPC's microphone port is DC coupled for use with external sensors, + * therefore we use a 50% mic bias in order to center the input signal + * with the DC input range of the codec. + */ + snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50); + + /* override mic boost control */ + for (i = 0; i < spec->gen.kctls.used; i++) { + struct snd_kcontrol_new *kctl = + snd_array_elem(&spec->gen.kctls, i); + if (!strcmp(kctl->name, "Mic Boost Volume")) { + kctl->put = olpc_xo_mic_boost_put; + break; } - if (err < 0) - return err; - } - - if (spec->private_imux.num_items > 1 && !spec->auto_mic) { - err = snd_hda_add_new_ctls(codec, cx_auto_capture_mixers); - if (err < 0) - return err; - } - - return 0; -} - -static int cx_auto_build_controls(struct hda_codec *codec) -{ - struct conexant_spec *spec = codec->spec; - int err; - - err = cx_auto_build_output_controls(codec); - if (err < 0) - return err; - err = cx_auto_build_input_controls(codec); - if (err < 0) - return err; - err = conexant_build_controls(codec); - if (err < 0) - return err; - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - if (spec->vmaster_mute.sw_kctl) { - spec->vmaster_mute.hook = cx_auto_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, - spec->vmaster_mute_led); - if (err < 0) - return err; } - return 0; } -static int cx_auto_search_adcs(struct hda_codec *codec) +/* + * Fix max input level on mixer widget to 0dB + * (originally it has 0x2b steps with 0dB offset 0x14) + */ +static void cxt_fixup_cap_mix_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - struct conexant_spec *spec = codec->spec; - hda_nid_t nid, end_nid; - - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int caps = get_wcaps(codec, nid); - if (get_wcaps_type(caps) != AC_WID_AUD_IN) - continue; - if (caps & AC_WCAP_DIGITAL) - continue; - if (snd_BUG_ON(spec->num_adc_nids >= - ARRAY_SIZE(spec->private_adc_nids))) - break; - spec->private_adc_nids[spec->num_adc_nids++] = nid; - } - spec->adc_nids = spec->private_adc_nids; - return 0; + snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, + (0x14 << AC_AMPCAP_OFFSET_SHIFT) | + (0x14 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); } -static const struct hda_codec_ops cx_auto_patch_ops = { - .build_controls = cx_auto_build_controls, - .build_pcms = conexant_build_pcms, - .init = cx_auto_init, - .free = conexant_free, - .unsol_event = snd_hda_jack_unsol_event, -#ifdef CONFIG_PM - .suspend = conexant_suspend, -#endif - .reboot_notify = snd_hda_shutup_pins, -}; - /* - * pin fix-up + * Fix max input level on mixer widget to 0dB + * (originally it has 0x1e steps with 0 dB offset 0x17) */ -enum { - CXT_PINCFG_LENOVO_X200, - CXT_PINCFG_LENOVO_TP410, - CXT_FIXUP_STEREO_DMIC, -}; - -static void cxt_fixup_stereo_dmic(struct hda_codec *codec, +static void cxt_fixup_cap_mix_amp_5047(struct hda_codec *codec, const struct hda_fixup *fix, int action) { - struct conexant_spec *spec = codec->spec; - spec->fixup_stereo_dmic = 1; + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); } /* ThinkPad X200 & co with cxt5051 */ @@ -4432,6 +3206,18 @@ static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { {} }; +/* Lemote A1004/A1205 with cxt5066 */ +static const struct hda_pintbl cxt_pincfg_lemote[] = { + { 0x1a, 0x90a10020 }, /* Internal mic */ + { 0x1b, 0x03a11020 }, /* External mic */ + { 0x1d, 0x400101f0 }, /* Not used */ + { 0x1e, 0x40a701f0 }, /* Not used */ + { 0x20, 0x404501f0 }, /* Not used */ + { 0x22, 0x404401f0 }, /* Not used */ + { 0x23, 0x40a701f0 }, /* Not used */ + {} +}; + static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_X200] = { .type = HDA_FIXUP_PINS, @@ -4440,11 +3226,115 @@ static const struct hda_fixup cxt_fixups[] = { [CXT_PINCFG_LENOVO_TP410] = { .type = HDA_FIXUP_PINS, .v.pins = cxt_pincfg_lenovo_tp410, + .chained = true, + .chain_id = CXT_FIXUP_THINKPAD_ACPI, + }, + [CXT_PINCFG_LEMOTE_A1004] = { + .type = HDA_FIXUP_PINS, + .chained = true, + .chain_id = CXT_FIXUP_INC_MIC_BOOST, + .v.pins = cxt_pincfg_lemote, + }, + [CXT_PINCFG_LEMOTE_A1205] = { + .type = HDA_FIXUP_PINS, + .v.pins = cxt_pincfg_lemote, }, [CXT_FIXUP_STEREO_DMIC] = { .type = HDA_FIXUP_FUNC, .v.func = cxt_fixup_stereo_dmic, }, + [CXT_FIXUP_INC_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt5066_increase_mic_boost, + }, + [CXT_FIXUP_HEADPHONE_MIC_PIN] = { + .type = HDA_FIXUP_PINS, + .chained = true, + .chain_id = CXT_FIXUP_HEADPHONE_MIC, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { } + } + }, + [CXT_FIXUP_HEADPHONE_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_headphone_mic, + }, + [CXT_FIXUP_GPIO1] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 }, + { 0x01, AC_VERB_SET_GPIO_DATA, 0x01 }, + { } + }, + }, + [CXT_FIXUP_THINKPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = hda_fixup_thinkpad_acpi, + }, + [CXT_FIXUP_OLPC_XO] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_olpc_xo, + }, + [CXT_FIXUP_CAP_MIX_AMP] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_cap_mix_amp, + }, + [CXT_FIXUP_TOSHIBA_P105] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x10, 0x961701f0 }, /* speaker/hp */ + { 0x12, 0x02a1901e }, /* ext mic */ + { 0x14, 0x95a70110 }, /* int mic */ + {} + }, + }, + [CXT_FIXUP_HP_530] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x90a60160 }, /* int mic */ + {} + }, + .chained = true, + .chain_id = CXT_FIXUP_CAP_MIX_AMP, + }, + [CXT_FIXUP_CAP_MIX_AMP_5047] = { + .type = HDA_FIXUP_FUNC, + .v.func = cxt_fixup_cap_mix_amp_5047, + }, +}; + +static const struct snd_pci_quirk cxt5045_fixups[] = { + SND_PCI_QUIRK(0x103c, 0x30d5, "HP 530", CXT_FIXUP_HP_530), + SND_PCI_QUIRK(0x1179, 0xff31, "Toshiba P105", CXT_FIXUP_TOSHIBA_P105), + /* HP, Packard Bell, Fujitsu-Siemens & Lenovo laptops have + * really bad sound over 0dB on NID 0x17. + */ + SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x1631, "Packard Bell", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x1734, "Fujitsu", CXT_FIXUP_CAP_MIX_AMP), + SND_PCI_QUIRK_VENDOR(0x17aa, "Lenovo", CXT_FIXUP_CAP_MIX_AMP), + {} +}; + +static const struct hda_model_fixup cxt5045_fixup_models[] = { + { .id = CXT_FIXUP_CAP_MIX_AMP, .name = "cap-mix-amp" }, + { .id = CXT_FIXUP_TOSHIBA_P105, .name = "toshiba-p105" }, + { .id = CXT_FIXUP_HP_530, .name = "hp-530" }, + {} +}; + +static const struct snd_pci_quirk cxt5047_fixups[] = { + /* HP laptops have really bad sound over 0 dB on NID 0x10. + */ + SND_PCI_QUIRK_VENDOR(0x103c, "HP", CXT_FIXUP_CAP_MIX_AMP_5047), + {} +}; + +static const struct hda_model_fixup cxt5047_fixup_models[] = { + { .id = CXT_FIXUP_CAP_MIX_AMP_5047, .name = "cap-mix-amp" }, + {} }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -4452,15 +3342,40 @@ static const struct snd_pci_quirk cxt5051_fixups[] = { {} }; +static const struct hda_model_fixup cxt5051_fixup_models[] = { + { .id = CXT_PINCFG_LENOVO_X200, .name = "lenovo-x200" }, + {} +}; + static const struct snd_pci_quirk cxt5066_fixups[] = { + SND_PCI_QUIRK(0x1025, 0x0543, "Acer Aspire One 522", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1025, 0x054c, "Acer Aspire 3830TG", CXT_FIXUP_GPIO1), + SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215e, "Lenovo T410", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), + SND_PCI_QUIRK(0x17aa, 0x21da, "Lenovo X220", CXT_PINCFG_LENOVO_TP410), + SND_PCI_QUIRK(0x17aa, 0x21db, "Lenovo X220-tablet", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x3977, "Lenovo IdeaPad U310", CXT_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x17aa, 0x397b, "Lenovo S205", CXT_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", CXT_FIXUP_THINKPAD_ACPI), + SND_PCI_QUIRK(0x1c06, 0x2011, "Lemote A1004", CXT_PINCFG_LEMOTE_A1004), + SND_PCI_QUIRK(0x1c06, 0x2012, "Lemote A1205", CXT_PINCFG_LEMOTE_A1205), + {} +}; + +static const struct hda_model_fixup cxt5066_fixup_models[] = { + { .id = CXT_FIXUP_STEREO_DMIC, .name = "stereo-dmic" }, + { .id = CXT_FIXUP_GPIO1, .name = "gpio1" }, + { .id = CXT_FIXUP_HEADPHONE_MIC_PIN, .name = "headphone-mic-pin" }, + { .id = CXT_PINCFG_LENOVO_TP410, .name = "tp410" }, + { .id = CXT_FIXUP_THINKPAD_ACPI, .name = "thinkpad" }, + { .id = CXT_PINCFG_LEMOTE_A1004, .name = "lemote-a1004" }, + { .id = CXT_FIXUP_OLPC_XO, .name = "olpc-xo" }, {} }; @@ -4485,32 +3400,48 @@ static int patch_conexant_auto(struct hda_codec *codec) struct conexant_spec *spec; int err; - printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); + codec_info(codec, "%s: BIOS auto-probing.\n", codec->chip_name); spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); codec->spec = spec; - snd_hda_gen_init(&spec->gen); + + cx_auto_parse_beep(codec); + cx_auto_parse_eapd(codec); + spec->gen.own_eapd_ctl = 1; + if (spec->dynamic_eapd) + spec->gen.vmaster_mute.hook = cx_auto_vmaster_hook; switch (codec->vendor_id) { case 0x14f15045: codec->single_adc_amp = 1; + spec->gen.mixer_nid = 0x17; + spec->gen.add_stereo_mix_input = 1; + snd_hda_pick_fixup(codec, cxt5045_fixup_models, + cxt5045_fixups, cxt_fixups); + break; + case 0x14f15047: + codec->pin_amp_workaround = 1; + spec->gen.mixer_nid = 0x19; + spec->gen.add_stereo_mix_input = 1; + snd_hda_pick_fixup(codec, cxt5047_fixup_models, + cxt5047_fixups, cxt_fixups); break; case 0x14f15051: add_cx5051_fake_mutes(codec); codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups); + snd_hda_pick_fixup(codec, cxt5051_fixup_models, + cxt5051_fixups, cxt_fixups); break; default: codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups); + snd_hda_pick_fixup(codec, cxt5066_fixup_models, + cxt5066_fixups, cxt_fixups); break; } - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - /* Show mute-led control only on HP laptops * This is a sort of white-list: on HP laptops, EAPD corresponds * only to the mute-LED without actualy amp function. Meanwhile, @@ -4519,38 +3450,50 @@ static int patch_conexant_auto(struct hda_codec *codec) */ switch (codec->subsystem_id >> 16) { case 0x103c: - spec->vmaster_mute_led = 1; + spec->gen.vmaster_mute_enum = 1; break; } - err = cx_auto_search_adcs(codec); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, + spec->parse_flags); if (err < 0) - return err; - err = cx_auto_parse_auto_config(codec); - if (err < 0) { - kfree(codec->spec); - codec->spec = NULL; - return err; - } - spec->capture_stream = &cx_auto_pcm_analog_capture; + goto error; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + goto error; + codec->patch_ops = cx_auto_patch_ops; - if (spec->beep_amp) - snd_hda_attach_beep_device(codec, spec->beep_amp); /* Some laptops with Conexant chips show stalls in S3 resume, * which falls into the single-cmd mode. * Better to make reset, then. */ if (!codec->bus->sync_write) { - snd_printd("hda_codec: " + codec_info(codec, "Enable sync_write for stable communication\n"); codec->bus->sync_write = 1; codec->bus->allow_bus_reset = 1; } + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; + + error: + cx_auto_free(codec); + return err; } +#ifndef ENABLE_CXT_STATIC_QUIRKS +#define patch_cxt5045 patch_conexant_auto +#define patch_cxt5047 patch_conexant_auto +#define patch_cxt5051 patch_conexant_auto +#define patch_cxt5066 patch_conexant_auto +#endif + /* */ @@ -4595,6 +3538,14 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_conexant_auto }, { .id = 0x14f15111, .name = "CX20753/4", .patch = patch_conexant_auto }, + { .id = 0x14f15113, .name = "CX20755", + .patch = patch_conexant_auto }, + { .id = 0x14f15114, .name = "CX20756", + .patch = patch_conexant_auto }, + { .id = 0x14f15115, .name = "CX20757", + .patch = patch_conexant_auto }, + { .id = 0x14f151d7, .name = "CX20952", + .patch = patch_conexant_auto }, {} /* terminator */ }; @@ -4618,6 +3569,10 @@ MODULE_ALIAS("snd-hda-codec-id:14f150b9"); MODULE_ALIAS("snd-hda-codec-id:14f1510f"); MODULE_ALIAS("snd-hda-codec-id:14f15110"); MODULE_ALIAS("snd-hda-codec-id:14f15111"); +MODULE_ALIAS("snd-hda-codec-id:14f15113"); +MODULE_ALIAS("snd-hda-codec-id:14f15114"); +MODULE_ALIAS("snd-hda-codec-id:14f15115"); +MODULE_ALIAS("snd-hda-codec-id:14f151d7"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 71555cc54db..ba4ca52072f 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c @@ -6,6 +6,7 @@ * Copyright (c) 2006 ATI Technologies Inc. * Copyright (c) 2008 NVIDIA Corp. All rights reserved. * Copyright (c) 2008 Wei Ni <wni@nvidia.com> + * Copyright (c) 2013 Anssi Hannula <anssi.hannula@iki.fi> * * Authors: * Wu Fengguang <wfg@linux.intel.com> @@ -44,15 +45,11 @@ static bool static_hdmi_pcm; module_param(static_hdmi_pcm, bool, 0644); MODULE_PARM_DESC(static_hdmi_pcm, "Don't restrict PCM parameters per ELD info"); -/* - * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device - * could support N independent pipes, each of them can be connected to one or - * more ports (DVI, HDMI or DisplayPort). - * - * The HDA correspondence of pipes/ports are converter/pin nodes. - */ -#define MAX_HDMI_CVTS 8 -#define MAX_HDMI_PINS 8 +#define is_haswell(codec) ((codec)->vendor_id == 0x80862807) +#define is_broadwell(codec) ((codec)->vendor_id == 0x80862808) +#define is_haswell_plus(codec) (is_haswell(codec) || is_broadwell(codec)) + +#define is_valleyview(codec) ((codec)->vendor_id == 0x80862882) struct hdmi_spec_per_cvt { hda_nid_t cvt_nid; @@ -64,31 +61,83 @@ struct hdmi_spec_per_cvt { unsigned int maxbps; }; +/* max. connections to a widget */ +#define HDA_MAX_CONNECTIONS 32 + struct hdmi_spec_per_pin { hda_nid_t pin_nid; int num_mux_nids; hda_nid_t mux_nids[HDA_MAX_CONNECTIONS]; + int mux_idx; + hda_nid_t cvt_nid; struct hda_codec *codec; struct hdmi_eld sink_eld; + struct mutex lock; struct delayed_work work; + struct snd_kcontrol *eld_ctl; int repoll_count; + bool setup; /* the stream has been set up by prepare callback */ + int channels; /* current number of channels */ bool non_pcm; bool chmap_set; /* channel-map override by ALSA API? */ unsigned char chmap[8]; /* ALSA API channel-map */ + char pcm_name[8]; /* filled in build_pcm callbacks */ +#ifdef CONFIG_PROC_FS + struct snd_info_entry *proc_entry; +#endif +}; + +struct cea_channel_speaker_allocation; + +/* operations used by generic code that can be overridden by patches */ +struct hdmi_ops { + int (*pin_get_eld)(struct hda_codec *codec, hda_nid_t pin_nid, + unsigned char *buf, int *eld_size); + + /* get and set channel assigned to each HDMI ASP (audio sample packet) slot */ + int (*pin_get_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid, + int asp_slot); + int (*pin_set_slot_channel)(struct hda_codec *codec, hda_nid_t pin_nid, + int asp_slot, int channel); + + void (*pin_setup_infoframe)(struct hda_codec *codec, hda_nid_t pin_nid, + int ca, int active_channels, int conn_type); + + /* enable/disable HBR (HD passthrough) */ + int (*pin_hbr_setup)(struct hda_codec *codec, hda_nid_t pin_nid, bool hbr); + + int (*setup_stream)(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, u32 stream_tag, int format); + + /* Helpers for producing the channel map TLVs. These can be overridden + * for devices that have non-standard mapping requirements. */ + int (*chmap_cea_alloc_validate_get_type)(struct cea_channel_speaker_allocation *cap, + int channels); + void (*cea_alloc_to_tlv_chmap)(struct cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels); + + /* check that the user-given chmap is supported */ + int (*chmap_validate)(int ca, int channels, unsigned char *chmap); }; struct hdmi_spec { int num_cvts; - struct hdmi_spec_per_cvt cvts[MAX_HDMI_CVTS]; + struct snd_array cvts; /* struct hdmi_spec_per_cvt */ + hda_nid_t cvt_nids[4]; /* only for haswell fix */ int num_pins; - struct hdmi_spec_per_pin pins[MAX_HDMI_PINS]; - struct hda_pcm pcm_rec[MAX_HDMI_PINS]; + struct snd_array pins; /* struct hdmi_spec_per_pin */ + struct snd_array pcm_rec; /* struct hda_pcm */ unsigned int channels_max; /* max over all cvts */ + struct hdmi_eld temp_eld; + struct hdmi_ops ops; + + bool dyn_pin_out; + /* - * Non-generic ATI/NVIDIA specific + * Non-generic VIA/NVIDIA specific */ struct hda_multi_out multiout; struct hda_pcm_stream pcm_playback; @@ -298,40 +347,50 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { * HDMI routines */ -static int pin_nid_to_pin_index(struct hdmi_spec *spec, hda_nid_t pin_nid) +#define get_pin(spec, idx) \ + ((struct hdmi_spec_per_pin *)snd_array_elem(&spec->pins, idx)) +#define get_cvt(spec, idx) \ + ((struct hdmi_spec_per_cvt *)snd_array_elem(&spec->cvts, idx)) +#define get_pcm_rec(spec, idx) \ + ((struct hda_pcm *)snd_array_elem(&spec->pcm_rec, idx)) + +static int pin_nid_to_pin_index(struct hda_codec *codec, hda_nid_t pin_nid) { + struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (spec->pins[pin_idx].pin_nid == pin_nid) + if (get_pin(spec, pin_idx)->pin_nid == pin_nid) return pin_idx; - snd_printk(KERN_WARNING "HDMI: pin nid %d not registered\n", pin_nid); + codec_warn(codec, "HDMI: pin nid %d not registered\n", pin_nid); return -EINVAL; } -static int hinfo_to_pin_index(struct hdmi_spec *spec, +static int hinfo_to_pin_index(struct hda_codec *codec, struct hda_pcm_stream *hinfo) { + struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) - if (&spec->pcm_rec[pin_idx].stream[0] == hinfo) + if (get_pcm_rec(spec, pin_idx)->stream == hinfo) return pin_idx; - snd_printk(KERN_WARNING "HDMI: hinfo %p not registered\n", hinfo); + codec_warn(codec, "HDMI: hinfo %p not registered\n", hinfo); return -EINVAL; } -static int cvt_nid_to_cvt_index(struct hdmi_spec *spec, hda_nid_t cvt_nid) +static int cvt_nid_to_cvt_index(struct hda_codec *codec, hda_nid_t cvt_nid) { + struct hdmi_spec *spec = codec->spec; int cvt_idx; for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) - if (spec->cvts[cvt_idx].cvt_nid == cvt_nid) + if (get_cvt(spec, cvt_idx)->cvt_nid == cvt_nid) return cvt_idx; - snd_printk(KERN_WARNING "HDMI: cvt nid %d not registered\n", cvt_nid); + codec_warn(codec, "HDMI: cvt nid %d not registered\n", cvt_nid); return -EINVAL; } @@ -339,14 +398,20 @@ static int hdmi_eld_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hdmi_spec *spec; + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin; + struct hdmi_eld *eld; int pin_idx; - spec = codec->spec; uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; pin_idx = kcontrol->private_value; - uinfo->count = spec->pins[pin_idx].sink_eld.eld_size; + per_pin = get_pin(spec, pin_idx); + eld = &per_pin->sink_eld; + + mutex_lock(&per_pin->lock); + uinfo->count = eld->eld_valid ? eld->eld_size : 0; + mutex_unlock(&per_pin->lock); return 0; } @@ -355,14 +420,28 @@ static int hdmi_eld_ctl_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct hdmi_spec *spec; + struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_pin *per_pin; + struct hdmi_eld *eld; int pin_idx; - spec = codec->spec; pin_idx = kcontrol->private_value; + per_pin = get_pin(spec, pin_idx); + eld = &per_pin->sink_eld; - memcpy(ucontrol->value.bytes.data, - spec->pins[pin_idx].sink_eld.eld_buffer, ELD_MAX_SIZE); + mutex_lock(&per_pin->lock); + if (eld->eld_size > ARRAY_SIZE(ucontrol->value.bytes.data)) { + mutex_unlock(&per_pin->lock); + snd_BUG(); + return -EINVAL; + } + + memset(ucontrol->value.bytes.data, 0, + ARRAY_SIZE(ucontrol->value.bytes.data)); + if (eld->eld_valid) + memcpy(ucontrol->value.bytes.data, eld->eld_buffer, + eld->eld_size); + mutex_unlock(&per_pin->lock); return 0; } @@ -388,10 +467,11 @@ static int hdmi_create_eld_ctl(struct hda_codec *codec, int pin_idx, kctl->private_value = pin_idx; kctl->id.device = device; - err = snd_hda_ctl_add(codec, spec->pins[pin_idx].pin_nid, kctl); + err = snd_hda_ctl_add(codec, get_pin(spec, pin_idx)->pin_nid, kctl); if (err < 0) return err; + get_pin(spec, pin_idx)->eld_ctl = kctl; return 0; } @@ -427,13 +507,25 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid) { + struct hdmi_spec *spec = codec->spec; + int pin_out; + /* Unmute */ 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_UNMUTE); - /* Disable pin out until stream is active*/ + + if (spec->dyn_pin_out) + /* Disable pin out until stream is active */ + pin_out = 0; + else + /* Enable pin out: some machines with GM965 gets broken output + * when the pin is disabled or changed while using with HDMI + */ + pin_out = PIN_OUT; + snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out); } static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid) @@ -450,6 +542,68 @@ static void hdmi_set_channel_count(struct hda_codec *codec, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); } +/* + * ELD proc files + */ + +#ifdef CONFIG_PROC_FS +static void print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_spec_per_pin *per_pin = entry->private_data; + + mutex_lock(&per_pin->lock); + snd_hdmi_print_eld_info(&per_pin->sink_eld, buffer); + mutex_unlock(&per_pin->lock); +} + +static void write_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_spec_per_pin *per_pin = entry->private_data; + + mutex_lock(&per_pin->lock); + snd_hdmi_write_eld_info(&per_pin->sink_eld, buffer); + mutex_unlock(&per_pin->lock); +} + +static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) +{ + char name[32]; + struct hda_codec *codec = per_pin->codec; + struct snd_info_entry *entry; + int err; + + snprintf(name, sizeof(name), "eld#%d.%d", codec->addr, index); + err = snd_card_proc_new(codec->bus->card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, per_pin, print_eld_info); + entry->c.text.write = write_eld_info; + entry->mode |= S_IWUSR; + per_pin->proc_entry = entry; + + return 0; +} + +static void eld_proc_free(struct hdmi_spec_per_pin *per_pin) +{ + if (!per_pin->codec->bus->shutdown && per_pin->proc_entry) { + snd_device_free(per_pin->codec->bus->card, per_pin->proc_entry); + per_pin->proc_entry = NULL; + } +} +#else +static inline int eld_proc_new(struct hdmi_spec_per_pin *per_pin, + int index) +{ + return 0; +} +static inline void eld_proc_free(struct hdmi_spec_per_pin *per_pin) +{ +} +#endif /* * Channel mapping routines @@ -514,7 +668,7 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) * expand ELD's notions to match the ones used by Audio InfoFrame. */ for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (eld->spk_alloc & (1 << i)) + if (eld->info.spk_alloc & (1 << i)) spk_mask |= eld_speaker_allocation_bits[i]; } @@ -528,7 +682,18 @@ static int hdmi_channel_allocation(struct hdmi_eld *eld, int channels) } } - snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); + if (!ca) { + /* if there was no match, select the regular ALSA channel + * allocation with the matching number of channels */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels) { + ca = channel_allocations[i].ca_index; + break; + } + } + } + + snd_print_channel_allocation(eld->info.spk_alloc, buf, sizeof(buf)); snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", ca, channels, buf); @@ -539,74 +704,90 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid) { #ifdef CONFIG_SND_DEBUG_VERBOSE + struct hdmi_spec *spec = codec->spec; int i; - int slot; + int channel; for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", - slot >> 4, slot & 0xf); + channel = spec->ops.pin_get_slot_channel(codec, pin_nid, i); + codec_dbg(codec, "HDMI: ASP channel %d => slot %d\n", + channel, i); } #endif } - static void hdmi_std_setup_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid, bool non_pcm, int ca) { + struct hdmi_spec *spec = codec->spec; + struct cea_channel_speaker_allocation *ch_alloc; int i; int err; int order; int non_pcm_mapping[8]; order = get_channel_allocation_order(ca); + ch_alloc = &channel_allocations[order]; if (hdmi_channel_mapping[ca][1] == 0) { - for (i = 0; i < channel_allocations[order].channels; i++) - hdmi_channel_mapping[ca][i] = i | (i << 4); - for (; i < 8; i++) - hdmi_channel_mapping[ca][i] = 0xf | (i << 4); + int hdmi_slot = 0; + /* fill actual channel mappings in ALSA channel (i) order */ + for (i = 0; i < ch_alloc->channels; i++) { + while (!ch_alloc->speakers[7 - hdmi_slot] && !WARN_ON(hdmi_slot >= 8)) + hdmi_slot++; /* skip zero slots */ + + hdmi_channel_mapping[ca][i] = (i << 4) | hdmi_slot++; + } + /* fill the rest of the slots with ALSA channel 0xf */ + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) + if (!ch_alloc->speakers[7 - hdmi_slot]) + hdmi_channel_mapping[ca][i++] = (0xf << 4) | hdmi_slot; } if (non_pcm) { - for (i = 0; i < channel_allocations[order].channels; i++) - non_pcm_mapping[i] = i | (i << 4); + for (i = 0; i < ch_alloc->channels; i++) + non_pcm_mapping[i] = (i << 4) | i; for (; i < 8; i++) - non_pcm_mapping[i] = 0xf | (i << 4); + non_pcm_mapping[i] = (0xf << 4) | i; } for (i = 0; i < 8; i++) { - err = snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]); + int slotsetup = non_pcm ? non_pcm_mapping[i] : hdmi_channel_mapping[ca][i]; + int hdmi_slot = slotsetup & 0x0f; + int channel = (slotsetup & 0xf0) >> 4; + err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, channel); if (err) { - snd_printdd(KERN_NOTICE - "HDMI: channel mapping failed\n"); + codec_dbg(codec, "HDMI: channel mapping failed\n"); break; } } - - hdmi_debug_channel_mapping(codec, pin_nid); } struct channel_map_table { unsigned char map; /* ALSA API channel map position */ - unsigned char cea_slot; /* CEA slot value */ int spk_mask; /* speaker position bit mask */ }; static struct channel_map_table map_tables[] = { - { SNDRV_CHMAP_FL, 0x00, FL }, - { SNDRV_CHMAP_FR, 0x01, FR }, - { SNDRV_CHMAP_RL, 0x04, RL }, - { SNDRV_CHMAP_RR, 0x05, RR }, - { SNDRV_CHMAP_LFE, 0x02, LFE }, - { SNDRV_CHMAP_FC, 0x03, FC }, - { SNDRV_CHMAP_RLC, 0x06, RLC }, - { SNDRV_CHMAP_RRC, 0x07, RRC }, + { SNDRV_CHMAP_FL, FL }, + { SNDRV_CHMAP_FR, FR }, + { SNDRV_CHMAP_RL, RL }, + { SNDRV_CHMAP_RR, RR }, + { SNDRV_CHMAP_LFE, LFE }, + { SNDRV_CHMAP_FC, FC }, + { SNDRV_CHMAP_RLC, RLC }, + { SNDRV_CHMAP_RRC, RRC }, + { SNDRV_CHMAP_RC, RC }, + { SNDRV_CHMAP_FLC, FLC }, + { SNDRV_CHMAP_FRC, FRC }, + { SNDRV_CHMAP_TFL, FLH }, + { SNDRV_CHMAP_TFR, FRH }, + { SNDRV_CHMAP_FLW, FLW }, + { SNDRV_CHMAP_FRW, FRW }, + { SNDRV_CHMAP_TC, TC }, + { SNDRV_CHMAP_TFC, FCH }, {} /* terminator */ }; @@ -622,25 +803,19 @@ static int to_spk_mask(unsigned char c) } /* from ALSA API channel position to CEA slot */ -static int to_cea_slot(unsigned char c) +static int to_cea_slot(int ordered_ca, unsigned char pos) { - struct channel_map_table *t = map_tables; - for (; t->map; t++) { - if (t->map == c) - return t->cea_slot; - } - return 0x0f; -} + int mask = to_spk_mask(pos); + int i; -/* from CEA slot to ALSA API channel position */ -static int from_cea_slot(unsigned char c) -{ - struct channel_map_table *t = map_tables; - for (; t->map; t++) { - if (t->cea_slot == c) - return t->map; + if (mask) { + for (i = 0; i < 8; i++) { + if (channel_allocations[ordered_ca].speakers[7 - i] == mask) + return i; + } } - return 0; + + return -1; } /* from speaker bit mask to ALSA API channel position */ @@ -654,6 +829,14 @@ static int spk_to_chmap(int spk) return 0; } +/* from CEA slot to ALSA API channel position */ +static int from_cea_slot(int ordered_ca, unsigned char slot) +{ + int mask = channel_allocations[ordered_ca].speakers[7 - slot]; + + return spk_to_chmap(mask); +} + /* get the CA index corresponding to the given ALSA API channel map */ static int hdmi_manual_channel_allocation(int chs, unsigned char *map) { @@ -680,18 +863,29 @@ static int hdmi_manual_channel_allocation(int chs, unsigned char *map) /* set up the channel slots for the given ALSA API channel map */ static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid, - int chs, unsigned char *map) + int chs, unsigned char *map, + int ca) { - int i; - for (i = 0; i < 8; i++) { - int val, err; - if (i < chs) - val = to_cea_slot(map[i]); - else - val = 0xf; - val |= (i << 4); - err = snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, val); + struct hdmi_spec *spec = codec->spec; + int ordered_ca = get_channel_allocation_order(ca); + int alsa_pos, hdmi_slot; + int assignments[8] = {[0 ... 7] = 0xf}; + + for (alsa_pos = 0; alsa_pos < chs; alsa_pos++) { + + hdmi_slot = to_cea_slot(ordered_ca, map[alsa_pos]); + + if (hdmi_slot < 0) + continue; /* unassigned channel */ + + assignments[hdmi_slot] = alsa_pos; + } + + for (hdmi_slot = 0; hdmi_slot < 8; hdmi_slot++) { + int err; + + err = spec->ops.pin_set_slot_channel(codec, pin_nid, hdmi_slot, + assignments[hdmi_slot]); if (err) return -EINVAL; } @@ -702,9 +896,10 @@ static int hdmi_manual_setup_channel_mapping(struct hda_codec *codec, static void hdmi_setup_fake_chmap(unsigned char *map, int ca) { int i; + int ordered_ca = get_channel_allocation_order(ca); for (i = 0; i < 8; i++) { - if (i < channel_allocations[ca].channels) - map[i] = from_cea_slot((hdmi_channel_mapping[ca][i] >> 4) & 0x0f); + if (i < channel_allocations[ordered_ca].channels) + map[i] = from_cea_slot(ordered_ca, hdmi_channel_mapping[ca][i] & 0x0f); else map[i] = 0; } @@ -712,15 +907,34 @@ static void hdmi_setup_fake_chmap(unsigned char *map, int ca) static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t pin_nid, bool non_pcm, int ca, - int channels, unsigned char *map) + int channels, unsigned char *map, + bool chmap_set) { - if (!non_pcm && map) { + if (!non_pcm && chmap_set) { hdmi_manual_setup_channel_mapping(codec, pin_nid, - channels, map); + channels, map, ca); } else { hdmi_std_setup_channel_mapping(codec, pin_nid, non_pcm, ca); hdmi_setup_fake_chmap(map, ca); } + + hdmi_debug_channel_mapping(codec, pin_nid); +} + +static int hdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, + int asp_slot, int channel) +{ + return snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + (channel << 4) | asp_slot); +} + +static int hdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, + int asp_slot) +{ + return (snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, + asp_slot) & 0xf0) >> 4; } /* @@ -756,12 +970,12 @@ static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) int size; size = snd_hdmi_get_eld_size(codec, pin_nid); - printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); + codec_dbg(codec, "HDMI: ELD buf size is %d\n", size); for (i = 0; i < 8; i++) { size = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); + codec_dbg(codec, "HDMI: DIP GP[%d] buf size is %d\n", i, size); } #endif } @@ -783,12 +997,12 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) hdmi_write_dip_byte(codec, pin_nid, 0x0); hdmi_get_dip_index(codec, pin_nid, &pi, &bi); if (pi != i) - snd_printd(KERN_INFO "dip index %d: %d != %d\n", + codec_dbg(codec, "dip index %d: %d != %d\n", bi, pi, i); if (bi == 0) /* byte index wrapped around */ break; } - snd_printd(KERN_INFO + codec_dbg(codec, "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", i, size, j); } @@ -844,49 +1058,33 @@ static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, return true; } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, - bool non_pcm, - struct snd_pcm_substream *substream) +static void hdmi_pin_setup_infoframe(struct hda_codec *codec, + hda_nid_t pin_nid, + int ca, int active_channels, + int conn_type) { - struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - hda_nid_t pin_nid = per_pin->pin_nid; - int channels = substream->runtime->channels; - struct hdmi_eld *eld; - int ca; union audio_infoframe ai; - eld = &spec->pins[pin_idx].sink_eld; - if (!eld->monitor_present) - return; - - if (!non_pcm && per_pin->chmap_set) - ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); - else - ca = hdmi_channel_allocation(eld, channels); - if (ca < 0) - ca = 0; - memset(&ai, 0, sizeof(ai)); - if (eld->conn_type == 0) { /* HDMI */ + if (conn_type == 0) { /* HDMI */ struct hdmi_audio_infoframe *hdmi_ai = &ai.hdmi; hdmi_ai->type = 0x84; hdmi_ai->ver = 0x01; hdmi_ai->len = 0x0a; - hdmi_ai->CC02_CT47 = channels - 1; + hdmi_ai->CC02_CT47 = active_channels - 1; hdmi_ai->CA = ca; hdmi_checksum_audio_infoframe(hdmi_ai); - } else if (eld->conn_type == 1) { /* DisplayPort */ + } else if (conn_type == 1) { /* DisplayPort */ struct dp_audio_infoframe *dp_ai = &ai.dp; dp_ai->type = 0x84; dp_ai->len = 0x1b; dp_ai->ver = 0x11 << 2; - dp_ai->CC02_CT47 = channels - 1; + dp_ai->CC02_CT47 = active_channels - 1; dp_ai->CA = ca; } else { - snd_printd("HDMI: unknown connection type at pin %d\n", + codec_dbg(codec, "HDMI: unknown connection type at pin %d\n", pin_nid); return; } @@ -898,59 +1096,98 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, int pin_idx, */ if (!hdmi_infoframe_uptodate(codec, pin_nid, ai.bytes, sizeof(ai))) { - snd_printdd("hdmi_setup_audio_infoframe: " - "pin=%d channels=%d\n", + codec_dbg(codec, + "hdmi_pin_setup_infoframe: pin=%d channels=%d ca=0x%02x\n", pin_nid, - channels); - hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, - channels, per_pin->chmap); + active_channels, ca); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, ai.bytes, sizeof(ai)); hdmi_start_infoframe_trans(codec, pin_nid); - } else { - /* For non-pcm audio switch, setup new channel mapping - * accordingly */ - if (per_pin->non_pcm != non_pcm) - hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, - channels, per_pin->chmap); } +} + +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin, + bool non_pcm) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid = per_pin->pin_nid; + int channels = per_pin->channels; + int active_channels; + struct hdmi_eld *eld; + int ca, ordered_ca; + + if (!channels) + return; + + if (is_haswell_plus(codec)) + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, + AMP_OUT_UNMUTE); + + eld = &per_pin->sink_eld; + + if (!non_pcm && per_pin->chmap_set) + ca = hdmi_manual_channel_allocation(channels, per_pin->chmap); + else + ca = hdmi_channel_allocation(eld, channels); + if (ca < 0) + ca = 0; + + ordered_ca = get_channel_allocation_order(ca); + active_channels = channel_allocations[ordered_ca].channels; + + hdmi_set_channel_count(codec, per_pin->cvt_nid, active_channels); + + /* + * always configure channel mapping, it may have been changed by the + * user in the meantime + */ + hdmi_setup_channel_mapping(codec, pin_nid, non_pcm, ca, + channels, per_pin->chmap, + per_pin->chmap_set); + + spec->ops.pin_setup_infoframe(codec, pin_nid, ca, active_channels, + eld->info.conn_type); per_pin->non_pcm = non_pcm; } - /* * Unsolicited events */ -static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); +static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll); -static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +static void jack_callback(struct hda_codec *codec, struct hda_jack_tbl *jack) { struct hdmi_spec *spec = codec->spec; + int pin_idx = pin_nid_to_pin_index(codec, jack->nid); + if (pin_idx < 0) + return; + + if (hdmi_present_sense(get_pin(spec, pin_idx), 1)) + snd_hda_jack_report_sync(codec); +} + +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ int tag = res >> AC_UNSOL_RES_TAG_SHIFT; - int pin_nid; - int pin_idx; struct hda_jack_tbl *jack; + int dev_entry = (res & AC_UNSOL_RES_DE) >> AC_UNSOL_RES_DE_SHIFT; jack = snd_hda_jack_tbl_get_from_tag(codec, tag); if (!jack) return; - pin_nid = jack->nid; jack->jack_dirty = 1; - _snd_printd(SND_PR_VERBOSE, - "HDMI hot plug event: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, + codec_dbg(codec, + "HDMI hot plug event: Codec=%d Pin=%d Device=%d Inactive=%d Presence_Detect=%d ELD_Valid=%d\n", + codec->addr, jack->nid, dev_entry, !!(res & AC_UNSOL_RES_IA), !!(res & AC_UNSOL_RES_PD), !!(res & AC_UNSOL_RES_ELDV)); - pin_idx = pin_nid_to_pin_index(spec, pin_nid); - if (pin_idx < 0) - return; - - hdmi_present_sense(&spec->pins[pin_idx], 1); - snd_hda_jack_report_sync(codec); + jack_callback(codec, jack); } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) @@ -960,7 +1197,7 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); - printk(KERN_INFO + codec_info(codec, "HDMI CP event: CODEC=%d TAG=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", codec->addr, tag, @@ -982,7 +1219,7 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; if (!snd_hda_jack_tbl_get_from_tag(codec, tag)) { - snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); + codec_dbg(codec, "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -992,6 +1229,27 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) hdmi_non_intrinsic_event(codec, res); } +static void haswell_verify_D0(struct hda_codec *codec, + hda_nid_t cvt_nid, hda_nid_t nid) +{ + int pwr; + + /* For Haswell, the converter 1/2 may keep in D3 state after bootup, + * thus pins could only choose converter 0 for use. Make sure the + * converters are in correct power state */ + if (!snd_hda_check_power_state(codec, cvt_nid, AC_PWRST_D0)) + snd_hda_codec_write(codec, cvt_nid, 0, AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + if (!snd_hda_check_power_state(codec, nid, AC_PWRST_D0)) { + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + msleep(40); + pwr = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_POWER_STATE, 0); + pwr = (pwr & AC_PWRST_ACTUAL) >> AC_PWRST_ACTUAL_SHIFT; + codec_dbg(codec, "Haswell HDMI audio: Power for pin 0x%x is now D%d\n", nid, pwr); + } +} + /* * Callbacks */ @@ -1000,24 +1258,26 @@ static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) #define is_hbr_format(format) \ ((format & AC_FMT_TYPE_NON_PCM) && (format & AC_FMT_CHAN_MASK) == 7) -static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, - hda_nid_t pin_nid, u32 stream_tag, int format) +static int hdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, + bool hbr) { - int pinctl; - int new_pinctl = 0; + int pinctl, new_pinctl; if (snd_hda_query_pin_caps(codec, pin_nid) & AC_PINCAP_HBR) { pinctl = snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + if (pinctl < 0) + return hbr ? -EINVAL : 0; + new_pinctl = pinctl & ~AC_PINCTL_EPT; - if (is_hbr_format(format)) + if (hbr) new_pinctl |= AC_PINCTL_EPT_HBR; else new_pinctl |= AC_PINCTL_EPT_NATIVE; - snd_printdd("hdmi_setup_stream: " - "NID=0x%x, %spinctl=0x%x\n", + codec_dbg(codec, + "hdmi_pin_hbr_setup: NID=0x%x, %spinctl=0x%x\n", pin_nid, pinctl == new_pinctl ? "" : "new-", new_pinctl); @@ -1026,41 +1286,45 @@ static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, new_pinctl); - - } - if (is_hbr_format(format) && !new_pinctl) { - snd_printdd("hdmi_setup_stream: HBR is not supported\n"); + } else if (hbr) return -EINVAL; + + return 0; +} + +static int hdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, u32 stream_tag, int format) +{ + struct hdmi_spec *spec = codec->spec; + int err; + + if (is_haswell_plus(codec)) + haswell_verify_D0(codec, cvt_nid, pin_nid); + + err = spec->ops.pin_hbr_setup(codec, pin_nid, is_hbr_format(format)); + + if (err) { + codec_dbg(codec, "hdmi_setup_stream: HBR is not supported\n"); + return err; } snd_hda_codec_setup_stream(codec, cvt_nid, stream_tag, 0, format); return 0; } -/* - * HDA PCM callbacks - */ -static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int hdmi_choose_cvt(struct hda_codec *codec, + int pin_idx, int *cvt_id, int *mux_id) { struct hdmi_spec *spec = codec->spec; - struct snd_pcm_runtime *runtime = substream->runtime; - int pin_idx, cvt_idx, mux_idx = 0; struct hdmi_spec_per_pin *per_pin; - struct hdmi_eld *eld; struct hdmi_spec_per_cvt *per_cvt = NULL; + int cvt_idx, mux_idx = 0; - /* Validate hinfo */ - pin_idx = hinfo_to_pin_index(spec, hinfo); - if (snd_BUG_ON(pin_idx < 0)) - return -EINVAL; - per_pin = &spec->pins[pin_idx]; - eld = &per_pin->sink_eld; + per_pin = get_pin(spec, pin_idx); /* Dynamically assign converter to stream */ for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = get_cvt(spec, cvt_idx); /* Must not already be assigned */ if (per_cvt->assigned) @@ -1074,17 +1338,129 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, continue; break; } + /* No free converters */ if (cvt_idx == spec->num_cvts) return -ENODEV; + per_pin->mux_idx = mux_idx; + + if (cvt_id) + *cvt_id = cvt_idx; + if (mux_id) + *mux_id = mux_idx; + + return 0; +} + +/* Assure the pin select the right convetor */ +static void intel_verify_pin_cvt_connect(struct hda_codec *codec, + struct hdmi_spec_per_pin *per_pin) +{ + hda_nid_t pin_nid = per_pin->pin_nid; + int mux_idx, curr; + + mux_idx = per_pin->mux_idx; + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (curr != mux_idx) + snd_hda_codec_write_cache(codec, pin_nid, 0, + AC_VERB_SET_CONNECT_SEL, + mux_idx); +} + +/* Intel HDMI workaround to fix audio routing issue: + * For some Intel display codecs, pins share the same connection list. + * So a conveter can be selected by multiple pins and playback on any of these + * pins will generate sound on the external display, because audio flows from + * the same converter to the display pipeline. Also muting one pin may make + * other pins have no sound output. + * So this function assures that an assigned converter for a pin is not selected + * by any other pins. + */ +static void intel_not_share_assigned_cvt(struct hda_codec *codec, + hda_nid_t pin_nid, int mux_idx) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t nid, end_nid; + int cvt_idx, curr; + struct hdmi_spec_per_cvt *per_cvt; + + /* configure all pins, including "no physical connection" ones */ + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wid_caps = get_wcaps(codec, nid); + unsigned int wid_type = get_wcaps_type(wid_caps); + + if (wid_type != AC_WID_PIN) + continue; + + if (nid == pin_nid) + continue; + + curr = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (curr != mux_idx) + continue; + + /* choose an unassigned converter. The conveters in the + * connection list are in the same order as in the codec. + */ + for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { + per_cvt = get_cvt(spec, cvt_idx); + if (!per_cvt->assigned) { + codec_dbg(codec, + "choose cvt %d for pin nid %d\n", + cvt_idx, nid); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, + cvt_idx); + break; + } + } + } +} + +/* + * HDA PCM callbacks + */ +static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hdmi_spec *spec = codec->spec; + struct snd_pcm_runtime *runtime = substream->runtime; + int pin_idx, cvt_idx, mux_idx = 0; + struct hdmi_spec_per_pin *per_pin; + struct hdmi_eld *eld; + struct hdmi_spec_per_cvt *per_cvt = NULL; + int err; + + /* Validate hinfo */ + pin_idx = hinfo_to_pin_index(codec, hinfo); + if (snd_BUG_ON(pin_idx < 0)) + return -EINVAL; + per_pin = get_pin(spec, pin_idx); + eld = &per_pin->sink_eld; + + err = hdmi_choose_cvt(codec, pin_idx, &cvt_idx, &mux_idx); + if (err < 0) + return err; + + per_cvt = get_cvt(spec, cvt_idx); /* Claim converter */ per_cvt->assigned = 1; + per_pin->cvt_nid = per_cvt->cvt_nid; hinfo->nid = per_cvt->cvt_nid; - snd_hda_codec_write(codec, per_pin->pin_nid, 0, + snd_hda_codec_write_cache(codec, per_pin->pin_nid, 0, AC_VERB_SET_CONNECT_SEL, mux_idx); + + /* configure unused pins to choose other converters */ + if (is_haswell_plus(codec) || is_valleyview(codec)) + intel_not_share_assigned_cvt(codec, per_pin->pin_nid, mux_idx); + snd_hda_spdif_ctls_assign(codec, pin_idx, per_cvt->cvt_nid); /* Initially set the converter's capabilities */ @@ -1096,10 +1472,14 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, /* Restrict capabilities by ELD if this isn't disabled */ if (!static_hdmi_pcm && eld->eld_valid) { - snd_hdmi_eld_update_pcm_info(eld, hinfo); + snd_hdmi_eld_update_pcm_info(&eld->info, hinfo); if (hinfo->channels_min > hinfo->channels_max || - !hinfo->rates || !hinfo->formats) + !hinfo->rates || !hinfo->formats) { + per_cvt->assigned = 0; + hinfo->nid = 0; + snd_hda_spdif_ctls_unassign(codec, pin_idx); return -ENODEV; + } } /* Store the updated parameters */ @@ -1119,13 +1499,12 @@ static int hdmi_pcm_open(struct hda_pcm_stream *hinfo, static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) { struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; if (!(get_wcaps(codec, pin_nid) & AC_WCAP_CONN_LIST)) { - snd_printk(KERN_WARNING - "HDMI: pin %d wcaps %#x " - "does not support connection list\n", + codec_warn(codec, + "HDMI: pin %d wcaps %#x does not support connection list\n", pin_nid, get_wcaps(codec, pin_nid)); return -EINVAL; } @@ -1137,10 +1516,13 @@ static int hdmi_read_pin_conn(struct hda_codec *codec, int pin_idx) return 0; } -static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) +static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) { + struct hda_jack_tbl *jack; struct hda_codec *codec = per_pin->codec; - struct hdmi_eld *eld = &per_pin->sink_eld; + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld = &spec->temp_eld; + struct hdmi_eld *pin_eld = &per_pin->sink_eld; hda_nid_t pin_nid = per_pin->pin_nid; /* * Always execute a GetPinSense verb here, even when called from @@ -1150,28 +1532,96 @@ static void hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll) * specification worked this way. Hence, we just ignore the data in * the unsolicited response to avoid custom WARs. */ - int present = snd_hda_pin_sense(codec, pin_nid); - bool eld_valid = false; - - memset(eld, 0, offsetof(struct hdmi_eld, eld_buffer)); - - eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); - if (eld->monitor_present) - eld_valid = !!(present & AC_PINSENSE_ELDV); + int present; + bool update_eld = false; + bool eld_changed = false; + bool ret; + + snd_hda_power_up(codec); + present = snd_hda_pin_sense(codec, pin_nid); + + mutex_lock(&per_pin->lock); + pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); + if (pin_eld->monitor_present) + eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + else + eld->eld_valid = false; - _snd_printd(SND_PR_VERBOSE, + codec_dbg(codec, "HDMI status: Codec=%d Pin=%d Presence_Detect=%d ELD_Valid=%d\n", - codec->addr, pin_nid, eld->monitor_present, eld_valid); + codec->addr, pin_nid, pin_eld->monitor_present, eld->eld_valid); + + if (eld->eld_valid) { + if (spec->ops.pin_get_eld(codec, pin_nid, eld->eld_buffer, + &eld->eld_size) < 0) + eld->eld_valid = false; + else { + memset(&eld->info, 0, sizeof(struct parsed_hdmi_eld)); + if (snd_hdmi_parse_eld(&eld->info, eld->eld_buffer, + eld->eld_size) < 0) + eld->eld_valid = false; + } - if (eld_valid) { - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) - snd_hdmi_show_eld(eld); + if (eld->eld_valid) { + snd_hdmi_show_eld(&eld->info); + update_eld = true; + } else if (repoll) { queue_delayed_work(codec->bus->workq, &per_pin->work, msecs_to_jiffies(300)); + goto unlock; + } + } + + if (pin_eld->eld_valid && !eld->eld_valid) { + update_eld = true; + eld_changed = true; + } + if (update_eld) { + bool old_eld_valid = pin_eld->eld_valid; + pin_eld->eld_valid = eld->eld_valid; + eld_changed = pin_eld->eld_size != eld->eld_size || + memcmp(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size) != 0; + if (eld_changed) + memcpy(pin_eld->eld_buffer, eld->eld_buffer, + eld->eld_size); + pin_eld->eld_size = eld->eld_size; + pin_eld->info = eld->info; + + /* + * Re-setup pin and infoframe. This is needed e.g. when + * - sink is first plugged-in (infoframe is not set up if !monitor_present) + * - transcoder can change during stream playback on Haswell + * and this can make HW reset converter selection on a pin. + */ + if (eld->eld_valid && !old_eld_valid && per_pin->setup) { + if (is_haswell_plus(codec) || is_valleyview(codec)) { + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, pin_nid, + per_pin->mux_idx); + } + + hdmi_setup_audio_infoframe(codec, per_pin, + per_pin->non_pcm); } } + + if (eld_changed) + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE | SNDRV_CTL_EVENT_MASK_INFO, + &per_pin->eld_ctl->id); + unlock: + ret = !repoll || !pin_eld->monitor_present || pin_eld->eld_valid; + + jack = snd_hda_jack_tbl_get(codec, pin_nid); + if (jack) + jack->block_report = !ret; + + mutex_unlock(&per_pin->lock); + snd_hda_power_down(codec); + return ret; } static void hdmi_repoll_eld(struct work_struct *work) @@ -1182,9 +1632,13 @@ static void hdmi_repoll_eld(struct work_struct *work) if (per_pin->repoll_count++ > 6) per_pin->repoll_count = 0; - hdmi_present_sense(per_pin, per_pin->repoll_count); + if (hdmi_present_sense(per_pin, per_pin->repoll_count)) + snd_hda_jack_report_sync(per_pin->codec); } +static void intel_haswell_fixup_connect_list(struct hda_codec *codec, + hda_nid_t nid); + static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct hdmi_spec *spec = codec->spec; @@ -1193,20 +1647,21 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) struct hdmi_spec_per_pin *per_pin; int err; - caps = snd_hda_param_read(codec, pin_nid, AC_PAR_PIN_CAP); + caps = snd_hda_query_pin_caps(codec, pin_nid); if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) return 0; - config = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_CONFIG_DEFAULT, 0); + config = snd_hda_codec_get_pincfg(codec, pin_nid); if (get_defcfg_connect(config) == AC_JACK_PORT_NONE) return 0; - if (snd_BUG_ON(spec->num_pins >= MAX_HDMI_PINS)) - return -E2BIG; + if (is_haswell_plus(codec)) + intel_haswell_fixup_connect_list(codec, pin_nid); pin_idx = spec->num_pins; - per_pin = &spec->pins[pin_idx]; + per_pin = snd_array_new(&spec->pins); + if (!per_pin) + return -ENOMEM; per_pin->pin_nid = pin_nid; per_pin->non_pcm = false; @@ -1223,19 +1678,16 @@ static int hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) { struct hdmi_spec *spec = codec->spec; - int cvt_idx; struct hdmi_spec_per_cvt *per_cvt; unsigned int chans; int err; - if (snd_BUG_ON(spec->num_cvts >= MAX_HDMI_CVTS)) - return -E2BIG; - chans = get_wcaps(codec, cvt_nid); chans = get_wcaps_channels(chans); - cvt_idx = spec->num_cvts; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = snd_array_new(&spec->cvts); + if (!per_cvt) + return -ENOMEM; per_cvt->cvt_nid = cvt_nid; per_cvt->channels_min = 2; @@ -1252,6 +1704,8 @@ static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) if (err < 0) return err; + if (spec->num_cvts < ARRAY_SIZE(spec->cvt_nids)) + spec->cvt_nids[spec->num_cvts] = cvt_nid; spec->num_cvts++; return 0; @@ -1264,7 +1718,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) nodes = snd_hda_get_sub_nodes(codec, codec->afg, &nid); if (!nid || nodes < 0) { - snd_printk(KERN_WARNING "HDMI: failed to get afg sub nodes\n"); + codec_warn(codec, "HDMI: failed to get afg sub nodes\n"); return -EINVAL; } @@ -1272,7 +1726,7 @@ static int hdmi_parse_codec(struct hda_codec *codec) unsigned int caps; unsigned int type; - caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); + caps = get_wcaps(codec, nid); type = get_wcaps_type(caps); if (!(caps & AC_WCAP_DIGITAL)) @@ -1288,29 +1742,11 @@ static int hdmi_parse_codec(struct hda_codec *codec) } } - /* - * G45/IbexPeak don't support EPSS: the unsolicited pin hot plug event - * can be lost and presence sense verb will become inaccurate if the - * HDA link is powered off at hot plug or hw initialization time. - */ -#ifdef CONFIG_PM - if (!(snd_hda_param_read(codec, codec->afg, AC_PAR_POWER_STATE) & - AC_PWRST_EPSS)) - codec->bus->power_keep_link_on = 1; -#endif - return 0; } /* */ -static char *get_hdmi_pcm_name(int idx) -{ - static char names[MAX_HDMI_PINS][8]; - sprintf(&names[idx][0], "HDMI %d", idx); - return &names[idx][0]; -} - static bool check_non_pcm_per_cvt(struct hda_codec *codec, hda_nid_t cvt_nid) { struct hda_spdif_out *spdif; @@ -1336,23 +1772,42 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, { hda_nid_t cvt_nid = hinfo->nid; struct hdmi_spec *spec = codec->spec; - int pin_idx = hinfo_to_pin_index(spec, hinfo); - hda_nid_t pin_nid = spec->pins[pin_idx].pin_nid; - int pinctl; + int pin_idx = hinfo_to_pin_index(codec, hinfo); + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + hda_nid_t pin_nid = per_pin->pin_nid; bool non_pcm; + int pinctl; - non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); + if (is_haswell_plus(codec) || is_valleyview(codec)) { + /* Verify pin:cvt selections to avoid silent audio after S3. + * After S3, the audio driver restores pin:cvt selections + * but this can happen before gfx is ready and such selection + * is overlooked by HW. Thus multiple pins can share a same + * default convertor and mute control will affect each other, + * which can cause a resumed audio playback become silent + * after S3. + */ + intel_verify_pin_cvt_connect(codec, per_pin); + intel_not_share_assigned_cvt(codec, pin_nid, per_pin->mux_idx); + } - hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); + non_pcm = check_non_pcm_per_cvt(codec, cvt_nid); + mutex_lock(&per_pin->lock); + per_pin->channels = substream->runtime->channels; + per_pin->setup = true; - hdmi_setup_audio_infoframe(codec, pin_idx, non_pcm, substream); + hdmi_setup_audio_infoframe(codec, per_pin, non_pcm); + mutex_unlock(&per_pin->lock); - pinctl = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl | PIN_OUT); + if (spec->dyn_pin_out) { + pinctl = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl | PIN_OUT); + } - return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); + return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); } static int generic_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, @@ -1374,28 +1829,37 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo, int pinctl; if (hinfo->nid) { - cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid); + cvt_idx = cvt_nid_to_cvt_index(codec, hinfo->nid); if (snd_BUG_ON(cvt_idx < 0)) return -EINVAL; - per_cvt = &spec->cvts[cvt_idx]; + per_cvt = get_cvt(spec, cvt_idx); snd_BUG_ON(!per_cvt->assigned); per_cvt->assigned = 0; hinfo->nid = 0; - pin_idx = hinfo_to_pin_index(spec, hinfo); + pin_idx = hinfo_to_pin_index(codec, hinfo); if (snd_BUG_ON(pin_idx < 0)) return -EINVAL; - per_pin = &spec->pins[pin_idx]; + per_pin = get_pin(spec, pin_idx); + + if (spec->dyn_pin_out) { + pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write(codec, per_pin->pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl & ~PIN_OUT); + } - pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - snd_hda_codec_write(codec, per_pin->pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - pinctl & ~PIN_OUT); snd_hda_spdif_ctls_unassign(codec, pin_idx); + + mutex_lock(&per_pin->lock); per_pin->chmap_set = false; memset(per_pin->chmap, 0, sizeof(per_pin->chmap)); + + per_pin->setup = false; + per_pin->channels = 0; + mutex_unlock(&per_pin->lock); } return 0; @@ -1424,14 +1888,40 @@ static int hdmi_chmap_ctl_info(struct snd_kcontrol *kcontrol, return 0; } +static int hdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, + int channels) +{ + /* If the speaker allocation matches the channel count, it is OK.*/ + if (cap->channels != channels) + return -1; + + /* all channels are remappable freely */ + return SNDRV_CTL_TLVT_CHMAP_VAR; +} + +static void hdmi_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) +{ + int count = 0; + int c; + + for (c = 7; c >= 0; c--) { + int spk = cap->speakers[c]; + if (!spk) + continue; + + chmap[count++] = spk_to_chmap(spk); + } + + WARN_ON(count != channels); +} + static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) { struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; - const unsigned int valid_mask = - FL | FR | RL | RR | LFE | FC | RLC | RRC; unsigned int __user *dst; int chs, count = 0; @@ -1442,18 +1932,19 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, size -= 8; dst = tlv + 2; for (chs = 2; chs <= spec->channels_max; chs++) { - int i, c; + int i; struct cea_channel_speaker_allocation *cap; cap = channel_allocations; for (i = 0; i < ARRAY_SIZE(channel_allocations); i++, cap++) { int chs_bytes = chs * 4; - if (cap->channels != chs) - continue; - if (cap->spk_mask & ~valid_mask) + int type = spec->ops.chmap_cea_alloc_validate_get_type(cap, chs); + unsigned int tlv_chmap[8]; + + if (type < 0) continue; if (size < 8) return -ENOMEM; - if (put_user(SNDRV_CTL_TLVT_CHMAP_VAR, dst) || + if (put_user(type, dst) || put_user(chs_bytes, dst + 1)) return -EFAULT; dst += 2; @@ -1463,14 +1954,10 @@ static int hdmi_chmap_ctl_tlv(struct snd_kcontrol *kcontrol, int op_flag, return -ENOMEM; size -= chs_bytes; count += chs_bytes; - for (c = 7; c >= 0; c--) { - int spk = cap->speakers[c]; - if (!spk) - continue; - if (put_user(spk_to_chmap(spk), dst)) - return -EFAULT; - dst++; - } + spec->ops.cea_alloc_to_tlv_chmap(cap, tlv_chmap, chs); + if (copy_to_user(dst, tlv_chmap, chs_bytes)) + return -EFAULT; + dst += chs; } } if (put_user(count, tlv + 1)) @@ -1485,7 +1972,7 @@ static int hdmi_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; int pin_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); int i; for (i = 0; i < ARRAY_SIZE(per_pin->chmap); i++) @@ -1500,16 +1987,16 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = info->private_data; struct hdmi_spec *spec = codec->spec; int pin_idx = kcontrol->private_value; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); unsigned int ctl_idx; struct snd_pcm_substream *substream; unsigned char chmap[8]; - int i, ca, prepared = 0; + int i, err, ca, prepared = 0; ctl_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); substream = snd_pcm_chmap_substream(info, ctl_idx); if (!substream || !substream->runtime) - return -EBADFD; + return 0; /* just for avoiding error from alsactl restore */ switch (substream->runtime->status->state) { case SNDRV_PCM_STATE_OPEN: case SNDRV_PCM_STATE_SETUP: @@ -1528,11 +2015,17 @@ static int hdmi_chmap_ctl_put(struct snd_kcontrol *kcontrol, ca = hdmi_manual_channel_allocation(ARRAY_SIZE(chmap), chmap); if (ca < 0) return -EINVAL; + if (spec->ops.chmap_validate) { + err = spec->ops.chmap_validate(ca, ARRAY_SIZE(chmap), chmap); + if (err) + return err; + } + mutex_lock(&per_pin->lock); per_pin->chmap_set = true; memcpy(per_pin->chmap, chmap, sizeof(chmap)); if (prepared) - hdmi_setup_audio_infoframe(codec, pin_idx, per_pin->non_pcm, - substream); + hdmi_setup_audio_infoframe(codec, per_pin, per_pin->non_pcm); + mutex_unlock(&per_pin->lock); return 0; } @@ -1545,9 +2038,14 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { struct hda_pcm *info; struct hda_pcm_stream *pstr; - - info = &spec->pcm_rec[pin_idx]; - info->name = get_hdmi_pcm_name(pin_idx); + struct hdmi_spec_per_pin *per_pin; + + per_pin = get_pin(spec, pin_idx); + sprintf(per_pin->pcm_name, "HDMI %d", pin_idx); + info = snd_array_new(&spec->pcm_rec); + if (!info) + return -ENOMEM; + info->name = per_pin->pcm_name; info->pcm_type = HDA_PCM_TYPE_HDMI; info->own_chmap = true; @@ -1558,7 +2056,7 @@ static int generic_hdmi_build_pcms(struct hda_codec *codec) } codec->num_pcms = spec->num_pins; - codec->pcm_info = spec->pcm_rec; + codec->pcm_info = spec->pcm_rec.list; return 0; } @@ -1567,11 +2065,14 @@ static int generic_hdmi_build_jack(struct hda_codec *codec, int pin_idx) { char hdmi_str[32] = "HDMI/DP"; struct hdmi_spec *spec = codec->spec; - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - int pcmdev = spec->pcm_rec[pin_idx].device; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + int pcmdev = get_pcm_rec(spec, pin_idx)->device; if (pcmdev > 0) sprintf(hdmi_str + strlen(hdmi_str), ",pcm=%d", pcmdev); + if (!is_jack_detectable(codec, per_pin->pin_nid)) + strncat(hdmi_str, " Phantom", + sizeof(hdmi_str) - strlen(hdmi_str) - 1); return snd_hda_jack_add_kctl(codec, per_pin->pin_nid, hdmi_str, 0); } @@ -1583,23 +2084,23 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); err = generic_hdmi_build_jack(codec, pin_idx); if (err < 0) return err; - err = snd_hda_create_spdif_out_ctls(codec, - per_pin->pin_nid, - per_pin->mux_nids[0]); + err = snd_hda_create_dig_out_ctls(codec, + per_pin->pin_nid, + per_pin->mux_nids[0], + HDA_PCM_TYPE_HDMI); if (err < 0) return err; snd_hda_spdif_ctls_unassign(codec, pin_idx); /* add control for ELD Bytes */ - err = hdmi_create_eld_ctl(codec, - pin_idx, - spec->pcm_rec[pin_idx].device); + err = hdmi_create_eld_ctl(codec, pin_idx, + get_pcm_rec(spec, pin_idx)->device); if (err < 0) return err; @@ -1612,6 +2113,9 @@ static int generic_hdmi_build_controls(struct hda_codec *codec) struct snd_pcm_chmap *chmap; struct snd_kcontrol *kctl; int i; + + if (!codec->pcm_info[pin_idx].pcm) + break; err = snd_pcm_add_chmap_ctls(codec->pcm_info[pin_idx].pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, 0, pin_idx, &chmap); @@ -1637,12 +2141,12 @@ static int generic_hdmi_init_per_pins(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - struct hdmi_eld *eld = &per_pin->sink_eld; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); per_pin->codec = codec; + mutex_init(&per_pin->lock); INIT_DELAYED_WORK(&per_pin->work, hdmi_repoll_eld); - snd_hda_eld_proc_new(codec, eld, pin_idx); + eld_proc_new(per_pin, pin_idx); } return 0; } @@ -1653,40 +2157,161 @@ static int generic_hdmi_init(struct hda_codec *codec) int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); hda_nid_t pin_nid = per_pin->pin_nid; hdmi_init_pin(codec, pin_nid); - snd_hda_jack_detect_enable(codec, pin_nid, pin_nid); + snd_hda_jack_detect_enable_callback(codec, pin_nid, pin_nid, + codec->jackpoll_interval > 0 ? jack_callback : NULL); } return 0; } +static void hdmi_array_init(struct hdmi_spec *spec, int nums) +{ + snd_array_init(&spec->pins, sizeof(struct hdmi_spec_per_pin), nums); + snd_array_init(&spec->cvts, sizeof(struct hdmi_spec_per_cvt), nums); + snd_array_init(&spec->pcm_rec, sizeof(struct hda_pcm), nums); +} + +static void hdmi_array_free(struct hdmi_spec *spec) +{ + snd_array_free(&spec->pins); + snd_array_free(&spec->cvts); + snd_array_free(&spec->pcm_rec); +} + static void generic_hdmi_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int pin_idx; for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { - struct hdmi_spec_per_pin *per_pin = &spec->pins[pin_idx]; - struct hdmi_eld *eld = &per_pin->sink_eld; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); cancel_delayed_work(&per_pin->work); - snd_hda_eld_proc_free(codec, eld); + eld_proc_free(per_pin); } flush_workqueue(codec->bus->workq); + hdmi_array_free(spec); kfree(spec); } +#ifdef CONFIG_PM +static int generic_hdmi_resume(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int pin_idx; + + codec->patch_ops.init(codec); + snd_hda_codec_resume_amp(codec); + snd_hda_codec_resume_cache(codec); + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + hdmi_present_sense(per_pin, 1); + } + return 0; +} +#endif + static const struct hda_codec_ops generic_hdmi_patch_ops = { .init = generic_hdmi_init, .free = generic_hdmi_free, .build_pcms = generic_hdmi_build_pcms, .build_controls = generic_hdmi_build_controls, .unsol_event = hdmi_unsol_event, +#ifdef CONFIG_PM + .resume = generic_hdmi_resume, +#endif }; +static const struct hdmi_ops generic_standard_hdmi_ops = { + .pin_get_eld = snd_hdmi_get_eld, + .pin_get_slot_channel = hdmi_pin_get_slot_channel, + .pin_set_slot_channel = hdmi_pin_set_slot_channel, + .pin_setup_infoframe = hdmi_pin_setup_infoframe, + .pin_hbr_setup = hdmi_pin_hbr_setup, + .setup_stream = hdmi_setup_stream, + .chmap_cea_alloc_validate_get_type = hdmi_chmap_cea_alloc_validate_get_type, + .cea_alloc_to_tlv_chmap = hdmi_cea_alloc_to_tlv_chmap, +}; + + +static void intel_haswell_fixup_connect_list(struct hda_codec *codec, + hda_nid_t nid) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t conns[4]; + int nconns; + + nconns = snd_hda_get_connections(codec, nid, conns, ARRAY_SIZE(conns)); + if (nconns == spec->num_cvts && + !memcmp(conns, spec->cvt_nids, spec->num_cvts * sizeof(hda_nid_t))) + return; + + /* override pins connection list */ + codec_dbg(codec, "hdmi: haswell: override pin connection 0x%x\n", nid); + snd_hda_override_conn_list(codec, nid, spec->num_cvts, spec->cvt_nids); +} + +#define INTEL_VENDOR_NID 0x08 +#define INTEL_GET_VENDOR_VERB 0xf81 +#define INTEL_SET_VENDOR_VERB 0x781 +#define INTEL_EN_DP12 0x02 /* enable DP 1.2 features */ +#define INTEL_EN_ALL_PIN_CVTS 0x01 /* enable 2nd & 3rd pins and convertors */ + +static void intel_haswell_enable_all_pins(struct hda_codec *codec, + bool update_tree) +{ + unsigned int vendor_param; + + vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_ALL_PIN_CVTS) + return; + + vendor_param |= INTEL_EN_ALL_PIN_CVTS; + vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, + INTEL_SET_VENDOR_VERB, vendor_param); + if (vendor_param == -1) + return; + + if (update_tree) + snd_hda_codec_update_widgets(codec); +} + +static void intel_haswell_fixup_enable_dp12(struct hda_codec *codec) +{ + unsigned int vendor_param; + + vendor_param = snd_hda_codec_read(codec, INTEL_VENDOR_NID, 0, + INTEL_GET_VENDOR_VERB, 0); + if (vendor_param == -1 || vendor_param & INTEL_EN_DP12) + return; + + /* enable DP1.2 mode */ + vendor_param |= INTEL_EN_DP12; + snd_hda_codec_write_cache(codec, INTEL_VENDOR_NID, 0, + INTEL_SET_VENDOR_VERB, vendor_param); +} + +/* Haswell needs to re-issue the vendor-specific verbs before turning to D0. + * Otherwise you may get severe h/w communication errors. + */ +static void haswell_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state) +{ + if (power_state == AC_PWRST_D0) { + intel_haswell_enable_all_pins(codec, false); + intel_haswell_fixup_enable_dp12(codec); + } + + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, power_state); + snd_hda_codec_set_power_to_all(codec, fg, power_state); +} + static int patch_generic_hdmi(struct hda_codec *codec) { struct hdmi_spec *spec; @@ -1695,13 +2320,30 @@ static int patch_generic_hdmi(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; + spec->ops = generic_standard_hdmi_ops; codec->spec = spec; + hdmi_array_init(spec, 4); + + if (is_haswell_plus(codec)) { + intel_haswell_enable_all_pins(codec, true); + intel_haswell_fixup_enable_dp12(codec); + } + + if (is_haswell(codec) || is_valleyview(codec)) { + codec->depop_delay = 0; + } + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec); return -EINVAL; } codec->patch_ops = generic_hdmi_patch_ops; + if (is_haswell_plus(codec)) { + codec->patch_ops.set_power_state = haswell_set_power_state; + codec->dp_mst = true; + } + generic_hdmi_init_per_pins(codec); init_channel_allocations(); @@ -1716,24 +2358,30 @@ static int patch_generic_hdmi(struct hda_codec *codec) static int simple_playback_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; + struct hda_pcm *info; unsigned int chans; struct hda_pcm_stream *pstr; + struct hdmi_spec_per_cvt *per_cvt; - codec->num_pcms = 1; - codec->pcm_info = info; - - chans = get_wcaps(codec, spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + chans = get_wcaps(codec, per_cvt->cvt_nid); chans = get_wcaps_channels(chans); - info->name = get_hdmi_pcm_name(0); + info = snd_array_new(&spec->pcm_rec); + if (!info) + return -ENOMEM; + info->name = get_pin(spec, 0)->pcm_name; + sprintf(info->name, "HDMI 0"); info->pcm_type = HDA_PCM_TYPE_HDMI; pstr = &info->stream[SNDRV_PCM_STREAM_PLAYBACK]; *pstr = spec->pcm_playback; - pstr->nid = spec->cvts[0].cvt_nid; + pstr->nid = per_cvt->cvt_nid; if (pstr->channels_max <= 2 && chans && chans <= 16) pstr->channels_max = chans; + codec->num_pcms = 1; + codec->pcm_info = info; + return 0; } @@ -1753,11 +2401,13 @@ static void simple_hdmi_unsol_event(struct hda_codec *codec, static int simple_playback_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hdmi_spec_per_cvt *per_cvt; int err; - err = snd_hda_create_spdif_out_ctls(codec, - spec->cvts[0].cvt_nid, - spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + err = snd_hda_create_dig_out_ctls(codec, per_cvt->cvt_nid, + per_cvt->cvt_nid, + HDA_PCM_TYPE_HDMI); if (err < 0) return err; return simple_hdmi_build_jack(codec, 0); @@ -1766,7 +2416,8 @@ static int simple_playback_build_controls(struct hda_codec *codec) static int simple_playback_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - hda_nid_t pin = spec->pins[0].pin_nid; + struct hdmi_spec_per_pin *per_pin = get_pin(spec, 0); + hda_nid_t pin = per_pin->pin_nid; snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); @@ -1782,6 +2433,7 @@ static void simple_playback_free(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + hdmi_array_free(spec); kfree(spec); } @@ -1945,20 +2597,29 @@ static int patch_simple_hdmi(struct hda_codec *codec, hda_nid_t cvt_nid, hda_nid_t pin_nid) { struct hdmi_spec *spec; + struct hdmi_spec_per_cvt *per_cvt; + struct hdmi_spec_per_pin *per_pin; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (!spec) return -ENOMEM; codec->spec = spec; + hdmi_array_init(spec, 1); spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; spec->multiout.dig_out_nid = cvt_nid; spec->num_cvts = 1; spec->num_pins = 1; - spec->cvts[0].cvt_nid = cvt_nid; - spec->pins[0].pin_nid = pin_nid; + per_pin = snd_array_new(&spec->pins); + per_cvt = snd_array_new(&spec->cvts); + if (!per_pin || !per_cvt) { + simple_playback_free(codec); + return -ENOMEM; + } + per_cvt->cvt_nid = cvt_nid; + per_pin->pin_nid = pin_nid; spec->pcm_playback = simple_pcm_playback; codec->patch_ops = simple_hdmi_patch_ops; @@ -2035,9 +2696,11 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, int i; struct hdmi_spec *spec = codec->spec; struct hda_spdif_out *spdif; + struct hdmi_spec_per_cvt *per_cvt; mutex_lock(&codec->spdif_mutex); - spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); + per_cvt = get_cvt(spec, 0); + spdif = snd_hda_spdif_out_of_nid(codec, per_cvt->cvt_nid); chs = substream->runtime->channels; @@ -2159,13 +2822,17 @@ static int nvhdmi_7x_8ch_build_pcms(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; int err = simple_playback_build_pcms(codec); - spec->pcm_rec[0].own_chmap = true; + if (!err) { + struct hda_pcm *info = get_pcm_rec(spec, 0); + info->own_chmap = true; + } return err; } static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info; struct snd_pcm_chmap *chmap; int err; @@ -2174,7 +2841,8 @@ static int nvhdmi_7x_8ch_build_controls(struct hda_codec *codec) return err; /* add channel maps */ - err = snd_pcm_add_chmap_ctls(spec->pcm_rec[0].pcm, + info = get_pcm_rec(spec, 0); + err = snd_pcm_add_chmap_ctls(info->pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, 8, 0, &chmap); if (err < 0) @@ -2213,48 +2881,399 @@ static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) } /* - * ATI-specific implementations - * - * FIXME: we may omit the whole this and use the generic code once after - * it's confirmed to work. + * NVIDIA codecs ignore ASP mapping for 2ch - confirmed on: + * - 0x10de0015 + * - 0x10de0040 + */ +static int nvhdmi_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, + int channels) +{ + if (cap->ca_index == 0x00 && channels == 2) + return SNDRV_CTL_TLVT_CHMAP_FIXED; + + return hdmi_chmap_cea_alloc_validate_get_type(cap, channels); +} + +static int nvhdmi_chmap_validate(int ca, int chs, unsigned char *map) +{ + if (ca == 0x00 && (map[0] != SNDRV_CHMAP_FL || map[1] != SNDRV_CHMAP_FR)) + return -EINVAL; + + return 0; +} + +static int patch_nvhdmi(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int err; + + err = patch_generic_hdmi(codec); + if (err) + return err; + + spec = codec->spec; + spec->dyn_pin_out = true; + + spec->ops.chmap_cea_alloc_validate_get_type = + nvhdmi_chmap_cea_alloc_validate_get_type; + spec->ops.chmap_validate = nvhdmi_chmap_validate; + + return 0; +} + +/* + * ATI/AMD-specific implementations */ -#define ATIHDMI_CVT_NID 0x02 /* audio converter */ -#define ATIHDMI_PIN_NID 0x03 /* HDMI output pin */ +#define is_amdhdmi_rev3_or_later(codec) \ + ((codec)->vendor_id == 0x1002aa01 && ((codec)->revision_id & 0xff00) >= 0x0300) +#define has_amd_full_remap_support(codec) is_amdhdmi_rev3_or_later(codec) + +/* ATI/AMD specific HDA pin verbs, see the AMD HDA Verbs specification */ +#define ATI_VERB_SET_CHANNEL_ALLOCATION 0x771 +#define ATI_VERB_SET_DOWNMIX_INFO 0x772 +#define ATI_VERB_SET_MULTICHANNEL_01 0x777 +#define ATI_VERB_SET_MULTICHANNEL_23 0x778 +#define ATI_VERB_SET_MULTICHANNEL_45 0x779 +#define ATI_VERB_SET_MULTICHANNEL_67 0x77a +#define ATI_VERB_SET_HBR_CONTROL 0x77c +#define ATI_VERB_SET_MULTICHANNEL_1 0x785 +#define ATI_VERB_SET_MULTICHANNEL_3 0x786 +#define ATI_VERB_SET_MULTICHANNEL_5 0x787 +#define ATI_VERB_SET_MULTICHANNEL_7 0x788 +#define ATI_VERB_SET_MULTICHANNEL_MODE 0x789 +#define ATI_VERB_GET_CHANNEL_ALLOCATION 0xf71 +#define ATI_VERB_GET_DOWNMIX_INFO 0xf72 +#define ATI_VERB_GET_MULTICHANNEL_01 0xf77 +#define ATI_VERB_GET_MULTICHANNEL_23 0xf78 +#define ATI_VERB_GET_MULTICHANNEL_45 0xf79 +#define ATI_VERB_GET_MULTICHANNEL_67 0xf7a +#define ATI_VERB_GET_HBR_CONTROL 0xf7c +#define ATI_VERB_GET_MULTICHANNEL_1 0xf85 +#define ATI_VERB_GET_MULTICHANNEL_3 0xf86 +#define ATI_VERB_GET_MULTICHANNEL_5 0xf87 +#define ATI_VERB_GET_MULTICHANNEL_7 0xf88 +#define ATI_VERB_GET_MULTICHANNEL_MODE 0xf89 + +/* AMD specific HDA cvt verbs */ +#define ATI_VERB_SET_RAMP_RATE 0x770 +#define ATI_VERB_GET_RAMP_RATE 0xf70 + +#define ATI_OUT_ENABLE 0x1 + +#define ATI_MULTICHANNEL_MODE_PAIRED 0 +#define ATI_MULTICHANNEL_MODE_SINGLE 1 + +#define ATI_HBR_CAPABLE 0x01 +#define ATI_HBR_ENABLE 0x10 -static int atihdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) +static int atihdmi_pin_get_eld(struct hda_codec *codec, hda_nid_t nid, + unsigned char *buf, int *eld_size) +{ + /* call hda_eld.c ATI/AMD-specific function */ + return snd_hdmi_get_eld_ati(codec, nid, buf, eld_size, + is_amdhdmi_rev3_or_later(codec)); +} + +static void atihdmi_pin_setup_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, int ca, + int active_channels, int conn_type) +{ + snd_hda_codec_write(codec, pin_nid, 0, ATI_VERB_SET_CHANNEL_ALLOCATION, ca); +} + +static int atihdmi_paired_swap_fc_lfe(int pos) +{ + /* + * ATI/AMD have automatic FC/LFE swap built-in + * when in pairwise mapping mode. + */ + + switch (pos) { + /* see channel_allocations[].speakers[] */ + case 2: return 3; + case 3: return 2; + default: break; + } + + return pos; +} + +static int atihdmi_paired_chmap_validate(int ca, int chs, unsigned char *map) +{ + struct cea_channel_speaker_allocation *cap; + int i, j; + + /* check that only channel pairs need to be remapped on old pre-rev3 ATI/AMD */ + + cap = &channel_allocations[get_channel_allocation_order(ca)]; + for (i = 0; i < chs; ++i) { + int mask = to_spk_mask(map[i]); + bool ok = false; + bool companion_ok = false; + + if (!mask) + continue; + + for (j = 0 + i % 2; j < 8; j += 2) { + int chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j); + if (cap->speakers[chan_idx] == mask) { + /* channel is in a supported position */ + ok = true; + + if (i % 2 == 0 && i + 1 < chs) { + /* even channel, check the odd companion */ + int comp_chan_idx = 7 - atihdmi_paired_swap_fc_lfe(j + 1); + int comp_mask_req = to_spk_mask(map[i+1]); + int comp_mask_act = cap->speakers[comp_chan_idx]; + + if (comp_mask_req == comp_mask_act) + companion_ok = true; + else + return -EINVAL; + } + break; + } + } + + if (!ok) + return -EINVAL; + + if (companion_ok) + i++; /* companion channel already checked */ + } + + return 0; +} + +static int atihdmi_pin_set_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, + int hdmi_slot, int stream_channel) +{ + int verb; + int ati_channel_setup = 0; + + if (hdmi_slot > 7) + return -EINVAL; + + if (!has_amd_full_remap_support(codec)) { + hdmi_slot = atihdmi_paired_swap_fc_lfe(hdmi_slot); + + /* In case this is an odd slot but without stream channel, do not + * disable the slot since the corresponding even slot could have a + * channel. In case neither have a channel, the slot pair will be + * disabled when this function is called for the even slot. */ + if (hdmi_slot % 2 != 0 && stream_channel == 0xf) + return 0; + + hdmi_slot -= hdmi_slot % 2; + + if (stream_channel != 0xf) + stream_channel -= stream_channel % 2; + } + + verb = ATI_VERB_SET_MULTICHANNEL_01 + hdmi_slot/2 + (hdmi_slot % 2) * 0x00e; + + /* ati_channel_setup format: [7..4] = stream_channel_id, [1] = mute, [0] = enable */ + + if (stream_channel != 0xf) + ati_channel_setup = (stream_channel << 4) | ATI_OUT_ENABLE; + + return snd_hda_codec_write(codec, pin_nid, 0, verb, ati_channel_setup); +} + +static int atihdmi_pin_get_slot_channel(struct hda_codec *codec, hda_nid_t pin_nid, + int asp_slot) +{ + bool was_odd = false; + int ati_asp_slot = asp_slot; + int verb; + int ati_channel_setup; + + if (asp_slot > 7) + return -EINVAL; + + if (!has_amd_full_remap_support(codec)) { + ati_asp_slot = atihdmi_paired_swap_fc_lfe(asp_slot); + if (ati_asp_slot % 2 != 0) { + ati_asp_slot -= 1; + was_odd = true; + } + } + + verb = ATI_VERB_GET_MULTICHANNEL_01 + ati_asp_slot/2 + (ati_asp_slot % 2) * 0x00e; + + ati_channel_setup = snd_hda_codec_read(codec, pin_nid, 0, verb, 0); + + if (!(ati_channel_setup & ATI_OUT_ENABLE)) + return 0xf; + + return ((ati_channel_setup & 0xf0) >> 4) + !!was_odd; +} + +static int atihdmi_paired_chmap_cea_alloc_validate_get_type(struct cea_channel_speaker_allocation *cap, + int channels) +{ + int c; + + /* + * Pre-rev3 ATI/AMD codecs operate in a paired channel mode, so + * we need to take that into account (a single channel may take 2 + * channel slots if we need to carry a silent channel next to it). + * On Rev3+ AMD codecs this function is not used. + */ + int chanpairs = 0; + + /* We only produce even-numbered channel count TLVs */ + if ((channels % 2) != 0) + return -1; + + for (c = 0; c < 7; c += 2) { + if (cap->speakers[c] || cap->speakers[c+1]) + chanpairs++; + } + + if (chanpairs * 2 != channels) + return -1; + + return SNDRV_CTL_TLVT_CHMAP_PAIRED; +} + +static void atihdmi_paired_cea_alloc_to_tlv_chmap(struct cea_channel_speaker_allocation *cap, + unsigned int *chmap, int channels) +{ + /* produce paired maps for pre-rev3 ATI/AMD codecs */ + int count = 0; + int c; + + for (c = 7; c >= 0; c--) { + int chan = 7 - atihdmi_paired_swap_fc_lfe(7 - c); + int spk = cap->speakers[chan]; + if (!spk) { + /* add N/A channel if the companion channel is occupied */ + if (cap->speakers[chan + (chan % 2 ? -1 : 1)]) + chmap[count++] = SNDRV_CHMAP_NA; + + continue; + } + + chmap[count++] = spk_to_chmap(spk); + } + + WARN_ON(count != channels); +} + +static int atihdmi_pin_hbr_setup(struct hda_codec *codec, hda_nid_t pin_nid, + bool hbr) +{ + int hbr_ctl, hbr_ctl_new; + + hbr_ctl = snd_hda_codec_read(codec, pin_nid, 0, ATI_VERB_GET_HBR_CONTROL, 0); + if (hbr_ctl >= 0 && (hbr_ctl & ATI_HBR_CAPABLE)) { + if (hbr) + hbr_ctl_new = hbr_ctl | ATI_HBR_ENABLE; + else + hbr_ctl_new = hbr_ctl & ~ATI_HBR_ENABLE; + + codec_dbg(codec, + "atihdmi_pin_hbr_setup: NID=0x%x, %shbr-ctl=0x%x\n", + pin_nid, + hbr_ctl == hbr_ctl_new ? "" : "new-", + hbr_ctl_new); + + if (hbr_ctl != hbr_ctl_new) + snd_hda_codec_write(codec, pin_nid, 0, + ATI_VERB_SET_HBR_CONTROL, + hbr_ctl_new); + + } else if (hbr) + return -EINVAL; + + return 0; +} + +static int atihdmi_setup_stream(struct hda_codec *codec, hda_nid_t cvt_nid, + hda_nid_t pin_nid, u32 stream_tag, int format) +{ + + if (is_amdhdmi_rev3_or_later(codec)) { + int ramp_rate = 180; /* default as per AMD spec */ + /* disable ramp-up/down for non-pcm as per AMD spec */ + if (format & AC_FMT_TYPE_NON_PCM) + ramp_rate = 0; + + snd_hda_codec_write(codec, cvt_nid, 0, ATI_VERB_SET_RAMP_RATE, ramp_rate); + } + + return hdmi_setup_stream(codec, cvt_nid, pin_nid, stream_tag, format); +} + + +static int atihdmi_init(struct hda_codec *codec) { struct hdmi_spec *spec = codec->spec; - int chans = substream->runtime->channels; - int i, err; + int pin_idx, err; - err = simple_playback_pcm_prepare(hinfo, codec, stream_tag, format, - substream); - if (err < 0) + err = generic_hdmi_init(codec); + + if (err) return err; - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chans - 1); - /* FIXME: XXX */ - for (i = 0; i < chans; i++) { - snd_hda_codec_write(codec, spec->cvts[0].cvt_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - (i << 4) | i); + + for (pin_idx = 0; pin_idx < spec->num_pins; pin_idx++) { + struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx); + + /* make sure downmix information in infoframe is zero */ + snd_hda_codec_write(codec, per_pin->pin_nid, 0, ATI_VERB_SET_DOWNMIX_INFO, 0); + + /* enable channel-wise remap mode if supported */ + if (has_amd_full_remap_support(codec)) + snd_hda_codec_write(codec, per_pin->pin_nid, 0, + ATI_VERB_SET_MULTICHANNEL_MODE, + ATI_MULTICHANNEL_MODE_SINGLE); } + return 0; } static int patch_atihdmi(struct hda_codec *codec) { struct hdmi_spec *spec; - int err = patch_simple_hdmi(codec, ATIHDMI_CVT_NID, ATIHDMI_PIN_NID); - if (err < 0) + struct hdmi_spec_per_cvt *per_cvt; + int err, cvt_idx; + + err = patch_generic_hdmi(codec); + + if (err) return err; + + codec->patch_ops.init = atihdmi_init; + spec = codec->spec; - spec->pcm_playback.ops.prepare = atihdmi_playback_pcm_prepare; + + spec->ops.pin_get_eld = atihdmi_pin_get_eld; + spec->ops.pin_get_slot_channel = atihdmi_pin_get_slot_channel; + spec->ops.pin_set_slot_channel = atihdmi_pin_set_slot_channel; + spec->ops.pin_setup_infoframe = atihdmi_pin_setup_infoframe; + spec->ops.pin_hbr_setup = atihdmi_pin_hbr_setup; + spec->ops.setup_stream = atihdmi_setup_stream; + + if (!has_amd_full_remap_support(codec)) { + /* override to ATI/AMD-specific versions with pairwise mapping */ + spec->ops.chmap_cea_alloc_validate_get_type = + atihdmi_paired_chmap_cea_alloc_validate_get_type; + spec->ops.cea_alloc_to_tlv_chmap = atihdmi_paired_cea_alloc_to_tlv_chmap; + spec->ops.chmap_validate = atihdmi_paired_chmap_validate; + } + + /* ATI/AMD converters do not advertise all of their capabilities */ + for (cvt_idx = 0; cvt_idx < spec->num_cvts; cvt_idx++) { + per_cvt = get_cvt(spec, cvt_idx); + per_cvt->channels_max = max(per_cvt->channels_max, 8u); + per_cvt->rates |= SUPPORTED_RATES; + per_cvt->formats |= SUPPORTED_FORMATS; + per_cvt->maxbps = max(per_cvt->maxbps, 24u); + } + + spec->channels_max = max(spec->channels_max, 8u); + return 0; } @@ -2268,13 +3287,22 @@ static int patch_via_hdmi(struct hda_codec *codec) } /* + * called from hda_codec.c for generic HDMI support + */ +int snd_hda_parse_hdmi_codec(struct hda_codec *codec) +{ + return patch_generic_hdmi(codec); +} +EXPORT_SYMBOL_GPL(snd_hda_parse_hdmi_codec); + +/* * patch entries */ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x1002793c, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x10027919, .name = "RS600 HDMI", .patch = patch_atihdmi }, { .id = 0x1002791a, .name = "RS690/780 HDMI", .patch = patch_atihdmi }, -{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x1002aa01, .name = "R6xx HDMI", .patch = patch_atihdmi }, { .id = 0x10951390, .name = "SiI1390 HDMI", .patch = patch_generic_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_generic_hdmi }, { .id = 0x17e80047, .name = "Chrontel HDMI", .patch = patch_generic_hdmi }, @@ -2283,30 +3311,34 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x10de0005, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0006, .name = "MCP77/78 HDMI", .patch = patch_nvhdmi_8ch_7x }, { .id = 0x10de0007, .name = "MCP79/7A HDMI", .patch = patch_nvhdmi_8ch_7x }, -{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_generic_hdmi }, -{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de000a, .name = "GPU 0a HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de000b, .name = "GPU 0b HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de000c, .name = "MCP89 HDMI", .patch = patch_nvhdmi }, +{ .id = 0x10de000d, .name = "GPU 0d HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0010, .name = "GPU 10 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0011, .name = "GPU 11 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0012, .name = "GPU 12 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0013, .name = "GPU 13 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0014, .name = "GPU 14 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0015, .name = "GPU 15 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0016, .name = "GPU 16 HDMI/DP", .patch = patch_nvhdmi }, /* 17 is known to be absent */ -{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_generic_hdmi }, -{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_generic_hdmi }, +{ .id = 0x10de0018, .name = "GPU 18 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0019, .name = "GPU 19 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de001a, .name = "GPU 1a HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de001b, .name = "GPU 1b HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de001c, .name = "GPU 1c HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0028, .name = "Tegra12x HDMI", .patch = patch_nvhdmi }, +{ .id = 0x10de0040, .name = "GPU 40 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0041, .name = "GPU 41 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0042, .name = "GPU 42 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0043, .name = "GPU 43 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0044, .name = "GPU 44 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0051, .name = "GPU 51 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0060, .name = "GPU 60 HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, +{ .id = 0x10de0070, .name = "GPU 70 HDMI/DP", .patch = patch_nvhdmi }, +{ .id = 0x10de0071, .name = "GPU 71 HDMI/DP", .patch = patch_nvhdmi }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x11069f80, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, { .id = 0x11069f81, .name = "VX900 HDMI/DP", .patch = patch_via_hdmi }, @@ -2320,7 +3352,9 @@ static const struct hda_codec_preset snd_hda_preset_hdmi[] = { { .id = 0x80862805, .name = "CougarPoint HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862806, .name = "PantherPoint HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862807, .name = "Haswell HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862808, .name = "Broadwell HDMI", .patch = patch_generic_hdmi }, { .id = 0x80862880, .name = "CedarTrail HDMI", .patch = patch_generic_hdmi }, +{ .id = 0x80862882, .name = "Valleyview2 HDMI", .patch = patch_generic_hdmi }, { .id = 0x808629fb, .name = "Crestline HDMI", .patch = patch_generic_hdmi }, {} /* terminator */ }; @@ -2352,13 +3386,17 @@ MODULE_ALIAS("snd-hda-codec-id:10de0019"); MODULE_ALIAS("snd-hda-codec-id:10de001a"); MODULE_ALIAS("snd-hda-codec-id:10de001b"); MODULE_ALIAS("snd-hda-codec-id:10de001c"); +MODULE_ALIAS("snd-hda-codec-id:10de0028"); MODULE_ALIAS("snd-hda-codec-id:10de0040"); MODULE_ALIAS("snd-hda-codec-id:10de0041"); MODULE_ALIAS("snd-hda-codec-id:10de0042"); MODULE_ALIAS("snd-hda-codec-id:10de0043"); MODULE_ALIAS("snd-hda-codec-id:10de0044"); MODULE_ALIAS("snd-hda-codec-id:10de0051"); +MODULE_ALIAS("snd-hda-codec-id:10de0060"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); +MODULE_ALIAS("snd-hda-codec-id:10de0070"); +MODULE_ALIAS("snd-hda-codec-id:10de0071"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_ALIAS("snd-hda-codec-id:11069f80"); MODULE_ALIAS("snd-hda-codec-id:11069f81"); @@ -2373,7 +3411,9 @@ MODULE_ALIAS("snd-hda-codec-id:80862804"); MODULE_ALIAS("snd-hda-codec-id:80862805"); MODULE_ALIAS("snd-hda-codec-id:80862806"); MODULE_ALIAS("snd-hda-codec-id:80862807"); +MODULE_ALIAS("snd-hda-codec-id:80862808"); MODULE_ALIAS("snd-hda-codec-id:80862880"); +MODULE_ALIAS("snd-hda-codec-id:80862882"); MODULE_ALIAS("snd-hda-codec-id:808629fb"); MODULE_LICENSE("GPL"); diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 48d9d609f89..b60824e9040 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -27,20 +27,21 @@ #include <linux/delay.h> #include <linux/slab.h> #include <linux/pci.h> +#include <linux/dmi.h> #include <linux/module.h> #include <sound/core.h> #include <sound/jack.h> #include "hda_codec.h" #include "hda_local.h" #include "hda_auto_parser.h" -#include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" + +/* keep halting ALC5505 DSP, for power saving */ +#define HALT_REALTEK_ALC5505 /* unsol event tags */ -#define ALC_FRONT_EVENT 0x01 -#define ALC_DCVOL_EVENT 0x02 -#define ALC_HP_EVENT 0x04 -#define ALC_MIC_EVENT 0x08 +#define ALC_DCVOL_EVENT 0x08 /* for GPIO Poll */ #define GPIO_MASK 0x03 @@ -54,6 +55,20 @@ enum { ALC_INIT_GPIO3, }; +enum { + ALC_HEADSET_MODE_UNKNOWN, + ALC_HEADSET_MODE_UNPLUGGED, + ALC_HEADSET_MODE_HEADSET, + ALC_HEADSET_MODE_MIC, + ALC_HEADSET_MODE_HEADPHONE, +}; + +enum { + ALC_HEADSET_TYPE_UNKNOWN, + ALC_HEADSET_TYPE_CTIA, + ALC_HEADSET_TYPE_OMTP, +}; + struct alc_customize_define { unsigned int sku_cfg; unsigned char port_connectivity; @@ -67,355 +82,51 @@ struct alc_customize_define { unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ }; -struct alc_multi_io { - hda_nid_t pin; /* multi-io widget pin NID */ - hda_nid_t dac; /* DAC to be connected */ - unsigned int ctl_in; /* cached input-pin control value */ -}; - -enum { - ALC_AUTOMUTE_PIN, /* change the pin control */ - ALC_AUTOMUTE_AMP, /* mute/unmute the pin AMP */ - ALC_AUTOMUTE_MIXER, /* mute/unmute mixer widget AMP */ -}; - -#define MAX_VOL_NIDS 0x40 - -/* make compatible with old code */ -#define alc_apply_pincfgs snd_hda_apply_pincfgs -#define alc_apply_fixup snd_hda_apply_fixup -#define alc_pick_fixup snd_hda_pick_fixup -#define alc_fixup hda_fixup -#define alc_pincfg hda_pintbl -#define alc_model_fixup hda_model_fixup - -#define ALC_FIXUP_PINS HDA_FIXUP_PINS -#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS -#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC - -#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE -#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE -#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT -#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD - - struct alc_spec { - struct hda_gen_spec gen; + struct hda_gen_spec gen; /* must be at head */ /* codec parameterization */ const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; - const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ - char stream_name_analog[32]; /* analog PCM stream */ - const struct hda_pcm_stream *stream_analog_playback; - const struct hda_pcm_stream *stream_analog_capture; - const struct hda_pcm_stream *stream_analog_alt_playback; - const struct hda_pcm_stream *stream_analog_alt_capture; - - char stream_name_digital[32]; /* digital PCM stream */ - const struct hda_pcm_stream *stream_digital_playback; - const struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; /* playback set-up - * max_channels, dacs must be set - * dig_out_nid and hp_nid are optional - */ - hda_nid_t alt_dac_nid; - hda_nid_t slave_dig_outs[3]; /* optional - for auto-parsing */ - int dig_out_type; - - /* capture */ - unsigned int num_adc_nids; - const hda_nid_t *adc_nids; - const hda_nid_t *capsrc_nids; - hda_nid_t dig_in_nid; /* digital-in NID; optional */ - hda_nid_t mixer_nid; /* analog-mixer NID */ - DECLARE_BITMAP(vol_ctls, MAX_VOL_NIDS << 1); - DECLARE_BITMAP(sw_ctls, MAX_VOL_NIDS << 1); - - /* capture setup for dynamic dual-adc switch */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - /* capture source */ - unsigned int num_mux_defs; - const struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - hda_nid_t ext_mic_pin; - hda_nid_t dock_mic_pin; - hda_nid_t int_mic_pin; - - /* channel model */ - const struct hda_channel_mode *channel_mode; - int num_channel_mode; - int need_dac_fix; - int const_channel_count; - int ext_channel_count; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; struct alc_customize_define cdefine; - struct snd_array kctls; - struct hda_input_mux private_imux[3]; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t private_adc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t private_capsrc_nids[AUTO_CFG_MAX_OUTS]; - hda_nid_t imux_pins[HDA_MAX_NUM_INPUTS]; - unsigned int dyn_adc_idx[HDA_MAX_NUM_INPUTS]; - int int_mic_idx, ext_mic_idx, dock_mic_idx; /* for auto-mic */ + unsigned int parse_flags; /* flag for snd_hda_parse_pin_defcfg() */ + + /* inverted dmic fix */ + unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ + unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ hda_nid_t inv_dmic_pin; + /* mute LED for HP laptops, see alc269_fixup_mic_mute_hook() */ + int mute_led_polarity; + hda_nid_t mute_led_nid; + + unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */ + + hda_nid_t headset_mic_pin; + hda_nid_t headphone_mic_pin; + int current_headset_mode; + int current_headset_type; + /* hooks */ void (*init_hook)(struct hda_codec *codec); #ifdef CONFIG_PM void (*power_hook)(struct hda_codec *codec); #endif void (*shutup)(struct hda_codec *codec); - void (*automute_hook)(struct hda_codec *codec); - - /* for pin sensing */ - unsigned int hp_jack_present:1; - unsigned int line_jack_present:1; - unsigned int master_mute:1; - unsigned int auto_mic:1; - unsigned int auto_mic_valid_imux:1; /* valid imux for auto-mic */ - unsigned int automute_speaker:1; /* automute speaker outputs */ - unsigned int automute_lo:1; /* automute LO outputs */ - unsigned int detect_hp:1; /* Headphone detection enabled */ - unsigned int detect_lo:1; /* Line-out detection enabled */ - unsigned int automute_speaker_possible:1; /* there are speakers and either LO or HP */ - unsigned int automute_lo_possible:1; /* there are line outs and HP */ - unsigned int keep_vref_in_automute:1; /* Don't clear VREF in automute */ - - /* other flags */ - unsigned int no_analog :1; /* digital I/O only */ - unsigned int dyn_adc_switch:1; /* switch ADCs (for ALC275) */ - unsigned int single_input_src:1; - unsigned int vol_in_capsrc:1; /* use capsrc volume (ADC has no vol) */ - unsigned int parse_flags; /* passed to snd_hda_parse_pin_defcfg() */ - unsigned int shared_mic_hp:1; /* HP/Mic-in sharing */ - unsigned int inv_dmic_fixup:1; /* has inverted digital-mic workaround */ - unsigned int inv_dmic_muted:1; /* R-ch of inv d-mic is muted? */ - unsigned int no_primary_hp:1; /* Don't prefer HP pins to speaker pins */ - - /* auto-mute control */ - int automute_mode; - hda_nid_t automute_mixer_nid[AUTO_CFG_MAX_OUTS]; int init_amp; int codec_variant; /* flag for other variants */ - - /* for virtual master */ - hda_nid_t vmaster_nid; - struct hda_vmaster_mute_hook vmaster_mute; -#ifdef CONFIG_PM - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; -#endif + unsigned int has_alc5505_dsp:1; + unsigned int no_depop_delay:1; /* for PLL fix */ hda_nid_t pll_nid; unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; - - /* multi-io */ - int multi_ios; - struct alc_multi_io multi_io[4]; - - /* bind volumes */ - struct snd_array bind_ctls; }; -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, - int dir, unsigned int bits) -{ - if (!nid) - return false; - if (get_wcaps(codec, nid) & (1 << (dir + 1))) - if (query_amp_caps(codec, nid, dir) & bits) - return true; - return false; -} - -#define nid_has_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) -#define nid_has_volume(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_NUM_STEPS) - -/* - * input MUX handling - */ -static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); - if (mux_idx >= spec->num_mux_defs) - mux_idx = 0; - if (!spec->input_mux[mux_idx].num_items && mux_idx > 0) - mux_idx = 0; - return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); -} - -static int alc_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; - return 0; -} - -static bool alc_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t new_adc = spec->adc_nids[spec->dyn_adc_idx[cur]]; - - if (spec->cur_adc && spec->cur_adc != new_adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = new_adc; - snd_hda_codec_setup_stream(codec, new_adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - return true; - } - return false; -} - -static inline hda_nid_t get_capsrc(struct alc_spec *spec, int idx) -{ - return spec->capsrc_nids ? - spec->capsrc_nids[idx] : spec->adc_nids[idx]; -} - -static void call_update_outputs(struct hda_codec *codec); -static void alc_inv_dmic_sync(struct hda_codec *codec, bool force); - -/* for shared I/O, change the pin-control accordingly */ -static void update_shared_mic_hp(struct hda_codec *codec, bool set_as_mic) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; - /* NOTE: this assumes that there are only two inputs, the - * first is the real internal mic and the second is HP/mic jack. - */ - - val = snd_hda_get_default_vref(codec, pin); - - /* This pin does not have vref caps - let's enable vref on pin 0x18 - instead, as suggested by Realtek */ - if (val == AC_PINCTL_VREF_HIZ) { - const hda_nid_t vref_pin = 0x18; - /* Sanity check pin 0x18 */ - if (get_wcaps_type(get_wcaps(codec, vref_pin)) == AC_WID_PIN && - get_defcfg_connect(snd_hda_codec_get_pincfg(codec, vref_pin)) == AC_JACK_PORT_NONE) { - unsigned int vref_val = snd_hda_get_default_vref(codec, vref_pin); - if (vref_val != AC_PINCTL_VREF_HIZ) - snd_hda_set_pin_ctl(codec, vref_pin, PIN_IN | (set_as_mic ? vref_val : 0)); - } - } - - val = set_as_mic ? val | PIN_IN : PIN_HP; - snd_hda_set_pin_ctl(codec, pin, val); - - spec->automute_speaker = !set_as_mic; - call_update_outputs(codec); -} - -/* select the given imux item; either unmute exclusively or select the route */ -static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, - unsigned int idx, bool force) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - unsigned int mux_idx; - int i, type, num_conns; - hda_nid_t nid; - - if (!spec->input_mux) - return 0; - - mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; - imux = &spec->input_mux[mux_idx]; - if (!imux->num_items && mux_idx > 0) - imux = &spec->input_mux[0]; - if (!imux->num_items) - return 0; - - if (idx >= imux->num_items) - idx = imux->num_items - 1; - if (spec->cur_mux[adc_idx] == idx && !force) - return 0; - spec->cur_mux[adc_idx] = idx; - - if (spec->shared_mic_hp) - update_shared_mic_hp(codec, spec->cur_mux[adc_idx]); - - if (spec->dyn_adc_switch) { - alc_dyn_adc_pcm_resetup(codec, idx); - adc_idx = spec->dyn_adc_idx[idx]; - } - - nid = get_capsrc(spec, adc_idx); - - /* no selection? */ - num_conns = snd_hda_get_num_conns(codec, nid); - if (num_conns <= 1) - return 1; - - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_AUD_MIX) { - /* Matrix-mixer style (e.g. ALC882) */ - int active = imux->items[idx].index; - for (i = 0; i < num_conns; i++) { - unsigned int v = (i == active) ? 0 : HDA_AMP_MUTE; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, i, - HDA_AMP_MUTE, v); - } - } else { - /* MUX style (e.g. ALC880) */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); - } - alc_inv_dmic_sync(codec, true); - return 1; -} - -static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - return alc_mux_select(codec, adc_idx, - ucontrol->value.enumerated.item[0], false); -} - -/* - * set up the input pin config (depending on the given auto-pin type) - */ -static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, - int auto_pin_type) -{ - unsigned int val = PIN_IN; - if (auto_pin_type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); -} - /* * Append the given mixer and verb elements for the later use * The mixer array is referred in build_controls(), and init_verbs are @@ -485,171 +196,6 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, alc_fix_pll(codec); } -/* - * Jack detections for HP auto-mute and mic-switch - */ - -/* check each pin in the given array; returns true if any of them is plugged */ -static bool detect_jacks(struct hda_codec *codec, int num_pins, hda_nid_t *pins) -{ - int i, present = 0; - - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - if (!nid) - break; - present |= snd_hda_jack_detect(codec, nid); - } - return present; -} - -/* standard HP/line-out auto-mute helper */ -static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, - bool mute, bool hp_out) -{ - struct alc_spec *spec = codec->spec; - unsigned int mute_bits = mute ? HDA_AMP_MUTE : 0; - unsigned int pin_bits = mute ? 0 : (hp_out ? PIN_HP : PIN_OUT); - int i; - - for (i = 0; i < num_pins; i++) { - hda_nid_t nid = pins[i]; - unsigned int val; - if (!nid) - break; - switch (spec->automute_mode) { - case ALC_AUTOMUTE_PIN: - /* don't reset VREF value in case it's controlling - * the amp (see alc861_fixup_asus_amp_vref_0f()) - */ - if (spec->keep_vref_in_automute) { - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - val &= ~PIN_HP; - } else - val = 0; - val |= pin_bits; - snd_hda_set_pin_ctl(codec, nid, val); - break; - case ALC_AUTOMUTE_AMP: - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, mute_bits); - break; - case ALC_AUTOMUTE_MIXER: - nid = spec->automute_mixer_nid[i]; - if (!nid) - break; - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 0, - HDA_AMP_MUTE, mute_bits); - snd_hda_codec_amp_stereo(codec, nid, HDA_INPUT, 1, - HDA_AMP_MUTE, mute_bits); - break; - } - } -} - -/* Toggle outputs muting */ -static void update_outputs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int on; - - /* Control HP pins/amps depending on master_mute state; - * in general, HP pins/amps control should be enabled in all cases, - * but currently set only for master_mute, just to be safe - */ - if (!spec->shared_mic_hp) /* don't change HP-pin when shared with mic */ - do_automute(codec, ARRAY_SIZE(spec->autocfg.hp_pins), - spec->autocfg.hp_pins, spec->master_mute, true); - - if (!spec->automute_speaker) - on = 0; - else - on = spec->hp_jack_present | spec->line_jack_present; - on |= spec->master_mute; - do_automute(codec, ARRAY_SIZE(spec->autocfg.speaker_pins), - spec->autocfg.speaker_pins, on, false); - - /* toggle line-out mutes if needed, too */ - /* if LO is a copy of either HP or Speaker, don't need to handle it */ - if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0] || - spec->autocfg.line_out_pins[0] == spec->autocfg.speaker_pins[0]) - return; - if (!spec->automute_lo) - on = 0; - else - on = spec->hp_jack_present; - on |= spec->master_mute; - do_automute(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), - spec->autocfg.line_out_pins, on, false); -} - -static void call_update_outputs(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->automute_hook) - spec->automute_hook(codec); - else - update_outputs(codec); -} - -/* standard HP-automute helper */ -static void alc_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - - spec->hp_jack_present = - detect_jacks(codec, ARRAY_SIZE(spec->autocfg.hp_pins), - spec->autocfg.hp_pins); - if (!spec->detect_hp || (!spec->automute_speaker && !spec->automute_lo)) - return; - call_update_outputs(codec); -} - -/* standard line-out-automute helper */ -static void alc_line_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - return; - /* check LO jack only when it's different from HP */ - if (spec->autocfg.line_out_pins[0] == spec->autocfg.hp_pins[0]) - return; - - spec->line_jack_present = - detect_jacks(codec, ARRAY_SIZE(spec->autocfg.line_out_pins), - spec->autocfg.line_out_pins); - if (!spec->automute_speaker || !spec->detect_lo) - return; - call_update_outputs(codec); -} - -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -/* standard mic auto-switch helper */ -static void alc_mic_automute(struct hda_codec *codec, struct hda_jack_tbl *jack) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t *pins = spec->imux_pins; - - if (!spec->auto_mic || !spec->auto_mic_valid_imux) - return; - if (snd_BUG_ON(!spec->adc_nids)) - return; - if (snd_BUG_ON(spec->int_mic_idx < 0 || spec->ext_mic_idx < 0)) - return; - - if (snd_hda_jack_detect(codec, pins[spec->ext_mic_idx])) - alc_mux_select(codec, 0, spec->ext_mic_idx, false); - else if (spec->dock_mic_idx >= 0 && - snd_hda_jack_detect(codec, pins[spec->dock_mic_idx])) - alc_mux_select(codec, 0, spec->dock_mic_idx, false); - else - alc_mux_select(codec, 0, spec->int_mic_idx, false); -} - /* update the master volume per volume-knob's unsol event */ static void alc_update_knob_master(struct hda_codec *codec, struct hda_jack_tbl *jack) { @@ -679,14 +225,6 @@ static void alc880_unsol_event(struct hda_codec *codec, unsigned int res) snd_hda_jack_unsol_event(codec, res >> 2); } -/* call init functions of standard auto-mute helpers */ -static void alc_inithook(struct hda_codec *codec) -{ - alc_hp_automute(codec, NULL); - alc_line_automute(codec, NULL); - alc_mic_automute(codec, NULL); -} - /* additional initialization for ALC888 variants */ static void alc888_coef_init(struct hda_codec *codec) { @@ -743,8 +281,12 @@ static void alc_auto_setup_eapd(struct hda_codec *codec, bool on) */ static void alc_eapd_shutup(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; + alc_auto_setup_eapd(codec, false); - msleep(200); + if (!spec->no_depop_delay) + msleep(200); + snd_hda_shutup_pins(codec); } /* generic EAPD initialization */ @@ -807,366 +349,6 @@ static void alc_auto_init_amp(struct hda_codec *codec, int type) } } -/* - * Auto-Mute mode mixer enum support - */ -static int alc_automute_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - static const char * const texts2[] = { - "Disabled", "Enabled" - }; - static const char * const texts3[] = { - "Disabled", "Speaker Only", "Line Out+Speaker" - }; - const char * const *texts; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - if (spec->automute_speaker_possible && spec->automute_lo_possible) { - uinfo->value.enumerated.items = 3; - texts = texts3; - } else { - uinfo->value.enumerated.items = 2; - texts = texts2; - } - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int alc_automute_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned int val = 0; - if (spec->automute_speaker) - val++; - if (spec->automute_lo) - val++; - - ucontrol->value.enumerated.item[0] = val; - return 0; -} - -static int alc_automute_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - - switch (ucontrol->value.enumerated.item[0]) { - case 0: - if (!spec->automute_speaker && !spec->automute_lo) - return 0; - spec->automute_speaker = 0; - spec->automute_lo = 0; - break; - case 1: - if (spec->automute_speaker_possible) { - if (!spec->automute_lo && spec->automute_speaker) - return 0; - spec->automute_speaker = 1; - spec->automute_lo = 0; - } else if (spec->automute_lo_possible) { - if (spec->automute_lo) - return 0; - spec->automute_lo = 1; - } else - return -EINVAL; - break; - case 2: - if (!spec->automute_lo_possible || !spec->automute_speaker_possible) - return -EINVAL; - if (spec->automute_speaker && spec->automute_lo) - return 0; - spec->automute_speaker = 1; - spec->automute_lo = 1; - break; - default: - return -EINVAL; - } - call_update_outputs(codec); - return 1; -} - -static const struct snd_kcontrol_new alc_automute_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Auto-Mute Mode", - .info = alc_automute_mode_info, - .get = alc_automute_mode_get, - .put = alc_automute_mode_put, -}; - -static struct snd_kcontrol_new *alc_kcontrol_new(struct alc_spec *spec) -{ - snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32); - return snd_array_new(&spec->kctls); -} - -static int alc_add_automute_mode_enum(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_automute_mode_enum; - knew->name = kstrdup("Auto-Mute Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - return 0; -} - -/* - * Check the availability of HP/line-out auto-mute; - * Set up appropriately if really supported - */ -static void alc_init_automute(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int present = 0; - int i; - - if (cfg->hp_pins[0]) - present++; - if (cfg->line_out_pins[0]) - present++; - if (cfg->speaker_pins[0]) - present++; - if (present < 2) /* need two different output types */ - return; - - if (!cfg->speaker_pins[0] && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = cfg->line_outs; - } - - if (!cfg->hp_pins[0] && - cfg->line_out_type == AUTO_PIN_HP_OUT) { - memcpy(cfg->hp_pins, cfg->line_out_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = cfg->line_outs; - } - - spec->automute_mode = ALC_AUTOMUTE_PIN; - - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", - nid); - snd_hda_jack_detect_enable_callback(codec, nid, ALC_HP_EVENT, - alc_hp_automute); - spec->detect_hp = 1; - } - - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && cfg->line_outs) { - if (cfg->speaker_outs) - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - if (!is_jack_detectable(codec, nid)) - continue; - snd_printdd("realtek: Enable Line-Out " - "auto-muting on NID 0x%x\n", nid); - snd_hda_jack_detect_enable_callback(codec, nid, ALC_FRONT_EVENT, - alc_line_automute); - spec->detect_lo = 1; - } - spec->automute_lo_possible = spec->detect_hp; - } - - spec->automute_speaker_possible = cfg->speaker_outs && - (spec->detect_hp || spec->detect_lo); - - spec->automute_lo = spec->automute_lo_possible; - spec->automute_speaker = spec->automute_speaker_possible; - - if (spec->automute_speaker_possible || spec->automute_lo_possible) - /* create a control for automute mode */ - alc_add_automute_mode_enum(codec); -} - -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} - -/* check whether dynamic ADC-switching is available */ -static bool alc_check_dyn_adc_switch(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux[0]; - int i, n, idx; - hda_nid_t cap, pin; - - if (imux != spec->input_mux) /* no dynamic imux? */ - return false; - - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - if (!pin) - return false; - if (get_connection_index(codec, cap, pin) < 0) - break; - } - if (i >= imux->num_items) - return true; /* no ADC-switch is needed */ - } - - for (i = 0; i < imux->num_items; i++) { - pin = spec->imux_pins[i]; - for (n = 0; n < spec->num_adc_nids; n++) { - cap = spec->private_capsrc_nids[n]; - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - imux->items[i].index = idx; - spec->dyn_adc_idx[i] = n; - break; - } - } - } - - snd_printdd("realtek: enabling ADC switching\n"); - spec->dyn_adc_switch = 1; - return true; -} - -/* check whether all auto-mic pins are valid; setup indices if OK */ -static bool alc_auto_mic_check_imux(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - - if (!spec->auto_mic) - return false; - if (spec->auto_mic_valid_imux) - return true; /* already checked */ - - /* fill up imux indices */ - if (!alc_check_dyn_adc_switch(codec)) { - spec->auto_mic = 0; - return false; - } - - imux = spec->input_mux; - spec->ext_mic_idx = find_idx_in_nid_list(spec->ext_mic_pin, - spec->imux_pins, imux->num_items); - spec->int_mic_idx = find_idx_in_nid_list(spec->int_mic_pin, - spec->imux_pins, imux->num_items); - spec->dock_mic_idx = find_idx_in_nid_list(spec->dock_mic_pin, - spec->imux_pins, imux->num_items); - if (spec->ext_mic_idx < 0 || spec->int_mic_idx < 0) { - spec->auto_mic = 0; - return false; /* no corresponding imux */ - } - - snd_hda_jack_detect_enable_callback(codec, spec->ext_mic_pin, - ALC_MIC_EVENT, alc_mic_automute); - if (spec->dock_mic_pin) - snd_hda_jack_detect_enable_callback(codec, spec->dock_mic_pin, - ALC_MIC_EVENT, - alc_mic_automute); - - spec->auto_mic_valid_imux = 1; - spec->auto_mic = 1; - return true; -} - -/* - * Check the availability of auto-mic switch; - * Set up if really supported - */ -static void alc_init_auto_mic(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext, dock; - int i; - - if (spec->shared_mic_hp) - return; /* no auto-mic for the shared I/O */ - - spec->ext_mic_idx = spec->int_mic_idx = spec->dock_mic_idx = -1; - - fixed = ext = dock = 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - unsigned int defcfg; - defcfg = snd_hda_codec_get_pincfg(codec, nid); - switch (snd_hda_get_input_pin_attr(defcfg)) { - case INPUT_PIN_ATTR_INT: - if (fixed) - return; /* already occupied */ - if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ - fixed = nid; - break; - case INPUT_PIN_ATTR_UNUSED: - return; /* invalid entry */ - case INPUT_PIN_ATTR_DOCK: - if (dock) - return; /* already occupied */ - if (cfg->inputs[i].type > AUTO_PIN_LINE_IN) - return; /* invalid type */ - dock = nid; - break; - default: - if (ext) - return; /* already occupied */ - if (cfg->inputs[i].type != AUTO_PIN_MIC) - return; /* invalid type */ - ext = nid; - break; - } - } - if (!ext && dock) { - ext = dock; - dock = 0; - } - if (!ext || !fixed) - return; - if (!is_jack_detectable(codec, ext)) - return; /* no unsol support */ - if (dock && !is_jack_detectable(codec, dock)) - return; /* no unsol support */ - - /* check imux indices */ - spec->ext_mic_pin = ext; - spec->int_mic_pin = fixed; - spec->dock_mic_pin = dock; - - spec->auto_mic = 1; - if (!alc_auto_mic_check_imux(codec)) - return; - - snd_printdd("realtek: Enable auto-mic switch on NID 0x%x/0x%x/0x%x\n", - ext, fixed, dock); -} - -/* check the availabilities of auto-mute and auto-mic switches */ -static void alc_auto_check_switches(struct hda_codec *codec) -{ - alc_init_automute(codec); - alc_init_auto_mic(codec); -} /* * Realtek SSID verification @@ -1187,6 +369,17 @@ static void alc_fixup_sku_ignore(struct hda_codec *codec, } } +static void alc_fixup_no_depop_delay(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PROBE) { + spec->no_depop_delay = 1; + codec->depop_delay = 0; + } +} + static int alc_auto_parse_customize_define(struct hda_codec *codec) { unsigned int ass, tmp, i; @@ -1202,6 +395,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) goto do_sku; } + if (!codec->bus->pci) + return -1; ass = codec->subsystem_id & 0xffff; if (ass != codec->bus->pci->subsystem_device && (ass & 1)) goto do_sku; @@ -1212,8 +407,8 @@ static int alc_auto_parse_customize_define(struct hda_codec *codec) ass = snd_hda_codec_get_pincfg(codec, nid); if (!(ass & 1)) { - printk(KERN_INFO "hda_codec: %s: SKU not ready 0x%08x\n", - codec->chip_name, ass); + codec_info(codec, "%s: SKU not ready 0x%08x\n", + codec->chip_name, ass); return -1; } @@ -1237,21 +432,30 @@ do_sku: spec->cdefine.swap = (ass & 0x2) >> 1; spec->cdefine.override = ass & 0x1; - snd_printd("SKU: Nid=0x%x sku_cfg=0x%08x\n", + codec_dbg(codec, "SKU: Nid=0x%x sku_cfg=0x%08x\n", nid, spec->cdefine.sku_cfg); - snd_printd("SKU: port_connectivity=0x%x\n", + codec_dbg(codec, "SKU: port_connectivity=0x%x\n", spec->cdefine.port_connectivity); - snd_printd("SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); - snd_printd("SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); - snd_printd("SKU: customization=0x%08x\n", spec->cdefine.customization); - snd_printd("SKU: external_amp=0x%x\n", spec->cdefine.external_amp); - snd_printd("SKU: platform_type=0x%x\n", spec->cdefine.platform_type); - snd_printd("SKU: swap=0x%x\n", spec->cdefine.swap); - snd_printd("SKU: override=0x%x\n", spec->cdefine.override); + codec_dbg(codec, "SKU: enable_pcbeep=0x%x\n", spec->cdefine.enable_pcbeep); + codec_dbg(codec, "SKU: check_sum=0x%08x\n", spec->cdefine.check_sum); + codec_dbg(codec, "SKU: customization=0x%08x\n", spec->cdefine.customization); + codec_dbg(codec, "SKU: external_amp=0x%x\n", spec->cdefine.external_amp); + codec_dbg(codec, "SKU: platform_type=0x%x\n", spec->cdefine.platform_type); + codec_dbg(codec, "SKU: swap=0x%x\n", spec->cdefine.swap); + codec_dbg(codec, "SKU: override=0x%x\n", spec->cdefine.override); return 0; } +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} /* return true if the given NID is found in the list */ static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) { @@ -1267,9 +471,7 @@ static bool found_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) * 7 ~ 0 : Assembly ID * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 */ -static int alc_subsystem_id(struct hda_codec *codec, - hda_nid_t porta, hda_nid_t porte, - hda_nid_t portd, hda_nid_t porti) +static int alc_subsystem_id(struct hda_codec *codec, const hda_nid_t *ports) { unsigned int ass, tmp, i; unsigned nid; @@ -1283,7 +485,8 @@ static int alc_subsystem_id(struct hda_codec *codec, } ass = codec->subsystem_id & 0xffff; - if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) + if (codec->bus->pci && + ass != codec->bus->pci->subsystem_device && (ass & 1)) goto do_sku; /* invalid SSID, check the special NID pin defcfg instead */ @@ -1299,8 +502,8 @@ static int alc_subsystem_id(struct hda_codec *codec, if (codec->vendor_id == 0x10ec0260) nid = 0x17; ass = snd_hda_codec_get_pincfg(codec, nid); - snd_printd("realtek: No valid SSID, " - "checking pincfg 0x%08x for NID 0x%x\n", + codec_dbg(codec, + "realtek: No valid SSID, checking pincfg 0x%08x for NID 0x%x\n", ass, nid); if (!(ass & 1)) return 0; @@ -1316,7 +519,7 @@ static int alc_subsystem_id(struct hda_codec *codec, if (((ass >> 16) & 0xf) != tmp) return 0; do_sku: - snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", + codec_dbg(codec, "realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", ass & 0xffff, codec->vendor_id); /* * 0 : override @@ -1354,25 +557,16 @@ do_sku: * 15 : 1 --> enable the function "Mute internal speaker * when the external headphone out jack is plugged" */ - if (!spec->autocfg.hp_pins[0] && - !(spec->autocfg.line_out_pins[0] && - spec->autocfg.line_out_type == AUTO_PIN_HP_OUT)) { + if (!spec->gen.autocfg.hp_pins[0] && + !(spec->gen.autocfg.line_out_pins[0] && + spec->gen.autocfg.line_out_type == AUTO_PIN_HP_OUT)) { hda_nid_t nid; tmp = (ass >> 11) & 0x3; /* HP to chassis */ - if (tmp == 0) - nid = porta; - else if (tmp == 1) - nid = porte; - else if (tmp == 2) - nid = portd; - else if (tmp == 3) - nid = porti; - else - return 1; - if (found_in_nid_list(nid, spec->autocfg.line_out_pins, - spec->autocfg.line_outs)) + nid = ports[tmp]; + if (found_in_nid_list(nid, spec->gen.autocfg.line_out_pins, + spec->gen.autocfg.line_outs)) return 1; - spec->autocfg.hp_pins[0] = nid; + spec->gen.autocfg.hp_pins[0] = nid; } return 1; } @@ -1381,10 +575,10 @@ do_sku: * ports contains an array of 4 pin NIDs for port-A, E, D and I */ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) { - if (!alc_subsystem_id(codec, ports[0], ports[1], ports[2], ports[3])) { + if (!alc_subsystem_id(codec, ports)) { struct alc_spec *spec = codec->spec; - snd_printd("realtek: " - "Enable default setup for auto mode as fallback\n"); + codec_dbg(codec, + "realtek: Enable default setup for auto mode as fallback\n"); spec->init_amp = ALC_INIT_DEFAULT; } } @@ -1392,26 +586,35 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) /* * COEF access helper functions */ -static int alc_read_coef_idx(struct hda_codec *codec, - unsigned int coef_idx) + +static int alc_read_coefex_idx(struct hda_codec *codec, + hda_nid_t nid, + unsigned int coef_idx) { unsigned int val; - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); - val = snd_hda_codec_read(codec, 0x20, 0, + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF, 0); return val; } -static void alc_write_coef_idx(struct hda_codec *codec, unsigned int coef_idx, +#define alc_read_coef_idx(codec, coef_idx) \ + alc_read_coefex_idx(codec, 0x20, coef_idx) + +static void alc_write_coefex_idx(struct hda_codec *codec, hda_nid_t nid, + unsigned int coef_idx, unsigned int coef_val) { - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, coef_idx); - snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_PROC_COEF, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PROC_COEF, coef_val); } +#define alc_write_coef_idx(codec, coef_idx, coef_val) \ + alc_write_coefex_idx(codec, 0x20, coef_idx, coef_val) + /* a special bypass for COEF 0; read the cached value at the second time */ static unsigned int alc_get_coef0(struct hda_codec *codec) { @@ -1422,252 +625,54 @@ static unsigned int alc_get_coef0(struct hda_codec *codec) } /* - * Digital I/O handling */ -/* set right pin controls for digital I/O */ -static void alc_auto_init_digital(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - hda_nid_t pin, dac; - - for (i = 0; i < spec->autocfg.dig_outs; i++) { - pin = spec->autocfg.dig_out_pins[i]; - if (!pin) - continue; - snd_hda_set_pin_ctl(codec, pin, PIN_OUT); - if (!i) - dac = spec->multiout.dig_out_nid; - else - dac = spec->slave_dig_outs[i - 1]; - if (!dac || !(get_wcaps(codec, dac) & AC_WCAP_OUT_AMP)) - continue; - snd_hda_codec_write(codec, dac, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); - } - pin = spec->autocfg.dig_in_pin; - if (pin) - snd_hda_set_pin_ctl(codec, pin, PIN_IN); -} - -/* parse digital I/Os and set up NIDs in BIOS auto-parse mode */ -static void alc_auto_parse_digital(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i, err, nums; - hda_nid_t dig_nid; - - /* support multiple SPDIFs; the secondary is set up as a slave */ - nums = 0; - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t conn[4]; - err = snd_hda_get_connections(codec, - spec->autocfg.dig_out_pins[i], - conn, ARRAY_SIZE(conn)); - if (err <= 0) - continue; - dig_nid = conn[0]; /* assume the first element is audio-out */ - if (!nums) { - spec->multiout.dig_out_nid = dig_nid; - spec->dig_out_type = spec->autocfg.dig_out_type[0]; - } else { - spec->multiout.slave_dig_outs = spec->slave_dig_outs; - if (nums >= ARRAY_SIZE(spec->slave_dig_outs) - 1) - break; - spec->slave_dig_outs[nums - 1] = dig_nid; - } - nums++; - } - - if (spec->autocfg.dig_in_pin) { - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } - } -} - -/* - * capture mixer elements - */ -static int alc_cap_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_volume_info(kcontrol, uinfo); - mutex_unlock(&codec->control_mutex); - return err; -} - -static int alc_cap_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *tlv) +static hda_nid_t get_adc_nid(struct hda_codec *codec, int adc_idx, int imux_idx) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - unsigned long val; - int err; - - mutex_lock(&codec->control_mutex); - if (spec->vol_in_capsrc) - val = HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[0], 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(spec->adc_nids[0], 3, 0, HDA_INPUT); - kcontrol->private_value = val; - err = snd_hda_mixer_amp_tlv(kcontrol, op_flag, size, tlv); - mutex_unlock(&codec->control_mutex); - return err; + struct hda_gen_spec *spec = codec->spec; + if (spec->dyn_adc_switch) + adc_idx = spec->dyn_adc_idx[imux_idx]; + return spec->adc_nids[adc_idx]; } -typedef int (*getput_call_t)(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol); - -static int alc_cap_getput_caller(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol, - getput_call_t func, bool is_put) +static void alc_inv_dmic_sync_adc(struct hda_codec *codec, int adc_idx) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct alc_spec *spec = codec->spec; - int i, err = 0; - - mutex_lock(&codec->control_mutex); - if (is_put && spec->dyn_adc_switch) { - for (i = 0; i < spec->num_adc_nids; i++) { - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - if (err < 0) - goto error; - } - } else { - i = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - if (spec->vol_in_capsrc) - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->capsrc_nids[i], - 3, 0, HDA_OUTPUT); - else - kcontrol->private_value = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], - 3, 0, HDA_INPUT); - err = func(kcontrol, ucontrol); - } - if (err >= 0 && is_put) - alc_inv_dmic_sync(codec, false); - error: - mutex_unlock(&codec->control_mutex); - return err; -} - -static int alc_cap_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_get, false); -} - -static int alc_cap_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_volume_put, true); -} - -/* capture mixer elements */ -#define alc_cap_sw_info snd_ctl_boolean_stereo_info - -static int alc_cap_sw_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_get, false); -} - -static int alc_cap_sw_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - return alc_cap_getput_caller(kcontrol, ucontrol, - snd_hda_mixer_amp_switch_put, true); -} + struct hda_input_mux *imux = &spec->gen.input_mux; + struct nid_path *path; + hda_nid_t nid; + int i, dir, parm; + unsigned int val; -#define _DEFINE_CAPMIX(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Switch", \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, \ - .count = num, \ - .info = alc_cap_sw_info, \ - .get = alc_cap_sw_get, \ - .put = alc_cap_sw_put, \ - }, \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Capture Volume", \ - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK), \ - .count = num, \ - .info = alc_cap_vol_info, \ - .get = alc_cap_vol_get, \ - .put = alc_cap_vol_put, \ - .tlv = { .c = alc_cap_vol_tlv }, \ + for (i = 0; i < imux->num_items; i++) { + if (spec->gen.imux_pins[i] == spec->inv_dmic_pin) + break; } + if (i >= imux->num_items) + return; -#define _DEFINE_CAPSRC(num) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - /* .name = "Capture Source", */ \ - .name = "Input Source", \ - .count = num, \ - .info = alc_mux_enum_info, \ - .get = alc_mux_enum_get, \ - .put = alc_mux_enum_put, \ - } + path = snd_hda_get_nid_path(codec, spec->inv_dmic_pin, + get_adc_nid(codec, adc_idx, i)); + val = path->ctls[NID_PATH_MUTE_CTL]; + if (!val) + return; + nid = get_amp_nid_(val); + dir = get_amp_direction_(val); + parm = AC_AMP_SET_RIGHT | + (dir == HDA_OUTPUT ? AC_AMP_SET_OUTPUT : AC_AMP_SET_INPUT); -#define DEFINE_CAPMIX(num) \ -static const struct snd_kcontrol_new alc_capture_mixer ## num[] = { \ - _DEFINE_CAPMIX(num), \ - _DEFINE_CAPSRC(num), \ - { } /* end */ \ -} + /* flush all cached amps at first */ + snd_hda_codec_flush_cache(codec); -#define DEFINE_CAPMIX_NOSRC(num) \ -static const struct snd_kcontrol_new alc_capture_mixer_nosrc ## num[] = { \ - _DEFINE_CAPMIX(num), \ - { } /* end */ \ + /* we care only right channel */ + val = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); + if (val & 0x80) /* if already muted, we don't need to touch */ + return; + val |= 0x80; + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, + parm | val); } -/* up to three ADCs */ -DEFINE_CAPMIX(1); -DEFINE_CAPMIX(2); -DEFINE_CAPMIX(3); -DEFINE_CAPMIX_NOSRC(1); -DEFINE_CAPMIX_NOSRC(2); -DEFINE_CAPMIX_NOSRC(3); - /* * Inverted digital-mic handling * @@ -1686,43 +691,32 @@ DEFINE_CAPMIX_NOSRC(3); static void alc_inv_dmic_sync(struct hda_codec *codec, bool force) { struct alc_spec *spec = codec->spec; - int i; + int src, nums; if (!spec->inv_dmic_fixup) return; if (!spec->inv_dmic_muted && !force) return; - for (i = 0; i < spec->num_adc_nids; i++) { - int src = spec->dyn_adc_switch ? 0 : i; + nums = spec->gen.dyn_adc_switch ? 1 : spec->gen.num_adc_nids; + for (src = 0; src < nums; src++) { bool dmic_fixup = false; - hda_nid_t nid; - int parm, dir, v; if (spec->inv_dmic_muted && - spec->imux_pins[spec->cur_mux[src]] == spec->inv_dmic_pin) + spec->gen.imux_pins[spec->gen.cur_mux[src]] == spec->inv_dmic_pin) dmic_fixup = true; if (!dmic_fixup && !force) continue; - if (spec->vol_in_capsrc) { - nid = spec->capsrc_nids[i]; - parm = AC_AMP_SET_RIGHT | AC_AMP_SET_OUTPUT; - dir = HDA_OUTPUT; - } else { - nid = spec->adc_nids[i]; - parm = AC_AMP_SET_RIGHT | AC_AMP_SET_INPUT; - dir = HDA_INPUT; - } - /* we care only right channel */ - v = snd_hda_codec_amp_read(codec, nid, 1, dir, 0); - if (v & 0x80) /* if already muted, we don't need to touch */ - continue; - if (dmic_fixup) /* add mute for d-mic */ - v |= 0x80; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - parm | v); + alc_inv_dmic_sync_adc(codec, src); } } +static void alc_inv_dmic_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + alc_inv_dmic_sync(codec, false); +} + static int alc_inv_dmic_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1749,6 +743,7 @@ static int alc_inv_dmic_sw_put(struct snd_kcontrol *kcontrol, static const struct snd_kcontrol_new alc_inv_dmic_sw = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Inverted Internal Mic Capture Switch", .info = snd_ctl_boolean_mono_info, .get = alc_inv_dmic_sw_get, .put = alc_inv_dmic_sw_put, @@ -1757,55 +752,24 @@ static const struct snd_kcontrol_new alc_inv_dmic_sw = { static int alc_add_inv_dmic_mixer(struct hda_codec *codec, hda_nid_t nid) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol_new *knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_inv_dmic_sw; - knew->name = kstrdup("Inverted Internal Mic Capture Switch", GFP_KERNEL); - if (!knew->name) + + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &alc_inv_dmic_sw)) return -ENOMEM; spec->inv_dmic_fixup = 1; spec->inv_dmic_muted = 0; spec->inv_dmic_pin = nid; + spec->gen.cap_sync_hook = alc_inv_dmic_hook; return 0; } /* typically the digital mic is put at node 0x12 */ static void alc_fixup_inv_dmic_0x12(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PROBE) alc_add_inv_dmic_mixer(codec, 0x12); } -/* - * virtual master controls - */ - -/* - * slave controls for virtual master - */ -static const char * const alc_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "Mono", "Line Out", - "CLFE", "Bass Speaker", "PCM", - NULL, -}; - -/* - * build control elements - */ - -#define NID_MAPPING (-1) - -#define SUBDEV_SPEAKER_ (0 << 6) -#define SUBDEV_HP_ (1 << 6) -#define SUBDEV_LINE_ (2 << 6) -#define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) -#define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) -#define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) - -static void alc_free_kctls(struct hda_codec *codec); #ifdef CONFIG_SND_HDA_INPUT_BEEP /* additional beep mixers; the actual parameters are overwritten at build */ @@ -1816,44 +780,20 @@ static const struct snd_kcontrol_new alc_beep_mixer[] = { }; #endif -static int __alc_build_controls(struct hda_codec *codec) +static int alc_build_controls(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - struct snd_kcontrol *kctl = NULL; - const struct snd_kcontrol_new *knew; - int i, j, err; - unsigned int u; - hda_nid_t nid; + int i, err; + + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); if (err < 0) return err; } - if (spec->cap_mixer) { - err = snd_hda_add_new_ctls(codec, spec->cap_mixer); - if (err < 0) - return err; - } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - if (!spec->no_analog) { - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } #ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ @@ -1872,130 +812,7 @@ static int __alc_build_controls(struct hda_codec *codec) } #endif - /* if we have no master control, let's create it */ - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, alc_slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (!spec->no_analog && - !snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, alc_slave_pfxs, - "Playback Switch", - true, &spec->vmaster_mute.sw_kctl); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - if (spec->capsrc_nids || spec->adc_nids) { - kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); - if (!kctl) - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, - get_capsrc(spec, i)); - if (err < 0) - return err; - } - } - if (spec->cap_mixer && spec->adc_nids) { - const char *kname = kctl ? kctl->id.name : NULL; - for (knew = spec->cap_mixer; knew->name; knew++) { - if (kname && strcmp(knew->name, kname) == 0) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - for (i = 0; kctl && i < kctl->count; i++) { - err = snd_hda_add_nid(codec, kctl, i, - spec->adc_nids[i]); - if (err < 0) - return err; - } - } - } - - /* other nid->control mapping */ - for (i = 0; i < spec->num_mixers; i++) { - for (knew = spec->mixers[i]; knew->name; knew++) { - if (knew->iface != NID_MAPPING) - continue; - kctl = snd_hda_find_mixer_ctl(codec, knew->name); - if (kctl == NULL) - continue; - u = knew->subdevice; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0x3f; - if (nid == 0) - continue; - switch (u & 0xc0) { - case SUBDEV_SPEAKER_: - nid = spec->autocfg.speaker_pins[nid]; - break; - case SUBDEV_LINE_: - nid = spec->autocfg.line_out_pins[nid]; - break; - case SUBDEV_HP_: - nid = spec->autocfg.hp_pins[nid]; - break; - default: - continue; - } - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - u = knew->private_value; - for (j = 0; j < 4; j++, u >>= 8) { - nid = u & 0xff; - if (nid == 0) - continue; - err = snd_hda_add_nid(codec, kctl, 0, nid); - if (err < 0) - return err; - } - } - } - - alc_free_kctls(codec); /* no longer needed */ - - return 0; -} - -static int alc_build_jacks(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->shared_mic_hp) { - int err; - int nid = spec->autocfg.inputs[1].pin; - err = snd_hda_jack_add_kctl(codec, nid, "Headphone Mic", 0); - if (err < 0) - return err; - err = snd_hda_jack_detect_enable(codec, nid, 0); - if (err < 0) - return err; - } - - return snd_hda_jack_add_kctls(codec, &spec->autocfg); -} - -static int alc_build_controls(struct hda_codec *codec) -{ - int err = __alc_build_controls(codec); - if (err < 0) - return err; - - err = alc_build_jacks(codec); - if (err < 0) - return err; - alc_apply_fixup(codec, ALC_FIXUP_ACT_BUILD); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_BUILD); return 0; } @@ -2004,9 +821,6 @@ static int alc_build_controls(struct hda_codec *codec) * Common callbacks */ -static void alc_init_special_input_src(struct hda_codec *codec); -static void alc_auto_init_std(struct hda_codec *codec); - static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -2017,343 +831,9 @@ static int alc_init(struct hda_codec *codec) alc_fix_pll(codec); alc_auto_init_amp(codec, spec->init_amp); - snd_hda_gen_apply_verbs(codec); - alc_init_special_input_src(codec); - alc_auto_init_std(codec); - - alc_apply_fixup(codec, ALC_FIXUP_ACT_INIT); - - hda_call_check_power_status(codec, 0x01); - return 0; -} - -#ifdef CONFIG_PM -static int alc_check_power_status(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); -} -#endif - -/* - * Analog playback callbacks - */ -static int alc_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int alc_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital out - */ -static int alc_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int alc_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int alc_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); -} - -static int alc_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -/* - * Analog capture - */ -static int alc_alt_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number + 1], - stream_tag, 0, format); - return 0; -} - -static int alc_alt_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - - snd_hda_codec_cleanup_stream(codec, - spec->adc_nids[substream->number + 1]); - return 0; -} - -/* analog capture with dynamic dual-adc changes */ -static int dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - spec->cur_adc = spec->adc_nids[spec->dyn_adc_idx[spec->cur_mux[0]]]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - return 0; -} - -static int dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct alc_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - return 0; -} - -static const struct hda_pcm_stream dyn_adc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0, /* fill later */ - .ops = { - .prepare = dyn_adc_capture_pcm_prepare, - .cleanup = dyn_adc_capture_pcm_cleanup - }, -}; - -/* - */ -static const struct hda_pcm_stream alc_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static const struct hda_pcm_stream alc_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -static const struct hda_pcm_stream alc_pcm_analog_alt_capture = { - .substreams = 2, /* can be overridden */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .prepare = alc_alt_capture_pcm_prepare, - .cleanup = alc_alt_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ - .ops = { - .open = alc_dig_playback_pcm_open, - .close = alc_dig_playback_pcm_close, - .prepare = alc_dig_playback_pcm_prepare, - .cleanup = alc_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream alc_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in alc_build_pcms */ -}; - -/* Used by alc_build_pcms to flag that a PCM has no playback stream */ -static const struct hda_pcm_stream alc_pcm_null_stream = { - .substreams = 0, - .channels_min = 0, - .channels_max = 0, -}; - -static int alc_build_pcms(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - const struct hda_pcm_stream *p; - bool have_multi_adcs; - int i; - - codec->num_pcms = 1; - codec->pcm_info = info; + snd_hda_gen_init(codec); - if (spec->no_analog) - goto skip_analog; - - snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; - - if (spec->multiout.num_dacs > 0) { - p = spec->stream_analog_playback; - if (!p) - p = &alc_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - } - if (spec->adc_nids) { - p = spec->stream_analog_capture; - if (!p) { - if (spec->dyn_adc_switch) - p = &dyn_adc_pcm_analog_capture; - else - p = &alc_pcm_analog_capture; - } - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; - } - - if (spec->channel_mode) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = 0; - for (i = 0; i < spec->num_channel_mode; i++) { - if (spec->channel_mode[i].channels > info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = spec->channel_mode[i].channels; - } - } - } - - skip_analog: - /* SPDIF for stream index #1 */ - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - codec->num_pcms = 2; - codec->slave_dig_outs = spec->multiout.slave_dig_outs; - info = spec->pcm_rec + 1; - info->name = spec->stream_name_digital; - if (spec->dig_out_type) - info->pcm_type = spec->dig_out_type; - else - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - p = spec->stream_digital_playback; - if (!p) - p = &alc_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - p = spec->stream_digital_capture; - if (!p) - p = &alc_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - /* FIXME: do we need this for all Realtek codec models? */ - codec->spdif_status_reset = 1; - } - - if (spec->no_analog) - return 0; - - /* If the use of more than one ADC is requested for the current - * model, configure a second analog capture-only PCM. - */ - have_multi_adcs = (spec->num_adc_nids > 1) && - !spec->dyn_adc_switch && !spec->auto_mic && - (!spec->input_mux || spec->input_mux->num_items > 1); - /* Additional Analaog capture for index #2 */ - if (spec->alt_dac_nid || have_multi_adcs) { - codec->num_pcms = 3; - info = spec->pcm_rec + 2; - info->name = spec->stream_name_analog; - if (spec->alt_dac_nid) { - p = spec->stream_analog_alt_playback; - if (!p) - p = &alc_pcm_analog_alt_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = *p; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->alt_dac_nid; - } else { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = 0; - } - if (have_multi_adcs) { - p = spec->stream_analog_alt_capture; - if (!p) - p = &alc_pcm_analog_alt_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = *p; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[1]; - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids - 1; - } else { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - alc_pcm_null_stream; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = 0; - } - } + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_INIT); return 0; } @@ -2364,48 +844,11 @@ static inline void alc_shutup(struct hda_codec *codec) if (spec && spec->shutup) spec->shutup(codec); - snd_hda_shutup_pins(codec); -} - -static void alc_free_kctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - -static void alc_free_bind_ctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - if (spec->bind_ctls.list) { - struct hda_bind_ctls **ctl = spec->bind_ctls.list; - int i; - for (i = 0; i < spec->bind_ctls.used; i++) - kfree(ctl[i]); - } - snd_array_free(&spec->bind_ctls); + else + snd_hda_shutup_pins(codec); } -static void alc_free(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (!spec) - return; - - alc_shutup(codec); - alc_free_kctls(codec); - alc_free_bind_ctls(codec); - snd_hda_gen_free(&spec->gen); - kfree(spec); - snd_hda_detach_beep_device(codec); -} +#define alc_free snd_hda_gen_free #ifdef CONFIG_PM static void alc_power_eapd(struct hda_codec *codec) @@ -2426,7 +869,10 @@ static int alc_suspend(struct hda_codec *codec) #ifdef CONFIG_PM static int alc_resume(struct hda_codec *codec) { - msleep(150); /* to avoid pop noise */ + struct alc_spec *spec = codec->spec; + + if (!spec->no_depop_delay) + msleep(150); /* to avoid pop noise */ codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); @@ -2440,16 +886,14 @@ static int alc_resume(struct hda_codec *codec) */ static const struct hda_codec_ops alc_patch_ops = { .build_controls = alc_build_controls, - .build_pcms = alc_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = alc_init, .free = alc_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM .resume = alc_resume, -#endif -#ifdef CONFIG_PM .suspend = alc_suspend, - .check_power_status = alc_check_power_status, + .check_power_status = snd_hda_gen_check_power_status, #endif .reboot_notify = alc_shutup, }; @@ -2468,7 +912,7 @@ static int alc_codec_rename(struct hda_codec *codec, const char *name) } /* - * Rename codecs appropriately from COEF value + * Rename codecs appropriately from COEF value or subvendor id */ struct alc_codec_rename_table { unsigned int vendor_id; @@ -2477,7 +921,15 @@ struct alc_codec_rename_table { const char *name; }; +struct alc_codec_rename_pci_table { + unsigned int codec_vendor_id; + unsigned short pci_subvendor; + unsigned short pci_subdevice; + const char *name; +}; + static struct alc_codec_rename_table rename_tbl[] = { + { 0x10ec0221, 0xf00f, 0x1003, "ALC231" }, { 0x10ec0269, 0xfff0, 0x3010, "ALC277" }, { 0x10ec0269, 0xf0f0, 0x2010, "ALC259" }, { 0x10ec0269, 0xf0f0, 0x3010, "ALC258" }, @@ -2486,6 +938,7 @@ static struct alc_codec_rename_table rename_tbl[] = { { 0x10ec0269, 0xffff, 0x6023, "ALC281X" }, { 0x10ec0269, 0x00f0, 0x0020, "ALC269VC" }, { 0x10ec0269, 0x00f0, 0x0030, "ALC269VD" }, + { 0x10ec0662, 0xffff, 0x4020, "ALC656" }, { 0x10ec0887, 0x00f0, 0x0030, "ALC887-VD" }, { 0x10ec0888, 0x00f0, 0x0030, "ALC888-VD" }, { 0x10ec0888, 0xf0f0, 0x3020, "ALC886" }, @@ -2496,9 +949,35 @@ static struct alc_codec_rename_table rename_tbl[] = { { } /* terminator */ }; +static struct alc_codec_rename_pci_table rename_pci_tbl[] = { + { 0x10ec0280, 0x1028, 0, "ALC3220" }, + { 0x10ec0282, 0x1028, 0, "ALC3221" }, + { 0x10ec0283, 0x1028, 0, "ALC3223" }, + { 0x10ec0288, 0x1028, 0, "ALC3263" }, + { 0x10ec0292, 0x1028, 0, "ALC3226" }, + { 0x10ec0293, 0x1028, 0, "ALC3235" }, + { 0x10ec0255, 0x1028, 0, "ALC3234" }, + { 0x10ec0668, 0x1028, 0, "ALC3661" }, + { 0x10ec0275, 0x1028, 0, "ALC3260" }, + { 0x10ec0899, 0x1028, 0, "ALC3861" }, + { 0x10ec0670, 0x1025, 0, "ALC669X" }, + { 0x10ec0676, 0x1025, 0, "ALC679X" }, + { 0x10ec0282, 0x1043, 0, "ALC3229" }, + { 0x10ec0233, 0x1043, 0, "ALC3236" }, + { 0x10ec0280, 0x103c, 0, "ALC3228" }, + { 0x10ec0282, 0x103c, 0, "ALC3227" }, + { 0x10ec0286, 0x103c, 0, "ALC3242" }, + { 0x10ec0290, 0x103c, 0, "ALC3241" }, + { 0x10ec0668, 0x103c, 0, "ALC3662" }, + { 0x10ec0283, 0x17aa, 0, "ALC3239" }, + { 0x10ec0292, 0x17aa, 0, "ALC3232" }, + { } /* terminator */ +}; + static int alc_codec_rename_from_preset(struct hda_codec *codec) { const struct alc_codec_rename_table *p; + const struct alc_codec_rename_pci_table *q; for (p = rename_tbl; p->vendor_id; p++) { if (p->vendor_id != codec->vendor_id) @@ -2506,1740 +985,22 @@ static int alc_codec_rename_from_preset(struct hda_codec *codec) if ((alc_get_coef0(codec) & p->coef_mask) == p->coef_bits) return alc_codec_rename(codec, p->name); } - return 0; -} - -/* - * Automatic parse of I/O pins from the BIOS configuration - */ -enum { - ALC_CTL_WIDGET_VOL, - ALC_CTL_WIDGET_MUTE, - ALC_CTL_BIND_MUTE, - ALC_CTL_BIND_VOL, - ALC_CTL_BIND_SW, -}; -static const struct snd_kcontrol_new alc_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_BIND_MUTE(NULL, 0, 0, 0), - HDA_BIND_VOL(NULL, 0), - HDA_BIND_SW(NULL, 0), -}; - -/* add dynamic controls */ -static int add_control(struct alc_spec *spec, int type, const char *name, - int cidx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_control_templates[type]; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - knew->index = cidx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -static int add_control_with_pfx(struct alc_spec *spec, int type, - const char *pfx, const char *dir, - const char *sfx, int cidx, unsigned long val) -{ - char name[32]; - snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); - return add_control(spec, type, name, cidx, val); -} - -#define add_pb_vol_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", 0, val) -#define add_pb_sw_ctrl(spec, type, pfx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", 0, val) -#define __add_pb_vol_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Volume", cidx, val) -#define __add_pb_sw_ctrl(spec, type, pfx, cidx, val) \ - add_control_with_pfx(spec, type, pfx, "Playback", "Switch", cidx, val) - -static const char * const channel_name[4] = { - "Front", "Surround", "CLFE", "Side" -}; - -static const char *alc_get_line_out_pfx(struct alc_spec *spec, int ch, - bool can_be_master, int *index) -{ - struct auto_pin_cfg *cfg = &spec->autocfg; - - *index = 0; - if (cfg->line_outs == 1 && !spec->multi_ios && - !cfg->hp_outs && !cfg->speaker_outs && can_be_master) - return "Master"; - - switch (cfg->line_out_type) { - case AUTO_PIN_SPEAKER_OUT: - if (cfg->line_outs == 1) - return "Speaker"; - if (cfg->line_outs == 2) - return ch ? "Bass Speaker" : "Speaker"; - break; - case AUTO_PIN_HP_OUT: - /* for multi-io case, only the primary out */ - if (ch && spec->multi_ios) - break; - *index = ch; - return "Headphone"; - default: - if (cfg->line_outs == 1 && !spec->multi_ios) - return "PCM"; - break; - } - if (ch >= ARRAY_SIZE(channel_name)) { - snd_BUG(); - return "PCM"; - } - - return channel_name[ch]; -} - -#ifdef CONFIG_PM -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct alc_spec *spec, hda_nid_t mix, int idx) -{ - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) - return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} -#else -#define add_loopback_list(spec, mix, idx) /* NOP */ -#endif - -/* create input playback/capture controls for the given pin */ -static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, - const char *ctlname, int ctlidx, - int idx, hda_nid_t mix_nid) -{ - int err; - - err = __add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - err = __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, ctlidx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - add_loopback_list(spec, mix_nid, idx); - return 0; -} - -static int alc_is_input_pin(struct hda_codec *codec, hda_nid_t nid) -{ - unsigned int pincap = snd_hda_query_pin_caps(codec, nid); - return (pincap & AC_PINCAP_IN) != 0; -} - -/* Parse the codec tree and retrieve ADCs and corresponding capsrc MUXs */ -static int alc_auto_fill_adc_caps(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - hda_nid_t *adc_nids = spec->private_adc_nids; - hda_nid_t *cap_nids = spec->private_capsrc_nids; - int max_nums = ARRAY_SIZE(spec->private_adc_nids); - int i, nums = 0; - - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - hda_nid_t src; - unsigned int caps = get_wcaps(codec, nid); - int type = get_wcaps_type(caps); - - if (type != AC_WID_AUD_IN || (caps & AC_WCAP_DIGITAL)) - continue; - adc_nids[nums] = nid; - cap_nids[nums] = nid; - src = nid; - for (;;) { - int n; - type = get_wcaps_type(get_wcaps(codec, src)); - if (type == AC_WID_PIN) - break; - if (type == AC_WID_AUD_SEL) { - cap_nids[nums] = src; - break; - } - n = snd_hda_get_num_conns(codec, src); - if (n > 1) { - cap_nids[nums] = src; - break; - } else if (n != 1) - break; - if (snd_hda_get_connections(codec, src, &src, 1) != 1) - break; - } - if (++nums >= max_nums) - break; - } - spec->adc_nids = spec->private_adc_nids; - spec->capsrc_nids = spec->private_capsrc_nids; - spec->num_adc_nids = nums; - return nums; -} - -/* create playback/capture controls for input pins */ -static int alc_auto_create_input_ctls(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t mixer = spec->mixer_nid; - struct hda_input_mux *imux = &spec->private_imux[0]; - int num_adcs; - int i, c, err, idx, type_idx = 0; - const char *prev_label = NULL; - - num_adcs = alc_auto_fill_adc_caps(codec); - if (num_adcs < 0) + if (!codec->bus->pci) return 0; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin; - const char *label; - - pin = cfg->inputs[i].pin; - if (!alc_is_input_pin(codec, pin)) + for (q = rename_pci_tbl; q->codec_vendor_id; q++) { + if (q->codec_vendor_id != codec->vendor_id) continue; - - label = hda_get_autocfg_input_label(codec, cfg, i); - if (spec->shared_mic_hp && !strcmp(label, "Misc")) - label = "Headphone Mic"; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - - if (mixer) { - idx = get_connection_index(codec, mixer, pin); - if (idx >= 0) { - err = new_analog_input(spec, pin, - label, type_idx, - idx, mixer); - if (err < 0) - return err; - } - } - - for (c = 0; c < num_adcs; c++) { - hda_nid_t cap = get_capsrc(spec, c); - idx = get_connection_index(codec, cap, pin); - if (idx >= 0) { - spec->imux_pins[imux->num_items] = pin; - snd_hda_add_imux_item(imux, label, idx, NULL); - break; - } - } - } - - spec->num_mux_defs = 1; - spec->input_mux = imux; - - return 0; -} - -/* create a shared input with the headphone out */ -static int alc_auto_create_shared_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int defcfg; - hda_nid_t nid; - - /* only one internal input pin? */ - if (cfg->num_inputs != 1) - return 0; - defcfg = snd_hda_codec_get_pincfg(codec, cfg->inputs[0].pin); - if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) - return 0; - - if (cfg->hp_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) - nid = cfg->hp_pins[0]; /* OK, we have a single HP-out */ - else if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_HP_OUT) - nid = cfg->line_out_pins[0]; /* OK, we have a single line-out */ - else - return 0; /* both not available */ - - if (!(snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_IN)) - return 0; /* no input */ - - cfg->inputs[1].pin = nid; - cfg->inputs[1].type = AUTO_PIN_MIC; - cfg->num_inputs = 2; - spec->shared_mic_hp = 1; - snd_printdd("realtek: Enable shared I/O jack on NID 0x%x\n", nid); - return 0; -} - -static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, - unsigned int pin_type) -{ - snd_hda_set_pin_ctl(codec, nid, pin_type); - /* unmute pin */ - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_UNMUTE); -} - -static int get_pin_type(int line_out_type) -{ - if (line_out_type == AUTO_PIN_HP_OUT) - return PIN_HP; - else - return PIN_OUT; -} - -static void alc_auto_init_analog_input(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (alc_is_input_pin(codec, nid)) { - alc_set_input_pin(codec, nid, cfg->inputs[i].type); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); - } - } - - /* mute all loopback inputs */ - if (spec->mixer_nid) { - int nums = snd_hda_get_num_conns(codec, spec->mixer_nid); - for (i = 0; i < nums; i++) - snd_hda_codec_write(codec, spec->mixer_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } -} - -/* convert from MIX nid to DAC */ -static hda_nid_t alc_auto_mix_to_dac(struct hda_codec *codec, hda_nid_t nid) -{ - hda_nid_t list[5]; - int i, num; - - if (get_wcaps_type(get_wcaps(codec, nid)) == AC_WID_AUD_OUT) - return nid; - num = snd_hda_get_connections(codec, nid, list, ARRAY_SIZE(list)); - for (i = 0; i < num; i++) { - if (get_wcaps_type(get_wcaps(codec, list[i])) == AC_WID_AUD_OUT) - return list[i]; - } - return 0; -} - -/* go down to the selector widget before the mixer */ -static hda_nid_t alc_go_down_to_selector(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t srcs[5]; - int num = snd_hda_get_connections(codec, pin, srcs, - ARRAY_SIZE(srcs)); - if (num != 1 || - get_wcaps_type(get_wcaps(codec, srcs[0])) != AC_WID_AUD_SEL) - return pin; - return srcs[0]; -} - -/* get MIX nid connected to the given pin targeted to DAC */ -static hda_nid_t alc_auto_dac_to_mix(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) - return mix[i]; - } - return 0; -} - -/* select the connection from pin to DAC if needed */ -static int alc_auto_select_dac(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - hda_nid_t mix[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, mix, ARRAY_SIZE(mix)); - if (num < 2) - return 0; - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, mix[i]) == dac) { - snd_hda_codec_update_cache(codec, pin, 0, - AC_VERB_SET_CONNECT_SEL, i); - return 0; - } - } - return 0; -} - -static bool alc_is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) -{ - struct alc_spec *spec = codec->spec; - int i; - if (found_in_nid_list(nid, spec->multiout.dac_nids, - ARRAY_SIZE(spec->private_dac_nids)) || - found_in_nid_list(nid, spec->multiout.hp_out_nid, - ARRAY_SIZE(spec->multiout.hp_out_nid)) || - found_in_nid_list(nid, spec->multiout.extra_out_nid, - ARRAY_SIZE(spec->multiout.extra_out_nid))) - return true; - for (i = 0; i < spec->multi_ios; i++) { - if (spec->multi_io[i].dac == nid) - return true; - } - return false; -} - -/* look for an empty DAC slot */ -static hda_nid_t alc_auto_look_for_dac(struct hda_codec *codec, hda_nid_t pin) -{ - hda_nid_t srcs[5]; - int i, num; - - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (!nid) - continue; - if (!alc_is_dac_already_used(codec, nid)) - return nid; - } - return 0; -} - -/* check whether the DAC is reachable from the pin */ -static bool alc_auto_is_dac_reachable(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t srcs[5]; - int i, num; - - if (!pin || !dac) - return false; - pin = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, pin, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - hda_nid_t nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (nid == dac) - return true; - } - return false; -} - -static hda_nid_t get_dac_if_single(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sel = alc_go_down_to_selector(codec, pin); - hda_nid_t nid, nid_found, srcs[5]; - int i, num = snd_hda_get_connections(codec, sel, srcs, - ARRAY_SIZE(srcs)); - if (num == 1) - return alc_auto_look_for_dac(codec, pin); - nid_found = 0; - for (i = 0; i < num; i++) { - if (srcs[i] == spec->mixer_nid) - continue; - nid = alc_auto_mix_to_dac(codec, srcs[i]); - if (nid && !alc_is_dac_already_used(codec, nid)) { - if (nid_found) - return 0; - nid_found = nid; - } - } - return nid_found; -} - -/* mark up volume and mute control NIDs: used during badness parsing and - * at creating actual controls - */ -static inline unsigned int get_ctl_pos(unsigned int data) -{ - hda_nid_t nid = get_amp_nid_(data); - unsigned int dir; - if (snd_BUG_ON(nid >= MAX_VOL_NIDS)) - return 0; - dir = get_amp_direction_(data); - return (nid << 1) | dir; -} - -#define is_ctl_used(bits, data) \ - test_bit(get_ctl_pos(data), bits) -#define mark_ctl_usage(bits, data) \ - set_bit(get_ctl_pos(data), bits) - -static void clear_vol_marks(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - memset(spec->vol_ctls, 0, sizeof(spec->vol_ctls)); - memset(spec->sw_ctls, 0, sizeof(spec->sw_ctls)); -} - -/* badness definition */ -enum { - /* No primary DAC is found for the main output */ - BAD_NO_PRIMARY_DAC = 0x10000, - /* No DAC is found for the extra output */ - BAD_NO_DAC = 0x4000, - /* No possible multi-ios */ - BAD_MULTI_IO = 0x103, - /* No individual DAC for extra output */ - BAD_NO_EXTRA_DAC = 0x102, - /* No individual DAC for extra surrounds */ - BAD_NO_EXTRA_SURR_DAC = 0x101, - /* Primary DAC shared with main surrounds */ - BAD_SHARED_SURROUND = 0x100, - /* Primary DAC shared with main CLFE */ - BAD_SHARED_CLFE = 0x10, - /* Primary DAC shared with extra surrounds */ - BAD_SHARED_EXTRA_SURROUND = 0x10, - /* Volume widget is shared */ - BAD_SHARED_VOL = 0x10, -}; - -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac); - -static int eval_shared_vol_badness(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - unsigned int val; - int badness = 0; - - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) { - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, nid)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->vol_ctls, val); - } else - badness += BAD_SHARED_VOL; - nid = alc_look_for_out_mute_nid(codec, pin, dac); - if (nid) { - unsigned int wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - else - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT); - if (is_ctl_used(spec->sw_ctls, val)) - badness += BAD_SHARED_VOL; - else - mark_ctl_usage(spec->sw_ctls, val); - } else - badness += BAD_SHARED_VOL; - return badness; -} - -struct badness_table { - int no_primary_dac; /* no primary DAC */ - int no_dac; /* no secondary DACs */ - int shared_primary; /* primary DAC is shared with main output */ - int shared_surr; /* secondary DAC shared with main or primary */ - int shared_clfe; /* third DAC shared with main or primary */ - int shared_surr_main; /* secondary DAC sahred with main/DAC0 */ -}; - -static struct badness_table main_out_badness = { - .no_primary_dac = BAD_NO_PRIMARY_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_PRIMARY_DAC, - .shared_surr = BAD_SHARED_SURROUND, - .shared_clfe = BAD_SHARED_CLFE, - .shared_surr_main = BAD_SHARED_SURROUND, -}; - -static struct badness_table extra_out_badness = { - .no_primary_dac = BAD_NO_DAC, - .no_dac = BAD_NO_DAC, - .shared_primary = BAD_NO_EXTRA_DAC, - .shared_surr = BAD_SHARED_EXTRA_SURROUND, - .shared_clfe = BAD_SHARED_EXTRA_SURROUND, - .shared_surr_main = BAD_NO_EXTRA_SURR_DAC, -}; - -/* try to assign DACs to pins and return the resultant badness */ -static int alc_auto_fill_dacs(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, hda_nid_t *dacs, - const struct badness_table *bad) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, j; - int badness = 0; - hda_nid_t dac; - - if (!num_outs) - return 0; - - for (i = 0; i < num_outs; i++) { - hda_nid_t pin = pins[i]; - if (!dacs[i]) - dacs[i] = alc_auto_look_for_dac(codec, pin); - if (!dacs[i] && !i) { - for (j = 1; j < num_outs; j++) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[j])) { - dacs[0] = dacs[j]; - dacs[j] = 0; - break; - } - } - } - dac = dacs[i]; - if (!dac) { - if (alc_auto_is_dac_reachable(codec, pin, dacs[0])) - dac = dacs[0]; - else if (cfg->line_outs > i && - alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[i])) - dac = spec->private_dac_nids[i]; - if (dac) { - if (!i) - badness += bad->shared_primary; - else if (i == 1) - badness += bad->shared_surr; - else - badness += bad->shared_clfe; - } else if (alc_auto_is_dac_reachable(codec, pin, - spec->private_dac_nids[0])) { - dac = spec->private_dac_nids[0]; - badness += bad->shared_surr_main; - } else if (!i) - badness += bad->no_primary_dac; - else - badness += bad->no_dac; - } - if (dac) - badness += eval_shared_vol_badness(codec, pin, dac); - } - - return badness; -} - -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset); - -static bool alc_map_singles(struct hda_codec *codec, int outs, - const hda_nid_t *pins, hda_nid_t *dacs) -{ - int i; - bool found = false; - for (i = 0; i < outs; i++) { - if (dacs[i]) - continue; - dacs[i] = get_dac_if_single(codec, pins[i]); - if (dacs[i]) - found = true; - } - return found; -} - -/* fill in the dac_nids table from the parsed pin configuration */ -static int fill_and_eval_dacs(struct hda_codec *codec, - bool fill_hardwired, - bool fill_mio_first) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err, badness; - - /* set num_dacs once to full for alc_auto_look_for_dac() */ - spec->multiout.num_dacs = cfg->line_outs; - spec->multiout.dac_nids = spec->private_dac_nids; - memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); - memset(spec->multiout.hp_out_nid, 0, sizeof(spec->multiout.hp_out_nid)); - memset(spec->multiout.extra_out_nid, 0, sizeof(spec->multiout.extra_out_nid)); - spec->multi_ios = 0; - clear_vol_marks(codec); - badness = 0; - - /* fill hard-wired DACs first */ - if (fill_hardwired) { - bool mapped; - do { - mapped = alc_map_singles(codec, cfg->line_outs, - cfg->line_out_pins, - spec->private_dac_nids); - mapped |= alc_map_singles(codec, cfg->hp_outs, - cfg->hp_pins, - spec->multiout.hp_out_nid); - mapped |= alc_map_singles(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid); - if (fill_mio_first && cfg->line_outs == 1 && - cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], true, 0); - if (!err) - mapped = true; - } - } while (mapped); - } - - badness += alc_auto_fill_dacs(codec, cfg->line_outs, cfg->line_out_pins, - spec->private_dac_nids, - &main_out_badness); - - /* re-count num_dacs and squash invalid entries */ - spec->multiout.num_dacs = 0; - for (i = 0; i < cfg->line_outs; i++) { - if (spec->private_dac_nids[i]) - spec->multiout.num_dacs++; - else { - memmove(spec->private_dac_nids + i, - spec->private_dac_nids + i + 1, - sizeof(hda_nid_t) * (cfg->line_outs - i - 1)); - spec->private_dac_nids[cfg->line_outs - 1] = 0; - } - } - - if (fill_mio_first && - cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - /* try to fill multi-io first */ - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - /* we don't count badness at this stage yet */ - } - - if (cfg->line_out_type != AUTO_PIN_HP_OUT) { - err = alc_auto_fill_dacs(codec, cfg->hp_outs, cfg->hp_pins, - spec->multiout.hp_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } - if (cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_dacs(codec, cfg->speaker_outs, - cfg->speaker_pins, - spec->multiout.extra_out_nid, - &extra_out_badness); - if (err < 0) - return err; - badness += err; - } - if (cfg->line_outs == 1 && cfg->line_out_type != AUTO_PIN_SPEAKER_OUT) { - err = alc_auto_fill_multi_ios(codec, cfg->line_out_pins[0], false, 0); - if (err < 0) - return err; - badness += err; - } - if (cfg->hp_outs && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - /* try multi-ios with HP + inputs */ - int offset = 0; - if (cfg->line_outs >= 3) - offset = 1; - err = alc_auto_fill_multi_ios(codec, cfg->hp_pins[0], false, - offset); - if (err < 0) - return err; - badness += err; - } - - if (spec->multi_ios == 2) { - for (i = 0; i < 2; i++) - spec->private_dac_nids[spec->multiout.num_dacs++] = - spec->multi_io[i].dac; - spec->ext_channel_count = 2; - } else if (spec->multi_ios) { - spec->multi_ios = 0; - badness += BAD_MULTI_IO; - } - - return badness; -} - -#define DEBUG_BADNESS - -#ifdef DEBUG_BADNESS -#define debug_badness snd_printdd -#else -#define debug_badness(...) -#endif - -static void debug_show_configs(struct alc_spec *spec, struct auto_pin_cfg *cfg) -{ - debug_badness("multi_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[2], - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3]); - if (spec->multi_ios > 0) - debug_badness("multi_ios(%d) = %x/%x : %x/%x\n", - spec->multi_ios, - spec->multi_io[0].pin, spec->multi_io[1].pin, - spec->multi_io[0].dac, spec->multi_io[1].dac); - debug_badness("hp_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->hp_pins[0], cfg->hp_pins[1], - cfg->hp_pins[2], cfg->hp_pins[2], - spec->multiout.hp_out_nid[0], - spec->multiout.hp_out_nid[1], - spec->multiout.hp_out_nid[2], - spec->multiout.hp_out_nid[3]); - debug_badness("spk_outs = %x/%x/%x/%x : %x/%x/%x/%x\n", - cfg->speaker_pins[0], cfg->speaker_pins[1], - cfg->speaker_pins[2], cfg->speaker_pins[3], - spec->multiout.extra_out_nid[0], - spec->multiout.extra_out_nid[1], - spec->multiout.extra_out_nid[2], - spec->multiout.extra_out_nid[3]); -} - -static int alc_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg *best_cfg; - int best_badness = INT_MAX; - int badness; - bool fill_hardwired = true, fill_mio_first = true; - bool best_wired = true, best_mio = true; - bool hp_spk_swapped = false; - - best_cfg = kmalloc(sizeof(*best_cfg), GFP_KERNEL); - if (!best_cfg) - return -ENOMEM; - *best_cfg = *cfg; - - for (;;) { - badness = fill_and_eval_dacs(codec, fill_hardwired, - fill_mio_first); - if (badness < 0) { - kfree(best_cfg); - return badness; - } - debug_badness("==> lo_type=%d, wired=%d, mio=%d, badness=0x%x\n", - cfg->line_out_type, fill_hardwired, fill_mio_first, - badness); - debug_show_configs(spec, cfg); - if (badness < best_badness) { - best_badness = badness; - *best_cfg = *cfg; - best_wired = fill_hardwired; - best_mio = fill_mio_first; - } - if (!badness) - break; - fill_mio_first = !fill_mio_first; - if (!fill_mio_first) - continue; - fill_hardwired = !fill_hardwired; - if (!fill_hardwired) - continue; - if (hp_spk_swapped) - break; - hp_spk_swapped = true; - if (cfg->speaker_outs > 0 && - cfg->line_out_type == AUTO_PIN_HP_OUT) { - cfg->hp_outs = cfg->line_outs; - memcpy(cfg->hp_pins, cfg->line_out_pins, - sizeof(cfg->hp_pins)); - cfg->line_outs = cfg->speaker_outs; - memcpy(cfg->line_out_pins, cfg->speaker_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = 0; - memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - fill_hardwired = true; - continue; - } - if (cfg->hp_outs > 0 && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) { - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - fill_hardwired = true; + if (q->pci_subvendor != codec->bus->pci->subsystem_vendor) continue; - } - break; + if (!q->pci_subdevice || + q->pci_subdevice == codec->bus->pci->subsystem_device) + return alc_codec_rename(codec, q->name); } - if (badness) { - *cfg = *best_cfg; - fill_and_eval_dacs(codec, best_wired, best_mio); - } - debug_badness("==> Best config: lo_type=%d, wired=%d, mio=%d\n", - cfg->line_out_type, best_wired, best_mio); - debug_show_configs(spec, cfg); - - if (cfg->line_out_pins[0]) - spec->vmaster_nid = - alc_look_for_out_vol_nid(codec, cfg->line_out_pins[0], - spec->multiout.dac_nids[0]); - - /* clear the bitmap flags for creating controls */ - clear_vol_marks(codec); - kfree(best_cfg); return 0; } -static int alc_auto_add_vol_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - struct alc_spec *spec = codec->spec; - unsigned int val; - if (!nid) - return 0; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - if (is_ctl_used(spec->vol_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->vol_ctls, val); - return __add_pb_vol_ctrl(codec->spec, ALC_CTL_WIDGET_VOL, pfx, cidx, - val); -} - -static int alc_auto_add_stereo_vol(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid) -{ - int chs = 1; - if (get_wcaps(codec, nid) & AC_WCAP_STEREO) - chs = 3; - return alc_auto_add_vol_ctl(codec, pfx, cidx, nid, chs); -} - -/* create a mute-switch for the given mixer widget; - * if it has multiple sources (e.g. DAC and loopback), create a bind-mute - */ -static int alc_auto_add_sw_ctl(struct hda_codec *codec, - const char *pfx, int cidx, - hda_nid_t nid, unsigned int chs) -{ - struct alc_spec *spec = codec->spec; - int wid_type; - int type; - unsigned long val; - if (!nid) - return 0; - wid_type = get_wcaps_type(get_wcaps(codec, nid)); - if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - } else if (snd_hda_get_num_conns(codec, nid) == 1) { - type = ALC_CTL_WIDGET_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT); - } else { - type = ALC_CTL_BIND_MUTE; - val = HDA_COMPOSE_AMP_VAL(nid, chs, 2, HDA_INPUT); - } - if (is_ctl_used(spec->sw_ctls, val) && chs != 2) /* exclude LFE */ - return 0; - mark_ctl_usage(spec->sw_ctls, val); - return __add_pb_sw_ctrl(codec->spec, type, pfx, cidx, val); -} - -static int alc_auto_add_stereo_sw(struct hda_codec *codec, const char *pfx, - int cidx, hda_nid_t nid) -{ - int chs = 1; - if (get_wcaps(codec, nid) & AC_WCAP_STEREO) - chs = 3; - return alc_auto_add_sw_ctl(codec, pfx, cidx, nid, chs); -} - -static hda_nid_t alc_look_for_out_mute_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_mute(codec, pin, HDA_OUTPUT)) - return pin; - else if (mix && nid_has_mute(codec, mix, HDA_INPUT)) - return mix; - else if (nid_has_mute(codec, dac, HDA_OUTPUT)) - return dac; - return 0; -} - -static hda_nid_t alc_look_for_out_vol_nid(struct hda_codec *codec, - hda_nid_t pin, hda_nid_t dac) -{ - hda_nid_t mix = alc_auto_dac_to_mix(codec, pin, dac); - if (nid_has_volume(codec, dac, HDA_OUTPUT)) - return dac; - else if (nid_has_volume(codec, mix, HDA_OUTPUT)) - return mix; - else if (nid_has_volume(codec, pin, HDA_OUTPUT)) - return pin; - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int alc_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct alc_spec *spec = codec->spec; - int i, err, noutputs; - - noutputs = cfg->line_outs; - if (spec->multi_ios > 0 && cfg->line_outs < 3) - noutputs += spec->multi_ios; - - for (i = 0; i < noutputs; i++) { - const char *name; - int index; - hda_nid_t dac, pin; - hda_nid_t sw, vol; - - dac = spec->multiout.dac_nids[i]; - if (!dac) - continue; - if (i >= cfg->line_outs) { - pin = spec->multi_io[i - 1].pin; - index = 0; - name = channel_name[i]; - } else { - pin = cfg->line_out_pins[i]; - name = alc_get_line_out_pfx(spec, i, true, &index); - } - - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - if (!name || !strcmp(name, "CLFE")) { - /* Center/LFE */ - err = alc_auto_add_vol_ctl(codec, "Center", 0, vol, 1); - if (err < 0) - return err; - err = alc_auto_add_vol_ctl(codec, "LFE", 0, vol, 2); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "Center", 0, sw, 1); - if (err < 0) - return err; - err = alc_auto_add_sw_ctl(codec, "LFE", 0, sw, 2); - if (err < 0) - return err; - } else { - err = alc_auto_add_stereo_vol(codec, name, index, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, name, index, sw); - if (err < 0) - return err; - } - } - return 0; -} - -static int alc_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, - hda_nid_t dac, const char *pfx, - int cidx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t sw, vol; - int err; - - if (!dac) { - unsigned int val; - /* the corresponding DAC is already occupied */ - if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) - return 0; /* no way */ - /* create a switch only */ - val = HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT); - if (is_ctl_used(spec->sw_ctls, val)) - return 0; /* already created */ - mark_ctl_usage(spec->sw_ctls, val); - return __add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, cidx, val); - } - - sw = alc_look_for_out_mute_nid(codec, pin, dac); - vol = alc_look_for_out_vol_nid(codec, pin, dac); - err = alc_auto_add_stereo_vol(codec, pfx, cidx, vol); - if (err < 0) - return err; - err = alc_auto_add_stereo_sw(codec, pfx, cidx, sw); - if (err < 0) - return err; - return 0; -} - -static struct hda_bind_ctls *new_bind_ctl(struct hda_codec *codec, - unsigned int nums, - struct hda_ctl_ops *ops) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls **ctlp, *ctl; - snd_array_init(&spec->bind_ctls, sizeof(ctl), 8); - ctlp = snd_array_new(&spec->bind_ctls); - if (!ctlp) - return NULL; - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * (nums + 1), GFP_KERNEL); - *ctlp = ctl; - if (ctl) - ctl->ops = ops; - return ctl; -} - -/* add playback controls for speaker and HP outputs */ -static int alc_auto_create_extra_outs(struct hda_codec *codec, int num_pins, - const hda_nid_t *pins, - const hda_nid_t *dacs, - const char *pfx) -{ - struct alc_spec *spec = codec->spec; - struct hda_bind_ctls *ctl; - char name[32]; - int i, n, err; - - if (!num_pins || !pins[0]) - return 0; - - if (num_pins == 1) { - hda_nid_t dac = *dacs; - if (!dac) - dac = spec->multiout.dac_nids[0]; - return alc_auto_create_extra_out(codec, *pins, dac, pfx, 0); - } - - for (i = 0; i < num_pins; i++) { - hda_nid_t dac; - if (dacs[num_pins - 1]) - dac = dacs[i]; /* with individual volumes */ - else - dac = 0; - if (num_pins == 2 && i == 1 && !strcmp(pfx, "Speaker")) { - err = alc_auto_create_extra_out(codec, pins[i], dac, - "Bass Speaker", 0); - } else if (num_pins >= 3) { - snprintf(name, sizeof(name), "%s %s", - pfx, channel_name[i]); - err = alc_auto_create_extra_out(codec, pins[i], dac, - name, 0); - } else { - err = alc_auto_create_extra_out(codec, pins[i], dac, - pfx, i); - } - if (err < 0) - return err; - } - if (dacs[num_pins - 1]) - return 0; - - /* Let's create a bind-controls for volumes */ - ctl = new_bind_ctl(codec, num_pins, &snd_hda_bind_vol); - if (!ctl) - return -ENOMEM; - n = 0; - for (i = 0; i < num_pins; i++) { - hda_nid_t vol; - if (!pins[i] || !dacs[i]) - continue; - vol = alc_look_for_out_vol_nid(codec, pins[i], dacs[i]); - if (vol) - ctl->values[n++] = - HDA_COMPOSE_AMP_VAL(vol, 3, 0, HDA_OUTPUT); - } - if (n) { - snprintf(name, sizeof(name), "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_BIND_VOL, name, 0, (long)ctl); - if (err < 0) - return err; - } - return 0; -} - -static int alc_auto_create_hp_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.hp_outs, - spec->autocfg.hp_pins, - spec->multiout.hp_out_nid, - "Headphone"); -} - -static int alc_auto_create_speaker_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - return alc_auto_create_extra_outs(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - spec->multiout.extra_out_nid, - "Speaker"); -} - -static void alc_auto_set_output_and_unmute(struct hda_codec *codec, - hda_nid_t pin, int pin_type, - hda_nid_t dac) -{ - int i, num; - hda_nid_t nid, mix = 0; - hda_nid_t srcs[HDA_MAX_CONNECTIONS]; - - alc_set_pin_output(codec, pin, pin_type); - nid = alc_go_down_to_selector(codec, pin); - num = snd_hda_get_connections(codec, nid, srcs, ARRAY_SIZE(srcs)); - for (i = 0; i < num; i++) { - if (alc_auto_mix_to_dac(codec, srcs[i]) != dac) - continue; - mix = srcs[i]; - break; - } - if (!mix) - return; - - /* need the manual connection? */ - if (num > 1) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, i); - /* unmute mixer widget inputs */ - if (nid_has_mute(codec, mix, HDA_INPUT)) { - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - snd_hda_codec_write(codec, mix, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(1)); - } - /* initialize volume */ - nid = alc_look_for_out_vol_nid(codec, pin, dac); - if (nid) - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); - - /* unmute DAC if it's not assigned to a mixer */ - nid = alc_look_for_out_mute_nid(codec, pin, dac); - if (nid == mix && nid_has_mute(codec, dac, HDA_OUTPUT)) - snd_hda_codec_write(codec, dac, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_ZERO); -} - -static void alc_auto_init_multi_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int pin_type = get_pin_type(spec->autocfg.line_out_type); - int i; - - for (i = 0; i <= HDA_SIDE; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - if (nid) - alc_auto_set_output_and_unmute(codec, nid, pin_type, - spec->multiout.dac_nids[i]); - } -} - -static void alc_auto_init_extra_out(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - hda_nid_t pin, dac; - - for (i = 0; i < spec->autocfg.hp_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_HP_OUT) - break; - pin = spec->autocfg.hp_pins[i]; - if (!pin) - break; - dac = spec->multiout.hp_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.hp_out_nid[0]) - dac = spec->multiout.hp_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_HP, dac); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) - break; - pin = spec->autocfg.speaker_pins[i]; - if (!pin) - break; - dac = spec->multiout.extra_out_nid[i]; - if (!dac) { - if (i > 0 && spec->multiout.extra_out_nid[0]) - dac = spec->multiout.extra_out_nid[0]; - else - dac = spec->multiout.dac_nids[0]; - } - alc_auto_set_output_and_unmute(codec, pin, PIN_OUT, dac); - } -} - -/* check whether the given pin can be a multi-io pin */ -static bool can_be_multiio_pin(struct hda_codec *codec, - unsigned int location, hda_nid_t nid) -{ - unsigned int defcfg, caps; - - defcfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(defcfg) != AC_JACK_PORT_COMPLEX) - return false; - if (location && get_defcfg_location(defcfg) != location) - return false; - caps = snd_hda_query_pin_caps(codec, nid); - if (!(caps & AC_PINCAP_OUT)) - return false; - return true; -} - -/* - * multi-io helper - * - * When hardwired is set, try to fill ony hardwired pins, and returns - * zero if any pins are filled, non-zero if nothing found. - * When hardwired is off, try to fill possible input pins, and returns - * the badness value. - */ -static int alc_auto_fill_multi_ios(struct hda_codec *codec, - hda_nid_t reference_pin, - bool hardwired, int offset) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int type, i, j, dacs, num_pins, old_pins; - unsigned int defcfg = snd_hda_codec_get_pincfg(codec, reference_pin); - unsigned int location = get_defcfg_location(defcfg); - int badness = 0; - - old_pins = spec->multi_ios; - if (old_pins >= 2) - goto end_fill; - - num_pins = 0; - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type != type) - continue; - if (can_be_multiio_pin(codec, location, - cfg->inputs[i].pin)) - num_pins++; - } - } - if (num_pins < 2) - goto end_fill; - - dacs = spec->multiout.num_dacs; - for (type = AUTO_PIN_LINE_IN; type >= AUTO_PIN_MIC; type--) { - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - hda_nid_t dac = 0; - - if (cfg->inputs[i].type != type) - continue; - if (!can_be_multiio_pin(codec, location, nid)) - continue; - for (j = 0; j < spec->multi_ios; j++) { - if (nid == spec->multi_io[j].pin) - break; - } - if (j < spec->multi_ios) - continue; - - if (offset && offset + spec->multi_ios < dacs) { - dac = spec->private_dac_nids[offset + spec->multi_ios]; - if (!alc_auto_is_dac_reachable(codec, nid, dac)) - dac = 0; - } - if (hardwired) - dac = get_dac_if_single(codec, nid); - else if (!dac) - dac = alc_auto_look_for_dac(codec, nid); - if (!dac) { - badness++; - continue; - } - spec->multi_io[spec->multi_ios].pin = nid; - spec->multi_io[spec->multi_ios].dac = dac; - spec->multi_ios++; - if (spec->multi_ios >= 2) - break; - } - } - end_fill: - if (badness) - badness = BAD_MULTI_IO; - if (old_pins == spec->multi_ios) { - if (hardwired) - return 1; /* nothing found */ - else - return badness; /* no badness if nothing found */ - } - if (!hardwired && spec->multi_ios < 2) { - spec->multi_ios = old_pins; - return badness; - } - - return 0; -} - -static int alc_auto_ch_mode_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->multi_ios + 1; - if (uinfo->value.enumerated.item > spec->multi_ios) - uinfo->value.enumerated.item = spec->multi_ios; - sprintf(uinfo->value.enumerated.name, "%dch", - (uinfo->value.enumerated.item + 1) * 2); - return 0; -} - -static int alc_auto_ch_mode_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = (spec->ext_channel_count - 1) / 2; - return 0; -} - -static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid = spec->multi_io[idx].pin; - - if (!spec->multi_io[idx].ctl_in) - spec->multi_io[idx].ctl_in = - snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (output) { - snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT); - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, 0); - alc_auto_select_dac(codec, nid, spec->multi_io[idx].dac); - } else { - if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_set_pin_ctl_cache(codec, nid, - spec->multi_io[idx].ctl_in); - } - return 0; -} - -static int alc_auto_ch_mode_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct alc_spec *spec = codec->spec; - int i, ch; - - ch = ucontrol->value.enumerated.item[0]; - if (ch < 0 || ch > spec->multi_ios) - return -EINVAL; - if (ch == (spec->ext_channel_count - 1) / 2) - return 0; - spec->ext_channel_count = (ch + 1) * 2; - for (i = 0; i < spec->multi_ios; i++) - alc_set_multi_io(codec, i, i < ch); - spec->multiout.max_channels = spec->ext_channel_count; - if (spec->need_dac_fix && !spec->const_channel_count) - spec->multiout.num_dacs = spec->multiout.max_channels / 2; - return 1; -} - -static const struct snd_kcontrol_new alc_auto_channel_mode_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Channel Mode", - .info = alc_auto_ch_mode_info, - .get = alc_auto_ch_mode_get, - .put = alc_auto_ch_mode_put, -}; - -static int alc_auto_add_multi_channel_mode(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - - if (spec->multi_ios > 0) { - struct snd_kcontrol_new *knew; - - knew = alc_kcontrol_new(spec); - if (!knew) - return -ENOMEM; - *knew = alc_auto_channel_mode_enum; - knew->name = kstrdup("Channel Mode", GFP_KERNEL); - if (!knew->name) - return -ENOMEM; - } - return 0; -} - -/* filter out invalid adc_nids (and capsrc_nids) that don't give all - * active input pins - */ -static void alc_remove_invalid_adc_nids(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - const struct hda_input_mux *imux; - hda_nid_t adc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - hda_nid_t capsrc_nids[ARRAY_SIZE(spec->private_adc_nids)]; - int i, n, nums; - - imux = spec->input_mux; - if (!imux) - return; - if (spec->dyn_adc_switch) - return; - - again: - nums = 0; - for (n = 0; n < spec->num_adc_nids; n++) { - hda_nid_t cap = spec->private_capsrc_nids[n]; - int num_conns = snd_hda_get_num_conns(codec, cap); - for (i = 0; i < imux->num_items; i++) { - hda_nid_t pin = spec->imux_pins[i]; - if (pin) { - if (get_connection_index(codec, cap, pin) < 0) - break; - } else if (num_conns <= imux->items[i].index) - break; - } - if (i >= imux->num_items) { - adc_nids[nums] = spec->private_adc_nids[n]; - capsrc_nids[nums++] = cap; - } - } - if (!nums) { - /* check whether ADC-switch is possible */ - if (!alc_check_dyn_adc_switch(codec)) { - if (spec->shared_mic_hp) { - spec->shared_mic_hp = 0; - spec->private_imux[0].num_items = 1; - goto again; - } - printk(KERN_WARNING "hda_codec: %s: no valid ADC found;" - " using fallback 0x%x\n", - codec->chip_name, spec->private_adc_nids[0]); - spec->num_adc_nids = 1; - spec->auto_mic = 0; - return; - } - } else if (nums != spec->num_adc_nids) { - memcpy(spec->private_adc_nids, adc_nids, - nums * sizeof(hda_nid_t)); - memcpy(spec->private_capsrc_nids, capsrc_nids, - nums * sizeof(hda_nid_t)); - spec->num_adc_nids = nums; - } - - if (spec->auto_mic) - alc_auto_mic_check_imux(codec); /* check auto-mic setups */ - else if (spec->input_mux->num_items == 1 || spec->shared_mic_hp) - spec->num_adc_nids = 1; /* reduce to a single ADC */ -} - -/* - * initialize ADC paths - */ -static void alc_auto_init_adc(struct hda_codec *codec, int adc_idx) -{ - struct alc_spec *spec = codec->spec; - hda_nid_t nid; - - nid = spec->adc_nids[adc_idx]; - /* mute ADC */ - if (nid_has_mute(codec, nid, HDA_INPUT)) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(0)); - return; - } - if (!spec->capsrc_nids) - return; - nid = spec->capsrc_nids[adc_idx]; - if (nid_has_mute(codec, nid, HDA_OUTPUT)) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE); -} - -static void alc_auto_init_input_src(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int c, nums; - - for (c = 0; c < spec->num_adc_nids; c++) - alc_auto_init_adc(codec, c); - if (spec->dyn_adc_switch) - nums = 1; - else - nums = spec->num_adc_nids; - for (c = 0; c < nums; c++) - alc_mux_select(codec, c, spec->cur_mux[c], true); -} - -/* add mic boosts if needed */ -static int alc_auto_add_mic_boost(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - int type_idx = 0; - hda_nid_t nid; - const char *prev_label = NULL; - - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type > AUTO_PIN_MIC) - break; - nid = cfg->inputs[i].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - const char *label; - char boost_label[32]; - - label = hda_get_autocfg_input_label(codec, cfg, i); - if (spec->shared_mic_hp && !strcmp(label, "Misc")) - label = "Headphone Mic"; - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - - snprintf(boost_label, sizeof(boost_label), - "%s Boost Volume", label); - err = add_control(spec, ALC_CTL_WIDGET_VOL, - boost_label, type_idx, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - } - return 0; -} - -/* select or unmute the given capsrc route */ -static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, - int idx) -{ - if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { - snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, - HDA_AMP_MUTE, 0); - } else if (snd_hda_get_num_conns(codec, cap) > 1) { - snd_hda_codec_write_cache(codec, cap, 0, - AC_VERB_SET_CONNECT_SEL, idx); - } -} - -/* set the default connection to that pin */ -static int init_capsrc_for_pin(struct hda_codec *codec, hda_nid_t pin) -{ - struct alc_spec *spec = codec->spec; - int i; - - if (!pin) - return 0; - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t cap = get_capsrc(spec, i); - int idx; - - idx = get_connection_index(codec, cap, pin); - if (idx < 0) - continue; - select_or_unmute_capsrc(codec, cap, idx); - return i; /* return the found index */ - } - return -1; /* not found */ -} - -/* initialize some special cases for input sources */ -static void alc_init_special_input_src(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.num_inputs; i++) - init_capsrc_for_pin(codec, spec->autocfg.inputs[i].pin); -} - -/* assign appropriate capture mixers */ -static void set_capture_mixer(struct hda_codec *codec) -{ - struct alc_spec *spec = codec->spec; - static const struct snd_kcontrol_new *caps[2][3] = { - { alc_capture_mixer_nosrc1, - alc_capture_mixer_nosrc2, - alc_capture_mixer_nosrc3 }, - { alc_capture_mixer1, - alc_capture_mixer2, - alc_capture_mixer3 }, - }; - - /* check whether either of ADC or MUX has a volume control */ - if (!nid_has_volume(codec, spec->adc_nids[0], HDA_INPUT)) { - if (!spec->capsrc_nids) - return; /* no volume */ - if (!nid_has_volume(codec, spec->capsrc_nids[0], HDA_OUTPUT)) - return; /* no volume in capsrc, too */ - spec->vol_in_capsrc = 1; - } - - if (spec->num_adc_nids > 0) { - int mux = 0; - int num_adcs = 0; - - if (spec->input_mux && spec->input_mux->num_items > 1) - mux = 1; - if (spec->auto_mic) { - num_adcs = 1; - mux = 0; - } else if (spec->dyn_adc_switch) - num_adcs = 1; - if (!num_adcs) { - if (spec->num_adc_nids > 3) - spec->num_adc_nids = 3; - else if (!spec->num_adc_nids) - return; - num_adcs = spec->num_adc_nids; - } - spec->cap_mixer = caps[mux][num_adcs - 1]; - } -} - -/* - * standard auto-parser initializations - */ -static void alc_auto_init_std(struct hda_codec *codec) -{ - alc_auto_init_multi_out(codec); - alc_auto_init_extra_out(codec); - alc_auto_init_analog_input(codec); - alc_auto_init_input_src(codec); - alc_auto_init_digital(codec); - alc_inithook(codec); -} /* * Digital-beep handlers @@ -4250,7 +1011,9 @@ static void alc_auto_init_std(struct hda_codec *codec) static const struct snd_pci_quirk beep_white_list[] = { SND_PCI_QUIRK(0x1043, 0x103c, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x115d, "ASUS", 1), SND_PCI_QUIRK(0x1043, 0x829f, "ASUS", 1), + SND_PCI_QUIRK(0x1043, 0x8376, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x83ce, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x831a, "EeePC", 1), SND_PCI_QUIRK(0x1043, 0x834a, "EeePC", 1), @@ -4282,81 +1045,20 @@ static int alc_parse_auto_config(struct hda_codec *codec, const hda_nid_t *ssid_nids) { struct alc_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; int err; err = snd_hda_parse_pin_defcfg(codec, cfg, ignore_nids, spec->parse_flags); if (err < 0) return err; - if (!cfg->line_outs) { - if (cfg->dig_outs || cfg->dig_in_pin) { - spec->multiout.max_channels = 2; - spec->no_analog = 1; - goto dig_only; - } - return 0; /* can't find valid BIOS pin config */ - } - - if (!spec->no_primary_hp && - cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs <= cfg->hp_outs) { - /* use HP as primary out */ - cfg->speaker_outs = cfg->line_outs; - memcpy(cfg->speaker_pins, cfg->line_out_pins, - sizeof(cfg->speaker_pins)); - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - } - - err = alc_auto_fill_dac_nids(codec); - if (err < 0) - return err; - err = alc_auto_add_multi_channel_mode(codec); - if (err < 0) - return err; - err = alc_auto_create_multi_out_ctls(codec, cfg); - if (err < 0) - return err; - err = alc_auto_create_hp_out(codec); - if (err < 0) - return err; - err = alc_auto_create_speaker_out(codec); - if (err < 0) - return err; - err = alc_auto_create_shared_input(codec); - if (err < 0) - return err; - err = alc_auto_create_input_ctls(codec); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - dig_only: - alc_auto_parse_digital(codec); - - if (!spec->no_analog) - alc_remove_invalid_adc_nids(codec); if (ssid_nids) alc_ssid_check(codec, ssid_nids); - if (!spec->no_analog) { - alc_auto_check_switches(codec); - err = alc_auto_add_mic_boost(codec); - if (err < 0) - return err; - } - - if (spec->kctls.list) - add_mixer(spec, spec->kctls.list); - - if (!spec->no_analog && !spec->cap_mixer) - set_capture_mixer(codec); + err = snd_hda_gen_parse_auto_config(codec, cfg); + if (err < 0) + return err; return 1; } @@ -4370,8 +1072,12 @@ static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) if (!spec) return -ENOMEM; codec->spec = spec; - spec->mixer_nid = mixer_nid; - snd_hda_gen_init(&spec->gen); + snd_hda_gen_spec_init(&spec->gen); + spec->gen.mixer_nid = mixer_nid; + spec->gen.own_eapd_ctl = 1; + codec->single_adc_amp = 1; + /* FIXME: do we need this for all Realtek codec models? */ + codec->spdif_status_reset = 1; err = alc_codec_rename_from_preset(codec); if (err < 0) { @@ -4396,6 +1102,7 @@ enum { ALC880_FIXUP_GPIO2, ALC880_FIXUP_MEDION_RIM, ALC880_FIXUP_LG, + ALC880_FIXUP_LG_LW25, ALC880_FIXUP_W810, ALC880_FIXUP_EAPD_COEF, ALC880_FIXUP_TCL_S700, @@ -4405,6 +1112,7 @@ enum { ALC880_FIXUP_UNIWILL, ALC880_FIXUP_UNIWILL_DIG, ALC880_FIXUP_Z71V, + ALC880_FIXUP_ASUS_W5A, ALC880_FIXUP_3ST_BASE, ALC880_FIXUP_3ST, ALC880_FIXUP_3ST_DIG, @@ -4414,27 +1122,28 @@ enum { ALC880_FIXUP_6ST_BASE, ALC880_FIXUP_6ST, ALC880_FIXUP_6ST_DIG, + ALC880_FIXUP_6ST_AUTOMUTE, }; /* enable the volume-knob widget support on NID 0x21 */ static void alc880_fixup_vol_knob(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PROBE) + if (action == HDA_FIXUP_ACT_PROBE) snd_hda_jack_detect_enable_callback(codec, 0x21, ALC_DCVOL_EVENT, alc_update_knob_master); } -static const struct alc_fixup alc880_fixups[] = { +static const struct hda_fixup alc880_fixups[] = { [ALC880_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC880_FIXUP_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, }, [ALC880_FIXUP_MEDION_RIM] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3060 }, @@ -4444,8 +1153,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_LG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x16, 0x411111f0 }, { 0x18, 0x411111f0 }, @@ -4453,9 +1162,17 @@ static const struct alc_fixup alc880_fixups[] = { { } } }, + [ALC880_FIXUP_LG_LW25] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x0181344f }, /* line-in */ + { 0x1b, 0x0321403f }, /* headphone */ + { } + } + }, [ALC880_FIXUP_W810] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x17, 0x411111f0 }, { } @@ -4464,7 +1181,7 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_EAPD_COEF] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -4473,7 +1190,7 @@ static const struct alc_fixup alc880_fixups[] = { }, }, [ALC880_FIXUP_TCL_S700] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -4484,13 +1201,13 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_GPIO2, }, [ALC880_FIXUP_VOL_KNOB] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc880_fixup_vol_knob, }, [ALC880_FIXUP_FUJITSU] = { /* override all pins as BIOS on old Amilo is broken */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ @@ -4509,8 +1226,8 @@ static const struct alc_fixup alc880_fixups[] = { }, [ALC880_FIXUP_F1734] = { /* almost compatible with FUJITSU, but no bass and SPDIF */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x411111f0 }, /* N/A */ @@ -4529,8 +1246,8 @@ static const struct alc_fixup alc880_fixups[] = { }, [ALC880_FIXUP_UNIWILL] = { /* need to fix HP and speaker pins to be parsed correctly */ - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0121411f }, /* HP */ { 0x15, 0x99030120 }, /* speaker */ { 0x16, 0x99030130 }, /* bass speaker */ @@ -4538,8 +1255,8 @@ static const struct alc_fixup alc880_fixups[] = { }, }, [ALC880_FIXUP_UNIWILL_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* disable bogus unused pins */ { 0x17, 0x411111f0 }, { 0x19, 0x411111f0 }, @@ -4549,8 +1266,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_Z71V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { /* set up the whole pins as BIOS is utterly broken */ { 0x14, 0x99030120 }, /* speaker */ { 0x15, 0x0121411f }, /* HP */ @@ -4566,9 +1283,29 @@ static const struct alc_fixup alc880_fixups[] = { { } } }, + [ALC880_FIXUP_ASUS_W5A] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* set up the whole pins as BIOS is utterly broken */ + { 0x14, 0x0121411f }, /* HP */ + { 0x15, 0x411111f0 }, /* N/A */ + { 0x16, 0x411111f0 }, /* N/A */ + { 0x17, 0x411111f0 }, /* N/A */ + { 0x18, 0x90a60160 }, /* mic */ + { 0x19, 0x411111f0 }, /* N/A */ + { 0x1a, 0x411111f0 }, /* N/A */ + { 0x1b, 0x411111f0 }, /* N/A */ + { 0x1c, 0x411111f0 }, /* N/A */ + { 0x1d, 0x411111f0 }, /* N/A */ + { 0x1e, 0xb743111e }, /* SPDIF out */ + { } + }, + .chained = true, + .chain_id = ALC880_FIXUP_GPIO1, + }, [ALC880_FIXUP_3ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* line-out */ { 0x15, 0x411111f0 }, /* N/A */ { 0x16, 0x411111f0 }, /* N/A */ @@ -4585,8 +1322,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_3ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4594,8 +1331,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_3ST_BASE, }, [ALC880_FIXUP_3ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, @@ -4603,8 +1340,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_3ST_BASE, }, [ALC880_FIXUP_5ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* front */ { 0x15, 0x411111f0 }, /* N/A */ { 0x16, 0x01011411 }, /* CLFE */ @@ -4621,8 +1358,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_5ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4630,8 +1367,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_5ST_BASE, }, [ALC880_FIXUP_5ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, @@ -4639,8 +1376,8 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_5ST_BASE, }, [ALC880_FIXUP_6ST_BASE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x01014010 }, /* front */ { 0x15, 0x01016412 }, /* surr */ { 0x16, 0x01011411 }, /* CLFE */ @@ -4657,8 +1394,8 @@ static const struct alc_fixup alc880_fixups[] = { } }, [ALC880_FIXUP_6ST] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x411111f0 }, /* N/A */ { } }, @@ -4666,20 +1403,31 @@ static const struct alc_fixup alc880_fixups[] = { .chain_id = ALC880_FIXUP_6ST_BASE, }, [ALC880_FIXUP_6ST_DIG] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1e, 0x0144111e }, /* SPDIF */ { } }, .chained = true, .chain_id = ALC880_FIXUP_6ST_BASE, }, + [ALC880_FIXUP_6ST_AUTOMUTE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x0121401f }, /* HP with jack detect */ + { } + }, + .chained_before = true, + .chain_id = ALC880_FIXUP_6ST_BASE, + }, }; static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x0f69, "Coeus G610P", ALC880_FIXUP_W810), + SND_PCI_QUIRK(0x1043, 0x10c3, "ASUS W5A", ALC880_FIXUP_ASUS_W5A), SND_PCI_QUIRK(0x1043, 0x1964, "ASUS Z71V", ALC880_FIXUP_Z71V), SND_PCI_QUIRK_VENDOR(0x1043, "ASUS", ALC880_FIXUP_GPIO1), + SND_PCI_QUIRK(0x147b, 0x1045, "ABit AA8XE", ALC880_FIXUP_6ST_AUTOMUTE), SND_PCI_QUIRK(0x1558, 0x5401, "Clevo GPIO2", ALC880_FIXUP_GPIO2), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo", ALC880_FIXUP_EAPD_COEF), SND_PCI_QUIRK(0x1584, 0x9050, "Uniwill", ALC880_FIXUP_UNIWILL_DIG), @@ -4688,6 +1436,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1584, 0x9077, "Uniwill P53", ALC880_FIXUP_VOL_KNOB), SND_PCI_QUIRK(0x161f, 0x203d, "W810", ALC880_FIXUP_W810), SND_PCI_QUIRK(0x161f, 0x205d, "Medion Rim 2150", ALC880_FIXUP_MEDION_RIM), + SND_PCI_QUIRK(0x1631, 0xe011, "PB 13201056", ALC880_FIXUP_6ST_AUTOMUTE), SND_PCI_QUIRK(0x1734, 0x107c, "FSC F1734", ALC880_FIXUP_F1734), SND_PCI_QUIRK(0x1734, 0x1094, "FSC Amilo M1451G", ALC880_FIXUP_FUJITSU), SND_PCI_QUIRK(0x1734, 0x10ac, "FSC AMILO Xi 1526", ALC880_FIXUP_F1734), @@ -4695,6 +1444,7 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { SND_PCI_QUIRK(0x1854, 0x003b, "LG", ALC880_FIXUP_LG), SND_PCI_QUIRK(0x1854, 0x005f, "LG P1 Express", ALC880_FIXUP_LG), SND_PCI_QUIRK(0x1854, 0x0068, "LG w1", ALC880_FIXUP_LG), + SND_PCI_QUIRK(0x1854, 0x0077, "LG LW25", ALC880_FIXUP_LG_LW25), SND_PCI_QUIRK(0x19db, 0x4188, "TCL S700", ALC880_FIXUP_TCL_S700), /* Below is the copied entries from alc880_quirks.c. @@ -4743,13 +1493,14 @@ static const struct snd_pci_quirk alc880_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc880_fixup_models[] = { +static const struct hda_model_fixup alc880_fixup_models[] = { {.id = ALC880_FIXUP_3ST, .name = "3stack"}, {.id = ALC880_FIXUP_3ST_DIG, .name = "3stack-digout"}, {.id = ALC880_FIXUP_5ST, .name = "5stack"}, {.id = ALC880_FIXUP_5ST_DIG, .name = "5stack-digout"}, {.id = ALC880_FIXUP_6ST, .name = "6stack"}, {.id = ALC880_FIXUP_6ST_DIG, .name = "6stack-digout"}, + {.id = ALC880_FIXUP_6ST_AUTOMUTE, .name = "6stack-automute"}, {} }; @@ -4767,29 +1518,26 @@ static int patch_alc880(struct hda_codec *codec) return err; spec = codec->spec; - spec->need_dac_fix = 1; + spec->gen.need_dac_fix = 1; + spec->gen.beep_nid = 0x01; - alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, + snd_hda_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, alc880_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc880_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; codec->patch_ops.unsol_event = alc880_unsol_event; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -4821,38 +1569,41 @@ enum { ALC260_FIXUP_REPLACER, ALC260_FIXUP_HP_B1900, ALC260_FIXUP_KN1, + ALC260_FIXUP_FSC_S7020, + ALC260_FIXUP_FSC_S7020_JWSE, + ALC260_FIXUP_VAIO_PINS, }; static void alc260_gpio1_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->hp_jack_present); + spec->gen.hp_jack_present); } static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PROBE) { + if (action == HDA_FIXUP_ACT_PROBE) { /* although the machine has only one output pin, we need to * toggle GPIO1 according to the jack state */ - spec->automute_hook = alc260_gpio1_automute; - spec->detect_hp = 1; - spec->automute_speaker = 1; - spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ - snd_hda_jack_detect_enable_callback(codec, 0x0f, ALC_HP_EVENT, - alc_hp_automute); - snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs); + spec->gen.automute_hook = alc260_gpio1_automute; + spec->gen.detect_hp = 1; + spec->gen.automute_speaker = 1; + spec->gen.autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ + snd_hda_jack_detect_enable_callback(codec, 0x0f, HDA_GEN_HP_EVENT, + snd_hda_gen_hp_automute); + snd_hda_add_verbs(codec, alc_gpio1_init_verbs); } } static void alc260_fixup_kn1(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - static const struct alc_pincfg pincfgs[] = { + static const struct hda_pintbl pincfgs[] = { { 0x0f, 0x02214000 }, /* HP/speaker */ { 0x12, 0x90a60160 }, /* int mic */ { 0x13, 0x02a19000 }, /* ext mic */ @@ -4869,70 +1620,114 @@ static void alc260_fixup_kn1(struct hda_codec *codec, }; switch (action) { - case ALC_FIXUP_ACT_PRE_PROBE: - alc_apply_pincfgs(codec, pincfgs); + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_apply_pincfgs(codec, pincfgs); break; - case ALC_FIXUP_ACT_PROBE: + case HDA_FIXUP_ACT_PROBE: spec->init_amp = ALC_INIT_NONE; break; } } -static const struct alc_fixup alc260_fixups[] = { +static void alc260_fixup_fsc_s7020(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PROBE) + spec->init_amp = ALC_INIT_NONE; +} + +static void alc260_fixup_fsc_s7020_jwse(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.add_jack_modes = 1; + spec->gen.hp_mic = 1; + } +} + +static const struct hda_fixup alc260_fixups[] = { [ALC260_FIXUP_HP_DC5750] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x11, 0x90130110 }, /* speaker */ { } } }, [ALC260_FIXUP_HP_PIN_0F] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x0f, 0x01214000 }, /* HP */ { } } }, [ALC260_FIXUP_COEF] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3040 }, + { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x1a, AC_VERB_SET_PROC_COEF, 0x3040 }, { } }, - .chained = true, - .chain_id = ALC260_FIXUP_HP_PIN_0F, }, [ALC260_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC260_FIXUP_GPIO1_TOGGLE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_gpio1_toggle, .chained = true, .chain_id = ALC260_FIXUP_HP_PIN_0F, }, [ALC260_FIXUP_REPLACER] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { - { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, - { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, + { 0x1a, AC_VERB_SET_COEF_INDEX, 0x07 }, + { 0x1a, AC_VERB_SET_PROC_COEF, 0x3050 }, { } }, .chained = true, .chain_id = ALC260_FIXUP_GPIO1_TOGGLE, }, [ALC260_FIXUP_HP_B1900] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_gpio1_toggle, .chained = true, .chain_id = ALC260_FIXUP_COEF, }, [ALC260_FIXUP_KN1] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc260_fixup_kn1, }, + [ALC260_FIXUP_FSC_S7020] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc260_fixup_fsc_s7020, + }, + [ALC260_FIXUP_FSC_S7020_JWSE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc260_fixup_fsc_s7020_jwse, + .chained = true, + .chain_id = ALC260_FIXUP_FSC_S7020, + }, + [ALC260_FIXUP_VAIO_PINS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* Pin configs are missing completely on some VAIOs */ + { 0x0f, 0x01211020 }, + { 0x10, 0x0001003f }, + { 0x11, 0x411111f0 }, + { 0x12, 0x01a15930 }, + { 0x13, 0x411111f0 }, + { 0x14, 0x411111f0 }, + { 0x15, 0x411111f0 }, + { 0x16, 0x411111f0 }, + { 0x17, 0x411111f0 }, + { 0x18, 0x411111f0 }, + { 0x19, 0x411111f0 }, + { } + } + }, }; static const struct snd_pci_quirk alc260_fixup_tbl[] = { @@ -4941,6 +1736,9 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = { SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x103c, 0x280a, "HP dc5750", ALC260_FIXUP_HP_DC5750), SND_PCI_QUIRK(0x103c, 0x30ba, "HP Presario B1900", ALC260_FIXUP_HP_B1900), + SND_PCI_QUIRK(0x104d, 0x81bb, "Sony VAIO", ALC260_FIXUP_VAIO_PINS), + SND_PCI_QUIRK(0x104d, 0x81e2, "Sony VAIO TX", ALC260_FIXUP_HP_PIN_0F), + SND_PCI_QUIRK(0x10cf, 0x1326, "FSC LifeBook S7020", ALC260_FIXUP_FSC_S7020), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FIXUP_GPIO1), SND_PCI_QUIRK(0x152d, 0x0729, "Quanta KN1", ALC260_FIXUP_KN1), SND_PCI_QUIRK(0x161f, 0x2057, "Replacer 672V", ALC260_FIXUP_REPLACER), @@ -4948,6 +1746,14 @@ static const struct snd_pci_quirk alc260_fixup_tbl[] = { {} }; +static const struct hda_model_fixup alc260_fixup_models[] = { + {.id = ALC260_FIXUP_GPIO1, .name = "gpio1"}, + {.id = ALC260_FIXUP_COEF, .name = "coef"}, + {.id = ALC260_FIXUP_FSC_S7020, .name = "fujitsu"}, + {.id = ALC260_FIXUP_FSC_S7020_JWSE, .name = "fujitsu-jwse"}, + {} +}; + /* */ static int patch_alc260(struct hda_codec *codec) @@ -4960,26 +1766,29 @@ static int patch_alc260(struct hda_codec *codec) return err; spec = codec->spec; + /* as quite a few machines require HP amp for speaker outputs, + * it's easier to enable it unconditionally; even if it's unneeded, + * it's almost harmless. + */ + spec->gen.prefer_hp_amp = 1; + spec->gen.beep_nid = 0x01; - alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, alc260_fixup_models, alc260_fixup_tbl, + alc260_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc260_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog) set_beep_amp(spec, 0x07, 0x05, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5011,6 +1820,7 @@ enum { ALC882_FIXUP_ACER_ASPIRE_7736, ALC882_FIXUP_ASUS_W90V, ALC889_FIXUP_CD, + ALC889_FIXUP_FRONT_HP_NO_PRESENCE, ALC889_FIXUP_VAIO_TT, ALC888_FIXUP_EEE1601, ALC882_FIXUP_EAPD, @@ -5028,14 +1838,19 @@ enum { ALC889_FIXUP_DAC_ROUTE, ALC889_FIXUP_MBP_VREF, ALC889_FIXUP_IMAC91_VREF, + ALC889_FIXUP_MBA11_VREF, + ALC889_FIXUP_MBA21_VREF, + ALC889_FIXUP_MP11_VREF, ALC882_FIXUP_INV_DMIC, ALC882_FIXUP_NO_PRIMARY_HP, + ALC887_FIXUP_ASUS_BASS, + ALC887_FIXUP_BASS_CHMAP, }; static void alc889_fixup_coef(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; alc889_coef_init(codec); } @@ -5075,9 +1890,9 @@ static void alc882_gpio_mute(struct hda_codec *codec, int pin, int muted) /* set up GPIO at initialization */ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; alc882_gpio_mute(codec, 0, 0); alc882_gpio_mute(codec, 1, 0); @@ -5088,9 +1903,9 @@ static void alc885_fixup_macpro_gpio(struct hda_codec *codec, * work correctly (bko#42740) */ static void alc889_fixup_dac_route(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) { + if (action == HDA_FIXUP_ACT_PRE_PROBE) { /* fake the connections during parsing the tree */ hda_nid_t conn1[2] = { 0x0c, 0x0d }; hda_nid_t conn2[2] = { 0x0e, 0x0f }; @@ -5098,7 +1913,7 @@ static void alc889_fixup_dac_route(struct hda_codec *codec, snd_hda_override_conn_list(codec, 0x15, 2, conn1); snd_hda_override_conn_list(codec, 0x18, 2, conn2); snd_hda_override_conn_list(codec, 0x1a, 2, conn2); - } else if (action == ALC_FIXUP_ACT_PROBE) { + } else if (action == HDA_FIXUP_ACT_PROBE) { /* restore the connections */ hda_nid_t conn[5] = { 0x0c, 0x0d, 0x0e, 0x0f, 0x26 }; snd_hda_override_conn_list(codec, 0x14, 5, conn); @@ -5110,62 +1925,92 @@ static void alc889_fixup_dac_route(struct hda_codec *codec, /* Set VREF on HP pin */ static void alc889_fixup_mbp_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; static hda_nid_t nids[2] = { 0x14, 0x15 }; int i; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; for (i = 0; i < ARRAY_SIZE(nids); i++) { unsigned int val = snd_hda_codec_get_pincfg(codec, nids[i]); if (get_defcfg_device(val) != AC_JACK_HP_OUT) continue; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, nids[i]); val |= AC_PINCTL_VREF_80; snd_hda_set_pin_ctl(codec, nids[i], val); - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; break; } } -/* Set VREF on speaker pins on imac91 */ -static void alc889_fixup_imac91_vref(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +static void alc889_fixup_mac_pins(struct hda_codec *codec, + const hda_nid_t *nids, int num_nids) { struct alc_spec *spec = codec->spec; - static hda_nid_t nids[2] = { 0x18, 0x1a }; int i; - if (action != ALC_FIXUP_ACT_INIT) - return; - for (i = 0; i < ARRAY_SIZE(nids); i++) { + for (i = 0; i < num_nids; i++) { unsigned int val; - val = snd_hda_codec_read(codec, nids[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, nids[i]); val |= AC_PINCTL_VREF_50; snd_hda_set_pin_ctl(codec, nids[i], val); } - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; +} + +/* Set VREF on speaker pins on imac91 */ +static void alc889_fixup_imac91_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static hda_nid_t nids[2] = { 0x18, 0x1a }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + +/* Set VREF on speaker pins on mba11 */ +static void alc889_fixup_mba11_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static hda_nid_t nids[1] = { 0x18 }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); +} + +/* Set VREF on speaker pins on mba21 */ +static void alc889_fixup_mba21_vref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + static hda_nid_t nids[2] = { 0x18, 0x19 }; + + if (action == HDA_FIXUP_ACT_INIT) + alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids)); } /* Don't take HP output as primary - * strangely, the speaker output doesn't work on VAIO Z through DAC 0x05 + * Strangely, the speaker output doesn't work on Vaio Z and some Vaio + * all-in-one desktop PCs (for example VGC-LN51JGB) through DAC 0x05 */ static void alc882_fixup_no_primary_hp(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PRE_PROBE) - spec->no_primary_hp = 1; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.no_primary_hp = 1; + spec->gen.no_multi_io = 1; + } } -static const struct alc_fixup alc882_fixups[] = { +static void alc_fixup_bass_chmap(struct hda_codec *codec, + const struct hda_fixup *fix, int action); + +static const struct hda_fixup alc882_fixups[] = { [ALC882_FIXUP_ABIT_AW9D_MAX] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x01080104 }, /* side */ { 0x16, 0x01011012 }, /* rear */ { 0x17, 0x01016011 }, /* clfe */ @@ -5173,47 +2018,56 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_LENOVO_Y530] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x99130112 }, /* rear int speakers */ { 0x16, 0x99130111 }, /* subwoofer */ { } } }, [ALC882_FIXUP_PB_M5210] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, {} } }, [ALC882_FIXUP_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC882_FIXUP_ASUS_W90V] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130110 }, /* fix sequence for CLFE */ { } } }, [ALC889_FIXUP_CD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1c, 0x993301f0 }, /* CD */ { } } }, + [ALC889_FIXUP_FRONT_HP_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1b, 0x02214120 }, /* Front HP jack is flaky, disable jack detect */ + { } + }, + .chained = true, + .chain_id = ALC889_FIXUP_CD, + }, [ALC889_FIXUP_VAIO_TT] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x90170111 }, /* hidden surround speaker */ { } } }, [ALC888_FIXUP_EEE1601] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x0b }, { 0x20, AC_VERB_SET_PROC_COEF, 0x0838 }, @@ -5221,7 +2075,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5230,7 +2084,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC883_FIXUP_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* change to EAPD mode */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5239,7 +2093,7 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC883_FIXUP_ACER_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* eanable EAPD on Acer laptops */ { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, @@ -5248,30 +2102,30 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, }, [ALC882_FIXUP_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio2_init_verbs, }, [ALC882_FIXUP_GPIO3] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio3_init_verbs, }, [ALC882_FIXUP_ASUS_W2JC] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = alc_gpio1_init_verbs, .chained = true, .chain_id = ALC882_FIXUP_EAPD, }, [ALC889_FIXUP_COEF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_coef, }, [ALC882_FIXUP_ACER_ASPIRE_4930G] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130111 }, /* CLFE speaker */ { 0x17, 0x99130112 }, /* surround speaker */ { } @@ -5280,8 +2134,8 @@ static const struct alc_fixup alc882_fixups[] = { .chain_id = ALC882_FIXUP_GPIO1, }, [ALC882_FIXUP_ACER_ASPIRE_8930G] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130111 }, /* CLFE speaker */ { 0x1b, 0x99130112 }, /* surround speaker */ { } @@ -5291,7 +2145,7 @@ static const struct alc_fixup alc882_fixups[] = { }, [ALC882_FIXUP_ASPIRE_8930G_VERBS] = { /* additional init verbs for Acer Aspire 8930G */ - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* Enable all DACs */ /* DAC DISABLE/MUTE 1? */ @@ -5325,33 +2179,64 @@ static const struct alc_fixup alc882_fixups[] = { .chain_id = ALC882_FIXUP_GPIO1, }, [ALC885_FIXUP_MACPRO_GPIO] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc885_fixup_macpro_gpio, }, [ALC889_FIXUP_DAC_ROUTE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_dac_route, }, [ALC889_FIXUP_MBP_VREF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_mbp_vref, .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, [ALC889_FIXUP_IMAC91_VREF] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc889_fixup_imac91_vref, .chained = true, .chain_id = ALC882_FIXUP_GPIO1, }, + [ALC889_FIXUP_MBA11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC889_FIXUP_MBP_VREF, + }, + [ALC889_FIXUP_MBA21_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba21_vref, + .chained = true, + .chain_id = ALC889_FIXUP_MBP_VREF, + }, + [ALC889_FIXUP_MP11_VREF] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc889_fixup_mba11_vref, + .chained = true, + .chain_id = ALC885_FIXUP_MACPRO_GPIO, + }, [ALC882_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, [ALC882_FIXUP_NO_PRIMARY_HP] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc882_fixup_no_primary_hp, }, + [ALC887_FIXUP_ASUS_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x99130130}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC887_FIXUP_BASS_CHMAP, + }, + [ALC887_FIXUP_BASS_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + }, }; static const struct snd_pci_quirk alc882_fixup_tbl[] = { @@ -5385,21 +2270,23 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1043, 0x1873, "ASUS W90V", ALC882_FIXUP_ASUS_W90V), SND_PCI_QUIRK(0x1043, 0x1971, "Asus W2JC", ALC882_FIXUP_ASUS_W2JC), SND_PCI_QUIRK(0x1043, 0x835f, "Asus Eee 1601", ALC888_FIXUP_EEE1601), + SND_PCI_QUIRK(0x1043, 0x84bc, "ASUS ET2700", ALC887_FIXUP_ASUS_BASS), SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC889_FIXUP_VAIO_TT), SND_PCI_QUIRK(0x104d, 0x905a, "Sony Vaio Z", ALC882_FIXUP_NO_PRIMARY_HP), + SND_PCI_QUIRK(0x104d, 0x9043, "Sony Vaio VGC-LN51JGB", ALC882_FIXUP_NO_PRIMARY_HP), /* All Apple entries are in codec SSIDs */ SND_PCI_QUIRK(0x106b, 0x00a0, "MacBookPro 3,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x00a1, "Macbook", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x00a4, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x0c00, "Mac Pro", ALC889_FIXUP_MP11_VREF), SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_FIXUP_MACPRO_GPIO), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD), - SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF), - SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBP_VREF), + SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF), + SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_FIXUP_MACPRO_GPIO), @@ -5407,6 +2294,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4100, "Macmini 3,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4200, "Mac Pro 5,1", ALC885_FIXUP_MACPRO_GPIO), + SND_PCI_QUIRK(0x106b, 0x4300, "iMac 9,1", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC889_FIXUP_IMAC91_VREF), SND_PCI_QUIRK(0x106b, 0x4a00, "Macbook 5,2", ALC889_FIXUP_IMAC91_VREF), @@ -5414,7 +2302,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { SND_PCI_QUIRK(0x1071, 0x8258, "Evesham Voyaeger", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x1462, 0x7350, "MSI-7350", ALC889_FIXUP_CD), SND_PCI_QUIRK_VENDOR(0x1462, "MSI", ALC882_FIXUP_GPIO3), - SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3", ALC889_FIXUP_CD), + SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte EP45-DS3/Z87X-UD3H", ALC889_FIXUP_FRONT_HP_NO_PRESENCE), SND_PCI_QUIRK(0x147b, 0x107a, "Abit AW9D-MAX", ALC882_FIXUP_ABIT_AW9D_MAX), SND_PCI_QUIRK_VENDOR(0x1558, "Clevo laptop", ALC882_FIXUP_EAPD), SND_PCI_QUIRK(0x161f, 0x2054, "Medion laptop", ALC883_FIXUP_EAPD), @@ -5423,7 +2311,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc882_fixup_models[] = { +static const struct hda_model_fixup alc882_fixup_models[] = { {.id = ALC882_FIXUP_ACER_ASPIRE_4930G, .name = "acer-aspire-4930g"}, {.id = ALC882_FIXUP_ACER_ASPIRE_8930G, .name = "acer-aspire-8930g"}, {.id = ALC883_FIXUP_ACER_EAPD, .name = "acer-aspire"}, @@ -5466,27 +2354,26 @@ static int patch_alc882(struct hda_codec *codec) break; } - alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, + snd_hda_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, alc882_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + /* automatic parse from the BIOS config */ err = alc882_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog && spec->gen.beep_nid) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5511,49 +2398,60 @@ static int alc262_parse_auto_config(struct hda_codec *codec) */ enum { ALC262_FIXUP_FSC_H270, + ALC262_FIXUP_FSC_S7110, ALC262_FIXUP_HP_Z200, ALC262_FIXUP_TYAN, ALC262_FIXUP_LENOVO_3000, ALC262_FIXUP_BENQ, ALC262_FIXUP_BENQ_T31, ALC262_FIXUP_INV_DMIC, + ALC262_FIXUP_INTEL_BAYLEYBAY, }; -static const struct alc_fixup alc262_fixups[] = { +static const struct hda_fixup alc262_fixups[] = { [ALC262_FIXUP_FSC_H270] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0221142f }, /* front HP */ { 0x1b, 0x0121141f }, /* rear HP */ { } } }, + [ALC262_FIXUP_FSC_S7110] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x15, 0x90170110 }, /* speaker */ + { } + }, + .chained = true, + .chain_id = ALC262_FIXUP_BENQ, + }, [ALC262_FIXUP_HP_Z200] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x16, 0x99130120 }, /* internal speaker */ { } } }, [ALC262_FIXUP_TYAN] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x1993e1f0 }, /* int AUX */ { } } }, [ALC262_FIXUP_LENOVO_3000] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - { 0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50 }, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, PIN_VREF50 }, {} }, .chained = true, .chain_id = ALC262_FIXUP_BENQ, }, [ALC262_FIXUP_BENQ] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3070 }, @@ -5561,7 +2459,7 @@ static const struct alc_fixup alc262_fixups[] = { } }, [ALC262_FIXUP_BENQ_T31] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { { 0x20, AC_VERB_SET_COEF_INDEX, 0x07 }, { 0x20, AC_VERB_SET_PROC_COEF, 0x3050 }, @@ -5569,24 +2467,29 @@ static const struct alc_fixup alc262_fixups[] = { } }, [ALC262_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC262_FIXUP_INTEL_BAYLEYBAY] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_depop_delay, + }, }; static const struct snd_pci_quirk alc262_fixup_tbl[] = { SND_PCI_QUIRK(0x103c, 0x170b, "HP Z200", ALC262_FIXUP_HP_Z200), - SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu", ALC262_FIXUP_BENQ), + SND_PCI_QUIRK(0x10cf, 0x1397, "Fujitsu Lifebook S7110", ALC262_FIXUP_FSC_S7110), SND_PCI_QUIRK(0x10cf, 0x142d, "Fujitsu Lifebook E8410", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x10f1, 0x2915, "Tyan Thunder n6650W", ALC262_FIXUP_TYAN), SND_PCI_QUIRK(0x1734, 0x1147, "FSC Celsius H270", ALC262_FIXUP_FSC_H270), SND_PCI_QUIRK(0x17aa, 0x384e, "Lenovo 3000", ALC262_FIXUP_LENOVO_3000), SND_PCI_QUIRK(0x17ff, 0x0560, "Benq ED8", ALC262_FIXUP_BENQ), SND_PCI_QUIRK(0x17ff, 0x058d, "Benq T31-16", ALC262_FIXUP_BENQ_T31), + SND_PCI_QUIRK(0x8086, 0x7270, "BayleyBay", ALC262_FIXUP_INTEL_BAYLEYBAY), {} }; -static const struct alc_model_fixup alc262_fixup_models[] = { +static const struct hda_model_fixup alc262_fixup_models[] = { {.id = ALC262_FIXUP_INV_DMIC, .name = "inv-dmic"}, {} }; @@ -5603,6 +2506,7 @@ static int patch_alc262(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.shared_mic_vref_pin = 0x18; #if 0 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is @@ -5618,28 +2522,27 @@ static int patch_alc262(struct hda_codec *codec) #endif alc_fix_pll_init(codec, 0x20, 0x0a, 10); - alc_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, + snd_hda_pick_fixup(codec, alc262_fixup_models, alc262_fixup_tbl, alc262_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + /* automatic parse from the BIOS config */ err = alc262_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog && spec->gen.beep_nid) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5677,17 +2580,44 @@ static const struct hda_verb alc268_beep_init_verbs[] = { enum { ALC268_FIXUP_INV_DMIC, + ALC268_FIXUP_HP_EAPD, + ALC268_FIXUP_SPDIF, }; -static const struct alc_fixup alc268_fixups[] = { +static const struct hda_fixup alc268_fixups[] = { [ALC268_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC268_FIXUP_HP_EAPD] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0}, + {} + } + }, + [ALC268_FIXUP_SPDIF] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1e, 0x014b1180 }, /* enable SPDIF out */ + {} + } + }, }; -static const struct alc_model_fixup alc268_fixup_models[] = { +static const struct hda_model_fixup alc268_fixup_models[] = { {.id = ALC268_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC268_FIXUP_HP_EAPD, .name = "hp-eapd"}, + {} +}; + +static const struct snd_pci_quirk alc268_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0139, "Acer TravelMate 6293", ALC268_FIXUP_SPDIF), + SND_PCI_QUIRK(0x1025, 0x015b, "Acer AOA 150 (ZG5)", ALC268_FIXUP_INV_DMIC), + /* below is codec SSID since multiple Toshiba laptops have the + * same PCI SSID 1179:ff00 + */ + SND_PCI_QUIRK(0x1179, 0xff06, "Toshiba P200", ALC268_FIXUP_HP_EAPD), {} }; @@ -5697,15 +2627,7 @@ static const struct alc_model_fixup alc268_fixup_models[] = { static int alc268_parse_auto_config(struct hda_codec *codec) { static const hda_nid_t alc268_ssids[] = { 0x15, 0x1b, 0x14, 0 }; - struct alc_spec *spec = codec->spec; - int err = alc_parse_auto_config(codec, NULL, alc268_ssids); - if (err > 0) { - if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) { - add_mixer(spec, alc268_beep_mixer); - snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs); - } - } - return err; + return alc_parse_auto_config(codec, NULL, alc268_ssids); } /* @@ -5713,7 +2635,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) static int patch_alc268(struct hda_codec *codec) { struct alc_spec *spec; - int i, has_beep, err; + int err; /* ALC268 has no aa-loopback mixer */ err = alc_alloc_spec(codec, 0); @@ -5721,27 +2643,20 @@ static int patch_alc268(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.beep_nid = 0x01; - alc_pick_fixup(codec, alc268_fixup_models, NULL, alc268_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, alc268_fixup_models, alc268_fixup_tbl, alc268_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc268_parse_auto_config(codec); if (err < 0) goto error; - has_beep = 0; - for (i = 0; i < spec->num_mixers; i++) { - if (spec->mixers[i] == alc268_beep_mixer) { - has_beep = 1; - break; - } - } - - if (has_beep) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (err > 0 && !spec->gen.no_analog && + spec->gen.autocfg.speaker_pins[0] != 0x1d) { + add_mixer(spec, alc268_beep_mixer); + snd_hda_add_verbs(codec, alc268_beep_init_verbs); if (!query_amp_caps(codec, 0x1d, HDA_INPUT)) /* override the amp caps for beep generator */ snd_hda_override_amp_caps(codec, 0x1d, HDA_INPUT, @@ -5754,7 +2669,7 @@ static int patch_alc268(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -5766,6 +2681,35 @@ static int patch_alc268(struct hda_codec *codec) /* * ALC269 */ + +static int playback_pcm_open(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, + hinfo); +} + +static int playback_pcm_prepare(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + unsigned int stream_tag, + unsigned int format, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, + stream_tag, format, substream); +} + +static int playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + struct hda_gen_spec *spec = codec->spec; + return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); +} + static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .substreams = 1, .channels_min = 2, @@ -5773,9 +2717,9 @@ static const struct hda_pcm_stream alc269_44k_pcm_analog_playback = { .rates = SNDRV_PCM_RATE_44100, /* fixed rate */ /* NID is set in alc_build_pcms */ .ops = { - .open = alc_playback_pcm_open, - .prepare = alc_playback_pcm_prepare, - .cleanup = alc_playback_pcm_cleanup + .open = playback_pcm_open, + .prepare = playback_pcm_prepare, + .cleanup = playback_pcm_cleanup }, }; @@ -5793,6 +2737,13 @@ enum { ALC269_TYPE_ALC269VB, ALC269_TYPE_ALC269VC, ALC269_TYPE_ALC269VD, + ALC269_TYPE_ALC280, + ALC269_TYPE_ALC282, + ALC269_TYPE_ALC283, + ALC269_TYPE_ALC284, + ALC269_TYPE_ALC285, + ALC269_TYPE_ALC286, + ALC269_TYPE_ALC255, }; /* @@ -5809,10 +2760,17 @@ static int alc269_parse_auto_config(struct hda_codec *codec) switch (spec->codec_variant) { case ALC269_TYPE_ALC269VA: case ALC269_TYPE_ALC269VC: + case ALC269_TYPE_ALC280: + case ALC269_TYPE_ALC284: + case ALC269_TYPE_ALC285: ssids = alc269va_ssids; break; case ALC269_TYPE_ALC269VB: case ALC269_TYPE_ALC269VD: + case ALC269_TYPE_ALC282: + case ALC269_TYPE_ALC283: + case ALC269_TYPE_ALC286: + case ALC269_TYPE_ALC255: ssids = alc269_ssids; break; default: @@ -5823,7 +2781,7 @@ static int alc269_parse_auto_config(struct hda_codec *codec) return alc_parse_auto_config(codec, alc269_ignore, ssids); } -static void alc269_toggle_power_output(struct hda_codec *codec, int power_up) +static void alc269vb_toggle_power_output(struct hda_codec *codec, int power_up) { int val = alc_read_coef_idx(codec, 0x04); if (power_up) @@ -5837,69 +2795,491 @@ static void alc269_shutup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (spec->codec_variant != ALC269_TYPE_ALC269VB) + if (spec->codec_variant == ALC269_TYPE_ALC269VB) + alc269vb_toggle_power_output(codec, 0); + if (spec->codec_variant == ALC269_TYPE_ALC269VB && + (alc_get_coef0(codec) & 0x00ff) == 0x018) { + msleep(150); + } + snd_hda_shutup_pins(codec); +} + +static void alc282_restore_default_value(struct hda_codec *codec) +{ + int val; + + /* Power Down Control */ + alc_write_coef_idx(codec, 0x03, 0x0002); + /* FIFO and filter clock */ + alc_write_coef_idx(codec, 0x05, 0x0700); + /* DMIC control */ + alc_write_coef_idx(codec, 0x07, 0x0200); + /* Analog clock */ + val = alc_read_coef_idx(codec, 0x06); + alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + /* JD */ + val = alc_read_coef_idx(codec, 0x08); + alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + /* JD offset1 */ + alc_write_coef_idx(codec, 0x0a, 0xcccc); + /* JD offset2 */ + alc_write_coef_idx(codec, 0x0b, 0xcccc); + /* LDO1/2/3, DAC/ADC */ + alc_write_coef_idx(codec, 0x0e, 0x6e00); + /* JD */ + val = alc_read_coef_idx(codec, 0x0f); + alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + /* Capless */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + /* Class D test 4 */ + alc_write_coef_idx(codec, 0x6f, 0x0); + /* IO power down directly */ + val = alc_read_coef_idx(codec, 0x0c); + alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + /* ANC */ + alc_write_coef_idx(codec, 0x34, 0xa0c0); + /* AGC MUX */ + val = alc_read_coef_idx(codec, 0x16); + alc_write_coef_idx(codec, 0x16, (val & ~0x0008) | 0x0); + /* DAC simple content protection */ + val = alc_read_coef_idx(codec, 0x1d); + alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + /* ADC simple content protection */ + val = alc_read_coef_idx(codec, 0x1f); + alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + /* DAC ADC Zero Detection */ + alc_write_coef_idx(codec, 0x21, 0x8804); + /* PLL */ + alc_write_coef_idx(codec, 0x63, 0x2902); + /* capless control 2 */ + alc_write_coef_idx(codec, 0x68, 0xa080); + /* capless control 3 */ + alc_write_coef_idx(codec, 0x69, 0x3400); + /* capless control 4 */ + alc_write_coef_idx(codec, 0x6a, 0x2f3e); + /* capless control 5 */ + alc_write_coef_idx(codec, 0x6b, 0x0); + /* class D test 2 */ + val = alc_read_coef_idx(codec, 0x6d); + alc_write_coef_idx(codec, 0x6d, (val & ~0x0fff) | 0x0900); + /* class D test 3 */ + alc_write_coef_idx(codec, 0x6e, 0x110a); + /* class D test 5 */ + val = alc_read_coef_idx(codec, 0x70); + alc_write_coef_idx(codec, 0x70, (val & ~0x00f8) | 0x00d8); + /* class D test 6 */ + alc_write_coef_idx(codec, 0x71, 0x0014); + /* classD OCP */ + alc_write_coef_idx(codec, 0x72, 0xc2ba); + /* classD pure DC test */ + val = alc_read_coef_idx(codec, 0x77); + alc_write_coef_idx(codec, 0x77, (val & ~0x0f80) | 0x0); + /* Class D amp control */ + alc_write_coef_idx(codec, 0x6c, 0xfc06); +} + +static void alc282_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + int coef78; + + alc282_restore_default_value(codec); + + if (!hp_pin) return; + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + coef78 = alc_read_coef_idx(codec, 0x78); - if ((alc_get_coef0(codec) & 0x00ff) == 0x017) - alc269_toggle_power_output(codec, 0); - if ((alc_get_coef0(codec) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); - msleep(150); + /* Index 0x78 Direct Drive HP AMP LPM Control 1 */ + /* Headphone capless set to high power mode */ + alc_write_coef_idx(codec, 0x78, 0x9004); + + if (hp_pin_sense) + msleep(2); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + if (hp_pin_sense) + msleep(100); + + /* Headphone capless set to normal mode */ + alc_write_coef_idx(codec, 0x78, coef78); +} + +static void alc282_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + int coef78; + + if (!hp_pin) { + alc269_shutup(codec); + return; + } + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + coef78 = alc_read_coef_idx(codec, 0x78); + alc_write_coef_idx(codec, 0x78, 0x9004); + + if (hp_pin_sense) + msleep(2); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + if (hp_pin_sense) + msleep(100); + + alc_auto_setup_eapd(codec, false); + snd_hda_shutup_pins(codec); + alc_write_coef_idx(codec, 0x78, coef78); +} + +static void alc283_restore_default_value(struct hda_codec *codec) +{ + int val; + + /* Power Down Control */ + alc_write_coef_idx(codec, 0x03, 0x0002); + /* FIFO and filter clock */ + alc_write_coef_idx(codec, 0x05, 0x0700); + /* DMIC control */ + alc_write_coef_idx(codec, 0x07, 0x0200); + /* Analog clock */ + val = alc_read_coef_idx(codec, 0x06); + alc_write_coef_idx(codec, 0x06, (val & ~0x00f0) | 0x0); + /* JD */ + val = alc_read_coef_idx(codec, 0x08); + alc_write_coef_idx(codec, 0x08, (val & ~0xfffc) | 0x0c2c); + /* JD offset1 */ + alc_write_coef_idx(codec, 0x0a, 0xcccc); + /* JD offset2 */ + alc_write_coef_idx(codec, 0x0b, 0xcccc); + /* LDO1/2/3, DAC/ADC */ + alc_write_coef_idx(codec, 0x0e, 0x6fc0); + /* JD */ + val = alc_read_coef_idx(codec, 0x0f); + alc_write_coef_idx(codec, 0x0f, (val & ~0xf800) | 0x1000); + /* Capless */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~0xfc00) | 0x0c00); + /* Class D test 4 */ + alc_write_coef_idx(codec, 0x3a, 0x0); + /* IO power down directly */ + val = alc_read_coef_idx(codec, 0x0c); + alc_write_coef_idx(codec, 0x0c, (val & ~0xfe00) | 0x0); + /* ANC */ + alc_write_coef_idx(codec, 0x22, 0xa0c0); + /* AGC MUX */ + val = alc_read_coefex_idx(codec, 0x53, 0x01); + alc_write_coefex_idx(codec, 0x53, 0x01, (val & ~0x000f) | 0x0008); + /* DAC simple content protection */ + val = alc_read_coef_idx(codec, 0x1d); + alc_write_coef_idx(codec, 0x1d, (val & ~0x00e0) | 0x0); + /* ADC simple content protection */ + val = alc_read_coef_idx(codec, 0x1f); + alc_write_coef_idx(codec, 0x1f, (val & ~0x00e0) | 0x0); + /* DAC ADC Zero Detection */ + alc_write_coef_idx(codec, 0x21, 0x8804); + /* PLL */ + alc_write_coef_idx(codec, 0x2e, 0x2902); + /* capless control 2 */ + alc_write_coef_idx(codec, 0x33, 0xa080); + /* capless control 3 */ + alc_write_coef_idx(codec, 0x34, 0x3400); + /* capless control 4 */ + alc_write_coef_idx(codec, 0x35, 0x2f3e); + /* capless control 5 */ + alc_write_coef_idx(codec, 0x36, 0x0); + /* class D test 2 */ + val = alc_read_coef_idx(codec, 0x38); + alc_write_coef_idx(codec, 0x38, (val & ~0x0fff) | 0x0900); + /* class D test 3 */ + alc_write_coef_idx(codec, 0x39, 0x110a); + /* class D test 5 */ + val = alc_read_coef_idx(codec, 0x3b); + alc_write_coef_idx(codec, 0x3b, (val & ~0x00f8) | 0x00d8); + /* class D test 6 */ + alc_write_coef_idx(codec, 0x3c, 0x0014); + /* classD OCP */ + alc_write_coef_idx(codec, 0x3d, 0xc2ba); + /* classD pure DC test */ + val = alc_read_coef_idx(codec, 0x42); + alc_write_coef_idx(codec, 0x42, (val & ~0x0f80) | 0x0); + /* test mode */ + alc_write_coef_idx(codec, 0x49, 0x0); + /* Class D DC enable */ + val = alc_read_coef_idx(codec, 0x40); + alc_write_coef_idx(codec, 0x40, (val & ~0xf800) | 0x9800); + /* DC offset */ + val = alc_read_coef_idx(codec, 0x42); + alc_write_coef_idx(codec, 0x42, (val & ~0xf000) | 0x2000); + /* Class D amp control */ + alc_write_coef_idx(codec, 0x37, 0xfc06); +} + +static void alc283_init(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + int val; + + if (!spec->gen.autocfg.hp_outs) { + if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) + hp_pin = spec->gen.autocfg.line_out_pins[0]; } + + alc283_restore_default_value(codec); + + if (!hp_pin) + return; + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + /* Index 0x43 Direct Drive HP AMP LPM Control 1 */ + /* Headphone capless set to high power mode */ + alc_write_coef_idx(codec, 0x43, 0x9004); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(85); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + + if (hp_pin_sense) + msleep(85); + /* Index 0x46 Combo jack auto switch control 2 */ + /* 3k pull low control for Headset jack. */ + val = alc_read_coef_idx(codec, 0x46); + alc_write_coef_idx(codec, 0x46, val & ~(3 << 12)); + /* Headphone capless set to normal mode */ + alc_write_coef_idx(codec, 0x43, 0x9614); } +static void alc283_shutup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + bool hp_pin_sense; + int val; + + if (!spec->gen.autocfg.hp_outs) { + if (spec->gen.autocfg.line_out_type == AC_JACK_HP_OUT) + hp_pin = spec->gen.autocfg.line_out_pins[0]; + } + + if (!hp_pin) { + alc269_shutup(codec); + return; + } + + hp_pin_sense = snd_hda_jack_detect(codec, hp_pin); + + alc_write_coef_idx(codec, 0x43, 0x9004); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); + + if (hp_pin_sense) + msleep(100); + + snd_hda_codec_write(codec, hp_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0); + + val = alc_read_coef_idx(codec, 0x46); + alc_write_coef_idx(codec, 0x46, val | (3 << 12)); + + if (hp_pin_sense) + msleep(100); + alc_auto_setup_eapd(codec, false); + snd_hda_shutup_pins(codec); + alc_write_coef_idx(codec, 0x43, 0x9614); +} + +static void alc5505_coef_set(struct hda_codec *codec, unsigned int index_reg, + unsigned int val) +{ + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1); + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val & 0xffff); /* LSB */ + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_PROC_COEF, val >> 16); /* MSB */ +} + +static int alc5505_coef_get(struct hda_codec *codec, unsigned int index_reg) +{ + unsigned int val; + + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_COEF_INDEX, index_reg >> 1); + val = snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0) + & 0xffff; + val |= snd_hda_codec_read(codec, 0x51, 0, AC_VERB_GET_PROC_COEF, 0) + << 16; + return val; +} + +static void alc5505_dsp_halt(struct hda_codec *codec) +{ + unsigned int val; + + alc5505_coef_set(codec, 0x3000, 0x000c); /* DSP CPU stop */ + alc5505_coef_set(codec, 0x880c, 0x0008); /* DDR enter self refresh */ + alc5505_coef_set(codec, 0x61c0, 0x11110080); /* Clock control for PLL and CPU */ + alc5505_coef_set(codec, 0x6230, 0xfc0d4011); /* Disable Input OP */ + alc5505_coef_set(codec, 0x61b4, 0x040a2b03); /* Stop PLL2 */ + alc5505_coef_set(codec, 0x61b0, 0x00005b17); /* Stop PLL1 */ + alc5505_coef_set(codec, 0x61b8, 0x04133303); /* Stop PLL3 */ + val = alc5505_coef_get(codec, 0x6220); + alc5505_coef_set(codec, 0x6220, (val | 0x3000)); /* switch Ringbuffer clock to DBUS clock */ +} + +static void alc5505_dsp_back_from_halt(struct hda_codec *codec) +{ + alc5505_coef_set(codec, 0x61b8, 0x04133302); + alc5505_coef_set(codec, 0x61b0, 0x00005b16); + alc5505_coef_set(codec, 0x61b4, 0x040a2b02); + alc5505_coef_set(codec, 0x6230, 0xf80d4011); + alc5505_coef_set(codec, 0x6220, 0x2002010f); + alc5505_coef_set(codec, 0x880c, 0x00000004); +} + +static void alc5505_dsp_init(struct hda_codec *codec) +{ + unsigned int val; + + alc5505_dsp_halt(codec); + alc5505_dsp_back_from_halt(codec); + alc5505_coef_set(codec, 0x61b0, 0x5b14); /* PLL1 control */ + alc5505_coef_set(codec, 0x61b0, 0x5b16); + alc5505_coef_set(codec, 0x61b4, 0x04132b00); /* PLL2 control */ + alc5505_coef_set(codec, 0x61b4, 0x04132b02); + alc5505_coef_set(codec, 0x61b8, 0x041f3300); /* PLL3 control*/ + alc5505_coef_set(codec, 0x61b8, 0x041f3302); + snd_hda_codec_write(codec, 0x51, 0, AC_VERB_SET_CODEC_RESET, 0); /* Function reset */ + alc5505_coef_set(codec, 0x61b8, 0x041b3302); + alc5505_coef_set(codec, 0x61b8, 0x04173302); + alc5505_coef_set(codec, 0x61b8, 0x04163302); + alc5505_coef_set(codec, 0x8800, 0x348b328b); /* DRAM control */ + alc5505_coef_set(codec, 0x8808, 0x00020022); /* DRAM control */ + alc5505_coef_set(codec, 0x8818, 0x00000400); /* DRAM control */ + + val = alc5505_coef_get(codec, 0x6200) >> 16; /* Read revision ID */ + if (val <= 3) + alc5505_coef_set(codec, 0x6220, 0x2002010f); /* I/O PAD Configuration */ + else + alc5505_coef_set(codec, 0x6220, 0x6002018f); + + alc5505_coef_set(codec, 0x61ac, 0x055525f0); /**/ + alc5505_coef_set(codec, 0x61c0, 0x12230080); /* Clock control */ + alc5505_coef_set(codec, 0x61b4, 0x040e2b02); /* PLL2 control */ + alc5505_coef_set(codec, 0x61bc, 0x010234f8); /* OSC Control */ + alc5505_coef_set(codec, 0x880c, 0x00000004); /* DRAM Function control */ + alc5505_coef_set(codec, 0x880c, 0x00000003); + alc5505_coef_set(codec, 0x880c, 0x00000010); + +#ifdef HALT_REALTEK_ALC5505 + alc5505_dsp_halt(codec); +#endif +} + +#ifdef HALT_REALTEK_ALC5505 +#define alc5505_dsp_suspend(codec) /* NOP */ +#define alc5505_dsp_resume(codec) /* NOP */ +#else +#define alc5505_dsp_suspend(codec) alc5505_dsp_halt(codec) +#define alc5505_dsp_resume(codec) alc5505_dsp_back_from_halt(codec) +#endif + #ifdef CONFIG_PM +static int alc269_suspend(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + if (spec->has_alc5505_dsp) + alc5505_dsp_suspend(codec); + return alc_suspend(codec); +} + static int alc269_resume(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - if (spec->codec_variant == ALC269_TYPE_ALC269VB || + if (spec->codec_variant == ALC269_TYPE_ALC269VB) + alc269vb_toggle_power_output(codec, 0); + if (spec->codec_variant == ALC269_TYPE_ALC269VB && (alc_get_coef0(codec) & 0x00ff) == 0x018) { - alc269_toggle_power_output(codec, 0); msleep(150); } codec->patch_ops.init(codec); - if (spec->codec_variant == ALC269_TYPE_ALC269VB || + if (spec->codec_variant == ALC269_TYPE_ALC269VB) + alc269vb_toggle_power_output(codec, 1); + if (spec->codec_variant == ALC269_TYPE_ALC269VB && (alc_get_coef0(codec) & 0x00ff) == 0x017) { - alc269_toggle_power_output(codec, 1); msleep(200); } - if (spec->codec_variant == ALC269_TYPE_ALC269VB || - (alc_get_coef0(codec) & 0x00ff) == 0x018) - alc269_toggle_power_output(codec, 1); - snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); + alc_inv_dmic_sync(codec, true); hda_call_check_power_status(codec, 0x01); + if (spec->has_alc5505_dsp) + alc5505_dsp_resume(codec); + return 0; } #endif /* CONFIG_PM */ static void alc269_fixup_pincfg_no_hp_to_lineout(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action == ALC_FIXUP_ACT_PRE_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; } static void alc269_fixup_hweq(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { int coef; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; coef = alc_read_coef_idx(codec, 0x1e); alc_write_coef_idx(codec, 0x1e, coef | 0x80); } +static void alc269_fixup_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; +} + static void alc271_fixup_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { static const struct hda_verb verbs[] = { {0x20, AC_VERB_SET_COEF_INDEX, 0x0d}, @@ -5908,7 +3288,8 @@ static void alc271_fixup_dmic(struct hda_codec *codec, }; unsigned int cfg; - if (strcmp(codec->chip_name, "ALC271X")) + if (strcmp(codec->chip_name, "ALC271X") && + strcmp(codec->chip_name, "ALC269VB")) return; cfg = snd_hda_codec_get_pincfg(codec, 0x12); if (get_defcfg_connect(cfg) == AC_JACK_PORT_FIXED) @@ -5916,26 +3297,26 @@ static void alc271_fixup_dmic(struct hda_codec *codec, } static void alc269_fixup_pcm_44k(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PROBE) return; /* Due to a hardware problem on Lenovo Ideadpad, we need to * fix the sample rate of analog I/O to 44.1kHz */ - spec->stream_analog_playback = &alc269_44k_pcm_analog_playback; - spec->stream_analog_capture = &alc269_44k_pcm_analog_capture; + spec->gen.stream_analog_playback = &alc269_44k_pcm_analog_playback; + spec->gen.stream_analog_capture = &alc269_44k_pcm_analog_capture; } static void alc269_fixup_stereo_dmic(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { int coef; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; /* The digital-mic unit sends PDM (differential signal) instead of * the standard PCM, thus you can't record a valid mono stream as is. @@ -5948,7 +3329,7 @@ static void alc269_fixup_stereo_dmic(struct hda_codec *codec, static void alc269_quanta_automute(struct hda_codec *codec) { - update_outputs(codec); + snd_hda_gen_update_outputs(codec); snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, 0x0c); @@ -5962,37 +3343,893 @@ static void alc269_quanta_automute(struct hda_codec *codec) } static void alc269_fixup_quanta_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PROBE) return; - spec->automute_hook = alc269_quanta_automute; + spec->gen.automute_hook = alc269_quanta_automute; +} + +static void alc269_x101_hp_automute_hook(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct alc_spec *spec = codec->spec; + int vref; + msleep(200); + snd_hda_gen_hp_automute(codec, jack); + + vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; + msleep(100); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + vref); + msleep(500); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + vref); +} + +static void alc269_fixup_x101_headset_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + spec->gen.hp_automute_hook = alc269_x101_hp_automute_hook; + } } -/* update mute-LED according to the speaker mute state via mic2 VREF pin */ -static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled) + +/* update mute-LED according to the speaker mute state via mic VREF pin */ +static void alc269_fixup_mic_mute_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; - unsigned int pinval = enabled ? 0x20 : 0x24; - snd_hda_set_pin_ctl_cache(codec, 0x19, pinval); + struct alc_spec *spec = codec->spec; + unsigned int pinval; + + if (spec->mute_led_polarity) + enabled = !enabled; + pinval = snd_hda_codec_get_pin_target(codec, spec->mute_led_nid); + pinval &= ~AC_PINCTL_VREFEN; + pinval |= enabled ? AC_PINCTL_VREF_HIZ : AC_PINCTL_VREF_80; + if (spec->mute_led_nid) + snd_hda_set_pin_ctl_cache(codec, spec->mute_led_nid, pinval); +} + +/* Make sure the led works even in runtime suspend */ +static unsigned int led_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + struct alc_spec *spec = codec->spec; + + if (power_state != AC_PWRST_D3 || nid != spec->mute_led_nid) + return power_state; + + /* Set pin ctl again, it might have just been set to 0 */ + snd_hda_set_pin_ctl(codec, nid, + snd_hda_codec_get_pin_target(codec, nid)); + + return AC_PWRST_D0; } -static void alc269_fixup_mic2_mute(struct hda_codec *codec, - const struct alc_fixup *fix, int action) +static void alc269_fixup_hp_mute_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; + const struct dmi_device *dev = NULL; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + int pol, pin; + if (sscanf(dev->name, "HP_Mute_LED_%d_%x", &pol, &pin) != 2) + continue; + if (pin < 0x0a || pin >= 0x10) + break; + spec->mute_led_polarity = pol; + spec->mute_led_nid = pin - 0x0a + 0x18; + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + codec_dbg(codec, + "Detected mute LED for %x:%d\n", spec->mute_led_nid, + spec->mute_led_polarity); + break; + } +} + +static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mute_led_polarity = 0; + spec->mute_led_nid = 0x18; + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + } +} + +static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mute_led_polarity = 0; + spec->mute_led_nid = 0x19; + spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; + spec->gen.vmaster_mute_enum = 1; + codec->power_filter = led_power_filter; + } +} + +/* turn on/off mute LED per vmaster hook */ +static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_led; + + if (enabled) + spec->gpio_led &= ~0x08; + else + spec->gpio_led |= 0x08; + if (spec->gpio_led != oldval) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); +} + +/* turn on/off mic-mute LED per capture hook */ +static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_led; + + if (!ucontrol) + return; + + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + spec->gpio_led &= ~0x10; + else + spec->gpio_led |= 0x10; + if (spec->gpio_led != oldval) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); +} + +static void alc269_fixup_hp_gpio_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x18 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x18 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook; + spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook; + spec->gpio_led = 0; + snd_hda_add_verbs(codec, gpio_init); + } +} + +static void alc_headset_mode_unplugged(struct hda_codec *codec) +{ + int val; + + switch (codec->vendor_id) { + case 0x10ec0255: + /* LDO and MISC control */ + alc_write_coef_idx(codec, 0x1b, 0x0c0b); + /* UAJ function set to menual mode */ + alc_write_coef_idx(codec, 0x45, 0xd089); + /* Direct Drive HP Amp control(Set to verb control)*/ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, val & ~(1<<14)); + /* Set MIC2 Vref gate with HP */ + alc_write_coef_idx(codec, 0x06, 0x6104); + /* Direct Drive HP Amp control */ + alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x1b, 0x0c0b); + alc_write_coef_idx(codec, 0x45, 0xc429); + val = alc_read_coef_idx(codec, 0x35); + alc_write_coef_idx(codec, 0x35, val & 0xbfff); + alc_write_coef_idx(codec, 0x06, 0x2104); + alc_write_coef_idx(codec, 0x1a, 0x0001); + alc_write_coef_idx(codec, 0x26, 0x0004); + alc_write_coef_idx(codec, 0x32, 0x42a3); + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x76, 0x000e); + alc_write_coef_idx(codec, 0x6c, 0x2400); + alc_write_coef_idx(codec, 0x18, 0x7308); + alc_write_coef_idx(codec, 0x6b, 0xc429); + break; + case 0x10ec0293: + /* SET Line1 JD to 0 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 6<<8); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | 0x0); + /* SET EN_OSW to 1 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | (1<<10) ); + /* Combo JD gating with LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | (1<<3)); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xc429); + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x15, 0x0d40); + alc_write_coef_idx(codec, 0xb7, 0x802b); + break; + } + codec_dbg(codec, "Headset jack set to unplugged mode.\n"); +} + + +static void alc_headset_mode_mic_in(struct hda_codec *codec, hda_nid_t hp_pin, + hda_nid_t mic_pin) +{ + int val; + + switch (codec->vendor_id) { + case 0x10ec0255: + alc_write_coef_idx(codec, 0x45, 0xc489); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_write_coefex_idx(codec, 0x57, 0x03, 0x8aa6); + /* Set MIC2 Vref gate to normal */ + alc_write_coef_idx(codec, 0x06, 0x6100); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + val = alc_read_coef_idx(codec, 0x35); + alc_write_coef_idx(codec, 0x35, val | 1<<14); + alc_write_coef_idx(codec, 0x06, 0x2100); + alc_write_coef_idx(codec, 0x1a, 0x0021); + alc_write_coef_idx(codec, 0x26, 0x008c); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0292: + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_write_coef_idx(codec, 0x19, 0xa208); + alc_write_coef_idx(codec, 0x2e, 0xacf0); + break; + case 0x10ec0293: + /* Set to TRS mode */ + alc_write_coef_idx(codec, 0x45, 0xc429); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + /* SET charge pump by verb */ + val = alc_read_coefex_idx(codec, 0x57, 0x05); + alc_write_coefex_idx(codec, 0x57, 0x05, (val & ~(1<<15|1<<13)) | (1<<15|1<<13)); + /* SET EN_OSW to 0 */ + val = alc_read_coefex_idx(codec, 0x57, 0x03); + alc_write_coefex_idx(codec, 0x57, 0x03, (val & ~(1<<10)) | 0x0); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0001); + snd_hda_set_pin_ctl_cache(codec, hp_pin, 0); + alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_write_coef_idx(codec, 0xb5, 0x1040); + val = alc_read_coef_idx(codec, 0xc3); + alc_write_coef_idx(codec, 0xc3, val | 1<<12); + snd_hda_set_pin_ctl_cache(codec, mic_pin, PIN_VREF50); + break; + } + codec_dbg(codec, "Headset jack set to mic-in mode.\n"); +} + +static void alc_headset_mode_default(struct hda_codec *codec) +{ + int val; + + switch (codec->vendor_id) { + case 0x10ec0255: + alc_write_coef_idx(codec, 0x45, 0xc089); + alc_write_coef_idx(codec, 0x45, 0xc489); + alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + alc_write_coef_idx(codec, 0x49, 0x0049); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x06, 0x2100); + alc_write_coef_idx(codec, 0x32, 0x4ea3); + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x76, 0x000e); + alc_write_coef_idx(codec, 0x6c, 0x2400); + alc_write_coef_idx(codec, 0x6b, 0xc429); + alc_write_coef_idx(codec, 0x18, 0x7308); + break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x000e); + /* Set to TRS type */ + alc_write_coef_idx(codec, 0x45, 0xC429); + /* Combo JD gating without LINE1-VREFO */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, (val & ~(1<<3)) | 0x0); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0041); + alc_write_coef_idx(codec, 0x15, 0x0d40); + alc_write_coef_idx(codec, 0xb7, 0x802b); + break; + } + codec_dbg(codec, "Headset jack set to headphone (default) mode.\n"); +} + +/* Iphone type */ +static void alc_headset_mode_ctia(struct hda_codec *codec) +{ + int val; + + switch (codec->vendor_id) { + case 0x10ec0255: + /* Set to CTIA type */ + alc_write_coef_idx(codec, 0x45, 0xd489); + alc_write_coef_idx(codec, 0x1b, 0x0c2b); + alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xd429); + alc_write_coef_idx(codec, 0x1b, 0x0c2b); + alc_write_coef_idx(codec, 0x32, 0x4ea3); + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x6b, 0xd429); + alc_write_coef_idx(codec, 0x76, 0x0008); + alc_write_coef_idx(codec, 0x18, 0x7388); + break; + case 0x10ec0293: + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xd429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0001); + alc_write_coef_idx(codec, 0x15, 0x0d60); + alc_write_coef_idx(codec, 0xc3, 0x0000); + break; + } + codec_dbg(codec, "Headset jack set to iPhone-style headset mode.\n"); +} + +/* Nokia type */ +static void alc_headset_mode_omtp(struct hda_codec *codec) +{ + int val; + + switch (codec->vendor_id) { + case 0x10ec0255: + /* Set to OMTP Type */ + alc_write_coef_idx(codec, 0x45, 0xe489); + alc_write_coef_idx(codec, 0x1b, 0x0c2b); + alc_write_coefex_idx(codec, 0x57, 0x03, 0x8ea6); + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xe429); + alc_write_coef_idx(codec, 0x1b, 0x0c2b); + alc_write_coef_idx(codec, 0x32, 0x4ea3); + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x6b, 0xe429); + alc_write_coef_idx(codec, 0x76, 0x0008); + alc_write_coef_idx(codec, 0x18, 0x7388); + break; + case 0x10ec0293: + /* Set to omtp type */ + alc_write_coef_idx(codec, 0x45, 0xe429); + /* SET Line1 JD to 1 */ + val = alc_read_coef_idx(codec, 0x10); + alc_write_coef_idx(codec, 0x10, (val & ~(7<<8)) | 7<<8); + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0001); + alc_write_coef_idx(codec, 0x15, 0x0d50); + alc_write_coef_idx(codec, 0xc3, 0x0000); + break; + } + codec_dbg(codec, "Headset jack set to Nokia-style headset mode.\n"); +} + +static void alc_determine_headset_type(struct hda_codec *codec) +{ + int val; + bool is_ctia = false; + struct alc_spec *spec = codec->spec; + + switch (codec->vendor_id) { + case 0x10ec0255: + /* combo jack auto switch control(Check type)*/ + alc_write_coef_idx(codec, 0x45, 0xd089); + /* combo jack auto switch control(Vref conteol) */ + alc_write_coef_idx(codec, 0x49, 0x0149); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0233: + case 0x10ec0283: + alc_write_coef_idx(codec, 0x45, 0xd029); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0292: + alc_write_coef_idx(codec, 0x6b, 0xd429); + msleep(300); + val = alc_read_coef_idx(codec, 0x6c); + is_ctia = (val & 0x001c) == 0x001c; + break; + case 0x10ec0293: + /* Combo Jack auto detect */ + val = alc_read_coef_idx(codec, 0x4a); + alc_write_coef_idx(codec, 0x4a, (val & 0xfff0) | 0x0008); + /* Set to ctia type */ + alc_write_coef_idx(codec, 0x45, 0xD429); + msleep(300); + val = alc_read_coef_idx(codec, 0x46); + is_ctia = (val & 0x0070) == 0x0070; + break; + case 0x10ec0668: + alc_write_coef_idx(codec, 0x11, 0x0001); + alc_write_coef_idx(codec, 0xb7, 0x802b); + alc_write_coef_idx(codec, 0x15, 0x0d60); + alc_write_coef_idx(codec, 0xc3, 0x0c00); + msleep(300); + val = alc_read_coef_idx(codec, 0xbe); + is_ctia = (val & 0x1c02) == 0x1c02; + break; + } + + codec_dbg(codec, "Headset jack detected iPhone-style headset: %s\n", + is_ctia ? "yes" : "no"); + spec->current_headset_type = is_ctia ? ALC_HEADSET_TYPE_CTIA : ALC_HEADSET_TYPE_OMTP; +} + +static void alc_update_headset_mode(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + + hda_nid_t mux_pin = spec->gen.imux_pins[spec->gen.cur_mux[0]]; + hda_nid_t hp_pin = spec->gen.autocfg.hp_pins[0]; + + int new_headset_mode; + + if (!snd_hda_jack_detect(codec, hp_pin)) + new_headset_mode = ALC_HEADSET_MODE_UNPLUGGED; + else if (mux_pin == spec->headset_mic_pin) + new_headset_mode = ALC_HEADSET_MODE_HEADSET; + else if (mux_pin == spec->headphone_mic_pin) + new_headset_mode = ALC_HEADSET_MODE_MIC; + else + new_headset_mode = ALC_HEADSET_MODE_HEADPHONE; + + if (new_headset_mode == spec->current_headset_mode) { + snd_hda_gen_update_outputs(codec); + return; + } + + switch (new_headset_mode) { + case ALC_HEADSET_MODE_UNPLUGGED: + alc_headset_mode_unplugged(codec); + spec->gen.hp_jack_present = false; + break; + case ALC_HEADSET_MODE_HEADSET: + if (spec->current_headset_type == ALC_HEADSET_TYPE_UNKNOWN) + alc_determine_headset_type(codec); + if (spec->current_headset_type == ALC_HEADSET_TYPE_CTIA) + alc_headset_mode_ctia(codec); + else if (spec->current_headset_type == ALC_HEADSET_TYPE_OMTP) + alc_headset_mode_omtp(codec); + spec->gen.hp_jack_present = true; + break; + case ALC_HEADSET_MODE_MIC: + alc_headset_mode_mic_in(codec, hp_pin, spec->headphone_mic_pin); + spec->gen.hp_jack_present = false; + break; + case ALC_HEADSET_MODE_HEADPHONE: + alc_headset_mode_default(codec); + spec->gen.hp_jack_present = true; + break; + } + if (new_headset_mode != ALC_HEADSET_MODE_MIC) { + snd_hda_set_pin_ctl_cache(codec, hp_pin, + AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); + if (spec->headphone_mic_pin) + snd_hda_set_pin_ctl_cache(codec, spec->headphone_mic_pin, + PIN_VREFHIZ); + } + spec->current_headset_mode = new_headset_mode; + + snd_hda_gen_update_outputs(codec); +} + +static void alc_update_headset_mode_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + alc_update_headset_mode(codec); +} + +static void alc_update_headset_jack_cb(struct hda_codec *codec, struct hda_jack_tbl *jack) +{ + struct alc_spec *spec = codec->spec; + spec->current_headset_type = ALC_HEADSET_TYPE_UNKNOWN; + snd_hda_gen_hp_automute(codec, jack); +} + +static void alc_probe_headset_mode(struct hda_codec *codec) +{ + int i; + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + + /* Find mic pins */ + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].is_headset_mic && !spec->headset_mic_pin) + spec->headset_mic_pin = cfg->inputs[i].pin; + if (cfg->inputs[i].is_headphone_mic && !spec->headphone_mic_pin) + spec->headphone_mic_pin = cfg->inputs[i].pin; + } + + spec->gen.cap_sync_hook = alc_update_headset_mode_hook; + spec->gen.automute_hook = alc_update_headset_mode; + spec->gen.hp_automute_hook = alc_update_headset_jack_cb; +} + +static void alc_fixup_headset_mode(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC | HDA_PINCFG_HEADPHONE_MIC; + break; + case HDA_FIXUP_ACT_PROBE: + alc_probe_headset_mode(codec); + break; + case HDA_FIXUP_ACT_INIT: + spec->current_headset_mode = 0; + alc_update_headset_mode(codec); + break; + } +} + +static void alc_fixup_headset_mode_no_hp_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + } + else + alc_fixup_headset_mode(codec, fix, action); +} + +static void alc255_set_default_jack_type(struct hda_codec *codec) +{ + /* Set to iphone type */ + alc_write_coef_idx(codec, 0x1b, 0x880b); + alc_write_coef_idx(codec, 0x45, 0xd089); + alc_write_coef_idx(codec, 0x1b, 0x080b); + alc_write_coef_idx(codec, 0x46, 0x0004); + alc_write_coef_idx(codec, 0x1b, 0x0c0b); + msleep(30); +} + +static void alc_fixup_headset_mode_alc255(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + alc255_set_default_jack_type(codec); + } + alc_fixup_headset_mode(codec, fix, action); +} + +static void alc_fixup_headset_mode_alc255_no_hp_mic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->parse_flags |= HDA_PINCFG_HEADSET_MIC; + alc255_set_default_jack_type(codec); + } + else + alc_fixup_headset_mode(codec, fix, action); +} + +static void alc_fixup_auto_mute_via_amp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->gen.auto_mute_via_amp = 1; + } +} + +static void alc_no_shutup(struct hda_codec *codec) +{ +} + +static void alc_fixup_no_shutup(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + spec->shutup = alc_no_shutup; + } +} + +static void alc_fixup_disable_aamix(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + struct alc_spec *spec = codec->spec; + /* Disable AA-loopback as it causes white noise */ + spec->gen.mixer_nid = 0; + } +} + +static unsigned int alc_power_filter_xps13(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + struct alc_spec *spec = codec->spec; + + /* Avoid pop noises when headphones are plugged in */ + if (spec->gen.hp_jack_present) + if (nid == codec->afg || nid == 0x02) + return AC_PWRST_D0; + return power_state; +} + +static void alc_fixup_dell_xps13(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PROBE) { + struct alc_spec *spec = codec->spec; + spec->shutup = alc_no_shutup; + codec->power_filter = alc_power_filter_xps13; + } +} + +static void alc_fixup_headset_mode_alc668(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + int val; + alc_write_coef_idx(codec, 0xc4, 0x8000); + val = alc_read_coef_idx(codec, 0xc2); + alc_write_coef_idx(codec, 0xc2, val & 0xfe); + snd_hda_set_pin_ctl_cache(codec, 0x18, 0); + } + alc_fixup_headset_mode(codec, fix, action); +} + +/* Returns the nid of the external mic input pin, or 0 if it cannot be found. */ +static int find_ext_mic_pin(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + hda_nid_t nid; + unsigned int defcfg; + int i; + + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].type != AUTO_PIN_MIC) + continue; + nid = cfg->inputs[i].pin; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (snd_hda_get_input_pin_attr(defcfg) == INPUT_PIN_ATTR_INT) + continue; + return nid; + } + + return 0; +} + +static void alc271_hp_gate_mic_jack(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PROBE) { + int mic_pin = find_ext_mic_pin(codec); + int hp_pin = spec->gen.autocfg.hp_pins[0]; + + if (snd_BUG_ON(!mic_pin || !hp_pin)) + return; + snd_hda_jack_set_gating_jack(codec, mic_pin, hp_pin); + } +} + +static void alc269_fixup_limit_int_mic_boost(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct alc_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + int i; + + /* The mic boosts on level 2 and 3 are too noisy + on the internal mic input. + Therefore limit the boost to 0 or 1. */ + + if (action != HDA_FIXUP_ACT_PROBE) + return; + + for (i = 0; i < cfg->num_inputs; i++) { + hda_nid_t nid = cfg->inputs[i].pin; + unsigned int defcfg; + if (cfg->inputs[i].type != AUTO_PIN_MIC) + continue; + defcfg = snd_hda_codec_get_pincfg(codec, nid); + if (snd_hda_get_input_pin_attr(defcfg) != INPUT_PIN_ATTR_INT) + continue; + + snd_hda_override_amp_caps(codec, nid, HDA_INPUT, + (0x00 << AC_AMPCAP_OFFSET_SHIFT) | + (0x01 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x2f << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); + } +} + +static void alc283_hp_automute_hook(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct alc_spec *spec = codec->spec; + int vref; + + msleep(200); + snd_hda_gen_hp_automute(codec, jack); + + vref = spec->gen.hp_jack_present ? PIN_VREF80 : 0; + + msleep(600); + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + vref); +} + +static void alc283_fixup_chromebook(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + int val; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_override_wcaps(codec, 0x03, 0); + /* Disable AA-loopback as it causes white noise */ + spec->gen.mixer_nid = 0; + break; + case HDA_FIXUP_ACT_INIT: + /* MIC2-VREF control */ + /* Set to manual mode */ + val = alc_read_coef_idx(codec, 0x06); + alc_write_coef_idx(codec, 0x06, val & ~0x000c); + /* Enable Line1 input control by verb */ + val = alc_read_coef_idx(codec, 0x1a); + alc_write_coef_idx(codec, 0x1a, val | (1 << 4)); + break; + } +} + +static void alc283_fixup_sense_combo_jack(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + int val; + switch (action) { - case ALC_FIXUP_ACT_BUILD: - spec->vmaster_mute.hook = alc269_fixup_mic2_mute_hook; - snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); - /* fallthru */ - case ALC_FIXUP_ACT_INIT: - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); + case HDA_FIXUP_ACT_PRE_PROBE: + spec->gen.hp_automute_hook = alc283_hp_automute_hook; + break; + case HDA_FIXUP_ACT_INIT: + /* MIC2-VREF control */ + /* Set to manual mode */ + val = alc_read_coef_idx(codec, 0x06); + alc_write_coef_idx(codec, 0x06, val & ~0x000c); break; } } +/* mute tablet speaker pin (0x14) via dock plugging in addition */ +static void asus_tx300_automute(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + snd_hda_gen_update_outputs(codec); + if (snd_hda_jack_detect(codec, 0x1b)) + spec->gen.mute_bits |= (1ULL << 0x14); +} + +static void alc282_fixup_asus_tx300(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + /* TX300 needs to set up GPIO2 for the speaker amp */ + static const struct hda_verb gpio2_verbs[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x04 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04 }, + { 0x01, AC_VERB_SET_GPIO_DATA, 0x04 }, + {} + }; + static const struct hda_pintbl dock_pins[] = { + { 0x1b, 0x21114000 }, /* dock speaker pin */ + {} + }; + struct snd_kcontrol *kctl; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_add_verbs(codec, gpio2_verbs); + snd_hda_apply_pincfgs(codec, dock_pins); + spec->gen.auto_mute_via_amp = 1; + spec->gen.automute_hook = asus_tx300_automute; + snd_hda_jack_detect_enable_callback(codec, 0x1b, + HDA_GEN_HP_EVENT, + snd_hda_gen_hp_automute); + break; + case HDA_FIXUP_ACT_BUILD: + /* this is a bit tricky; give more sane names for the main + * (tablet) speaker and the dock speaker, respectively + */ + kctl = snd_hda_find_mixer_ctl(codec, "Speaker Playback Switch"); + if (kctl) + strcpy(kctl->id.name, "Dock Speaker Playback Switch"); + kctl = snd_hda_find_mixer_ctl(codec, "Bass Speaker Playback Switch"); + if (kctl) + strcpy(kctl->id.name, "Speaker Playback Switch"); + break; + } +} + +static void alc290_fixup_mono_speakers(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + /* DAC node 0x03 is giving mono output. We therefore want to + make sure 0x14 (front speaker) and 0x15 (headphones) use the + stereo DAC, while leaving 0x17 (bass speaker) for node 0x03. */ + hda_nid_t conn1[2] = { 0x0c }; + snd_hda_override_conn_list(codec, 0x14, 1, conn1); + snd_hda_override_conn_list(codec, 0x15, 1, conn1); + } +} + +/* for hda_fixup_thinkpad_acpi() */ +#include "thinkpad_helper.c" enum { ALC269_FIXUP_SONY_VAIO, @@ -6002,31 +4239,71 @@ enum { ALC269_FIXUP_ASUS_G73JW, ALC269_FIXUP_LENOVO_EAPD, ALC275_FIXUP_SONY_HWEQ, + ALC275_FIXUP_SONY_DISABLE_AAMIX, ALC271_FIXUP_DMIC, ALC269_FIXUP_PCM_44K, ALC269_FIXUP_STEREO_DMIC, + ALC269_FIXUP_HEADSET_MIC, ALC269_FIXUP_QUANTA_MUTE, ALC269_FIXUP_LIFEBOOK, + ALC269_FIXUP_LIFEBOOK_EXTMIC, ALC269_FIXUP_AMIC, ALC269_FIXUP_DMIC, ALC269VB_FIXUP_AMIC, ALC269VB_FIXUP_DMIC, - ALC269_FIXUP_MIC2_MUTE_LED, + ALC269_FIXUP_HP_MUTE_LED, + ALC269_FIXUP_HP_MUTE_LED_MIC1, + ALC269_FIXUP_HP_MUTE_LED_MIC2, + ALC269_FIXUP_HP_GPIO_LED, ALC269_FIXUP_INV_DMIC, ALC269_FIXUP_LENOVO_DOCK, + ALC269_FIXUP_NO_SHUTUP, + ALC286_FIXUP_SONY_MIC_NO_PRESENCE, ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT, + ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, + ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + ALC269_FIXUP_HEADSET_MODE, + ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC, + ALC269_FIXUP_ASUS_X101_FUNC, + ALC269_FIXUP_ASUS_X101_VERB, + ALC269_FIXUP_ASUS_X101, + ALC271_FIXUP_AMIC_MIC2, + ALC271_FIXUP_HP_GATE_MIC_JACK, + ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572, + ALC269_FIXUP_ACER_AC700, + ALC269_FIXUP_LIMIT_INT_MIC_BOOST, + ALC269VB_FIXUP_ASUS_ZENBOOK, + ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A, + ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED, + ALC269VB_FIXUP_ORDISSIMO_EVE2, + ALC283_FIXUP_CHROME_BOOK, + ALC283_FIXUP_SENSE_COMBO_JACK, + ALC282_FIXUP_ASUS_TX300, + ALC283_FIXUP_INT_MIC, + ALC290_FIXUP_MONO_SPEAKERS, + ALC290_FIXUP_MONO_SPEAKERS_HSJACK, + ALC290_FIXUP_SUBWOOFER, + ALC290_FIXUP_SUBWOOFER_HSJACK, + ALC269_FIXUP_THINKPAD_ACPI, + ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC255_FIXUP_DELL2_MIC_NO_PRESENCE, + ALC255_FIXUP_HEADSET_MODE, + ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC, + ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + ALC292_FIXUP_TPT440_DOCK, }; -static const struct alc_fixup alc269_fixups[] = { +static const struct hda_fixup alc269_fixups[] = { [ALC269_FIXUP_SONY_VAIO] = { - .type = ALC_FIXUP_VERBS, - .v.verbs = (const struct hda_verb[]) { - {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREFGRD}, + .type = HDA_FIXUP_PINCTLS, + .v.pins = (const struct hda_pintbl[]) { + {0x19, PIN_VREFGRD}, {} } }, [ALC275_FIXUP_SONY_VAIO_GPIO2] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x01, AC_VERB_SET_GPIO_MASK, 0x04}, {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x04}, @@ -6037,7 +4314,7 @@ static const struct alc_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_SONY_VAIO }, [ALC269_FIXUP_DELL_M101Z] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* Enables internal speaker */ {0x20, AC_VERB_SET_COEF_INDEX, 13}, @@ -6046,50 +4323,60 @@ static const struct alc_fixup alc269_fixups[] = { } }, [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC269_FIXUP_ASUS_G73JW] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x99130111 }, /* subwoofer */ { } } }, [ALC269_FIXUP_LENOVO_EAPD] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} } }, [ALC275_FIXUP_SONY_HWEQ] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_hweq, .chained = true, .chain_id = ALC275_FIXUP_SONY_VAIO_GPIO2 }, + [ALC275_FIXUP_SONY_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC269_FIXUP_SONY_VAIO + }, [ALC271_FIXUP_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc271_fixup_dmic, }, [ALC269_FIXUP_PCM_44K] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_pcm_44k, .chained = true, .chain_id = ALC269_FIXUP_QUANTA_MUTE }, [ALC269_FIXUP_STEREO_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_stereo_dmic, }, + [ALC269_FIXUP_HEADSET_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_headset_mic, + }, [ALC269_FIXUP_QUANTA_MUTE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_quanta_mute, }, [ALC269_FIXUP_LIFEBOOK] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1a, 0x2101103f }, /* dock line-out */ { 0x1b, 0x23a11040 }, /* dock mic-in */ { } @@ -6097,9 +4384,16 @@ static const struct alc_fixup alc269_fixups[] = { .chained = true, .chain_id = ALC269_FIXUP_QUANTA_MUTE }, + [ALC269_FIXUP_LIFEBOOK_EXTMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1903c }, /* headset mic, with jack detect */ + { } + }, + }, [ALC269_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121401f }, /* HP out */ { 0x18, 0x01a19c20 }, /* mic */ @@ -6108,8 +4402,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x12, 0x99a3092f }, /* int-mic */ { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121401f }, /* HP out */ @@ -6118,8 +4412,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269VB_FIXUP_AMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6128,8 +4422,8 @@ static const struct alc_fixup alc269_fixups[] = { }, }, [ALC269VB_FIXUP_DMIC] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x12, 0x99a3092f }, /* int-mic */ { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ @@ -6137,17 +4431,33 @@ static const struct alc_fixup alc269_fixups[] = { { } }, }, - [ALC269_FIXUP_MIC2_MUTE_LED] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc269_fixup_mic2_mute, + [ALC269_FIXUP_HP_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_mute_led, + }, + [ALC269_FIXUP_HP_MUTE_LED_MIC1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_mute_led_mic1, + }, + [ALC269_FIXUP_HP_MUTE_LED_MIC2] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_mute_led_mic2, + }, + [ALC269_FIXUP_HP_GPIO_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_hp_gpio_led, }, [ALC269_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC269_FIXUP_NO_SHUTUP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_no_shutup, + }, [ALC269_FIXUP_LENOVO_DOCK] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x19, 0x23a11040 }, /* dock mic */ { 0x1b, 0x2121103f }, /* dock headphone */ { } @@ -6156,31 +4466,407 @@ static const struct alc_fixup alc269_fixups[] = { .chain_id = ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT }, [ALC269_FIXUP_PINCFG_NO_HP_TO_LINEOUT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc269_fixup_pincfg_no_hp_to_lineout, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, + [ALC269_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, + [ALC269_FIXUP_DELL2_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x21014020 }, /* dock line out */ + { 0x19, 0x21a19030 }, /* dock mic */ + { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC + }, + [ALC269_FIXUP_DELL3_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC + }, + [ALC269_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode, + }, + [ALC269_FIXUP_HEADSET_MODE_NO_HP_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_no_hp_mic, + }, + [ALC286_FIXUP_SONY_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MIC + }, + [ALC269_FIXUP_ASUS_X101_FUNC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_x101_headset_mic, + }, + [ALC269_FIXUP_ASUS_X101_VERB] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0310}, + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_ASUS_X101_FUNC + }, + [ALC269_FIXUP_ASUS_X101] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x04a1182c }, /* Headset mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_ASUS_X101_VERB + }, + [ALC271_FIXUP_AMIC_MIC2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x14, 0x99130110 }, /* speaker */ + { 0x19, 0x01a19c20 }, /* mic */ + { 0x1b, 0x99a7012f }, /* int-mic */ + { 0x21, 0x0121401f }, /* HP out */ + { } + }, + }, + [ALC271_FIXUP_HP_GATE_MIC_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc271_hp_gate_mic_jack, + .chained = true, + .chain_id = ALC271_FIXUP_AMIC_MIC2, + }, + [ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC271_FIXUP_HP_GATE_MIC_JACK, + }, + [ALC269_FIXUP_ACER_AC700] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x99a3092f }, /* int-mic */ + { 0x14, 0x99130110 }, /* speaker */ + { 0x18, 0x03a11c20 }, /* mic */ + { 0x1e, 0x0346101e }, /* SPDIF1 */ + { 0x21, 0x0321101f }, /* HP out */ + { } + }, + .chained = true, + .chain_id = ALC271_FIXUP_DMIC, + }, + [ALC269_FIXUP_LIMIT_INT_MIC_BOOST] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269_FIXUP_THINKPAD_ACPI, + }, + [ALC269VB_FIXUP_ASUS_ZENBOOK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269VB_FIXUP_DMIC, + }, + [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* class-D output amp +5dB */ + { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 }, + { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 }, + {} + }, + .chained = true, + .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK, + }, + [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc269_fixup_limit_int_mic_boost, + .chained = true, + .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC1, + }, + [ALC269VB_FIXUP_ORDISSIMO_EVE2] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x12, 0x99a3092f }, /* int-mic */ + { 0x18, 0x03a11d20 }, /* mic */ + { 0x19, 0x411111f0 }, /* Unused bogus pin */ + { } + }, + }, + [ALC283_FIXUP_CHROME_BOOK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc283_fixup_chromebook, + }, + [ALC283_FIXUP_SENSE_COMBO_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc283_fixup_sense_combo_jack, + .chained = true, + .chain_id = ALC283_FIXUP_CHROME_BOOK, + }, + [ALC282_FIXUP_ASUS_TX300] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc282_fixup_asus_tx300, + }, + [ALC283_FIXUP_INT_MIC] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x20, AC_VERB_SET_COEF_INDEX, 0x1a}, + {0x20, AC_VERB_SET_PROC_COEF, 0x0011}, + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST + }, + [ALC290_FIXUP_SUBWOOFER_HSJACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x17, 0x90170112 }, /* subwoofer */ + { } + }, + .chained = true, + .chain_id = ALC290_FIXUP_MONO_SPEAKERS_HSJACK, + }, + [ALC290_FIXUP_SUBWOOFER] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x17, 0x90170112 }, /* subwoofer */ + { } + }, + .chained = true, + .chain_id = ALC290_FIXUP_MONO_SPEAKERS, + }, + [ALC290_FIXUP_MONO_SPEAKERS] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc290_fixup_mono_speakers, + }, + [ALC290_FIXUP_MONO_SPEAKERS_HSJACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc290_fixup_mono_speakers, + .chained = true, + .chain_id = ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + }, + [ALC269_FIXUP_THINKPAD_ACPI] = { + .type = HDA_FIXUP_FUNC, + .v.func = hda_fixup_thinkpad_acpi, + }, + [ALC255_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { 0x1a, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC255_FIXUP_HEADSET_MODE + }, + [ALC255_FIXUP_DELL2_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC + }, + [ALC255_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc255, + }, + [ALC255_FIXUP_HEADSET_MODE_NO_HP_MIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc255_no_hp_mic, + }, + [ALC293_FIXUP_DELL1_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x18, 0x01a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1a, 0x01a1913c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_HEADSET_MODE + }, + [ALC292_FIXUP_TPT440_DOCK] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x16, 0x21211010 }, /* dock headphone */ + { 0x19, 0x21a11010 }, /* dock mic */ + { } + }, + .chained = true, + .chain_id = ALC269_FIXUP_LIMIT_INT_MIC_BOOST }, }; static const struct snd_pci_quirk alc269_fixup_tbl[] = { + SND_PCI_QUIRK(0x1025, 0x0283, "Acer TravelMate 8371", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x029b, "Acer 1810TZ", ALC269_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0349, "Acer AOD260", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_MIC2_MUTE_LED), - SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_DMIC), - SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_DMIC), + SND_PCI_QUIRK(0x1025, 0x047c, "Acer AC700", ALC269_FIXUP_ACER_AC700), + SND_PCI_QUIRK(0x1025, 0x0740, "Acer AO725", ALC271_FIXUP_HP_GATE_MIC_JACK), + SND_PCI_QUIRK(0x1025, 0x0742, "Acer AO756", ALC271_FIXUP_HP_GATE_MIC_JACK), + SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), + SND_PCI_QUIRK(0x1025, 0x0775, "Acer Aspire E1-572", ALC271_FIXUP_HP_GATE_MIC_JACK_E1_572), + SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), + SND_PCI_QUIRK(0x1028, 0x05bd, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05be, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c7, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05c9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05ca, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05cb, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05da, "Dell Vostro 5460", ALC290_FIXUP_SUBWOOFER), + SND_PCI_QUIRK(0x1028, 0x05de, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05e0, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05e9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05ea, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05eb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05ec, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05ed, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05ee, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f3, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f4, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f5, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f6, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f8, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05f9, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05fb, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0606, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0608, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0609, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0613, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0614, "Dell Inspiron 3135", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0615, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x0616, "Dell Vostro 5470", ALC290_FIXUP_SUBWOOFER_HSJACK), + SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK), + SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0668, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0669, "Dell", ALC255_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0684, "Dell", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x15cc, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x15cd, "Dell X5 Precision", ALC269_FIXUP_DELL2_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2), + SND_PCI_QUIRK(0x103c, 0x18e6, "HP", ALC269_FIXUP_HP_GPIO_LED), + SND_PCI_QUIRK(0x103c, 0x1973, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x1983, "HP Pavilion", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x218b, "HP", ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED), + /* ALC282 */ + SND_PCI_QUIRK(0x103c, 0x220d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x220e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x220f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2210, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2211, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2212, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2213, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2214, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2266, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2267, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2268, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2269, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x226f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22a0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22bf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c1, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cd, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22ce, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22cf, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22d0, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + /* ALC290 */ + SND_PCI_QUIRK(0x103c, 0x2260, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2261, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2262, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2263, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2264, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2265, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x227f, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2280, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2281, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2282, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2289, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228c, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228d, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x228e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c5, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c6, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c8, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c3, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x22c4, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2334, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2335, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2336, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), + SND_PCI_QUIRK_VENDOR(0x103c, "HP", ALC269_FIXUP_HP_MUTE_LED), + SND_PCI_QUIRK(0x1043, 0x103f, "ASUS TX300", ALC282_FIXUP_ASUS_TX300), + SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK), + SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW), SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x1c23, "Asus X55U", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS P901", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS S101", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005", ALC269_FIXUP_STEREO_DMIC), + SND_PCI_QUIRK(0x1043, 0x8516, "ASUS X101CH", ALC269_FIXUP_ASUS_X101), + SND_PCI_QUIRK(0x104d, 0x90b5, "Sony VAIO Pro 11", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x104d, 0x90b6, "Sony VAIO Pro 13", ALC286_FIXUP_SONY_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x104d, 0x9073, "Sony VAIO", ALC275_FIXUP_SONY_VAIO_GPIO2), SND_PCI_QUIRK(0x104d, 0x907b, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), SND_PCI_QUIRK(0x104d, 0x9084, "Sony VAIO", ALC275_FIXUP_SONY_HWEQ), + SND_PCI_QUIRK(0x104d, 0x9099, "Sony VAIO S13", ALC275_FIXUP_SONY_DISABLE_AAMIX), SND_PCI_QUIRK_VENDOR(0x104d, "Sony VAIO", ALC269_FIXUP_SONY_VAIO), - SND_PCI_QUIRK(0x1028, 0x0470, "Dell M101z", ALC269_FIXUP_DELL_M101Z), - SND_PCI_QUIRK_VENDOR(0x1025, "Acer Aspire", ALC271_FIXUP_DMIC), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook", ALC269_FIXUP_LIFEBOOK), + SND_PCI_QUIRK(0x10cf, 0x1845, "Lifebook U904", ALC269_FIXUP_LIFEBOOK_EXTMIC), SND_PCI_QUIRK(0x17aa, 0x20f2, "Thinkpad SL410/510", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x215e, "Thinkpad L512", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21b8, "Thinkpad Edge 14", ALC269_FIXUP_SKU_IGNORE), @@ -6188,10 +4874,25 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x21e9, "Thinkpad Edge 15", ALC269_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x17aa, 0x21f6, "Thinkpad T530", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fa, "Thinkpad X230", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x21f3, "Thinkpad T430", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x21fb, "Thinkpad T430s", ALC269_FIXUP_LENOVO_DOCK), SND_PCI_QUIRK(0x17aa, 0x2203, "Thinkpad X230 Tablet", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2208, "Thinkpad T431s", ALC269_FIXUP_LENOVO_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220c, "Thinkpad T440s", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x220e, "Thinkpad T440p", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2210, "Thinkpad T540p", ALC292_FIXUP_TPT440_DOCK), + SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), + SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC), + SND_PCI_QUIRK(0x17aa, 0x5026, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), + SND_PCI_QUIRK(0x17aa, 0x5109, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST), SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_FIXUP_PCM_44K), SND_PCI_QUIRK(0x17aa, 0x9e54, "LENOVO NB", ALC269_FIXUP_LENOVO_EAPD), + SND_PCI_QUIRK_VENDOR(0x17aa, "Thinkpad", ALC269_FIXUP_THINKPAD_ACPI), + SND_PCI_QUIRK(0x1b7d, 0xa831, "Ordissimo EVE2 ", ALC269VB_FIXUP_ORDISSIMO_EVE2), /* Also known as Malata PC-B1303 */ #if 0 /* Below is a quirk table taken from the old code. @@ -6244,16 +4945,161 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc269_fixup_models[] = { +static const struct hda_model_fixup alc269_fixup_models[] = { {.id = ALC269_FIXUP_AMIC, .name = "laptop-amic"}, {.id = ALC269_FIXUP_DMIC, .name = "laptop-dmic"}, {.id = ALC269_FIXUP_STEREO_DMIC, .name = "alc269-dmic"}, {.id = ALC271_FIXUP_DMIC, .name = "alc271-dmic"}, {.id = ALC269_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC269_FIXUP_HEADSET_MIC, .name = "headset-mic"}, {.id = ALC269_FIXUP_LENOVO_DOCK, .name = "lenovo-dock"}, + {.id = ALC269_FIXUP_HP_GPIO_LED, .name = "hp-gpio-led"}, + {.id = ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {.id = ALC269_FIXUP_DELL2_MIC_NO_PRESENCE, .name = "dell-headset-dock"}, + {.id = ALC283_FIXUP_CHROME_BOOK, .name = "alc283-dac-wcaps"}, + {.id = ALC283_FIXUP_SENSE_COMBO_JACK, .name = "alc283-sense-combo"}, + {.id = ALC292_FIXUP_TPT440_DOCK, .name = "tpt440-dock"}, {} }; +static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60140}, + {0x14, 0x90170110}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211020}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x90170140}, + {0x18, 0x40000000}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41163b05}, + {0x1e, 0x411111f0}, + {0x21, 0x0321102f}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60160}, + {0x14, 0x90170130}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60160}, + {0x14, 0x90170140}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211050}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60170}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0255, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60170}, + {0x14, 0x90170130}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211040}), + SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x17, 0x40020008}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40e00001}, + {0x1e, 0x411111f0}, + {0x21, 0x0321101f}), + SND_HDA_PIN_QUIRK(0x10ec0283, 0x1028, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x90a60160}, + {0x14, 0x90170120}, + {0x17, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}, + {0x21, 0x02211030}), + SND_HDA_PIN_QUIRK(0x10ec0292, 0x1028, "Dell", ALC269_FIXUP_DELL3_MIC_NO_PRESENCE, + {0x12, 0x90a60140}, + {0x13, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x40000000}, + {0x13, 0x90a60140}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x21014020}, + {0x18, 0x411111f0}, + {0x19, 0x21a19030}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0293, 0x1028, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE, + {0x12, 0x40000000}, + {0x13, 0x90a60140}, + {0x14, 0x90170110}, + {0x15, 0x0221401f}, + {0x16, 0x411111f0}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40700001}, + {0x1e, 0x411111f0}), + {} +}; static void alc269_fill_coef(struct hda_codec *codec) { @@ -6311,24 +5157,32 @@ static int patch_alc269(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.shared_mic_vref_pin = 0x18; - alc_pick_fixup(codec, alc269_fixup_models, + snd_hda_pick_fixup(codec, alc269_fixup_models, alc269_fixup_tbl, alc269_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_pin_fixup(codec, alc269_pin_fixup_tbl, alc269_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); - if (codec->vendor_id == 0x10ec0269) { + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + + switch (codec->vendor_id) { + case 0x10ec0269: spec->codec_variant = ALC269_TYPE_ALC269VA; switch (alc_get_coef0(codec) & 0x00f0) { case 0x0010: - if (codec->bus->pci->subsystem_vendor == 0x1025 && + if (codec->bus->pci && + codec->bus->pci->subsystem_vendor == 0x1025 && spec->cdefine.platform_type == 1) err = alc_codec_rename(codec, "ALC271X"); spec->codec_variant = ALC269_TYPE_ALC269VB; break; case 0x0020: - if (codec->bus->pci->subsystem_vendor == 0x17aa && + if (codec->bus->pci && + codec->bus->pci->subsystem_vendor == 0x17aa && codec->bus->pci->subsystem_device == 0x21f3) err = alc_codec_rename(codec, "ALC3202"); spec->codec_variant = ALC269_TYPE_ALC269VC; @@ -6343,6 +5197,43 @@ static int patch_alc269(struct hda_codec *codec) goto error; spec->init_hook = alc269_fill_coef; alc269_fill_coef(codec); + break; + + case 0x10ec0280: + case 0x10ec0290: + spec->codec_variant = ALC269_TYPE_ALC280; + break; + case 0x10ec0282: + spec->codec_variant = ALC269_TYPE_ALC282; + spec->shutup = alc282_shutup; + spec->init_hook = alc282_init; + break; + case 0x10ec0233: + case 0x10ec0283: + spec->codec_variant = ALC269_TYPE_ALC283; + spec->shutup = alc283_shutup; + spec->init_hook = alc283_init; + break; + case 0x10ec0284: + case 0x10ec0292: + spec->codec_variant = ALC269_TYPE_ALC284; + break; + case 0x10ec0285: + case 0x10ec0293: + spec->codec_variant = ALC269_TYPE_ALC285; + break; + case 0x10ec0286: + case 0x10ec0288: + spec->codec_variant = ALC269_TYPE_ALC286; + break; + case 0x10ec0255: + spec->codec_variant = ALC269_TYPE_ALC255; + break; + } + + if (snd_hda_codec_read(codec, 0x51, 0, AC_VERB_PARAMETERS, 0) == 0x10ec5505) { + spec->has_alc5505_dsp = 1; + spec->init_hook = alc5505_dsp_init; } /* automatic parse from the BIOS config */ @@ -6350,20 +5241,18 @@ static int patch_alc269(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog && spec->gen.beep_nid) set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; #ifdef CONFIG_PM + codec->patch_ops.suspend = alc269_suspend; codec->patch_ops.resume = alc269_resume; #endif - spec->shutup = alc269_shutup; + if (!spec->shutup) + spec->shutup = alc269_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6389,60 +5278,72 @@ enum { ALC861_FIXUP_AMP_VREF_0F, ALC861_FIXUP_NO_JACK_DETECT, ALC861_FIXUP_ASUS_A6RP, + ALC660_FIXUP_ASUS_W7J, }; /* On some laptops, VREF of pin 0x0f is abused for controlling the main amp */ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { struct alc_spec *spec = codec->spec; unsigned int val; - if (action != ALC_FIXUP_ACT_INIT) + if (action != HDA_FIXUP_ACT_INIT) return; - val = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + val = snd_hda_codec_get_pin_target(codec, 0x0f); if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) val |= AC_PINCTL_IN_EN; val |= AC_PINCTL_VREF_50; snd_hda_set_pin_ctl(codec, 0x0f, val); - spec->keep_vref_in_automute = 1; + spec->gen.keep_vref_in_automute = 1; } /* suppress the jack-detection */ static void alc_fixup_no_jack_detect(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) + if (action == HDA_FIXUP_ACT_PRE_PROBE) codec->no_jack_detect = 1; } -static const struct alc_fixup alc861_fixups[] = { +static const struct hda_fixup alc861_fixups[] = { [ALC861_FIXUP_FSC_AMILO_PI1505] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x0b, 0x0221101f }, /* HP */ { 0x0f, 0x90170310 }, /* speaker */ { } } }, [ALC861_FIXUP_AMP_VREF_0F] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861_fixup_asus_amp_vref_0f, }, [ALC861_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_no_jack_detect, }, [ALC861_FIXUP_ASUS_A6RP] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861_fixup_asus_amp_vref_0f, .chained = true, .chain_id = ALC861_FIXUP_NO_JACK_DETECT, + }, + [ALC660_FIXUP_ASUS_W7J] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + /* ASUS W7J needs a magic pin setup on unused NID 0x10 + * for enabling outputs + */ + {0x10, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x24}, + { } + }, } }; static const struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1043, 0x1253, "ASUS W7J", ALC660_FIXUP_ASUS_W7J), + SND_PCI_QUIRK(0x1043, 0x1263, "ASUS Z35HL", ALC660_FIXUP_ASUS_W7J), SND_PCI_QUIRK(0x1043, 0x1393, "ASUS A6Rp", ALC861_FIXUP_ASUS_A6RP), SND_PCI_QUIRK_VENDOR(0x1043, "ASUS laptop", ALC861_FIXUP_AMP_VREF_0F), SND_PCI_QUIRK(0x1462, 0x7254, "HP DX2200", ALC861_FIXUP_NO_JACK_DETECT), @@ -6464,28 +5365,25 @@ static int patch_alc861(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.beep_nid = 0x23; - alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc861_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) - goto error; + if (!spec->gen.no_analog) set_beep_amp(spec, 0x23, 0, HDA_OUTPUT); - } codec->patch_ops = alc_patch_ops; #ifdef CONFIG_PM spec->power_hook = alc_power_eapd; #endif - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6515,17 +5413,17 @@ enum { /* exclude VREF80 */ static void alc861vd_fixup_dallas(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action == ALC_FIXUP_ACT_PRE_PROBE) { - snd_hda_override_pin_caps(codec, 0x18, 0x00001714); - snd_hda_override_pin_caps(codec, 0x19, 0x0000171c); + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_override_pin_caps(codec, 0x18, 0x00000734); + snd_hda_override_pin_caps(codec, 0x19, 0x0000073c); } } -static const struct alc_fixup alc861vd_fixups[] = { +static const struct hda_fixup alc861vd_fixups[] = { [ALC660VD_FIX_ASUS_GPIO1] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { /* reset GPIO1 */ {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, @@ -6535,7 +5433,7 @@ static const struct alc_fixup alc861vd_fixups[] = { } }, [ALC861VD_FIX_DALLAS] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc861vd_fixup_dallas, }, }; @@ -6559,27 +5457,24 @@ static int patch_alc861vd(struct hda_codec *codec) return err; spec = codec->spec; + spec->gen.beep_nid = 0x23; - alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); /* automatic parse from the BIOS config */ err = alc861vd_parse_auto_config(codec); if (err < 0) goto error; - if (!spec->no_analog) { - err = snd_hda_attach_beep_device(codec, 0x23); - if (err < 0) - goto error; + if (!spec->gen.no_analog) set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); - } codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -6612,7 +5507,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) const hda_nid_t *ssids; if (codec->vendor_id == 0x10ec0272 || codec->vendor_id == 0x10ec0663 || - codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670) + codec->vendor_id == 0x10ec0665 || codec->vendor_id == 0x10ec0670 || + codec->vendor_id == 0x10ec0671) ssids = alc663_ssids; else ssids = alc662_ssids; @@ -6620,21 +5516,85 @@ static int alc662_parse_auto_config(struct hda_codec *codec) } static void alc272_fixup_mario(struct hda_codec *codec, - const struct alc_fixup *fix, int action) + const struct hda_fixup *fix, int action) { - if (action != ALC_FIXUP_ACT_PROBE) + if (action != HDA_FIXUP_ACT_PRE_PROBE) return; if (snd_hda_override_amp_caps(codec, 0x2, HDA_OUTPUT, (0x3b << AC_AMPCAP_OFFSET_SHIFT) | (0x3b << AC_AMPCAP_NUM_STEPS_SHIFT) | (0x03 << AC_AMPCAP_STEP_SIZE_SHIFT) | (0 << AC_AMPCAP_MUTE_SHIFT))) - printk(KERN_WARNING - "hda_codec: failed to override amp caps for NID 0x2\n"); + codec_warn(codec, "failed to override amp caps for NID 0x2\n"); +} + +static const struct snd_pcm_chmap_elem asus_pcm_2_1_chmaps[] = { + { .channels = 2, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, + { .channels = 4, + .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, + SNDRV_CHMAP_NA, SNDRV_CHMAP_LFE } }, /* LFE only on right */ + { } +}; + +/* override the 2.1 chmap */ +static void alc_fixup_bass_chmap(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_BUILD) { + struct alc_spec *spec = codec->spec; + spec->gen.pcm_rec[0].stream[0].chmap = asus_pcm_2_1_chmaps; + } +} + +/* turn on/off mute LED per vmaster hook */ +static void alc662_led_gpio1_mute_hook(void *private_data, int enabled) +{ + struct hda_codec *codec = private_data; + struct alc_spec *spec = codec->spec; + unsigned int oldval = spec->gpio_led; + + if (enabled) + spec->gpio_led &= ~0x01; + else + spec->gpio_led |= 0x01; + if (spec->gpio_led != oldval) + snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, + spec->gpio_led); +} + +/* avoid D3 for keeping GPIO up */ +static unsigned int gpio_led_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + struct alc_spec *spec = codec->spec; + if (nid == codec->afg && power_state == AC_PWRST_D3 && spec->gpio_led) + return AC_PWRST_D0; + return power_state; +} + +static void alc662_fixup_led_gpio1(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct alc_spec *spec = codec->spec; + static const struct hda_verb gpio_init[] = { + { 0x01, AC_VERB_SET_GPIO_MASK, 0x01 }, + { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x01 }, + {} + }; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook; + spec->gpio_led = 0; + snd_hda_add_verbs(codec, gpio_init); + codec->power_filter = gpio_led_power_filter; + } } enum { ALC662_FIXUP_ASPIRE, + ALC662_FIXUP_LED_GPIO1, ALC662_FIXUP_IDEAPAD, ALC272_FIXUP_MARIO, ALC662_FIXUP_CZC_P10T, @@ -6651,41 +5611,56 @@ enum { ALC662_FIXUP_NO_JACK_DETECT, ALC662_FIXUP_ZOTAC_Z68, ALC662_FIXUP_INV_DMIC, + ALC668_FIXUP_DELL_MIC_NO_PRESENCE, + ALC668_FIXUP_HEADSET_MODE, + ALC662_FIXUP_BASS_MODE4_CHMAP, + ALC662_FIXUP_BASS_16, + ALC662_FIXUP_BASS_1A, + ALC662_FIXUP_BASS_CHMAP, + ALC668_FIXUP_AUTO_MUTE, + ALC668_FIXUP_DELL_DISABLE_AAMIX, + ALC668_FIXUP_DELL_XPS13, }; -static const struct alc_fixup alc662_fixups[] = { +static const struct hda_fixup alc662_fixups[] = { [ALC662_FIXUP_ASPIRE] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x15, 0x99130112 }, /* subwoofer */ { } } }, + [ALC662_FIXUP_LED_GPIO1] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc662_fixup_led_gpio1, + }, [ALC662_FIXUP_IDEAPAD] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x17, 0x99130112 }, /* subwoofer */ { } - } + }, + .chained = true, + .chain_id = ALC662_FIXUP_LED_GPIO1, }, [ALC272_FIXUP_MARIO] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc272_fixup_mario, }, [ALC662_FIXUP_CZC_P10T] = { - .type = ALC_FIXUP_VERBS, + .type = HDA_FIXUP_VERBS, .v.verbs = (const struct hda_verb[]) { {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0}, {} } }, [ALC662_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_sku_ignore, }, [ALC662_FIXUP_HP_RP5800] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x0221201f }, /* HP out */ { } }, @@ -6693,8 +5668,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE1] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19c20 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6705,8 +5680,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE2] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x18, 0x01a19820 }, /* mic */ { 0x19, 0x99a3092f }, /* int-mic */ @@ -6717,8 +5692,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE3] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121441f }, /* HP */ { 0x18, 0x01a19840 }, /* mic */ @@ -6730,8 +5705,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE4] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x16, 0x99130111 }, /* speaker */ { 0x18, 0x01a19840 }, /* mic */ @@ -6743,8 +5718,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE5] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x0121441f }, /* HP */ { 0x16, 0x99130111 }, /* speaker */ @@ -6756,8 +5731,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE6] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x15, 0x01211420 }, /* HP2 */ { 0x18, 0x01a19840 }, /* mic */ @@ -6769,8 +5744,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE7] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x17, 0x99130111 }, /* speaker */ { 0x18, 0x01a19840 }, /* mic */ @@ -6783,8 +5758,8 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_ASUS_MODE8] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x14, 0x99130110 }, /* speaker */ { 0x12, 0x99a30970 }, /* int-mic */ { 0x15, 0x01214020 }, /* HP */ @@ -6797,29 +5772,103 @@ static const struct alc_fixup alc662_fixups[] = { .chain_id = ALC662_FIXUP_SKU_IGNORE }, [ALC662_FIXUP_NO_JACK_DETECT] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_no_jack_detect, }, [ALC662_FIXUP_ZOTAC_Z68] = { - .type = ALC_FIXUP_PINS, - .v.pins = (const struct alc_pincfg[]) { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { { 0x1b, 0x02214020 }, /* Front HP */ { } } }, [ALC662_FIXUP_INV_DMIC] = { - .type = ALC_FIXUP_FUNC, + .type = HDA_FIXUP_FUNC, .v.func = alc_fixup_inv_dmic_0x12, }, + [ALC668_FIXUP_DELL_XPS13] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_dell_xps13, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_DISABLE_AAMIX + }, + [ALC668_FIXUP_DELL_DISABLE_AAMIX] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_disable_aamix, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, + [ALC668_FIXUP_AUTO_MUTE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_auto_mute_via_amp, + .chained = true, + .chain_id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE + }, + [ALC668_FIXUP_DELL_MIC_NO_PRESENCE] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x19, 0x03a1913d }, /* use as headphone mic, without its own jack detect */ + { 0x1b, 0x03a1113c }, /* use as headset mic, without its own jack detect */ + { } + }, + .chained = true, + .chain_id = ALC668_FIXUP_HEADSET_MODE + }, + [ALC668_FIXUP_HEADSET_MODE] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_headset_mode_alc668, + }, + [ALC662_FIXUP_BASS_MODE4_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + .chained = true, + .chain_id = ALC662_FIXUP_ASUS_MODE4 + }, + [ALC662_FIXUP_BASS_16] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x16, 0x80106111}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, + }, + [ALC662_FIXUP_BASS_1A] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + {0x1a, 0x80106111}, /* bass speaker */ + {} + }, + .chained = true, + .chain_id = ALC662_FIXUP_BASS_CHMAP, + }, + [ALC662_FIXUP_BASS_CHMAP] = { + .type = HDA_FIXUP_FUNC, + .v.func = alc_fixup_bass_chmap, + }, }; static const struct snd_pci_quirk alc662_fixup_tbl[] = { SND_PCI_QUIRK(0x1019, 0x9087, "ECS", ALC662_FIXUP_ASUS_MODE2), + SND_PCI_QUIRK(0x1025, 0x022f, "Acer Aspire One", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x0308, "Acer Aspire 8942G", ALC662_FIXUP_ASPIRE), SND_PCI_QUIRK(0x1025, 0x031c, "Gateway NV79", ALC662_FIXUP_SKU_IGNORE), SND_PCI_QUIRK(0x1025, 0x0349, "eMachines eM250", ALC662_FIXUP_INV_DMIC), + SND_PCI_QUIRK(0x1025, 0x034a, "Gateway LT27", ALC662_FIXUP_INV_DMIC), SND_PCI_QUIRK(0x1025, 0x038b, "Acer Aspire 8943G", ALC662_FIXUP_ASPIRE), + SND_PCI_QUIRK(0x1028, 0x05d8, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x05db, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x060a, "Dell XPS 13", ALC668_FIXUP_DELL_XPS13), + SND_PCI_QUIRK(0x1028, 0x0625, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0626, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0696, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), + SND_PCI_QUIRK(0x1028, 0x0698, "Dell", ALC668_FIXUP_DELL_MIC_NO_PRESENCE), SND_PCI_QUIRK(0x103c, 0x1632, "HP RP5800", ALC662_FIXUP_HP_RP5800), + SND_PCI_QUIRK(0x1043, 0x11cd, "Asus N550", ALC662_FIXUP_BASS_1A), + SND_PCI_QUIRK(0x1043, 0x1477, "ASUS N56VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), + SND_PCI_QUIRK(0x1043, 0x15a7, "ASUS UX51VZH", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x1b73, "ASUS N55SF", ALC662_FIXUP_BASS_16), + SND_PCI_QUIRK(0x1043, 0x1bf3, "ASUS N76VZ", ALC662_FIXUP_BASS_MODE4_CHMAP), SND_PCI_QUIRK(0x1043, 0x8469, "ASUS mobo", ALC662_FIXUP_NO_JACK_DETECT), SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_FIXUP_ASUS_MODE2), SND_PCI_QUIRK(0x144d, 0xc051, "Samsung R720", ALC662_FIXUP_IDEAPAD), @@ -6888,7 +5937,7 @@ static const struct snd_pci_quirk alc662_fixup_tbl[] = { {} }; -static const struct alc_model_fixup alc662_fixup_models[] = { +static const struct hda_model_fixup alc662_fixup_models[] = { {.id = ALC272_FIXUP_MARIO, .name = "mario"}, {.id = ALC662_FIXUP_ASUS_MODE1, .name = "asus-mode1"}, {.id = ALC662_FIXUP_ASUS_MODE2, .name = "asus-mode2"}, @@ -6899,6 +5948,71 @@ static const struct alc_model_fixup alc662_fixup_models[] = { {.id = ALC662_FIXUP_ASUS_MODE7, .name = "asus-mode7"}, {.id = ALC662_FIXUP_ASUS_MODE8, .name = "asus-mode8"}, {.id = ALC662_FIXUP_INV_DMIC, .name = "inv-dmic"}, + {.id = ALC668_FIXUP_DELL_MIC_NO_PRESENCE, .name = "dell-headset-multi"}, + {} +}; + +static const struct snd_hda_pin_quirk alc662_pin_fixup_tbl[] = { + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30130}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30140}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x99a30150}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x411111f0}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x03011020}, + {0x18, 0x40000008}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x41000001}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}), + SND_HDA_PIN_QUIRK(0x10ec0668, 0x1028, "Dell XPS 15", ALC668_FIXUP_AUTO_MUTE, + {0x12, 0x90a60130}, + {0x14, 0x90170110}, + {0x15, 0x0321101f}, + {0x16, 0x40000000}, + {0x18, 0x411111f0}, + {0x19, 0x411111f0}, + {0x1a, 0x411111f0}, + {0x1b, 0x411111f0}, + {0x1d, 0x40d6832d}, + {0x1e, 0x411111f0}, + {0x1f, 0x411111f0}), {} }; @@ -6949,16 +6063,21 @@ static int patch_alc662(struct hda_codec *codec) spec->init_hook = alc662_fill_coef; alc662_fill_coef(codec); - alc_pick_fixup(codec, alc662_fixup_models, + snd_hda_pick_fixup(codec, alc662_fixup_models, alc662_fixup_tbl, alc662_fixups); - alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); + snd_hda_pick_pin_fixup(codec, alc662_pin_fixup_tbl, alc662_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); alc_auto_parse_customize_define(codec); + if (has_cdefine_beep(codec)) + spec->gen.beep_nid = 0x01; + if ((alc_get_coef0(codec) & (1 << 14)) && - codec->bus->pci->subsystem_vendor == 0x1025 && + codec->bus->pci && codec->bus->pci->subsystem_vendor == 0x1025 && spec->cdefine.platform_type == 1) { - if (alc_codec_rename(codec, "ALC272X") < 0) + err = alc_codec_rename(codec, "ALC272X"); + if (err < 0) goto error; } @@ -6967,10 +6086,7 @@ static int patch_alc662(struct hda_codec *codec) if (err < 0) goto error; - if (!spec->no_analog && has_cdefine_beep(codec)) { - err = snd_hda_attach_beep_device(codec, 0x1); - if (err < 0) - goto error; + if (!spec->gen.no_analog && spec->gen.beep_nid) { switch (codec->vendor_id) { case 0x10ec0662: set_beep_amp(spec, 0x0b, 0x05, HDA_INPUT); @@ -6978,6 +6094,7 @@ static int patch_alc662(struct hda_codec *codec) case 0x10ec0272: case 0x10ec0663: case 0x10ec0665: + case 0x10ec0668: set_beep_amp(spec, 0x0b, 0x04, HDA_INPUT); break; case 0x10ec0273: @@ -6989,7 +6106,7 @@ static int patch_alc662(struct hda_codec *codec) codec->patch_ops = alc_patch_ops; spec->shutup = alc_eapd_shutup; - alc_apply_fixup(codec, ALC_FIXUP_ACT_PROBE); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; @@ -7035,6 +6152,10 @@ static int patch_alc680(struct hda_codec *codec) */ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0221, .name = "ALC221", .patch = patch_alc269 }, + { .id = 0x10ec0231, .name = "ALC231", .patch = patch_alc269 }, + { .id = 0x10ec0233, .name = "ALC233", .patch = patch_alc269 }, + { .id = 0x10ec0235, .name = "ALC233", .patch = patch_alc269 }, + { .id = 0x10ec0255, .name = "ALC255", .patch = patch_alc269 }, { .id = 0x10ec0260, .name = "ALC260", .patch = patch_alc260 }, { .id = 0x10ec0262, .name = "ALC262", .patch = patch_alc262 }, { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, @@ -7047,7 +6168,13 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0280, .name = "ALC280", .patch = patch_alc269 }, { .id = 0x10ec0282, .name = "ALC282", .patch = patch_alc269 }, { .id = 0x10ec0283, .name = "ALC283", .patch = patch_alc269 }, + { .id = 0x10ec0284, .name = "ALC284", .patch = patch_alc269 }, + { .id = 0x10ec0285, .name = "ALC285", .patch = patch_alc269 }, + { .id = 0x10ec0286, .name = "ALC286", .patch = patch_alc269 }, + { .id = 0x10ec0288, .name = "ALC288", .patch = patch_alc269 }, { .id = 0x10ec0290, .name = "ALC290", .patch = patch_alc269 }, + { .id = 0x10ec0292, .name = "ALC292", .patch = patch_alc269 }, + { .id = 0x10ec0293, .name = "ALC293", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, @@ -7061,8 +6188,12 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { .patch = patch_alc662 }, { .id = 0x10ec0663, .name = "ALC663", .patch = patch_alc662 }, { .id = 0x10ec0665, .name = "ALC665", .patch = patch_alc662 }, + { .id = 0x10ec0667, .name = "ALC667", .patch = patch_alc662 }, + { .id = 0x10ec0668, .name = "ALC668", .patch = patch_alc662 }, { .id = 0x10ec0670, .name = "ALC670", .patch = patch_alc662 }, + { .id = 0x10ec0671, .name = "ALC671", .patch = patch_alc662 }, { .id = 0x10ec0680, .name = "ALC680", .patch = patch_alc680 }, + { .id = 0x10ec0867, .name = "ALC891", .patch = patch_alc882 }, { .id = 0x10ec0880, .name = "ALC880", .patch = patch_alc880 }, { .id = 0x10ec0882, .name = "ALC882", .patch = patch_alc882 }, { .id = 0x10ec0883, .name = "ALC883", .patch = patch_alc882 }, @@ -7078,6 +6209,7 @@ static const struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, { .id = 0x10ec0899, .name = "ALC898", .patch = patch_alc882 }, + { .id = 0x10ec0900, .name = "ALC1150", .patch = patch_alc882 }, {} /* terminator */ }; diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 6679a5095e5..3208ad69583 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c @@ -236,7 +236,7 @@ static int si3054_init(struct hda_codec *codec) } while ((val & SI3054_MEI_READY) != SI3054_MEI_READY && wait_count--); if((val&SI3054_MEI_READY) != SI3054_MEI_READY) { - snd_printk(KERN_ERR "si3054: cannot initialize. EXT MID = %04x\n", val); + codec_err(codec, "si3054: cannot initialize. EXT MID = %04x\n", val); /* let's pray that this is no fatal error */ /* return -EACCES; */ } @@ -247,7 +247,8 @@ static int si3054_init(struct hda_codec *codec) SET_REG(codec, SI3054_LINE_CFG1,0x200); if((GET_REG(codec,SI3054_LINE_STATUS) & (1<<6)) == 0) { - snd_printd("Link Frame Detect(FDT) is not ready (line status: %04x)\n", + codec_dbg(codec, + "Link Frame Detect(FDT) is not ready (line status: %04x)\n", GET_REG(codec,SI3054_LINE_STATUS)); } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 770013ff556..3744ea4e843 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -31,7 +31,6 @@ #include <linux/dmi.h> #include <linux/module.h> #include <sound/core.h> -#include <sound/asoundef.h> #include <sound/jack.h> #include <sound/tlv.h> #include "hda_codec.h" @@ -39,18 +38,14 @@ #include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" +#include "hda_generic.h" enum { - STAC_VREF_EVENT = 1, - STAC_INSERT_EVENT, + STAC_VREF_EVENT = 8, STAC_PWR_EVENT, - STAC_HP_EVENT, - STAC_LO_EVENT, - STAC_MIC_EVENT, }; enum { - STAC_AUTO, STAC_REF, STAC_9200_OQO, STAC_9200_DELL_D21, @@ -66,11 +61,11 @@ enum { STAC_9200_M4, STAC_9200_M4_2, STAC_9200_PANASONIC, + STAC_9200_EAPD_INIT, STAC_9200_MODELS }; enum { - STAC_9205_AUTO, STAC_9205_REF, STAC_9205_DELL_M42, STAC_9205_DELL_M43, @@ -80,7 +75,6 @@ enum { }; enum { - STAC_92HD73XX_AUTO, STAC_92HD73XX_NO_JD, /* no jack-detection */ STAC_92HD73XX_REF, STAC_92HD73XX_INTEL, @@ -89,11 +83,11 @@ enum { STAC_DELL_M6_BOTH, STAC_DELL_EQ, STAC_ALIENWARE_M17X, + STAC_92HD89XX_HP_FRONT_JACK, STAC_92HD73XX_MODELS }; enum { - STAC_92HD83XXX_AUTO, STAC_92HD83XXX_REF, STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, @@ -104,12 +98,15 @@ enum { STAC_92HD83XXX_HP_LED, STAC_92HD83XXX_HP_INV_LED, STAC_92HD83XXX_HP_MIC_LED, + STAC_HP_LED_GPIO10, STAC_92HD83XXX_HEADSET_JACK, + STAC_92HD83XXX_HP, + STAC_HP_ENVY_BASS, + STAC_HP_BNB13_EQ, STAC_92HD83XXX_MODELS }; enum { - STAC_92HD71BXX_AUTO, STAC_92HD71BXX_REF, STAC_DELL_M4_1, STAC_DELL_M4_2, @@ -118,12 +115,19 @@ enum { STAC_HP_DV4, STAC_HP_DV5, STAC_HP_HDX, - STAC_HP_DV4_1222NR, + STAC_92HD71BXX_HP, + STAC_92HD71BXX_NO_DMIC, + STAC_92HD71BXX_NO_SMUX, STAC_92HD71BXX_MODELS }; enum { - STAC_925x_AUTO, + STAC_92HD95_HP_LED, + STAC_92HD95_HP_BASS, + STAC_92HD95_MODELS +}; + +enum { STAC_925x_REF, STAC_M1, STAC_M1_2, @@ -136,7 +140,6 @@ enum { }; enum { - STAC_922X_AUTO, STAC_D945_REF, STAC_D945GTP3, STAC_D945GTP5, @@ -145,67 +148,46 @@ enum { STAC_INTEL_MAC_V3, STAC_INTEL_MAC_V4, STAC_INTEL_MAC_V5, - STAC_INTEL_MAC_AUTO, /* This model is selected if no module parameter - * is given, one of the above models will be - * chosen according to the subsystem id. */ - /* for backward compatibility */ - STAC_MACMINI, - STAC_MACBOOK, - STAC_MACBOOK_PRO_V1, - STAC_MACBOOK_PRO_V2, - STAC_IMAC_INTEL, - STAC_IMAC_INTEL_20, + STAC_INTEL_MAC_AUTO, STAC_ECS_202, STAC_922X_DELL_D81, STAC_922X_DELL_D82, STAC_922X_DELL_M81, STAC_922X_DELL_M82, + STAC_922X_INTEL_MAC_GPIO, STAC_922X_MODELS }; enum { - STAC_927X_AUTO, STAC_D965_REF_NO_JD, /* no jack-detection */ STAC_D965_REF, STAC_D965_3ST, STAC_D965_5ST, STAC_D965_5ST_NO_FP, + STAC_D965_VERBS, STAC_DELL_3ST, STAC_DELL_BIOS, + STAC_DELL_BIOS_AMIC, + STAC_DELL_BIOS_SPDIF, + STAC_927X_DELL_DMIC, STAC_927X_VOLKNOB, STAC_927X_MODELS }; enum { - STAC_9872_AUTO, STAC_9872_VAIO, STAC_9872_MODELS }; -struct sigmatel_mic_route { - hda_nid_t pin; - signed char mux_idx; - signed char dmux_idx; -}; - -#define MAX_PINS_NUM 16 -#define MAX_ADCS_NUM 4 -#define MAX_DMICS_NUM 4 - struct sigmatel_spec { - struct snd_kcontrol_new *mixers[4]; - unsigned int num_mixers; + struct hda_gen_spec gen; - int board_config; unsigned int eapd_switch: 1; - unsigned int surr_switch: 1; - unsigned int alt_switch: 1; - unsigned int hp_detect: 1; - unsigned int spdif_mute: 1; - unsigned int check_volume_offset:1; - unsigned int auto_mic:1; unsigned int linear_tone_beep:1; unsigned int headset_jack:1; /* 4-pin headset jack (hp + mono mic) */ + unsigned int volknob_init:1; /* special volume-knob initialization */ + unsigned int powerdown_adcs:1; + unsigned int have_spdif_mux:1; /* gpio lines */ unsigned int eapd_mask; @@ -217,15 +199,17 @@ struct sigmatel_spec { unsigned int gpio_led_polarity; unsigned int vref_mute_led_nid; /* pin NID for mute-LED vref control */ unsigned int vref_led; + int default_polarity; unsigned int mic_mute_led_gpio; /* capture mute LED GPIO */ - bool mic_mute_led_on; /* current mic mute state */ + unsigned int mic_enabled; /* current mic mute state (bitmask) */ /* stream */ unsigned int stream_delay; /* analog loopback */ const struct snd_kcontrol_new *aloopback_ctl; + unsigned int aloopback; unsigned char aloopback_mask; unsigned char aloopback_shift; @@ -233,647 +217,820 @@ struct sigmatel_spec { unsigned int power_map_bits; unsigned int num_pwrs; const hda_nid_t *pwr_nids; - const hda_nid_t *dac_list; - - /* playback */ - struct hda_input_mux *mono_mux; - unsigned int cur_mmux; - struct hda_multi_out multiout; - hda_nid_t dac_nids[5]; - hda_nid_t hp_dacs[5]; - hda_nid_t speaker_dacs[5]; - - int volume_offset; - - /* capture */ - const hda_nid_t *adc_nids; - unsigned int num_adcs; - const hda_nid_t *mux_nids; - unsigned int num_muxes; - const hda_nid_t *dmic_nids; - unsigned int num_dmics; - const hda_nid_t *dmux_nids; - unsigned int num_dmuxes; - const hda_nid_t *smux_nids; - unsigned int num_smuxes; - unsigned int num_analog_muxes; - - const unsigned long *capvols; /* amp-volume attr: HDA_COMPOSE_AMP_VAL() */ - const unsigned long *capsws; /* amp-mute attr: HDA_COMPOSE_AMP_VAL() */ - unsigned int num_caps; /* number of capture volume/switch elements */ - - struct sigmatel_mic_route ext_mic; - struct sigmatel_mic_route int_mic; - struct sigmatel_mic_route dock_mic; + unsigned int active_adcs; - const char * const *spdif_labels; - - hda_nid_t dig_in_nid; - hda_nid_t mono_nid; + /* beep widgets */ hda_nid_t anabeep_nid; - hda_nid_t digbeep_nid; - - /* pin widgets */ - const hda_nid_t *pin_nids; - unsigned int num_pins; - - /* codec specific stuff */ - const struct hda_verb *init; - const struct snd_kcontrol_new *mixer; - - /* capture source */ - struct hda_input_mux *dinput_mux; - unsigned int cur_dmux[2]; - struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - struct hda_input_mux *sinput_mux; - unsigned int cur_smux[2]; - unsigned int cur_amux; - hda_nid_t *amp_nids; - unsigned int powerdown_adcs; - - /* i/o switches */ - unsigned int io_switch[2]; - unsigned int clfe_swap; - hda_nid_t line_switch; /* shared line-in for input and output */ - hda_nid_t mic_switch; /* shared mic-in for input and output */ - hda_nid_t hp_switch; /* NID of HP as line-out */ - unsigned int aloopback; - - struct hda_pcm pcm_rec[2]; /* PCM information */ - - /* dynamic controls and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - struct hda_input_mux private_dimux; - struct hda_input_mux private_imux; - struct hda_input_mux private_smux; - struct hda_input_mux private_mono_mux; - /* auto spec */ - unsigned auto_pin_cnt; - hda_nid_t auto_pin_nids[MAX_PINS_NUM]; - unsigned auto_adc_cnt; - hda_nid_t auto_adc_nids[MAX_ADCS_NUM]; - hda_nid_t auto_mux_nids[MAX_ADCS_NUM]; - hda_nid_t auto_dmux_nids[MAX_ADCS_NUM]; - unsigned long auto_capvols[MAX_ADCS_NUM]; - unsigned auto_dmic_cnt; - hda_nid_t auto_dmic_nids[MAX_DMICS_NUM]; - - struct hda_vmaster_mute_hook vmaster_mute; + /* SPDIF-out mux */ + const char * const *spdif_labels; + struct hda_input_mux spdif_mux; + unsigned int cur_smux[2]; }; #define AC_VERB_IDT_SET_POWER_MAP 0x7ec #define AC_VERB_IDT_GET_POWER_MAP 0xfec -static const hda_nid_t stac9200_adc_nids[1] = { - 0x03, -}; - -static const hda_nid_t stac9200_mux_nids[1] = { - 0x0c, -}; - -static const hda_nid_t stac9200_dac_nids[1] = { - 0x02, -}; - static const hda_nid_t stac92hd73xx_pwr_nids[8] = { 0x0a, 0x0b, 0x0c, 0xd, 0x0e, 0x0f, 0x10, 0x11 }; -static const hda_nid_t stac92hd73xx_slave_dig_outs[2] = { - 0x26, 0, -}; - -static const hda_nid_t stac92hd73xx_adc_nids[2] = { - 0x1a, 0x1b -}; - -#define STAC92HD73XX_NUM_DMICS 2 -static const hda_nid_t stac92hd73xx_dmic_nids[STAC92HD73XX_NUM_DMICS + 1] = { - 0x13, 0x14, 0 +static const hda_nid_t stac92hd83xxx_pwr_nids[7] = { + 0x0a, 0x0b, 0x0c, 0xd, 0x0e, + 0x0f, 0x10 }; -#define STAC92HD73_DAC_COUNT 5 - -static const hda_nid_t stac92hd73xx_mux_nids[2] = { - 0x20, 0x21, +static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { + 0x0a, 0x0d, 0x0f }; -static const hda_nid_t stac92hd73xx_dmux_nids[2] = { - 0x20, 0x21, -}; -static const hda_nid_t stac92hd73xx_smux_nids[2] = { - 0x22, 0x23, -}; +/* + * PCM hooks + */ +static void stac_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + if (action == HDA_GEN_PCM_ACT_OPEN && spec->stream_delay) + msleep(spec->stream_delay); +} -#define STAC92HD73XX_NUM_CAPS 2 -static const unsigned long stac92hd73xx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x20, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), -}; -#define stac92hd73xx_capsws stac92hd73xx_capvols +static void stac_capture_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + int i, idx = 0; -#define STAC92HD83_DAC_COUNT 3 + if (!spec->powerdown_adcs) + return; -static const hda_nid_t stac92hd83xxx_pwr_nids[7] = { - 0x0a, 0x0b, 0x0c, 0xd, 0x0e, - 0x0f, 0x10 -}; + for (i = 0; i < spec->gen.num_all_adcs; i++) { + if (spec->gen.all_adcs[i] == hinfo->nid) { + idx = i; + break; + } + } -static const hda_nid_t stac92hd83xxx_slave_dig_outs[2] = { - 0x1e, 0, -}; + switch (action) { + case HDA_GEN_PCM_ACT_OPEN: + msleep(40); + snd_hda_codec_write(codec, hinfo->nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + spec->active_adcs |= (1 << idx); + break; + case HDA_GEN_PCM_ACT_CLOSE: + snd_hda_codec_write(codec, hinfo->nid, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + spec->active_adcs &= ~(1 << idx); + break; + } +} -static const hda_nid_t stac92hd83xxx_dmic_nids[] = { - 0x11, 0x20, -}; +/* + * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a + * funky external mute control using GPIO pins. + */ -static const hda_nid_t stac92hd71bxx_pwr_nids[3] = { - 0x0a, 0x0d, 0x0f -}; +static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, + unsigned int dir_mask, unsigned int data) +{ + unsigned int gpiostate, gpiomask, gpiodir; -static const hda_nid_t stac92hd71bxx_adc_nids[2] = { - 0x12, 0x13, -}; + codec_dbg(codec, "%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data); -static const hda_nid_t stac92hd71bxx_mux_nids[2] = { - 0x1a, 0x1b -}; + gpiostate = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); -static const hda_nid_t stac92hd71bxx_dmux_nids[2] = { - 0x1c, 0x1d, -}; + gpiomask = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_MASK, 0); + gpiomask |= mask; -static const hda_nid_t stac92hd71bxx_smux_nids[2] = { - 0x24, 0x25, -}; + gpiodir = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DIRECTION, 0); + gpiodir |= dir_mask; -#define STAC92HD71BXX_NUM_DMICS 2 -static const hda_nid_t stac92hd71bxx_dmic_nids[STAC92HD71BXX_NUM_DMICS + 1] = { - 0x18, 0x19, 0 -}; + /* Configure GPIOx as CMOS */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); -static const hda_nid_t stac92hd71bxx_dmic_5port_nids[STAC92HD71BXX_NUM_DMICS] = { - 0x18, 0 -}; + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_SET_GPIO_MASK, gpiomask); + snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ -static const hda_nid_t stac92hd71bxx_slave_dig_outs[2] = { - 0x22, 0 -}; + msleep(1); -#define STAC92HD71BXX_NUM_CAPS 2 -static const unsigned long stac92hd71bxx_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), -}; -#define stac92hd71bxx_capsws stac92hd71bxx_capvols + snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ +} -static const hda_nid_t stac925x_adc_nids[1] = { - 0x03, -}; +/* hook for controlling mic-mute LED GPIO */ +static void stac_capture_led_hook(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int mask; + bool cur_mute, prev_mute; -static const hda_nid_t stac925x_mux_nids[1] = { - 0x0f, -}; + if (!kcontrol || !ucontrol) + return; -static const hda_nid_t stac925x_dac_nids[1] = { - 0x02, -}; + mask = 1U << snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + prev_mute = !spec->mic_enabled; + if (ucontrol->value.integer.value[0] || + ucontrol->value.integer.value[1]) + spec->mic_enabled |= mask; + else + spec->mic_enabled &= ~mask; + cur_mute = !spec->mic_enabled; + if (cur_mute != prev_mute) { + if (cur_mute) + spec->gpio_data |= spec->mic_mute_led_gpio; + else + spec->gpio_data &= ~spec->mic_mute_led_gpio; + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + } +} -#define STAC925X_NUM_DMICS 1 -static const hda_nid_t stac925x_dmic_nids[STAC925X_NUM_DMICS + 1] = { - 0x15, 0 -}; +static int stac_vrefout_set(struct hda_codec *codec, + hda_nid_t nid, unsigned int new_vref) +{ + int error, pinctl; -static const hda_nid_t stac925x_dmux_nids[1] = { - 0x14, -}; + codec_dbg(codec, "%s, nid %x ctl %x\n", __func__, nid, new_vref); + pinctl = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); -static const unsigned long stac925x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_OUTPUT), -}; -static const unsigned long stac925x_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), -}; + if (pinctl < 0) + return pinctl; -static const hda_nid_t stac922x_adc_nids[2] = { - 0x06, 0x07, -}; + pinctl &= 0xff; + pinctl &= ~AC_PINCTL_VREFEN; + pinctl |= (new_vref & AC_PINCTL_VREFEN); -static const hda_nid_t stac922x_mux_nids[2] = { - 0x12, 0x13, -}; + error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl); + if (error < 0) + return error; -#define STAC922X_NUM_CAPS 2 -static const unsigned long stac922x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), -}; -#define stac922x_capsws stac922x_capvols + return 1; +} -static const hda_nid_t stac927x_slave_dig_outs[2] = { - 0x1f, 0, -}; +/* prevent codec AFG to D3 state when vref-out pin is used for mute LED */ +/* this hook is set in stac_setup_gpio() */ +static unsigned int stac_vref_led_power_filter(struct hda_codec *codec, + hda_nid_t nid, + unsigned int power_state) +{ + if (nid == codec->afg && power_state == AC_PWRST_D3) + return AC_PWRST_D1; + return snd_hda_gen_path_power_filter(codec, nid, power_state); +} -static const hda_nid_t stac927x_adc_nids[3] = { - 0x07, 0x08, 0x09 -}; +/* update mute-LED accoring to the master switch */ +static void stac_update_led_status(struct hda_codec *codec, int enabled) +{ + struct sigmatel_spec *spec = codec->spec; + int muted = !enabled; -static const hda_nid_t stac927x_mux_nids[3] = { - 0x15, 0x16, 0x17 -}; + if (!spec->gpio_led) + return; -static const hda_nid_t stac927x_smux_nids[1] = { - 0x21, -}; + /* LED state is inverted on these systems */ + if (spec->gpio_led_polarity) + muted = !muted; -static const hda_nid_t stac927x_dac_nids[6] = { - 0x02, 0x03, 0x04, 0x05, 0x06, 0 -}; + if (!spec->vref_mute_led_nid) { + if (muted) + spec->gpio_data |= spec->gpio_led; + else + spec->gpio_data &= ~spec->gpio_led; + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + } else { + spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; + stac_vrefout_set(codec, spec->vref_mute_led_nid, + spec->vref_led); + } +} -static const hda_nid_t stac927x_dmux_nids[1] = { - 0x1b, -}; +/* vmaster hook to update mute LED */ +static void stac_vmaster_hook(void *private_data, int val) +{ + stac_update_led_status(private_data, val); +} -#define STAC927X_NUM_DMICS 2 -static const hda_nid_t stac927x_dmic_nids[STAC927X_NUM_DMICS + 1] = { - 0x13, 0x14, 0 -}; +/* automute hook to handle GPIO mute and EAPD updates */ +static void stac_update_outputs(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; -#define STAC927X_NUM_CAPS 3 -static const unsigned long stac927x_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x19, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, HDA_INPUT), -}; -static const unsigned long stac927x_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), -}; + if (spec->gpio_mute) + spec->gen.master_mute = + !(snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); -static const char * const stac927x_spdif_labels[5] = { - "Digital Playback", "ADAT", "Analog Mux 1", - "Analog Mux 2", "Analog Mux 3" -}; + snd_hda_gen_update_outputs(codec); -static const hda_nid_t stac9205_adc_nids[2] = { - 0x12, 0x13 -}; + if (spec->eapd_mask && spec->eapd_switch) { + unsigned int val = spec->gpio_data; + if (spec->gen.speaker_muted) + val &= ~spec->eapd_mask; + else + val |= spec->eapd_mask; + if (spec->gpio_data != val) { + spec->gpio_data = val; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, + val); + } + } +} -static const hda_nid_t stac9205_mux_nids[2] = { - 0x19, 0x1a -}; +static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, + bool enable, bool do_write) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int idx, val; -static const hda_nid_t stac9205_dmux_nids[1] = { - 0x1d, -}; + for (idx = 0; idx < spec->num_pwrs; idx++) { + if (spec->pwr_nids[idx] == nid) + break; + } + if (idx >= spec->num_pwrs) + return; -static const hda_nid_t stac9205_smux_nids[1] = { - 0x21, -}; + idx = 1 << idx; -#define STAC9205_NUM_DMICS 2 -static const hda_nid_t stac9205_dmic_nids[STAC9205_NUM_DMICS + 1] = { - 0x17, 0x18, 0 -}; + val = spec->power_map_bits; + if (enable) + val &= ~idx; + else + val |= idx; -#define STAC9205_NUM_CAPS 2 -static const unsigned long stac9205_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_INPUT), - HDA_COMPOSE_AMP_VAL(0x1c, 3, 0, HDA_INPUT), -}; -static const unsigned long stac9205_capsws[] = { - HDA_COMPOSE_AMP_VAL(0x1d, 3, 0, HDA_OUTPUT), - HDA_COMPOSE_AMP_VAL(0x1e, 3, 0, HDA_OUTPUT), -}; + /* power down unused output ports */ + if (val != spec->power_map_bits) { + spec->power_map_bits = val; + if (do_write) + snd_hda_codec_write(codec, codec->afg, 0, + AC_VERB_IDT_SET_POWER_MAP, val); + } +} -static const hda_nid_t stac9200_pin_nids[8] = { - 0x08, 0x09, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, -}; +/* update power bit per jack plug/unplug */ +static void jack_update_power(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + struct sigmatel_spec *spec = codec->spec; + int i; -static const hda_nid_t stac925x_pin_nids[8] = { - 0x07, 0x08, 0x0a, 0x0b, - 0x0c, 0x0d, 0x10, 0x11, -}; + if (!spec->num_pwrs) + return; -static const hda_nid_t stac922x_pin_nids[10] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x15, 0x1b, -}; + if (jack && jack->nid) { + stac_toggle_power_map(codec, jack->nid, + snd_hda_jack_detect(codec, jack->nid), + true); + return; + } -static const hda_nid_t stac92hd73xx_pin_nids[13] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x22, 0x23 -}; + /* update all jacks */ + for (i = 0; i < spec->num_pwrs; i++) { + hda_nid_t nid = spec->pwr_nids[i]; + jack = snd_hda_jack_tbl_get(codec, nid); + if (!jack || !jack->action) + continue; + if (jack->action == STAC_PWR_EVENT || + jack->action <= HDA_GEN_LAST_EVENT) + stac_toggle_power_map(codec, nid, + snd_hda_jack_detect(codec, nid), + false); + } -#define STAC92HD71BXX_NUM_PINS 13 -static const hda_nid_t stac92hd71bxx_pin_nids_4port[STAC92HD71BXX_NUM_PINS] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x00, - 0x00, 0x14, 0x18, 0x19, 0x1e, - 0x1f, 0x20, 0x27 -}; -static const hda_nid_t stac92hd71bxx_pin_nids_6port[STAC92HD71BXX_NUM_PINS] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x14, 0x18, 0x19, 0x1e, - 0x1f, 0x20, 0x27 -}; + snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP, + spec->power_map_bits); +} -static const hda_nid_t stac927x_pin_nids[14] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, - 0x14, 0x21, 0x22, 0x23, -}; +static void stac_hp_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + snd_hda_gen_hp_automute(codec, jack); + jack_update_power(codec, jack); +} -static const hda_nid_t stac9205_pin_nids[12] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x14, 0x16, 0x17, 0x18, - 0x21, 0x22, -}; +static void stac_line_automute(struct hda_codec *codec, + struct hda_jack_tbl *jack) +{ + snd_hda_gen_line_automute(codec, jack); + jack_update_power(codec, jack); +} -static int stac92xx_dmux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static void stac_mic_autoswitch(struct hda_codec *codec, + struct hda_jack_tbl *jack) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->dinput_mux, uinfo); + snd_hda_gen_mic_autoswitch(codec, jack); + jack_update_power(codec, jack); } -static int stac92xx_dmux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static void stac_vref_event(struct hda_codec *codec, struct hda_jack_tbl *event) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int data; - ucontrol->value.enumerated.item[0] = spec->cur_dmux[dmux_idx]; - return 0; + data = snd_hda_codec_read(codec, codec->afg, 0, + AC_VERB_GET_GPIO_DATA, 0); + /* toggle VREF state based on GPIOx status */ + snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, + !!(data & (1 << event->private_data))); } -static int stac92xx_dmux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* initialize the power map and enable the power event to jacks that + * haven't been assigned to automute + */ +static void stac_init_power_map(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int dmux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + int i; - return snd_hda_input_mux_put(codec, spec->dinput_mux, ucontrol, - spec->dmux_nids[dmux_idx], &spec->cur_dmux[dmux_idx]); + for (i = 0; i < spec->num_pwrs; i++) { + hda_nid_t nid = spec->pwr_nids[i]; + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + def_conf = get_defcfg_connect(def_conf); + if (snd_hda_jack_tbl_get(codec, nid)) + continue; + if (def_conf == AC_JACK_PORT_COMPLEX && + !(spec->vref_mute_led_nid == nid || + is_jack_detectable(codec, nid))) { + snd_hda_jack_detect_enable_callback(codec, nid, + STAC_PWR_EVENT, + jack_update_power); + } else { + if (def_conf == AC_JACK_PORT_NONE) + stac_toggle_power_map(codec, nid, false, false); + else + stac_toggle_power_map(codec, nid, true, false); + } + } } -static int stac92xx_smux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +/* + */ + +static inline bool get_int_hint(struct hda_codec *codec, const char *key, + int *valp) +{ + return !snd_hda_get_int_hint(codec, key, valp); +} + +/* override some hints from the hwdep entry */ +static void stac_store_hints(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->sinput_mux, uinfo); + int val; + + if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { + spec->eapd_mask = spec->gpio_dir = spec->gpio_data = + spec->gpio_mask; + } + if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) + spec->gpio_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) + spec->gpio_dir &= spec->gpio_mask; + if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) + spec->eapd_mask &= spec->gpio_mask; + if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) + spec->gpio_mute &= spec->gpio_mask; + val = snd_hda_get_bool_hint(codec, "eapd_switch"); + if (val >= 0) + spec->eapd_switch = val; } -static int stac92xx_smux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* + * loopback controls + */ + +#define stac_aloopback_info snd_ctl_boolean_mono_info + +static int stac_aloopback_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct sigmatel_spec *spec = codec->spec; - unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx]; + ucontrol->value.integer.value[0] = !!(spec->aloopback & + (spec->aloopback_mask << idx)); return 0; } -static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_aloopback_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *smux = &spec->private_smux; - unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - int err, val; - hda_nid_t nid; + unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + unsigned int dac_mode; + unsigned int val, idx_val; - err = snd_hda_input_mux_put(codec, spec->sinput_mux, ucontrol, - spec->smux_nids[smux_idx], &spec->cur_smux[smux_idx]); - if (err < 0) - return err; + idx_val = spec->aloopback_mask << idx; + if (ucontrol->value.integer.value[0]) + val = spec->aloopback | idx_val; + else + val = spec->aloopback & ~idx_val; + if (spec->aloopback == val) + return 0; - if (spec->spdif_mute) { - if (smux_idx == 0) - nid = spec->multiout.dig_out_nid; - else - nid = codec->slave_dig_outs[smux_idx - 1]; - if (spec->cur_smux[smux_idx] == smux->num_items - 1) - val = HDA_AMP_MUTE; - else - val = 0; - /* un/mute SPDIF out */ - snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, - HDA_AMP_MUTE, val); + spec->aloopback = val; + + /* Only return the bits defined by the shift value of the + * first two bytes of the mask + */ + dac_mode = snd_hda_codec_read(codec, codec->afg, 0, + kcontrol->private_value & 0xFFFF, 0x0); + dac_mode >>= spec->aloopback_shift; + + if (spec->aloopback & idx_val) { + snd_hda_power_up(codec); + dac_mode |= idx_val; + } else { + snd_hda_power_down(codec); + dac_mode &= ~idx_val; } - return 0; + + snd_hda_codec_write_cache(codec, codec->afg, 0, + kcontrol->private_value >> 16, dac_mode); + + return 1; } -static int stac_vrefout_set(struct hda_codec *codec, - hda_nid_t nid, unsigned int new_vref) +#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ + { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = "Analog Loopback", \ + .count = cnt, \ + .info = stac_aloopback_info, \ + .get = stac_aloopback_get, \ + .put = stac_aloopback_put, \ + .private_value = verb_read | (verb_write << 16), \ + } + +/* + * Mute LED handling on HP laptops + */ + +/* check whether it's a HP laptop with a docking port */ +static bool hp_bnb2011_with_dock(struct hda_codec *codec) { - int error, pinctl; + if (codec->vendor_id != 0x111d7605 && + codec->vendor_id != 0x111d76d1) + return false; - snd_printdd("%s, nid %x ctl %x\n", __func__, nid, new_vref); - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + switch (codec->subsystem_id) { + case 0x103c1618: + case 0x103c1619: + case 0x103c161a: + case 0x103c161b: + case 0x103c161c: + case 0x103c161d: + case 0x103c161e: + case 0x103c161f: - if (pinctl < 0) - return pinctl; + case 0x103c162a: + case 0x103c162b: - pinctl &= 0xff; - pinctl &= ~AC_PINCTL_VREFEN; - pinctl |= (new_vref & AC_PINCTL_VREFEN); + case 0x103c1630: + case 0x103c1631: - error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl); - if (error < 0) - return error; + case 0x103c1633: + case 0x103c1634: + case 0x103c1635: - return 1; + case 0x103c3587: + case 0x103c3588: + case 0x103c3589: + case 0x103c358a: + + case 0x103c3667: + case 0x103c3668: + case 0x103c3669: + + return true; + } + return false; } -static unsigned int stac92xx_vref_set(struct hda_codec *codec, - hda_nid_t nid, unsigned int new_vref) +static bool hp_blike_system(u32 subsystem_id) { - int error; - unsigned int pincfg; - pincfg = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + switch (subsystem_id) { + case 0x103c1520: + case 0x103c1521: + case 0x103c1523: + case 0x103c1524: + case 0x103c1525: + case 0x103c1722: + case 0x103c1723: + case 0x103c1724: + case 0x103c1725: + case 0x103c1726: + case 0x103c1727: + case 0x103c1728: + case 0x103c1729: + case 0x103c172a: + case 0x103c172b: + case 0x103c307e: + case 0x103c307f: + case 0x103c3080: + case 0x103c3081: + case 0x103c7007: + case 0x103c7008: + return true; + } + return false; +} - pincfg &= 0xff; - pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - pincfg |= new_vref; +static void set_hp_led_gpio(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + unsigned int gpio; - if (new_vref == AC_PINCTL_VREF_HIZ) - pincfg |= AC_PINCTL_OUT_EN; - else - pincfg |= AC_PINCTL_IN_EN; + if (spec->gpio_led) + return; - error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg); - if (error < 0) - return error; + gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); + gpio &= AC_GPIO_IO_COUNT; + if (gpio > 3) + spec->gpio_led = 0x08; /* GPIO 3 */ else - return 1; + spec->gpio_led = 0x01; /* GPIO 0 */ } -static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) +/* + * This method searches for the mute LED GPIO configuration + * provided as OEM string in SMBIOS. The format of that string + * is HP_Mute_LED_P_G or HP_Mute_LED_P + * where P can be 0 or 1 and defines mute LED GPIO control state (low/high) + * that corresponds to the NOT muted state of the master volume + * and G is the index of the GPIO to use as the mute LED control (0..9) + * If _G portion is missing it is assigned based on the codec ID + * + * So, HP B-series like systems may have HP_Mute_LED_0 (current models) + * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings + * + * + * The dv-series laptops don't seem to have the HP_Mute_LED* strings in + * SMBIOS - at least the ones I have seen do not have them - which include + * my own system (HP Pavilion dv6-1110ax) and my cousin's + * HP Pavilion dv9500t CTO. + * Need more information on whether it is true across the entire series. + * -- kunal + */ +static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) { - unsigned int vref; - vref = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - vref &= AC_PINCTL_VREFEN; - return vref; + struct sigmatel_spec *spec = codec->spec; + const struct dmi_device *dev = NULL; + + if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { + get_int_hint(codec, "gpio_led_polarity", + &spec->gpio_led_polarity); + return 1; + } + + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { + if (sscanf(dev->name, "HP_Mute_LED_%u_%x", + &spec->gpio_led_polarity, + &spec->gpio_led) == 2) { + unsigned int max_gpio; + max_gpio = snd_hda_param_read(codec, codec->afg, + AC_PAR_GPIO_CAP); + max_gpio &= AC_GPIO_IO_COUNT; + if (spec->gpio_led < max_gpio) + spec->gpio_led = 1 << spec->gpio_led; + else + spec->vref_mute_led_nid = spec->gpio_led; + return 1; + } + if (sscanf(dev->name, "HP_Mute_LED_%u", + &spec->gpio_led_polarity) == 1) { + set_hp_led_gpio(codec); + return 1; + } + /* BIOS bug: unfilled OEM string */ + if (strstr(dev->name, "HP_Mute_LED_P_G")) { + set_hp_led_gpio(codec); + if (default_polarity >= 0) + spec->gpio_led_polarity = default_polarity; + else + spec->gpio_led_polarity = 1; + return 1; + } + } + + /* + * Fallback case - if we don't find the DMI strings, + * we statically set the GPIO - if not a B-series system + * and default polarity is provided + */ + if (!hp_blike_system(codec->subsystem_id) && + (default_polarity == 0 || default_polarity == 1)) { + set_hp_led_gpio(codec); + spec->gpio_led_polarity = default_polarity; + return 1; + } + return 0; } -static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) +/* check whether a built-in speaker is included in parsed pins */ +static bool has_builtin_speaker(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->input_mux, uinfo); + hda_nid_t *nid_pin; + int nids, i; + + if (spec->gen.autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) { + nid_pin = spec->gen.autocfg.line_out_pins; + nids = spec->gen.autocfg.line_outs; + } else { + nid_pin = spec->gen.autocfg.speaker_pins; + nids = spec->gen.autocfg.speaker_outs; + } + + for (i = 0; i < nids; i++) { + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid_pin[i]); + if (snd_hda_get_input_pin_attr(def_conf) == INPUT_PIN_ATTR_INT) + return true; + } + return false; } -static int stac92xx_mux_enum_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +/* + * PC beep controls + */ + +/* create PC beep volume controls */ +static int stac_auto_create_beep_ctls(struct hda_codec *codec, + hda_nid_t nid) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); + u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); + struct snd_kcontrol_new *knew; + static struct snd_kcontrol_new abeep_mute_ctl = + HDA_CODEC_MUTE(NULL, 0, 0, 0); + static struct snd_kcontrol_new dbeep_mute_ctl = + HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0); + static struct snd_kcontrol_new beep_vol_ctl = + HDA_CODEC_VOLUME(NULL, 0, 0, 0); - ucontrol->value.enumerated.item[0] = spec->cur_mux[adc_idx]; + /* check for mute support for the the amp */ + if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { + const struct snd_kcontrol_new *temp; + if (spec->anabeep_nid == nid) + temp = &abeep_mute_ctl; + else + temp = &dbeep_mute_ctl; + knew = snd_hda_gen_add_kctl(&spec->gen, + "Beep Playback Switch", temp); + if (!knew) + return -ENOMEM; + knew->private_value = + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT); + } + + /* check to see if there is volume support for the amp */ + if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { + knew = snd_hda_gen_add_kctl(&spec->gen, + "Beep Playback Volume", + &beep_vol_ctl); + if (!knew) + return -ENOMEM; + knew->private_value = + HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT); + } return 0; } -static int stac92xx_mux_enum_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +#ifdef CONFIG_SND_HDA_INPUT_BEEP +#define stac_dig_beep_switch_info snd_ctl_boolean_mono_info + +static int stac_dig_beep_switch_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int adc_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - const struct hda_input_mux *imux = spec->input_mux; - unsigned int idx, prev_idx, didx; - - idx = ucontrol->value.enumerated.item[0]; - if (idx >= imux->num_items) - idx = imux->num_items - 1; - prev_idx = spec->cur_mux[adc_idx]; - if (prev_idx == idx) - return 0; - if (idx < spec->num_analog_muxes) { - snd_hda_codec_write_cache(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[idx].index); - if (prev_idx >= spec->num_analog_muxes && - spec->mux_nids[adc_idx] != spec->dmux_nids[adc_idx]) { - imux = spec->dinput_mux; - /* 0 = analog */ - snd_hda_codec_write_cache(codec, - spec->dmux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); - } - } else { - imux = spec->dinput_mux; - /* first dimux item is hardcoded to select analog imux, - * so lets skip it - */ - didx = idx - spec->num_analog_muxes + 1; - snd_hda_codec_write_cache(codec, spec->dmux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[didx].index); - } - spec->cur_mux[adc_idx] = idx; - return 1; + ucontrol->value.integer.value[0] = codec->beep->enabled; + return 0; } -static int stac92xx_mono_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) +static int stac_dig_beep_switch_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - return snd_hda_input_mux_info(spec->mono_mux, uinfo); + return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); } -static int stac92xx_mono_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static const struct snd_kcontrol_new stac_dig_beep_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Beep Playback Switch", + .info = stac_dig_beep_switch_info, + .get = stac_dig_beep_switch_get, + .put = stac_dig_beep_switch_put, +}; + +static int stac_beep_switch_ctl(struct hda_codec *codec) { - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->cur_mmux; + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_dig_beep_ctrl)) + return -ENOMEM; return 0; } +#endif -static int stac92xx_mono_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +/* + * SPDIF-out mux controls + */ + +static int stac_smux_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, spec->mono_mux, ucontrol, - spec->mono_nid, &spec->cur_mmux); + return snd_hda_input_mux_info(&spec->spdif_mux, uinfo); } -#define stac92xx_aloopback_info snd_ctl_boolean_mono_info - -static int stac92xx_aloopback_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_smux_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); struct sigmatel_spec *spec = codec->spec; + unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - ucontrol->value.integer.value[0] = !!(spec->aloopback & - (spec->aloopback_mask << idx)); + ucontrol->value.enumerated.item[0] = spec->cur_smux[smux_idx]; return 0; } -static int stac92xx_aloopback_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int stac_smux_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct sigmatel_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - unsigned int dac_mode; - unsigned int val, idx_val; + unsigned int smux_idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - idx_val = spec->aloopback_mask << idx; - if (ucontrol->value.integer.value[0]) - val = spec->aloopback | idx_val; - else - val = spec->aloopback & ~idx_val; - if (spec->aloopback == val) - return 0; + return snd_hda_input_mux_put(codec, &spec->spdif_mux, ucontrol, + spec->gen.autocfg.dig_out_pins[smux_idx], + &spec->cur_smux[smux_idx]); +} - spec->aloopback = val; +static struct snd_kcontrol_new stac_smux_mixer = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "IEC958 Playback Source", + /* count set later */ + .info = stac_smux_enum_info, + .get = stac_smux_enum_get, + .put = stac_smux_enum_put, +}; - /* Only return the bits defined by the shift value of the - * first two bytes of the mask - */ - dac_mode = snd_hda_codec_read(codec, codec->afg, 0, - kcontrol->private_value & 0xFFFF, 0x0); - dac_mode >>= spec->aloopback_shift; +static const char * const stac_spdif_labels[] = { + "Digital Playback", "Analog Mux 1", "Analog Mux 2", NULL +}; - if (spec->aloopback & idx_val) { - snd_hda_power_up(codec); - dac_mode |= idx_val; - } else { - snd_hda_power_down(codec); - dac_mode &= ~idx_val; +static int stac_create_spdif_mux_ctls(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + const char * const *labels = spec->spdif_labels; + struct snd_kcontrol_new *kctl; + int i, num_cons; + + if (cfg->dig_outs < 1) + return 0; + + num_cons = snd_hda_get_num_conns(codec, cfg->dig_out_pins[0]); + if (num_cons <= 1) + return 0; + + if (!labels) + labels = stac_spdif_labels; + for (i = 0; i < num_cons; i++) { + if (snd_BUG_ON(!labels[i])) + return -EINVAL; + snd_hda_add_imux_item(&spec->spdif_mux, labels[i], i, NULL); } - snd_hda_codec_write_cache(codec, codec->afg, 0, - kcontrol->private_value >> 16, dac_mode); + kctl = snd_hda_gen_add_kctl(&spec->gen, NULL, &stac_smux_mixer); + if (!kctl) + return -ENOMEM; + kctl->count = cfg->dig_outs; - return 1; + return 0; } +/* + */ + static const struct hda_verb stac9200_core_init[] = { /* set dac0mux for dac converter */ { 0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, @@ -936,17 +1093,15 @@ static const struct hda_verb stac925x_core_init[] = { }; static const struct hda_verb stac922x_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x16, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, {} }; static const struct hda_verb d965_core_init[] = { - /* set master volume and direct control */ - { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* unmute node 0x1b */ { 0x1b, AC_VERB_SET_AMP_GAIN_MUTE, 0xb000}, - /* select node 0x03 as DAC */ + /* select node 0x03 as DAC */ { 0x0b, AC_VERB_SET_CONNECT_SEL, 0x01}, {} }; @@ -962,7 +1117,7 @@ static const struct hda_verb dell_3st_core_init[] = { }; static const struct hda_verb stac927x_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, @@ -978,260 +1133,103 @@ static const struct hda_verb stac927x_volknob_core_init[] = { }; static const struct hda_verb stac9205_core_init[] = { - /* set master volume and direct control */ + /* set master volume and direct control */ { 0x24, AC_VERB_SET_VOLUME_KNOB_CONTROL, 0xff}, /* enable analog pc beep path */ { 0x01, AC_VERB_SET_DIGI_CONVERT_2, 1 << 5}, {} }; -#define STAC_MONO_MUX \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Mono Mux", \ - .count = 1, \ - .info = stac92xx_mono_mux_enum_info, \ - .get = stac92xx_mono_mux_enum_get, \ - .put = stac92xx_mono_mux_enum_put, \ - } +static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3); -#define STAC_ANALOG_LOOPBACK(verb_read, verb_write, cnt) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = "Analog Loopback", \ - .count = cnt, \ - .info = stac92xx_aloopback_info, \ - .get = stac92xx_aloopback_get, \ - .put = stac92xx_aloopback_put, \ - .private_value = verb_read | (verb_write << 16), \ - } +static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4); -#define DC_BIAS(xname, idx, nid) \ - { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = idx, \ - .info = stac92xx_dc_bias_info, \ - .get = stac92xx_dc_bias_get, \ - .put = stac92xx_dc_bias_put, \ - .private_value = nid, \ - } +static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5); -static const struct snd_kcontrol_new stac9200_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0xb, 0, HDA_OUTPUT), - HDA_CODEC_VOLUME("Capture Volume", 0x0a, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Capture Switch", 0x0a, 0, HDA_OUTPUT), - { } /* end */ -}; +static const struct snd_kcontrol_new stac92hd71bxx_loopback = + STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2); -static const struct snd_kcontrol_new stac92hd73xx_6ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 3), - {} -}; +static const struct snd_kcontrol_new stac9205_loopback = + STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1); -static const struct snd_kcontrol_new stac92hd73xx_8ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 4), - {} -}; +static const struct snd_kcontrol_new stac927x_loopback = + STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1); -static const struct snd_kcontrol_new stac92hd73xx_10ch_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A1, 5), +static const struct hda_pintbl ref9200_pin_configs[] = { + { 0x08, 0x01c47010 }, + { 0x09, 0x01447010 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01114010 }, + { 0x0f, 0x02a19020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x01813122 }, {} }; - -static const struct snd_kcontrol_new stac92hd71bxx_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFA0, 0x7A0, 2) -}; - -static const struct snd_kcontrol_new stac925x_mixer[] = { - HDA_CODEC_VOLUME_MIN_MUTE("PCM Playback Volume", 0xe, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PCM Playback Switch", 0x0e, 0, HDA_OUTPUT), - { } /* end */ -}; - -static const struct snd_kcontrol_new stac9205_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFE0, 0x7E0, 1), +static const struct hda_pintbl gateway9200_m4_pin_configs[] = { + { 0x08, 0x400000fe }, + { 0x09, 0x404500f4 }, + { 0x0d, 0x400100f0 }, + { 0x0e, 0x90110010 }, + { 0x0f, 0x400100f1 }, + { 0x10, 0x02a1902e }, + { 0x11, 0x500000f2 }, + { 0x12, 0x500000f3 }, {} }; -static const struct snd_kcontrol_new stac927x_loopback[] = { - STAC_ANALOG_LOOPBACK(0xFEB, 0x7EB, 1), +static const struct hda_pintbl gateway9200_m4_2_pin_configs[] = { + { 0x08, 0x400000fe }, + { 0x09, 0x404500f4 }, + { 0x0d, 0x400100f0 }, + { 0x0e, 0x90110010 }, + { 0x0f, 0x400100f1 }, + { 0x10, 0x02a1902e }, + { 0x11, 0x500000f2 }, + { 0x12, 0x500000f3 }, {} }; -static struct snd_kcontrol_new stac_dmux_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Source", - /* count set later */ - .info = stac92xx_dmux_enum_info, - .get = stac92xx_dmux_enum_get, - .put = stac92xx_dmux_enum_put, -}; - -static struct snd_kcontrol_new stac_smux_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "IEC958 Playback Source", - /* count set later */ - .info = stac92xx_smux_enum_info, - .get = stac92xx_smux_enum_get, - .put = stac92xx_smux_enum_put, -}; - -static const char * const slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", "IEC958", "PCM", - NULL -}; - -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled); - -static void stac92xx_vmaster_hook(void *private_data, int val) -{ - stac92xx_update_led_status(private_data, val); -} - -static void stac92xx_free_kctls(struct hda_codec *codec); - -static int stac92xx_build_controls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int vmaster_tlv[4]; - int err; - int i; - - if (spec->mixer) { - err = snd_hda_add_new_ctls(codec, spec->mixer); - if (err < 0) - return err; - } - - for (i = 0; i < spec->num_mixers; i++) { - err = snd_hda_add_new_ctls(codec, spec->mixers[i]); - if (err < 0) - return err; - } - if (!spec->auto_mic && spec->num_dmuxes > 0 && - snd_hda_get_bool_hint(codec, "separate_dmux") == 1) { - stac_dmux_mixer.count = spec->num_dmuxes; - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&stac_dmux_mixer, codec)); - if (err < 0) - return err; - } - if (spec->num_smuxes > 0) { - int wcaps = get_wcaps(codec, spec->multiout.dig_out_nid); - struct hda_input_mux *smux = &spec->private_smux; - /* check for mute support on SPDIF out */ - if (wcaps & AC_WCAP_OUT_AMP) { - snd_hda_add_imux_item(smux, "Off", 0, NULL); - spec->spdif_mute = 1; - } - stac_smux_mixer.count = spec->num_smuxes; - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&stac_smux_mixer, codec)); - if (err < 0) - return err; - } - - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid && !(spec->gpio_dir & 0x01)) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - /* correct volume offset */ - vmaster_tlv[2] += vmaster_tlv[3] * spec->volume_offset; - /* minimum value is actually mute */ - vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - - err = __snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, slave_pfxs, - "Playback Switch", true, - &spec->vmaster_mute.sw_kctl); - if (err < 0) - return err; - - if (spec->gpio_led) { - spec->vmaster_mute.hook = stac92xx_vmaster_hook; - err = snd_hda_add_vmaster_hook(codec, &spec->vmaster_mute, true); - if (err < 0) - return err; - } - - if (spec->aloopback_ctl && - snd_hda_get_bool_hint(codec, "loopback") == 1) { - err = snd_hda_add_new_ctls(codec, spec->aloopback_ctl); - if (err < 0) - return err; - } - - stac92xx_free_kctls(codec); /* no longer needed */ - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - - return 0; -} - -static const unsigned int ref9200_pin_configs[8] = { - 0x01c47010, 0x01447010, 0x0221401f, 0x01114010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, -}; - -static const unsigned int gateway9200_m4_pin_configs[8] = { - 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, - 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, -}; -static const unsigned int gateway9200_m4_2_pin_configs[8] = { - 0x400000fe, 0x404500f4, 0x400100f0, 0x90110010, - 0x400100f1, 0x02a1902e, 0x500000f2, 0x500000f3, -}; - /* STAC 9200 pin configs for 102801A8 102801DE 102801E8 */ -static const unsigned int dell9200_d21_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x02214030, 0x01014010, - 0x02a19020, 0x01a19021, 0x90100140, 0x01813122, +static const struct hda_pintbl dell9200_d21_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x02214030 }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x02a19020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x01813122 }, + {} }; -/* +/* STAC 9200 pin configs for 102801C0 102801C1 */ -static const unsigned int dell9200_d22_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x02a19021, 0x90100140, 0x400001f2, +static const struct hda_pintbl dell9200_d22_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x01813020 }, + { 0x10, 0x02a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x400001f2 }, + {} }; -/* +/* STAC 9200 pin configs for 102801C4 (Dell Dimension E310) 102801C5 @@ -1240,9 +1238,16 @@ static const unsigned int dell9200_d22_pin_configs[8] = { 102801DA 102801E3 */ -static const unsigned int dell9200_d23_pin_configs[8] = { - 0x400001f0, 0x400001f1, 0x0221401f, 0x01014010, - 0x01813020, 0x01a19021, 0x90100140, 0x400001f2, +static const struct hda_pintbl dell9200_d23_pin_configs[] = { + { 0x08, 0x400001f0 }, + { 0x09, 0x400001f1 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01014010 }, + { 0x0f, 0x01813020 }, + { 0x10, 0x01a19021 }, + { 0x11, 0x90100140 }, + { 0x12, 0x400001f2 }, + {} }; @@ -1251,9 +1256,16 @@ static const unsigned int dell9200_d23_pin_configs[8] = { 102801B5 (Dell Inspiron 630m) 102801D8 (Dell Inspiron 640m) */ -static const unsigned int dell9200_m21_pin_configs[8] = { - 0x40c003fa, 0x03441340, 0x0321121f, 0x90170310, - 0x408003fb, 0x03a11020, 0x401003fc, 0x403003fd, +static const struct hda_pintbl dell9200_m21_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x03441340 }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fc }, + { 0x12, 0x403003fd }, + {} }; /* @@ -1264,9 +1276,16 @@ static const unsigned int dell9200_m21_pin_configs[8] = { 102801D4 102801D6 */ -static const unsigned int dell9200_m22_pin_configs[8] = { - 0x40c003fa, 0x0144131f, 0x0321121f, 0x90170310, - 0x90a70321, 0x03a11020, 0x401003fb, 0x40f000fc, +static const struct hda_pintbl dell9200_m22_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x0144131f }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x90a70321 }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fb }, + { 0x12, 0x40f000fc }, + {} }; /* @@ -1274,9 +1293,16 @@ static const unsigned int dell9200_m22_pin_configs[8] = { 102801CE (Dell XPS M1710) 102801CF (Dell Precision M90) */ -static const unsigned int dell9200_m23_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421421f, 0x90170310, - 0x408003fb, 0x04a1102e, 0x90170311, 0x403003fc, +static const struct hda_pintbl dell9200_m23_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421421f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x04a1102e }, + { 0x11, 0x90170311 }, + { 0x12, 0x403003fc }, + {} }; /* @@ -1286,9 +1312,16 @@ static const unsigned int dell9200_m23_pin_configs[8] = { 102801CB (Dell Latitude 120L) 102801D3 */ -static const unsigned int dell9200_m24_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0321121f, 0x90170310, - 0x408003fc, 0x03a11020, 0x401003fd, 0x403003fe, +static const struct hda_pintbl dell9200_m24_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x404003fb }, + { 0x0d, 0x0321121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fc }, + { 0x10, 0x03a11020 }, + { 0x11, 0x401003fd }, + { 0x12, 0x403003fe }, + {} }; /* @@ -1297,9 +1330,16 @@ static const unsigned int dell9200_m24_pin_configs[8] = { 102801EE 102801EF */ -static const unsigned int dell9200_m25_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x408003fb, 0x04a11020, 0x401003fc, 0x403003fd, +static const struct hda_pintbl dell9200_m25_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fb }, + { 0x10, 0x04a11020 }, + { 0x11, 0x401003fc }, + { 0x12, 0x403003fd }, + {} }; /* @@ -1307,64 +1347,159 @@ static const unsigned int dell9200_m25_pin_configs[8] = { 102801F5 (Dell Inspiron 1501) 102801F6 */ -static const unsigned int dell9200_m26_pin_configs[8] = { - 0x40c003fa, 0x404003fb, 0x0421121f, 0x90170310, - 0x408003fc, 0x04a11020, 0x401003fd, 0x403003fe, +static const struct hda_pintbl dell9200_m26_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x404003fb }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x408003fc }, + { 0x10, 0x04a11020 }, + { 0x11, 0x401003fd }, + { 0x12, 0x403003fe }, + {} }; /* STAC 9200-32 102801CD (Dell Inspiron E1705/9400) */ -static const unsigned int dell9200_m27_pin_configs[8] = { - 0x40c003fa, 0x01441340, 0x0421121f, 0x90170310, - 0x90170310, 0x04a11020, 0x90170310, 0x40f003fc, -}; - -static const unsigned int oqo9200_pin_configs[8] = { - 0x40c000f0, 0x404000f1, 0x0221121f, 0x02211210, - 0x90170111, 0x90a70120, 0x400000f2, 0x400000f3, -}; - - -static const unsigned int *stac9200_brd_tbl[STAC_9200_MODELS] = { - [STAC_REF] = ref9200_pin_configs, - [STAC_9200_OQO] = oqo9200_pin_configs, - [STAC_9200_DELL_D21] = dell9200_d21_pin_configs, - [STAC_9200_DELL_D22] = dell9200_d22_pin_configs, - [STAC_9200_DELL_D23] = dell9200_d23_pin_configs, - [STAC_9200_DELL_M21] = dell9200_m21_pin_configs, - [STAC_9200_DELL_M22] = dell9200_m22_pin_configs, - [STAC_9200_DELL_M23] = dell9200_m23_pin_configs, - [STAC_9200_DELL_M24] = dell9200_m24_pin_configs, - [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, -}; - -static const char * const stac9200_models[STAC_9200_MODELS] = { - [STAC_AUTO] = "auto", - [STAC_REF] = "ref", - [STAC_9200_OQO] = "oqo", - [STAC_9200_DELL_D21] = "dell-d21", - [STAC_9200_DELL_D22] = "dell-d22", - [STAC_9200_DELL_D23] = "dell-d23", - [STAC_9200_DELL_M21] = "dell-m21", - [STAC_9200_DELL_M22] = "dell-m22", - [STAC_9200_DELL_M23] = "dell-m23", - [STAC_9200_DELL_M24] = "dell-m24", - [STAC_9200_DELL_M25] = "dell-m25", - [STAC_9200_DELL_M26] = "dell-m26", - [STAC_9200_DELL_M27] = "dell-m27", - [STAC_9200_M4] = "gateway-m4", - [STAC_9200_M4_2] = "gateway-m4-2", - [STAC_9200_PANASONIC] = "panasonic", -}; - -static const struct snd_pci_quirk stac9200_cfg_tbl[] = { +static const struct hda_pintbl dell9200_m27_pin_configs[] = { + { 0x08, 0x40c003fa }, + { 0x09, 0x01441340 }, + { 0x0d, 0x0421121f }, + { 0x0e, 0x90170310 }, + { 0x0f, 0x90170310 }, + { 0x10, 0x04a11020 }, + { 0x11, 0x90170310 }, + { 0x12, 0x40f003fc }, + {} +}; + +static const struct hda_pintbl oqo9200_pin_configs[] = { + { 0x08, 0x40c000f0 }, + { 0x09, 0x404000f1 }, + { 0x0d, 0x0221121f }, + { 0x0e, 0x02211210 }, + { 0x0f, 0x90170111 }, + { 0x10, 0x90a70120 }, + { 0x11, 0x400000f2 }, + { 0x12, 0x400000f3 }, + {} +}; + + +static void stac9200_fixup_panasonic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_mask = spec->gpio_dir = 0x09; + spec->gpio_data = 0x00; + /* CF-74 has no headphone detection, and the driver should *NOT* + * do detection and HP/speaker toggle because the hardware does it. + */ + spec->gen.suppress_auto_mute = 1; + } +} + + +static const struct hda_fixup stac9200_fixups[] = { + [STAC_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref9200_pin_configs, + }, + [STAC_9200_OQO] = { + .type = HDA_FIXUP_PINS, + .v.pins = oqo9200_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_DELL_D21] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d21_pin_configs, + }, + [STAC_9200_DELL_D22] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d22_pin_configs, + }, + [STAC_9200_DELL_D23] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_d23_pin_configs, + }, + [STAC_9200_DELL_M21] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m21_pin_configs, + }, + [STAC_9200_DELL_M22] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m22_pin_configs, + }, + [STAC_9200_DELL_M23] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m23_pin_configs, + }, + [STAC_9200_DELL_M24] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m24_pin_configs, + }, + [STAC_9200_DELL_M25] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m25_pin_configs, + }, + [STAC_9200_DELL_M26] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m26_pin_configs, + }, + [STAC_9200_DELL_M27] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell9200_m27_pin_configs, + }, + [STAC_9200_M4] = { + .type = HDA_FIXUP_PINS, + .v.pins = gateway9200_m4_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_M4_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = gateway9200_m4_2_pin_configs, + .chained = true, + .chain_id = STAC_9200_EAPD_INIT, + }, + [STAC_9200_PANASONIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9200_fixup_panasonic, + }, + [STAC_9200_EAPD_INIT] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x08, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, + {} + }, + }, +}; + +static const struct hda_model_fixup stac9200_models[] = { + { .id = STAC_REF, .name = "ref" }, + { .id = STAC_9200_OQO, .name = "oqo" }, + { .id = STAC_9200_DELL_D21, .name = "dell-d21" }, + { .id = STAC_9200_DELL_D22, .name = "dell-d22" }, + { .id = STAC_9200_DELL_D23, .name = "dell-d23" }, + { .id = STAC_9200_DELL_M21, .name = "dell-m21" }, + { .id = STAC_9200_DELL_M22, .name = "dell-m22" }, + { .id = STAC_9200_DELL_M23, .name = "dell-m23" }, + { .id = STAC_9200_DELL_M24, .name = "dell-m24" }, + { .id = STAC_9200_DELL_M25, .name = "dell-m25" }, + { .id = STAC_9200_DELL_M26, .name = "dell-m26" }, + { .id = STAC_9200_DELL_M27, .name = "dell-m27" }, + { .id = STAC_9200_M4, .name = "gateway-m4" }, + { .id = STAC_9200_M4_2, .name = "gateway-m4-2" }, + { .id = STAC_9200_PANASONIC, .name = "panasonic" }, + {} +}; + +static const struct snd_pci_quirk stac9200_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), @@ -1440,70 +1575,159 @@ static const struct snd_pci_quirk stac9200_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref925x_pin_configs[8] = { - 0x40c003f0, 0x424503f2, 0x01813022, 0x02a19021, - 0x90a70320, 0x02214210, 0x01019020, 0x9033032e, +static const struct hda_pintbl ref925x_pin_configs[] = { + { 0x07, 0x40c003f0 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x01813022 }, + { 0x0b, 0x02a19021 }, + { 0x0c, 0x90a70320 }, + { 0x0d, 0x02214210 }, + { 0x10, 0x01019020 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM1_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM1_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM1_2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM1_2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM2_2_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM2_2_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM3_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x503303f3, +static const struct hda_pintbl stac925xM3_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x503303f3 }, + {} }; -static const unsigned int stac925xM5_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x9033032e, +static const struct hda_pintbl stac925xM5_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x9033032e }, + {} }; -static const unsigned int stac925xM6_pin_configs[8] = { - 0x40c003f4, 0x424503f2, 0x400000f3, 0x02a19020, - 0x40a000f0, 0x90100210, 0x400003f1, 0x90330320, +static const struct hda_pintbl stac925xM6_pin_configs[] = { + { 0x07, 0x40c003f4 }, + { 0x08, 0x424503f2 }, + { 0x0a, 0x400000f3 }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x40a000f0 }, + { 0x0d, 0x90100210 }, + { 0x10, 0x400003f1 }, + { 0x11, 0x90330320 }, + {} }; -static const 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_M3] = stac925xM3_pin_configs, - [STAC_M5] = stac925xM5_pin_configs, - [STAC_M6] = stac925xM6_pin_configs, +static const struct hda_fixup stac925x_fixups[] = { + [STAC_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref925x_pin_configs, + }, + [STAC_M1] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM1_pin_configs, + }, + [STAC_M1_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM1_2_pin_configs, + }, + [STAC_M2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM2_pin_configs, + }, + [STAC_M2_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM2_2_pin_configs, + }, + [STAC_M3] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM3_pin_configs, + }, + [STAC_M5] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM5_pin_configs, + }, + [STAC_M6] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac925xM6_pin_configs, + }, }; -static const char * const stac925x_models[STAC_925x_MODELS] = { - [STAC_925x_AUTO] = "auto", - [STAC_REF] = "ref", - [STAC_M1] = "m1", - [STAC_M1_2] = "m1-2", - [STAC_M2] = "m2", - [STAC_M2_2] = "m2-2", - [STAC_M3] = "m3", - [STAC_M5] = "m5", - [STAC_M6] = "m6", +static const struct hda_model_fixup stac925x_models[] = { + { .id = STAC_REF, .name = "ref" }, + { .id = STAC_M1, .name = "m1" }, + { .id = STAC_M1_2, .name = "m1-2" }, + { .id = STAC_M2, .name = "m2" }, + { .id = STAC_M2_2, .name = "m2-2" }, + { .id = STAC_M3, .name = "m3" }, + { .id = STAC_M5, .name = "m5" }, + { .id = STAC_M6, .name = "m6" }, + {} }; -static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { +static const struct snd_pci_quirk stac925x_fixup_tbl[] = { + /* SigmaTel reference board */ + SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), + SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), + + /* Default table for unknown ID */ + SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), + + /* gateway machines are checked via codec ssid */ 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), @@ -1517,67 +1741,212 @@ static const struct snd_pci_quirk stac925x_codec_id_cfg_tbl[] = { {} /* terminator */ }; -static const 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(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_REF), - SND_PCI_QUIRK(0x8384, 0x7632, "Stac9202 Reference Board", STAC_REF), - - /* Default table for unknown ID */ - SND_PCI_QUIRK(0x1002, 0x437b, "Gateway mobile", STAC_M2_2), - - {} /* terminator */ +static const struct hda_pintbl ref92hd73xx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02a19040 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x02214030 }, + { 0x0e, 0x0181302e }, + { 0x0f, 0x01014010 }, + { 0x10, 0x01014020 }, + { 0x11, 0x01014030 }, + { 0x12, 0x02319040 }, + { 0x13, 0x90a000f0 }, + { 0x14, 0x90a000f0 }, + { 0x22, 0x01452050 }, + { 0x23, 0x01452050 }, + {} }; -static const unsigned int ref92hd73xx_pin_configs[13] = { - 0x02214030, 0x02a19040, 0x01a19020, 0x02214030, - 0x0181302e, 0x01014010, 0x01014020, 0x01014030, - 0x02319040, 0x90a000f0, 0x90a000f0, 0x01452050, - 0x01452050, +static const struct hda_pintbl dell_m6_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x4f00000f }, + { 0x0c, 0x4f0000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x03a11020 }, + { 0x0f, 0x0321101f }, + { 0x10, 0x4f0000f0 }, + { 0x11, 0x4f0000f0 }, + { 0x12, 0x4f0000f0 }, + { 0x13, 0x90a60160 }, + { 0x14, 0x4f0000f0 }, + { 0x22, 0x4f0000f0 }, + { 0x23, 0x4f0000f0 }, + {} }; -static const unsigned int dell_m6_pin_configs[13] = { - 0x0321101f, 0x4f00000f, 0x4f0000f0, 0x90170110, - 0x03a11020, 0x0321101f, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, +static const struct hda_pintbl alienware_m17x_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x0321101f }, + { 0x0c, 0x03a11020 }, + { 0x0d, 0x03014020 }, + { 0x0e, 0x90170110 }, + { 0x0f, 0x4f0000f0 }, + { 0x10, 0x4f0000f0 }, + { 0x11, 0x4f0000f0 }, + { 0x12, 0x4f0000f0 }, + { 0x13, 0x90a60160 }, + { 0x14, 0x4f0000f0 }, + { 0x22, 0x4f0000f0 }, + { 0x23, 0x904601b0 }, + {} }; -static const unsigned int alienware_m17x_pin_configs[13] = { - 0x0321101f, 0x0321101f, 0x03a11020, 0x03014020, - 0x90170110, 0x4f0000f0, 0x4f0000f0, 0x4f0000f0, - 0x4f0000f0, 0x90a60160, 0x4f0000f0, 0x4f0000f0, - 0x904601b0, +static const struct hda_pintbl intel_dg45id_pin_configs[] = { + { 0x0a, 0x02214230 }, + { 0x0b, 0x02A19240 }, + { 0x0c, 0x01013214 }, + { 0x0d, 0x01014210 }, + { 0x0e, 0x01A19250 }, + { 0x0f, 0x01011212 }, + { 0x10, 0x01016211 }, + {} }; -static const unsigned int intel_dg45id_pin_configs[13] = { - 0x02214230, 0x02A19240, 0x01013214, 0x01014210, - 0x01A19250, 0x01011212, 0x01016211 +static const struct hda_pintbl stac92hd89xx_hp_front_jack_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02A19010 }, + {} }; -static const unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { - [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, - [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, - [STAC_DELL_M6_DMIC] = dell_m6_pin_configs, - [STAC_DELL_M6_BOTH] = dell_m6_pin_configs, - [STAC_DELL_EQ] = dell_m6_pin_configs, - [STAC_ALIENWARE_M17X] = alienware_m17x_pin_configs, - [STAC_92HD73XX_INTEL] = intel_dg45id_pin_configs, +static void stac92hd73xx_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, ref92hd73xx_pin_configs); + spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0; +} + +static void stac92hd73xx_fixup_dell(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + snd_hda_apply_pincfgs(codec, dell_m6_pin_configs); + spec->eapd_switch = 0; +} + +static void stac92hd73xx_fixup_dell_eq(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_add_verbs(codec, dell_eq_core_init); + spec->volknob_init = 1; +} + +/* Analog Mics */ +static void stac92hd73xx_fixup_dell_m6_amic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); +} + +/* Digital Mics */ +static void stac92hd73xx_fixup_dell_m6_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); +} + +/* Both */ +static void stac92hd73xx_fixup_dell_m6_both(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + stac92hd73xx_fixup_dell(codec); + snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); + snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); +} + +static void stac92hd73xx_fixup_alienware_m17x(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, alienware_m17x_pin_configs); + spec->eapd_switch = 0; +} + +static void stac92hd73xx_fixup_no_jd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} + +static const struct hda_fixup stac92hd73xx_fixups[] = { + [STAC_92HD73XX_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_ref, + }, + [STAC_DELL_M6_AMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_amic, + }, + [STAC_DELL_M6_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_dmic, + }, + [STAC_DELL_M6_BOTH] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_m6_both, + }, + [STAC_DELL_EQ] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_dell_eq, + }, + [STAC_ALIENWARE_M17X] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_alienware_m17x, + }, + [STAC_92HD73XX_INTEL] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_dg45id_pin_configs, + }, + [STAC_92HD73XX_NO_JD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd73xx_fixup_no_jd, + }, + [STAC_92HD89XX_HP_FRONT_JACK] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac92hd89xx_hp_front_jack_pin_configs, + } }; -static const char * const stac92hd73xx_models[STAC_92HD73XX_MODELS] = { - [STAC_92HD73XX_AUTO] = "auto", - [STAC_92HD73XX_NO_JD] = "no-jd", - [STAC_92HD73XX_REF] = "ref", - [STAC_92HD73XX_INTEL] = "intel", - [STAC_DELL_M6_AMIC] = "dell-m6-amic", - [STAC_DELL_M6_DMIC] = "dell-m6-dmic", - [STAC_DELL_M6_BOTH] = "dell-m6", - [STAC_DELL_EQ] = "dell-eq", - [STAC_ALIENWARE_M17X] = "alienware", +static const struct hda_model_fixup stac92hd73xx_models[] = { + { .id = STAC_92HD73XX_NO_JD, .name = "no-jd" }, + { .id = STAC_92HD73XX_REF, .name = "ref" }, + { .id = STAC_92HD73XX_INTEL, .name = "intel" }, + { .id = STAC_DELL_M6_AMIC, .name = "dell-m6-amic" }, + { .id = STAC_DELL_M6_DMIC, .name = "dell-m6-dmic" }, + { .id = STAC_DELL_M6_BOTH, .name = "dell-m6" }, + { .id = STAC_DELL_EQ, .name = "dell-eq" }, + { .id = STAC_ALIENWARE_M17X, .name = "alienware" }, + {} }; -static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd73xx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD73XX_REF), @@ -1615,81 +1984,710 @@ static const struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio XPS 1645", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0413, "Dell Studio 1558", STAC_DELL_M6_DMIC), - {} /* terminator */ -}; - -static const struct snd_pci_quirk stac92hd73xx_codec_id_cfg_tbl[] = { + /* codec SSID matching */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02a1, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x043a, "Alienware M17x", STAC_ALIENWARE_M17X), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0490, "Alienware M17x R3", STAC_DELL_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2b17, + "unknown HP", STAC_92HD89XX_HP_FRONT_JACK), {} /* terminator */ }; -static const unsigned int ref92hd83xxx_pin_configs[10] = { - 0x02214030, 0x02211010, 0x02a19020, 0x02170130, - 0x01014050, 0x01819040, 0x01014020, 0x90a3014e, - 0x01451160, 0x98560170, +static const struct hda_pintbl ref92hd83xxx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02211010 }, + { 0x0c, 0x02a19020 }, + { 0x0d, 0x02170130 }, + { 0x0e, 0x01014050 }, + { 0x0f, 0x01819040 }, + { 0x10, 0x01014020 }, + { 0x11, 0x90a3014e }, + { 0x1f, 0x01451160 }, + { 0x20, 0x98560170 }, + {} }; -static const unsigned int dell_s14_pin_configs[10] = { - 0x0221403f, 0x0221101f, 0x02a19020, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a60160, - 0x40f000f0, 0x40f000f0, +static const struct hda_pintbl dell_s14_pin_configs[] = { + { 0x0a, 0x0221403f }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x02a19020 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x10, 0x40f000f0 }, + { 0x11, 0x90a60160 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int dell_vostro_3500_pin_configs[10] = { - 0x02a11020, 0x0221101f, 0x400000f0, 0x90170110, - 0x400000f1, 0x400000f2, 0x400000f3, 0x90a60160, - 0x400000f4, 0x400000f5, +static const struct hda_pintbl dell_vostro_3500_pin_configs[] = { + { 0x0a, 0x02a11020 }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x400000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x400000f1 }, + { 0x0f, 0x400000f2 }, + { 0x10, 0x400000f3 }, + { 0x11, 0x90a60160 }, + { 0x1f, 0x400000f4 }, + { 0x20, 0x400000f5 }, + {} +}; + +static const struct hda_pintbl hp_dv7_4000_pin_configs[] = { + { 0x0a, 0x03a12050 }, + { 0x0b, 0x0321201f }, + { 0x0c, 0x40f000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x10, 0x90170110 }, + { 0x11, 0xd5a30140 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int hp_dv7_4000_pin_configs[10] = { - 0x03a12050, 0x0321201f, 0x40f000f0, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x90170110, 0xd5a30140, - 0x40f000f0, 0x40f000f0, +static const struct hda_pintbl hp_zephyr_pin_configs[] = { + { 0x0a, 0x01813050 }, + { 0x0b, 0x0421201f }, + { 0x0c, 0x04a1205e }, + { 0x0d, 0x96130310 }, + { 0x0e, 0x96130310 }, + { 0x0f, 0x0101401f }, + { 0x10, 0x1111611f }, + { 0x11, 0xd5a30130 }, + {} }; -static const unsigned int hp_zephyr_pin_configs[10] = { - 0x01813050, 0x0421201f, 0x04a1205e, 0x96130310, - 0x96130310, 0x0101401f, 0x1111611f, 0xd5a30130, - 0, 0, +static const struct hda_pintbl hp_cNB11_intquad_pin_configs[] = { + { 0x0a, 0x40f000f0 }, + { 0x0b, 0x0221101f }, + { 0x0c, 0x02a11020 }, + { 0x0d, 0x92170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x92170110 }, + { 0x10, 0x40f000f0 }, + { 0x11, 0xd5a30130 }, + { 0x1f, 0x40f000f0 }, + { 0x20, 0x40f000f0 }, + {} }; -static const unsigned int hp_cNB11_intquad_pin_configs[10] = { - 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, - 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, - 0x40f000f0, 0x40f000f0, +static void stac92hd83xxx_fixup_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (hp_bnb2011_with_dock(codec)) { + snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); + snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); + } + + if (find_mute_led_cfg(codec, spec->default_polarity)) + codec_dbg(codec, "mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); + + /* allow auto-switching of dock line-in */ + spec->gen.line_in_auto_switch = true; +} + +static void stac92hd83xxx_fixup_hp_zephyr(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, hp_zephyr_pin_configs); + snd_hda_add_verbs(codec, stac92hd83xxx_hp_zephyr_init); +} + +static void stac92hd83xxx_fixup_hp_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->default_polarity = 0; +} + +static void stac92hd83xxx_fixup_hp_inv_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->default_polarity = 1; +} + +static void stac92hd83xxx_fixup_hp_mic_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ + /* resetting controller clears GPIO, so we need to keep on */ + codec->bus->power_keep_link_on = 1; + } +} + +static void stac92hd83xxx_fixup_hp_led_gpio10(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_led = 0x10; /* GPIO4 */ + spec->default_polarity = 0; + } +} + +static void stac92hd83xxx_fixup_headset_jack(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->headset_jack = 1; +} + +static const struct hda_verb hp_bnb13_eq_verbs[] = { + /* 44.1KHz base */ + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x68 }, + { 0x22, 0x7A8, 0x17 }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x68 }, + { 0x22, 0x7AB, 0x17 }, + { 0x22, 0x7AC, 0x00 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x83 }, + { 0x22, 0x7A7, 0x2F }, + { 0x22, 0x7A8, 0xD1 }, + { 0x22, 0x7A9, 0x83 }, + { 0x22, 0x7AA, 0x2F }, + { 0x22, 0x7AB, 0xD1 }, + { 0x22, 0x7AC, 0x01 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x68 }, + { 0x22, 0x7A8, 0x17 }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x68 }, + { 0x22, 0x7AB, 0x17 }, + { 0x22, 0x7AC, 0x02 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x7C }, + { 0x22, 0x7A7, 0xC6 }, + { 0x22, 0x7A8, 0x0C }, + { 0x22, 0x7A9, 0x7C }, + { 0x22, 0x7AA, 0xC6 }, + { 0x22, 0x7AB, 0x0C }, + { 0x22, 0x7AC, 0x03 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC3 }, + { 0x22, 0x7A7, 0x25 }, + { 0x22, 0x7A8, 0xAF }, + { 0x22, 0x7A9, 0xC3 }, + { 0x22, 0x7AA, 0x25 }, + { 0x22, 0x7AB, 0xAF }, + { 0x22, 0x7AC, 0x04 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x85 }, + { 0x22, 0x7A8, 0x73 }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x85 }, + { 0x22, 0x7AB, 0x73 }, + { 0x22, 0x7AC, 0x05 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x85 }, + { 0x22, 0x7A7, 0x39 }, + { 0x22, 0x7A8, 0xC7 }, + { 0x22, 0x7A9, 0x85 }, + { 0x22, 0x7AA, 0x39 }, + { 0x22, 0x7AB, 0xC7 }, + { 0x22, 0x7AC, 0x06 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3C }, + { 0x22, 0x7A7, 0x90 }, + { 0x22, 0x7A8, 0xB0 }, + { 0x22, 0x7A9, 0x3C }, + { 0x22, 0x7AA, 0x90 }, + { 0x22, 0x7AB, 0xB0 }, + { 0x22, 0x7AC, 0x07 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x7A }, + { 0x22, 0x7A7, 0xC6 }, + { 0x22, 0x7A8, 0x39 }, + { 0x22, 0x7A9, 0x7A }, + { 0x22, 0x7AA, 0xC6 }, + { 0x22, 0x7AB, 0x39 }, + { 0x22, 0x7AC, 0x08 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC4 }, + { 0x22, 0x7A7, 0xE9 }, + { 0x22, 0x7A8, 0xDC }, + { 0x22, 0x7A9, 0xC4 }, + { 0x22, 0x7AA, 0xE9 }, + { 0x22, 0x7AB, 0xDC }, + { 0x22, 0x7AC, 0x09 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3D }, + { 0x22, 0x7A7, 0xE1 }, + { 0x22, 0x7A8, 0x0D }, + { 0x22, 0x7A9, 0x3D }, + { 0x22, 0x7AA, 0xE1 }, + { 0x22, 0x7AB, 0x0D }, + { 0x22, 0x7AC, 0x0A }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x89 }, + { 0x22, 0x7A7, 0xB6 }, + { 0x22, 0x7A8, 0xEB }, + { 0x22, 0x7A9, 0x89 }, + { 0x22, 0x7AA, 0xB6 }, + { 0x22, 0x7AB, 0xEB }, + { 0x22, 0x7AC, 0x0B }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x39 }, + { 0x22, 0x7A7, 0x9D }, + { 0x22, 0x7A8, 0xFE }, + { 0x22, 0x7A9, 0x39 }, + { 0x22, 0x7AA, 0x9D }, + { 0x22, 0x7AB, 0xFE }, + { 0x22, 0x7AC, 0x0C }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x76 }, + { 0x22, 0x7A7, 0x49 }, + { 0x22, 0x7A8, 0x15 }, + { 0x22, 0x7A9, 0x76 }, + { 0x22, 0x7AA, 0x49 }, + { 0x22, 0x7AB, 0x15 }, + { 0x22, 0x7AC, 0x0D }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC8 }, + { 0x22, 0x7A7, 0x80 }, + { 0x22, 0x7A8, 0xF5 }, + { 0x22, 0x7A9, 0xC8 }, + { 0x22, 0x7AA, 0x80 }, + { 0x22, 0x7AB, 0xF5 }, + { 0x22, 0x7AC, 0x0E }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x0F }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x90 }, + { 0x22, 0x7A7, 0x68 }, + { 0x22, 0x7A8, 0xF1 }, + { 0x22, 0x7A9, 0x90 }, + { 0x22, 0x7AA, 0x68 }, + { 0x22, 0x7AB, 0xF1 }, + { 0x22, 0x7AC, 0x10 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x34 }, + { 0x22, 0x7A7, 0x47 }, + { 0x22, 0x7A8, 0x6C }, + { 0x22, 0x7A9, 0x34 }, + { 0x22, 0x7AA, 0x47 }, + { 0x22, 0x7AB, 0x6C }, + { 0x22, 0x7AC, 0x11 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x6F }, + { 0x22, 0x7A7, 0x97 }, + { 0x22, 0x7A8, 0x0F }, + { 0x22, 0x7A9, 0x6F }, + { 0x22, 0x7AA, 0x97 }, + { 0x22, 0x7AB, 0x0F }, + { 0x22, 0x7AC, 0x12 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xCB }, + { 0x22, 0x7A7, 0xB8 }, + { 0x22, 0x7A8, 0x94 }, + { 0x22, 0x7A9, 0xCB }, + { 0x22, 0x7AA, 0xB8 }, + { 0x22, 0x7AB, 0x94 }, + { 0x22, 0x7AC, 0x13 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x14 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x95 }, + { 0x22, 0x7A7, 0x76 }, + { 0x22, 0x7A8, 0x5B }, + { 0x22, 0x7A9, 0x95 }, + { 0x22, 0x7AA, 0x76 }, + { 0x22, 0x7AB, 0x5B }, + { 0x22, 0x7AC, 0x15 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x31 }, + { 0x22, 0x7A7, 0xAC }, + { 0x22, 0x7A8, 0x31 }, + { 0x22, 0x7A9, 0x31 }, + { 0x22, 0x7AA, 0xAC }, + { 0x22, 0x7AB, 0x31 }, + { 0x22, 0x7AC, 0x16 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x6A }, + { 0x22, 0x7A7, 0x89 }, + { 0x22, 0x7A8, 0xA5 }, + { 0x22, 0x7A9, 0x6A }, + { 0x22, 0x7AA, 0x89 }, + { 0x22, 0x7AB, 0xA5 }, + { 0x22, 0x7AC, 0x17 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xCE }, + { 0x22, 0x7A7, 0x53 }, + { 0x22, 0x7A8, 0xCF }, + { 0x22, 0x7A9, 0xCE }, + { 0x22, 0x7AA, 0x53 }, + { 0x22, 0x7AB, 0xCF }, + { 0x22, 0x7AC, 0x18 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x19 }, + { 0x22, 0x7AD, 0x80 }, + /* 48KHz base */ + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x88 }, + { 0x22, 0x7A8, 0xDC }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x88 }, + { 0x22, 0x7AB, 0xDC }, + { 0x22, 0x7AC, 0x1A }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x82 }, + { 0x22, 0x7A7, 0xEE }, + { 0x22, 0x7A8, 0x46 }, + { 0x22, 0x7A9, 0x82 }, + { 0x22, 0x7AA, 0xEE }, + { 0x22, 0x7AB, 0x46 }, + { 0x22, 0x7AC, 0x1B }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x88 }, + { 0x22, 0x7A8, 0xDC }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x88 }, + { 0x22, 0x7AB, 0xDC }, + { 0x22, 0x7AC, 0x1C }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x7D }, + { 0x22, 0x7A7, 0x09 }, + { 0x22, 0x7A8, 0x28 }, + { 0x22, 0x7A9, 0x7D }, + { 0x22, 0x7AA, 0x09 }, + { 0x22, 0x7AB, 0x28 }, + { 0x22, 0x7AC, 0x1D }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC2 }, + { 0x22, 0x7A7, 0xE5 }, + { 0x22, 0x7A8, 0xB4 }, + { 0x22, 0x7A9, 0xC2 }, + { 0x22, 0x7AA, 0xE5 }, + { 0x22, 0x7AB, 0xB4 }, + { 0x22, 0x7AC, 0x1E }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0xA3 }, + { 0x22, 0x7A8, 0x1F }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0xA3 }, + { 0x22, 0x7AB, 0x1F }, + { 0x22, 0x7AC, 0x1F }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x84 }, + { 0x22, 0x7A7, 0xCA }, + { 0x22, 0x7A8, 0xF1 }, + { 0x22, 0x7A9, 0x84 }, + { 0x22, 0x7AA, 0xCA }, + { 0x22, 0x7AB, 0xF1 }, + { 0x22, 0x7AC, 0x20 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3C }, + { 0x22, 0x7A7, 0xD5 }, + { 0x22, 0x7A8, 0x9C }, + { 0x22, 0x7A9, 0x3C }, + { 0x22, 0x7AA, 0xD5 }, + { 0x22, 0x7AB, 0x9C }, + { 0x22, 0x7AC, 0x21 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x7B }, + { 0x22, 0x7A7, 0x35 }, + { 0x22, 0x7A8, 0x0F }, + { 0x22, 0x7A9, 0x7B }, + { 0x22, 0x7AA, 0x35 }, + { 0x22, 0x7AB, 0x0F }, + { 0x22, 0x7AC, 0x22 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC4 }, + { 0x22, 0x7A7, 0x87 }, + { 0x22, 0x7A8, 0x45 }, + { 0x22, 0x7A9, 0xC4 }, + { 0x22, 0x7AA, 0x87 }, + { 0x22, 0x7AB, 0x45 }, + { 0x22, 0x7AC, 0x23 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3E }, + { 0x22, 0x7A7, 0x0A }, + { 0x22, 0x7A8, 0x78 }, + { 0x22, 0x7A9, 0x3E }, + { 0x22, 0x7AA, 0x0A }, + { 0x22, 0x7AB, 0x78 }, + { 0x22, 0x7AC, 0x24 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x88 }, + { 0x22, 0x7A7, 0xE2 }, + { 0x22, 0x7A8, 0x05 }, + { 0x22, 0x7A9, 0x88 }, + { 0x22, 0x7AA, 0xE2 }, + { 0x22, 0x7AB, 0x05 }, + { 0x22, 0x7AC, 0x25 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x3A }, + { 0x22, 0x7A7, 0x1A }, + { 0x22, 0x7A8, 0xA3 }, + { 0x22, 0x7A9, 0x3A }, + { 0x22, 0x7AA, 0x1A }, + { 0x22, 0x7AB, 0xA3 }, + { 0x22, 0x7AC, 0x26 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x77 }, + { 0x22, 0x7A7, 0x1D }, + { 0x22, 0x7A8, 0xFB }, + { 0x22, 0x7A9, 0x77 }, + { 0x22, 0x7AA, 0x1D }, + { 0x22, 0x7AB, 0xFB }, + { 0x22, 0x7AC, 0x27 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xC7 }, + { 0x22, 0x7A7, 0xDA }, + { 0x22, 0x7A8, 0xE5 }, + { 0x22, 0x7A9, 0xC7 }, + { 0x22, 0x7AA, 0xDA }, + { 0x22, 0x7AB, 0xE5 }, + { 0x22, 0x7AC, 0x28 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x29 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x8E }, + { 0x22, 0x7A7, 0xD7 }, + { 0x22, 0x7A8, 0x22 }, + { 0x22, 0x7A9, 0x8E }, + { 0x22, 0x7AA, 0xD7 }, + { 0x22, 0x7AB, 0x22 }, + { 0x22, 0x7AC, 0x2A }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x35 }, + { 0x22, 0x7A7, 0x26 }, + { 0x22, 0x7A8, 0xC6 }, + { 0x22, 0x7A9, 0x35 }, + { 0x22, 0x7AA, 0x26 }, + { 0x22, 0x7AB, 0xC6 }, + { 0x22, 0x7AC, 0x2B }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x71 }, + { 0x22, 0x7A7, 0x28 }, + { 0x22, 0x7A8, 0xDE }, + { 0x22, 0x7A9, 0x71 }, + { 0x22, 0x7AA, 0x28 }, + { 0x22, 0x7AB, 0xDE }, + { 0x22, 0x7AC, 0x2C }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xCA }, + { 0x22, 0x7A7, 0xD9 }, + { 0x22, 0x7A8, 0x3A }, + { 0x22, 0x7A9, 0xCA }, + { 0x22, 0x7AA, 0xD9 }, + { 0x22, 0x7AB, 0x3A }, + { 0x22, 0x7AC, 0x2D }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x2E }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x93 }, + { 0x22, 0x7A7, 0x5E }, + { 0x22, 0x7A8, 0xD8 }, + { 0x22, 0x7A9, 0x93 }, + { 0x22, 0x7AA, 0x5E }, + { 0x22, 0x7AB, 0xD8 }, + { 0x22, 0x7AC, 0x2F }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x32 }, + { 0x22, 0x7A7, 0xB7 }, + { 0x22, 0x7A8, 0xB1 }, + { 0x22, 0x7A9, 0x32 }, + { 0x22, 0x7AA, 0xB7 }, + { 0x22, 0x7AB, 0xB1 }, + { 0x22, 0x7AC, 0x30 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x6C }, + { 0x22, 0x7A7, 0xA1 }, + { 0x22, 0x7A8, 0x28 }, + { 0x22, 0x7A9, 0x6C }, + { 0x22, 0x7AA, 0xA1 }, + { 0x22, 0x7AB, 0x28 }, + { 0x22, 0x7AC, 0x31 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0xCD }, + { 0x22, 0x7A7, 0x48 }, + { 0x22, 0x7A8, 0x4F }, + { 0x22, 0x7A9, 0xCD }, + { 0x22, 0x7AA, 0x48 }, + { 0x22, 0x7AB, 0x4F }, + { 0x22, 0x7AC, 0x32 }, + { 0x22, 0x7AD, 0x80 }, + { 0x22, 0x7A6, 0x40 }, + { 0x22, 0x7A7, 0x00 }, + { 0x22, 0x7A8, 0x00 }, + { 0x22, 0x7A9, 0x40 }, + { 0x22, 0x7AA, 0x00 }, + { 0x22, 0x7AB, 0x00 }, + { 0x22, 0x7AC, 0x33 }, + { 0x22, 0x7AD, 0x80 }, + /* common */ + { 0x22, 0x782, 0xC1 }, + { 0x22, 0x771, 0x2C }, + { 0x22, 0x772, 0x2C }, + { 0x22, 0x788, 0x04 }, + { 0x01, 0x7B0, 0x08 }, + {} }; -static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { - [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, - [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, - [STAC_DELL_S14] = dell_s14_pin_configs, - [STAC_DELL_VOSTRO_3500] = dell_vostro_3500_pin_configs, - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, - [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, - [STAC_HP_ZEPHYR] = hp_zephyr_pin_configs, +static const struct hda_fixup stac92hd83xxx_fixups[] = { + [STAC_92HD83XXX_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref92hd83xxx_pin_configs, + }, + [STAC_92HD83XXX_PWR_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref92hd83xxx_pin_configs, + }, + [STAC_DELL_S14] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_s14_pin_configs, + }, + [STAC_DELL_VOSTRO_3500] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_vostro_3500_pin_configs, + }, + [STAC_92HD83XXX_HP_cNB11_INTQUAD] = { + .type = HDA_FIXUP_PINS, + .v.pins = hp_cNB11_intquad_pin_configs, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp, + }, + [STAC_HP_DV7_4000] = { + .type = HDA_FIXUP_PINS, + .v.pins = hp_dv7_4000_pin_configs, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_HP_ZEPHYR] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_zephyr, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_INV_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_inv_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HP_MIC_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_mic_led, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_HP_LED_GPIO10] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_hp_led_gpio10, + .chained = true, + .chain_id = STAC_92HD83XXX_HP, + }, + [STAC_92HD83XXX_HEADSET_JACK] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd83xxx_fixup_headset_jack, + }, + [STAC_HP_ENVY_BASS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + { 0x0f, 0x90170111 }, + {} + }, + }, + [STAC_HP_BNB13_EQ] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = hp_bnb13_eq_verbs, + .chained = true, + .chain_id = STAC_92HD83XXX_HP_MIC_LED, + }, }; -static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { - [STAC_92HD83XXX_AUTO] = "auto", - [STAC_92HD83XXX_REF] = "ref", - [STAC_92HD83XXX_PWR_REF] = "mic-ref", - [STAC_DELL_S14] = "dell-s14", - [STAC_DELL_VOSTRO_3500] = "dell-vostro-3500", - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", - [STAC_HP_DV7_4000] = "hp-dv7-4000", - [STAC_HP_ZEPHYR] = "hp-zephyr", - [STAC_92HD83XXX_HP_LED] = "hp-led", - [STAC_92HD83XXX_HP_INV_LED] = "hp-inv-led", - [STAC_92HD83XXX_HP_MIC_LED] = "hp-mic-led", - [STAC_92HD83XXX_HEADSET_JACK] = "headset-jack", +static const struct hda_model_fixup stac92hd83xxx_models[] = { + { .id = STAC_92HD83XXX_REF, .name = "ref" }, + { .id = STAC_92HD83XXX_PWR_REF, .name = "mic-ref" }, + { .id = STAC_DELL_S14, .name = "dell-s14" }, + { .id = STAC_DELL_VOSTRO_3500, .name = "dell-vostro-3500" }, + { .id = STAC_92HD83XXX_HP_cNB11_INTQUAD, .name = "hp_cNB11_intquad" }, + { .id = STAC_HP_DV7_4000, .name = "hp-dv7-4000" }, + { .id = STAC_HP_ZEPHYR, .name = "hp-zephyr" }, + { .id = STAC_92HD83XXX_HP_LED, .name = "hp-led" }, + { .id = STAC_92HD83XXX_HP_INV_LED, .name = "hp-inv-led" }, + { .id = STAC_92HD83XXX_HP_MIC_LED, .name = "hp-mic-led" }, + { .id = STAC_92HD83XXX_HEADSET_JACK, .name = "headset-jack" }, + { .id = STAC_HP_ENVY_BASS, .name = "hp-envy-bass" }, + { .id = STAC_HP_BNB13_EQ, .name = "hp-bnb13-eq" }, + {} }; -static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd83xxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD83XXX_REF), @@ -1724,13 +2722,117 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP Pavilion dv7", STAC_HP_DV7_4000), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1888, + "HP Envy Spectre", STAC_HP_ENVY_BASS), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1899, + "HP Folio 13", STAC_HP_LED_GPIO10), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18df, - "HP Folio", STAC_92HD83XXX_HP_MIC_LED), + "HP Folio", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x18F8, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1909, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x190A, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1940, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1941, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1942, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1943, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1944, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1945, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1946, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1948, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1949, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194A, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194B, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194C, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194E, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x194F, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1950, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1951, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195A, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195B, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x195C, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1991, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2103, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2104, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2105, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2106, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2107, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2108, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2109, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210A, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x210B, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211C, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211D, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211E, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x211F, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2120, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2121, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2122, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2123, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213E, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x213F, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x2140, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B2, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B3, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B5, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x21B6, + "HP bNB13", STAC_HP_BNB13_EQ), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x1900, + "HP", STAC_92HD83XXX_HP_MIC_LED), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2000, + "HP", STAC_92HD83XXX_HP_MIC_LED), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x2100, + "HP", STAC_92HD83XXX_HP_MIC_LED), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, @@ -1763,76 +2865,299 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "HP", STAC_HP_ZEPHYR), SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3660, "HP Mini", STAC_92HD83XXX_HP_LED), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x144E, + "HP Pavilion dv5", STAC_92HD83XXX_HP_INV_LED), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x148a, + "HP Mini", STAC_92HD83XXX_HP_LED), + SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD83XXX_HP), {} /* terminator */ }; -static const struct snd_pci_quirk stac92hd83xxx_codec_id_cfg_tbl[] = { - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3561, - "HP", STAC_HP_ZEPHYR), - {} /* terminator */ +/* HP dv7 bass switch - GPIO5 */ +#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info +static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); + return 0; +} + +static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + struct sigmatel_spec *spec = codec->spec; + unsigned int gpio_data; + + gpio_data = (spec->gpio_data & ~0x20) | + (ucontrol->value.integer.value[0] ? 0x20 : 0); + if (gpio_data == spec->gpio_data) + return 0; + spec->gpio_data = gpio_data; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); + return 1; +} + +static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .info = stac_hp_bass_gpio_info, + .get = stac_hp_bass_gpio_get, + .put = stac_hp_bass_gpio_put, }; -static const unsigned int ref92hd71bxx_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x02214030, 0x02a19040, 0x01a19020, 0x01014010, - 0x0181302e, 0x01014010, 0x01019020, 0x90a000f0, - 0x90a000f0, 0x01452050, 0x01452050, 0x00000000, - 0x00000000 +static int stac_add_hp_bass_switch(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + if (!snd_hda_gen_add_kctl(&spec->gen, "Bass Speaker Playback Switch", + &stac_hp_bass_sw_ctrl)) + return -ENOMEM; + + spec->gpio_mask |= 0x20; + spec->gpio_dir |= 0x20; + spec->gpio_data |= 0x20; + return 0; +} + +static const struct hda_pintbl ref92hd71bxx_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x02a19040 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x0181302e }, + { 0x0f, 0x01014010 }, + { 0x14, 0x01019020 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x90a000f0 }, + { 0x1e, 0x01452050 }, + { 0x1f, 0x01452050 }, + {} }; -static const unsigned int dell_m4_1_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x40f000f0, 0x90170110, - 0x23a1902e, 0x23014250, 0x40f000f0, 0x90a000f0, - 0x40f000f0, 0x4f0000f0, 0x4f0000f0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_1_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x40f000f0 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x23a1902e }, + { 0x0f, 0x23014250 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x4f0000f0 }, + { 0x1f, 0x4f0000f0 }, + {} }; -static const unsigned int dell_m4_2_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, - 0x23a1902e, 0x23014250, 0x40f000f0, 0x40f000f0, - 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_2_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x23a1902e }, + { 0x0f, 0x23014250 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x40f000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x044413b0 }, + { 0x1f, 0x044413b0 }, + {} }; -static const unsigned int dell_m4_3_pin_configs[STAC92HD71BXX_NUM_PINS] = { - 0x0421101f, 0x04a11221, 0x90a70330, 0x90170110, - 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x90a000f0, - 0x40f000f0, 0x044413b0, 0x044413b0, 0x00000000, - 0x00000000 +static const struct hda_pintbl dell_m4_3_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11221 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170110 }, + { 0x0e, 0x40f000f0 }, + { 0x0f, 0x40f000f0 }, + { 0x14, 0x40f000f0 }, + { 0x18, 0x90a000f0 }, + { 0x19, 0x40f000f0 }, + { 0x1e, 0x044413b0 }, + { 0x1f, 0x044413b0 }, + {} }; -static const unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { - [STAC_92HD71BXX_REF] = ref92hd71bxx_pin_configs, - [STAC_DELL_M4_1] = dell_m4_1_pin_configs, - [STAC_DELL_M4_2] = dell_m4_2_pin_configs, - [STAC_DELL_M4_3] = dell_m4_3_pin_configs, - [STAC_HP_M4] = NULL, - [STAC_HP_DV4] = NULL, - [STAC_HP_DV5] = NULL, - [STAC_HP_HDX] = NULL, - [STAC_HP_DV4_1222NR] = NULL, +static void stac92hd71bxx_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + snd_hda_apply_pincfgs(codec, ref92hd71bxx_pin_configs); + spec->gpio_mask = spec->gpio_dir = spec->gpio_data = 0; +} + +static void stac92hd71bxx_fixup_hp_m4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_jack_tbl *jack; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + /* Enable VREF power saving on GPIO1 detect */ + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + STAC_VREF_EVENT, + stac_vref_event); + jack = snd_hda_jack_tbl_get(codec, codec->afg); + if (jack) + jack->private_data = 0x02; + + spec->gpio_mask |= 0x02; + + /* enable internal microphone */ + snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); +} + +static void stac92hd71bxx_fixup_hp_dv4(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->gpio_led = 0x01; +} + +static void stac92hd71bxx_fixup_hp_dv5(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + unsigned int cap; + + switch (action) { + case HDA_FIXUP_ACT_PRE_PROBE: + snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); + break; + + case HDA_FIXUP_ACT_PROBE: + /* enable bass on HP dv7 */ + cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); + cap &= AC_GPIO_IO_COUNT; + if (cap >= 6) + stac_add_hp_bass_switch(codec); + break; + } +} + +static void stac92hd71bxx_fixup_hp_hdx(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + spec->gpio_led = 0x08; +} + + +static void stac92hd71bxx_fixup_hp(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (hp_blike_system(codec->subsystem_id)) { + unsigned int pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); + if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || + get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || + get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { + /* It was changed in the BIOS to just satisfy MS DTM. + * Lets turn it back into slaved HP + */ + pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) + | (AC_JACK_HP_OUT << + AC_DEFCFG_DEVICE_SHIFT); + pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC + | AC_DEFCFG_SEQUENCE))) + | 0x1f; + snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); + } + } + + if (find_mute_led_cfg(codec, 1)) + codec_dbg(codec, "mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); + +} + +static const struct hda_fixup stac92hd71bxx_fixups[] = { + [STAC_92HD71BXX_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_ref, + }, + [STAC_DELL_M4_1] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_1_pin_configs, + }, + [STAC_DELL_M4_2] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_2_pin_configs, + }, + [STAC_DELL_M4_3] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_m4_3_pin_configs, + }, + [STAC_HP_M4] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_m4, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_HP_DV4] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_dv4, + .chained = true, + .chain_id = STAC_HP_DV5, + }, + [STAC_HP_DV5] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_dv5, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_HP_HDX] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp_hdx, + .chained = true, + .chain_id = STAC_92HD71BXX_HP, + }, + [STAC_92HD71BXX_HP] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd71bxx_fixup_hp, + }, }; -static const char * const stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { - [STAC_92HD71BXX_AUTO] = "auto", - [STAC_92HD71BXX_REF] = "ref", - [STAC_DELL_M4_1] = "dell-m4-1", - [STAC_DELL_M4_2] = "dell-m4-2", - [STAC_DELL_M4_3] = "dell-m4-3", - [STAC_HP_M4] = "hp-m4", - [STAC_HP_DV4] = "hp-dv4", - [STAC_HP_DV5] = "hp-dv5", - [STAC_HP_HDX] = "hp-hdx", - [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", +static const struct hda_model_fixup stac92hd71bxx_models[] = { + { .id = STAC_92HD71BXX_REF, .name = "ref" }, + { .id = STAC_DELL_M4_1, .name = "dell-m4-1" }, + { .id = STAC_DELL_M4_2, .name = "dell-m4-2" }, + { .id = STAC_DELL_M4_3, .name = "dell-m4-3" }, + { .id = STAC_HP_M4, .name = "hp-m4" }, + { .id = STAC_HP_DV4, .name = "hp-dv4" }, + { .id = STAC_HP_DV5, .name = "hp-dv5" }, + { .id = STAC_HP_HDX, .name = "hp-hdx" }, + { .id = STAC_HP_DV4, .name = "hp-dv4-1222nr" }, + {} }; -static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { +static const struct snd_pci_quirk stac92hd71bxx_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_92HD71BXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, "DFI LanParty", STAC_92HD71BXX_REF), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, - "HP dv4-1222nr", STAC_HP_DV4_1222NR), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x1720, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, @@ -1855,6 +3180,7 @@ static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP DV6", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), + SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_HP, "HP", STAC_92HD71BXX_HP), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, "unknown Dell", STAC_DELL_M4_1), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0234, @@ -1882,10 +3208,18 @@ static const struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref922x_pin_configs[10] = { - 0x01014010, 0x01016011, 0x01012012, 0x0221401f, - 0x01813122, 0x01011014, 0x01441030, 0x01c41030, - 0x40000100, 0x40000100, +static const struct hda_pintbl ref922x_pin_configs[] = { + { 0x0a, 0x01014010 }, + { 0x0b, 0x01016011 }, + { 0x0c, 0x01012012 }, + { 0x0d, 0x0221401f }, + { 0x0e, 0x01813122 }, + { 0x0f, 0x01011014 }, + { 0x10, 0x01441030 }, + { 0x11, 0x01c41030 }, + { 0x15, 0x40000100 }, + { 0x1b, 0x40000100 }, + {} }; /* @@ -1896,10 +3230,18 @@ static const unsigned int ref922x_pin_configs[10] = { 102801D1 102801D2 */ -static const unsigned int dell_922x_d81_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x400001f0, 0x400001f1, - 0x01813122, 0x400001f2, +static const struct hda_pintbl dell_922x_d81_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x01a19021 }, + { 0x0c, 0x01111012 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x02a19020 }, + { 0x0f, 0x01117011 }, + { 0x10, 0x400001f0 }, + { 0x11, 0x400001f1 }, + { 0x15, 0x01813122 }, + { 0x1b, 0x400001f2 }, + {} }; /* @@ -1907,130 +3249,312 @@ static const unsigned int dell_922x_d81_pin_configs[10] = { 102801AC 102801D0 */ -static const unsigned int dell_922x_d82_pin_configs[10] = { - 0x02214030, 0x01a19021, 0x01111012, 0x01114010, - 0x02a19020, 0x01117011, 0x01451140, 0x400001f0, - 0x01813122, 0x400001f1, +static const struct hda_pintbl dell_922x_d82_pin_configs[] = { + { 0x0a, 0x02214030 }, + { 0x0b, 0x01a19021 }, + { 0x0c, 0x01111012 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x02a19020 }, + { 0x0f, 0x01117011 }, + { 0x10, 0x01451140 }, + { 0x11, 0x400001f0 }, + { 0x15, 0x01813122 }, + { 0x1b, 0x400001f1 }, + {} }; /* STAC 922X pin configs for 102801BF */ -static const unsigned int dell_922x_m81_pin_configs[10] = { - 0x0321101f, 0x01112024, 0x01111222, 0x91174220, - 0x03a11050, 0x01116221, 0x90a70330, 0x01452340, - 0x40C003f1, 0x405003f0, +static const struct hda_pintbl dell_922x_m81_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x01112024 }, + { 0x0c, 0x01111222 }, + { 0x0d, 0x91174220 }, + { 0x0e, 0x03a11050 }, + { 0x0f, 0x01116221 }, + { 0x10, 0x90a70330 }, + { 0x11, 0x01452340 }, + { 0x15, 0x40C003f1 }, + { 0x1b, 0x405003f0 }, + {} }; /* STAC 9221 A1 pin configs for 102801D7 (Dell XPS M1210) */ -static const unsigned int dell_922x_m82_pin_configs[10] = { - 0x02211211, 0x408103ff, 0x02a1123e, 0x90100310, - 0x408003f1, 0x0221121f, 0x03451340, 0x40c003f2, - 0x508003f3, 0x405003f4, +static const struct hda_pintbl dell_922x_m82_pin_configs[] = { + { 0x0a, 0x02211211 }, + { 0x0b, 0x408103ff }, + { 0x0c, 0x02a1123e }, + { 0x0d, 0x90100310 }, + { 0x0e, 0x408003f1 }, + { 0x0f, 0x0221121f }, + { 0x10, 0x03451340 }, + { 0x11, 0x40c003f2 }, + { 0x15, 0x508003f3 }, + { 0x1b, 0x405003f4 }, + {} }; -static const unsigned int d945gtp3_pin_configs[10] = { - 0x0221401f, 0x01a19022, 0x01813021, 0x01014010, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x02a19120, 0x40000100, +static const struct hda_pintbl d945gtp3_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x01a19022 }, + { 0x0c, 0x01813021 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x40000100 }, + { 0x0f, 0x40000100 }, + { 0x10, 0x40000100 }, + { 0x11, 0x40000100 }, + { 0x15, 0x02a19120 }, + { 0x1b, 0x40000100 }, + {} }; -static const unsigned int d945gtp5_pin_configs[10] = { - 0x0221401f, 0x01011012, 0x01813024, 0x01014010, - 0x01a19021, 0x01016011, 0x01452130, 0x40000100, - 0x02a19320, 0x40000100, +static const struct hda_pintbl d945gtp5_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x01011012 }, + { 0x0c, 0x01813024 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19021 }, + { 0x0f, 0x01016011 }, + { 0x10, 0x01452130 }, + { 0x11, 0x40000100 }, + { 0x15, 0x02a19320 }, + { 0x1b, 0x40000100 }, + {} }; -static const unsigned int intel_mac_v1_pin_configs[10] = { - 0x0121e21f, 0x400000ff, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e030, 0x11c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v1_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x400000ff }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e030 }, + { 0x11, 0x11c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v2_pin_configs[10] = { - 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e230, 0x500000fa, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v2_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x90a7012e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e230 }, + { 0x11, 0x500000fa }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v3_pin_configs[10] = { - 0x0121e21f, 0x90a7012e, 0x9017e110, 0x400000fd, - 0x400000fe, 0x0181e020, 0x1145e230, 0x11c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v3_pin_configs[] = { + { 0x0a, 0x0121e21f }, + { 0x0b, 0x90a7012e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x400000fd }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0181e020 }, + { 0x10, 0x1145e230 }, + { 0x11, 0x11c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v4_pin_configs[10] = { - 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, - 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v4_pin_configs[] = { + { 0x0a, 0x0321e21f }, + { 0x0b, 0x03a1e02e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x9017e11f }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0381e020 }, + { 0x10, 0x1345e230 }, + { 0x11, 0x13c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int intel_mac_v5_pin_configs[10] = { - 0x0321e21f, 0x03a1e02e, 0x9017e110, 0x9017e11f, - 0x400000fe, 0x0381e020, 0x1345e230, 0x13c5e240, - 0x400000fc, 0x400000fb, +static const struct hda_pintbl intel_mac_v5_pin_configs[] = { + { 0x0a, 0x0321e21f }, + { 0x0b, 0x03a1e02e }, + { 0x0c, 0x9017e110 }, + { 0x0d, 0x9017e11f }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x0381e020 }, + { 0x10, 0x1345e230 }, + { 0x11, 0x13c5e240 }, + { 0x15, 0x400000fc }, + { 0x1b, 0x400000fb }, + {} }; -static const unsigned int ecs202_pin_configs[10] = { - 0x0221401f, 0x02a19020, 0x01a19020, 0x01114010, - 0x408000f0, 0x01813022, 0x074510a0, 0x40c400f1, - 0x9037012e, 0x40e000f2, +static const struct hda_pintbl ecs202_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x02a19020 }, + { 0x0c, 0x01a19020 }, + { 0x0d, 0x01114010 }, + { 0x0e, 0x408000f0 }, + { 0x0f, 0x01813022 }, + { 0x10, 0x074510a0 }, + { 0x11, 0x40c400f1 }, + { 0x15, 0x9037012e }, + { 0x1b, 0x40e000f2 }, + {} }; -static const unsigned int *stac922x_brd_tbl[STAC_922X_MODELS] = { - [STAC_D945_REF] = ref922x_pin_configs, - [STAC_D945GTP3] = d945gtp3_pin_configs, - [STAC_D945GTP5] = d945gtp5_pin_configs, - [STAC_INTEL_MAC_V1] = intel_mac_v1_pin_configs, - [STAC_INTEL_MAC_V2] = intel_mac_v2_pin_configs, - [STAC_INTEL_MAC_V3] = intel_mac_v3_pin_configs, - [STAC_INTEL_MAC_V4] = intel_mac_v4_pin_configs, - [STAC_INTEL_MAC_V5] = intel_mac_v5_pin_configs, - [STAC_INTEL_MAC_AUTO] = intel_mac_v3_pin_configs, - /* for backward compatibility */ - [STAC_MACMINI] = intel_mac_v3_pin_configs, - [STAC_MACBOOK] = intel_mac_v5_pin_configs, - [STAC_MACBOOK_PRO_V1] = intel_mac_v3_pin_configs, - [STAC_MACBOOK_PRO_V2] = intel_mac_v3_pin_configs, - [STAC_IMAC_INTEL] = intel_mac_v2_pin_configs, - [STAC_IMAC_INTEL_20] = intel_mac_v3_pin_configs, - [STAC_ECS_202] = ecs202_pin_configs, - [STAC_922X_DELL_D81] = dell_922x_d81_pin_configs, - [STAC_922X_DELL_D82] = dell_922x_d82_pin_configs, - [STAC_922X_DELL_M81] = dell_922x_m81_pin_configs, - [STAC_922X_DELL_M82] = dell_922x_m82_pin_configs, -}; - -static const char * const stac922x_models[STAC_922X_MODELS] = { - [STAC_922X_AUTO] = "auto", - [STAC_D945_REF] = "ref", - [STAC_D945GTP5] = "5stack", - [STAC_D945GTP3] = "3stack", - [STAC_INTEL_MAC_V1] = "intel-mac-v1", - [STAC_INTEL_MAC_V2] = "intel-mac-v2", - [STAC_INTEL_MAC_V3] = "intel-mac-v3", - [STAC_INTEL_MAC_V4] = "intel-mac-v4", - [STAC_INTEL_MAC_V5] = "intel-mac-v5", - [STAC_INTEL_MAC_AUTO] = "intel-mac-auto", +/* codec SSIDs for Intel Mac sharing the same PCI SSID 8384:7680 */ +static const struct snd_pci_quirk stac922x_intel_mac_fixup_tbl[] = { + SND_PCI_QUIRK(0x0000, 0x0100, "Mac Mini", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x0800, "Mac", STAC_INTEL_MAC_V1), + SND_PCI_QUIRK(0x106b, 0x0600, "Mac", STAC_INTEL_MAC_V2), + SND_PCI_QUIRK(0x106b, 0x0700, "Mac", STAC_INTEL_MAC_V2), + SND_PCI_QUIRK(0x106b, 0x0e00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x0f00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1600, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1700, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x0200, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1e00, "Mac", STAC_INTEL_MAC_V3), + SND_PCI_QUIRK(0x106b, 0x1a00, "Mac", STAC_INTEL_MAC_V4), + SND_PCI_QUIRK(0x106b, 0x0a00, "Mac", STAC_INTEL_MAC_V5), + SND_PCI_QUIRK(0x106b, 0x2200, "Mac", STAC_INTEL_MAC_V5), + {} +}; + +static const struct hda_fixup stac922x_fixups[]; + +/* remap the fixup from codec SSID and apply it */ +static void stac922x_fixup_intel_mac_auto(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + snd_hda_pick_fixup(codec, NULL, stac922x_intel_mac_fixup_tbl, + stac922x_fixups); + if (codec->fixup_id != STAC_INTEL_MAC_AUTO) + snd_hda_apply_fixup(codec, action); +} + +static void stac922x_fixup_intel_mac_gpio(struct hda_codec *codec, + const struct hda_fixup *fix, + int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + spec->gpio_mask = spec->gpio_dir = 0x03; + spec->gpio_data = 0x03; + } +} + +static const struct hda_fixup stac922x_fixups[] = { + [STAC_D945_REF] = { + .type = HDA_FIXUP_PINS, + .v.pins = ref922x_pin_configs, + }, + [STAC_D945GTP3] = { + .type = HDA_FIXUP_PINS, + .v.pins = d945gtp3_pin_configs, + }, + [STAC_D945GTP5] = { + .type = HDA_FIXUP_PINS, + .v.pins = d945gtp5_pin_configs, + }, + [STAC_INTEL_MAC_AUTO] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac922x_fixup_intel_mac_auto, + }, + [STAC_INTEL_MAC_V1] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v1_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V2] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v2_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V3] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v3_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V4] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v4_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_INTEL_MAC_V5] = { + .type = HDA_FIXUP_PINS, + .v.pins = intel_mac_v5_pin_configs, + .chained = true, + .chain_id = STAC_922X_INTEL_MAC_GPIO, + }, + [STAC_922X_INTEL_MAC_GPIO] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac922x_fixup_intel_mac_gpio, + }, + [STAC_ECS_202] = { + .type = HDA_FIXUP_PINS, + .v.pins = ecs202_pin_configs, + }, + [STAC_922X_DELL_D81] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_d81_pin_configs, + }, + [STAC_922X_DELL_D82] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_d82_pin_configs, + }, + [STAC_922X_DELL_M81] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_m81_pin_configs, + }, + [STAC_922X_DELL_M82] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_922x_m82_pin_configs, + }, +}; + +static const struct hda_model_fixup stac922x_models[] = { + { .id = STAC_D945_REF, .name = "ref" }, + { .id = STAC_D945GTP5, .name = "5stack" }, + { .id = STAC_D945GTP3, .name = "3stack" }, + { .id = STAC_INTEL_MAC_V1, .name = "intel-mac-v1" }, + { .id = STAC_INTEL_MAC_V2, .name = "intel-mac-v2" }, + { .id = STAC_INTEL_MAC_V3, .name = "intel-mac-v3" }, + { .id = STAC_INTEL_MAC_V4, .name = "intel-mac-v4" }, + { .id = STAC_INTEL_MAC_V5, .name = "intel-mac-v5" }, + { .id = STAC_INTEL_MAC_AUTO, .name = "intel-mac-auto" }, + { .id = STAC_ECS_202, .name = "ecs202" }, + { .id = STAC_922X_DELL_D81, .name = "dell-d81" }, + { .id = STAC_922X_DELL_D82, .name = "dell-d82" }, + { .id = STAC_922X_DELL_M81, .name = "dell-m81" }, + { .id = STAC_922X_DELL_M82, .name = "dell-m82" }, /* for backward compatibility */ - [STAC_MACMINI] = "macmini", - [STAC_MACBOOK] = "macbook", - [STAC_MACBOOK_PRO_V1] = "macbook-pro-v1", - [STAC_MACBOOK_PRO_V2] = "macbook-pro", - [STAC_IMAC_INTEL] = "imac-intel", - [STAC_IMAC_INTEL_20] = "imac-intel-20", - [STAC_ECS_202] = "ecs202", - [STAC_922X_DELL_D81] = "dell-d81", - [STAC_922X_DELL_D82] = "dell-d82", - [STAC_922X_DELL_M81] = "dell-m81", - [STAC_922X_DELL_M82] = "dell-m82", -}; - -static const struct snd_pci_quirk stac922x_cfg_tbl[] = { + { .id = STAC_INTEL_MAC_V3, .name = "macmini" }, + { .id = STAC_INTEL_MAC_V5, .name = "macbook" }, + { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro-v1" }, + { .id = STAC_INTEL_MAC_V3, .name = "macbook-pro" }, + { .id = STAC_INTEL_MAC_V2, .name = "imac-intel" }, + { .id = STAC_INTEL_MAC_V3, .name = "imac-intel-20" }, + {} +}; + +static const struct snd_pci_quirk stac922x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D945_REF), @@ -2093,9 +3617,10 @@ static const struct snd_pci_quirk stac922x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x0204, "Intel D945", STAC_D945_REF), /* other systems */ + /* Apple Intel Mac (Mac Mini, MacBook, MacBook Pro...) */ - SND_PCI_QUIRK(0x8384, 0x7680, - "Mac", STAC_INTEL_MAC_AUTO), + SND_PCI_QUIRK(0x8384, 0x7680, "Mac", STAC_INTEL_MAC_AUTO), + /* Dell systems */ SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01a7, "unknown Dell", STAC_922X_DELL_D81), @@ -2121,65 +3646,238 @@ static const struct snd_pci_quirk stac922x_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref927x_pin_configs[14] = { - 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x0101201f, - 0x183301f0, 0x18a001f0, 0x18a001f0, 0x01442070, - 0x01c42190, 0x40000100, +static const struct hda_pintbl ref927x_pin_configs[] = { + { 0x0a, 0x02214020 }, + { 0x0b, 0x02a19080 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x0101201f }, + { 0x12, 0x183301f0 }, + { 0x13, 0x18a001f0 }, + { 0x14, 0x18a001f0 }, + { 0x21, 0x01442070 }, + { 0x22, 0x01c42190 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_3st_pin_configs[14] = { - 0x0221401f, 0x02a19120, 0x40000100, 0x01014011, - 0x01a19021, 0x01813024, 0x40000100, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x40000100, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_3st_pin_configs[] = { + { 0x0a, 0x0221401f }, + { 0x0b, 0x02a19120 }, + { 0x0c, 0x40000100 }, + { 0x0d, 0x01014011 }, + { 0x0e, 0x01a19021 }, + { 0x0f, 0x01813024 }, + { 0x10, 0x40000100 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x40000100 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_5st_pin_configs[14] = { - 0x02214020, 0x02a19080, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x01442070, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_5st_pin_configs[] = { + { 0x0a, 0x02214020 }, + { 0x0b, 0x02a19080 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x01442070 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int d965_5st_no_fp_pin_configs[14] = { - 0x40000100, 0x40000100, 0x0181304e, 0x01014010, - 0x01a19040, 0x01011012, 0x01016011, 0x40000100, - 0x40000100, 0x40000100, 0x40000100, 0x01442070, - 0x40000100, 0x40000100 +static const struct hda_pintbl d965_5st_no_fp_pin_configs[] = { + { 0x0a, 0x40000100 }, + { 0x0b, 0x40000100 }, + { 0x0c, 0x0181304e }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01a19040 }, + { 0x0f, 0x01011012 }, + { 0x10, 0x01016011 }, + { 0x11, 0x40000100 }, + { 0x12, 0x40000100 }, + { 0x13, 0x40000100 }, + { 0x14, 0x40000100 }, + { 0x21, 0x01442070 }, + { 0x22, 0x40000100 }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int dell_3st_pin_configs[14] = { - 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, - 0x01111212, 0x01116211, 0x01813050, 0x01112214, - 0x403003fa, 0x90a60040, 0x90a60040, 0x404003fb, - 0x40c003fc, 0x40000100 +static const struct hda_pintbl dell_3st_pin_configs[] = { + { 0x0a, 0x02211230 }, + { 0x0b, 0x02a11220 }, + { 0x0c, 0x01a19040 }, + { 0x0d, 0x01114210 }, + { 0x0e, 0x01111212 }, + { 0x0f, 0x01116211 }, + { 0x10, 0x01813050 }, + { 0x11, 0x01112214 }, + { 0x12, 0x403003fa }, + { 0x13, 0x90a60040 }, + { 0x14, 0x90a60040 }, + { 0x21, 0x404003fb }, + { 0x22, 0x40c003fc }, + { 0x23, 0x40000100 }, + {} }; -static const unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { - [STAC_D965_REF_NO_JD] = ref927x_pin_configs, - [STAC_D965_REF] = ref927x_pin_configs, - [STAC_D965_3ST] = d965_3st_pin_configs, - [STAC_D965_5ST] = d965_5st_pin_configs, - [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs, - [STAC_DELL_3ST] = dell_3st_pin_configs, - [STAC_DELL_BIOS] = NULL, - [STAC_927X_VOLKNOB] = NULL, +static void stac927x_fixup_ref_no_jd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + /* no jack detecion for ref-no-jd model */ + if (action == HDA_FIXUP_ACT_PRE_PROBE) + codec->no_jack_detect = 1; +} + +static void stac927x_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, ref927x_pin_configs); + spec->eapd_mask = spec->gpio_mask = 0; + spec->gpio_dir = spec->gpio_data = 0; + } +} + +static void stac927x_fixup_dell_dmic(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action != HDA_FIXUP_ACT_PRE_PROBE) + return; + + if (codec->subsystem_id != 0x1028022f) { + /* GPIO2 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = 0x04; + spec->gpio_dir = spec->gpio_data = 0x04; + } + + snd_hda_add_verbs(codec, dell_3st_core_init); + spec->volknob_init = 1; +} + +static void stac927x_fixup_volknob(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_add_verbs(codec, stac927x_volknob_core_init); + spec->volknob_init = 1; + } +} + +static const struct hda_fixup stac927x_fixups[] = { + [STAC_D965_REF_NO_JD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_ref_no_jd, + .chained = true, + .chain_id = STAC_D965_REF, + }, + [STAC_D965_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_ref, + }, + [STAC_D965_3ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_3st_pin_configs, + .chained = true, + .chain_id = STAC_D965_VERBS, + }, + [STAC_D965_5ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_5st_pin_configs, + .chained = true, + .chain_id = STAC_D965_VERBS, + }, + [STAC_D965_VERBS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = d965_core_init, + }, + [STAC_D965_5ST_NO_FP] = { + .type = HDA_FIXUP_PINS, + .v.pins = d965_5st_no_fp_pin_configs, + }, + [STAC_DELL_3ST] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_3st_pin_configs, + .chained = true, + .chain_id = STAC_927X_DELL_DMIC, + }, + [STAC_DELL_BIOS] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* correct the front output jack as a hp out */ + { 0x0f, 0x0221101f }, + /* correct the front input jack as a mic */ + { 0x0e, 0x02a79130 }, + {} + }, + .chained = true, + .chain_id = STAC_927X_DELL_DMIC, + }, + [STAC_DELL_BIOS_AMIC] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* configure the analog microphone on some laptops */ + { 0x0c, 0x90a79130 }, + {} + }, + .chained = true, + .chain_id = STAC_DELL_BIOS, + }, + [STAC_DELL_BIOS_SPDIF] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* correct the device field to SPDIF out */ + { 0x21, 0x01442070 }, + {} + }, + .chained = true, + .chain_id = STAC_DELL_BIOS, + }, + [STAC_927X_DELL_DMIC] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_dell_dmic, + }, + [STAC_927X_VOLKNOB] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac927x_fixup_volknob, + }, }; -static const char * const stac927x_models[STAC_927X_MODELS] = { - [STAC_927X_AUTO] = "auto", - [STAC_D965_REF_NO_JD] = "ref-no-jd", - [STAC_D965_REF] = "ref", - [STAC_D965_3ST] = "3stack", - [STAC_D965_5ST] = "5stack", - [STAC_D965_5ST_NO_FP] = "5stack-no-fp", - [STAC_DELL_3ST] = "dell-3stack", - [STAC_DELL_BIOS] = "dell-bios", - [STAC_927X_VOLKNOB] = "volknob", +static const struct hda_model_fixup stac927x_models[] = { + { .id = STAC_D965_REF_NO_JD, .name = "ref-no-jd" }, + { .id = STAC_D965_REF, .name = "ref" }, + { .id = STAC_D965_3ST, .name = "3stack" }, + { .id = STAC_D965_5ST, .name = "5stack" }, + { .id = STAC_D965_5ST_NO_FP, .name = "5stack-no-fp" }, + { .id = STAC_DELL_3ST, .name = "dell-3stack" }, + { .id = STAC_DELL_BIOS, .name = "dell-bios" }, + { .id = STAC_DELL_BIOS_AMIC, .name = "dell-bios-amic" }, + { .id = STAC_927X_VOLKNOB, .name = "volknob" }, + {} }; -static const struct snd_pci_quirk stac927x_cfg_tbl[] = { +static const struct snd_pci_quirk stac927x_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_D965_REF), @@ -2201,12 +3899,12 @@ static const struct snd_pci_quirk stac927x_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f3, "Dell Inspiron 1420", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x01f7, "Dell XPS M1730", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0227, "Dell Vostro 1400 ", STAC_DELL_BIOS), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022e, "Dell ", STAC_DELL_BIOS_SPDIF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x022f, "Dell Inspiron 1525", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0242, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0243, "Dell ", STAC_DELL_BIOS), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ff, "Dell ", STAC_DELL_BIOS), - SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0209, "Dell XPS 1330", STAC_DELL_BIOS_SPDIF), /* 965 based 5 stack systems */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_INTEL, 0xff00, 0x2300, "Intel D965", STAC_D965_5ST), @@ -2217,10 +3915,20 @@ static const struct snd_pci_quirk stac927x_cfg_tbl[] = { {} /* terminator */ }; -static const unsigned int ref9205_pin_configs[12] = { - 0x40000100, 0x40000100, 0x01016011, 0x01014010, - 0x01813122, 0x01a19021, 0x01019020, 0x40000100, - 0x90a000f0, 0x90a000f0, 0x01441030, 0x01c41030 +static const struct hda_pintbl ref9205_pin_configs[] = { + { 0x0a, 0x40000100 }, + { 0x0b, 0x40000100 }, + { 0x0c, 0x01016011 }, + { 0x0d, 0x01014010 }, + { 0x0e, 0x01813122 }, + { 0x0f, 0x01a19021 }, + { 0x14, 0x01019020 }, + { 0x16, 0x40000100 }, + { 0x17, 0x90a000f0 }, + { 0x18, 0x90a000f0 }, + { 0x21, 0x01441030 }, + { 0x22, 0x01c41030 }, + {} }; /* @@ -2234,10 +3942,20 @@ static const unsigned int ref9205_pin_configs[12] = { 10280228 (Dell Vostro 1500) 10280229 (Dell Vostro 1700) */ -static const unsigned int dell_9205_m42_pin_configs[12] = { - 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, - 0x400003FB, 0x400003FC, 0x400003FD, 0x40F000F9, - 0x90A60330, 0x400003FF, 0x0144131F, 0x40C003FE, +static const struct hda_pintbl dell_9205_m42_pin_configs[] = { + { 0x0a, 0x0321101F }, + { 0x0b, 0x03A11020 }, + { 0x0c, 0x400003FA }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400003FB }, + { 0x0f, 0x400003FC }, + { 0x14, 0x400003FD }, + { 0x16, 0x40F000F9 }, + { 0x17, 0x90A60330 }, + { 0x18, 0x400003FF }, + { 0x21, 0x0144131F }, + { 0x22, 0x40C003FE }, + {} }; /* @@ -2250,36 +3968,126 @@ static const unsigned int dell_9205_m42_pin_configs[12] = { 10280200 10280201 */ -static const unsigned int dell_9205_m43_pin_configs[12] = { - 0x0321101f, 0x03a11020, 0x90a70330, 0x90170310, - 0x400000fe, 0x400000ff, 0x400000fd, 0x40f000f9, - 0x400000fa, 0x400000fc, 0x0144131f, 0x40c003f8, +static const struct hda_pintbl dell_9205_m43_pin_configs[] = { + { 0x0a, 0x0321101f }, + { 0x0b, 0x03a11020 }, + { 0x0c, 0x90a70330 }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400000fe }, + { 0x0f, 0x400000ff }, + { 0x14, 0x400000fd }, + { 0x16, 0x40f000f9 }, + { 0x17, 0x400000fa }, + { 0x18, 0x400000fc }, + { 0x21, 0x0144131f }, + { 0x22, 0x40c003f8 }, + /* Enable SPDIF in/out */ + { 0x1f, 0x01441030 }, + { 0x20, 0x1c410030 }, + {} }; -static const unsigned int dell_9205_m44_pin_configs[12] = { - 0x0421101f, 0x04a11020, 0x400003fa, 0x90170310, - 0x400003fb, 0x400003fc, 0x400003fd, 0x400003f9, - 0x90a60330, 0x400003ff, 0x01441340, 0x40c003fe, +static const struct hda_pintbl dell_9205_m44_pin_configs[] = { + { 0x0a, 0x0421101f }, + { 0x0b, 0x04a11020 }, + { 0x0c, 0x400003fa }, + { 0x0d, 0x90170310 }, + { 0x0e, 0x400003fb }, + { 0x0f, 0x400003fc }, + { 0x14, 0x400003fd }, + { 0x16, 0x400003f9 }, + { 0x17, 0x90a60330 }, + { 0x18, 0x400003ff }, + { 0x21, 0x01441340 }, + { 0x22, 0x40c003fe }, + {} }; -static const unsigned int *stac9205_brd_tbl[STAC_9205_MODELS] = { - [STAC_9205_REF] = ref9205_pin_configs, - [STAC_9205_DELL_M42] = dell_9205_m42_pin_configs, - [STAC_9205_DELL_M43] = dell_9205_m43_pin_configs, - [STAC_9205_DELL_M44] = dell_9205_m44_pin_configs, - [STAC_9205_EAPD] = NULL, +static void stac9205_fixup_ref(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, ref9205_pin_configs); + /* SPDIF-In enabled */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0; + } +} + +static void stac9205_fixup_dell_m43(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + struct hda_jack_tbl *jack; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) { + snd_hda_apply_pincfgs(codec, dell_9205_m43_pin_configs); + + /* Enable unsol response for GPIO4/Dock HP connection */ + snd_hda_codec_write_cache(codec, codec->afg, 0, + AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); + snd_hda_jack_detect_enable_callback(codec, codec->afg, + STAC_VREF_EVENT, + stac_vref_event); + jack = snd_hda_jack_tbl_get(codec, codec->afg); + if (jack) + jack->private_data = 0x01; + + spec->gpio_dir = 0x0b; + spec->eapd_mask = 0x01; + spec->gpio_mask = 0x1b; + spec->gpio_mute = 0x10; + /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, + * GPIO3 Low = DRM + */ + spec->gpio_data = 0x01; + } +} + +static void stac9205_fixup_eapd(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct sigmatel_spec *spec = codec->spec; + + if (action == HDA_FIXUP_ACT_PRE_PROBE) + spec->eapd_switch = 0; +} + +static const struct hda_fixup stac9205_fixups[] = { + [STAC_9205_REF] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_ref, + }, + [STAC_9205_DELL_M42] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_9205_m42_pin_configs, + }, + [STAC_9205_DELL_M43] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_dell_m43, + }, + [STAC_9205_DELL_M44] = { + .type = HDA_FIXUP_PINS, + .v.pins = dell_9205_m44_pin_configs, + }, + [STAC_9205_EAPD] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac9205_fixup_eapd, + }, + {} }; -static const char * const stac9205_models[STAC_9205_MODELS] = { - [STAC_9205_AUTO] = "auto", - [STAC_9205_REF] = "ref", - [STAC_9205_DELL_M42] = "dell-m42", - [STAC_9205_DELL_M43] = "dell-m43", - [STAC_9205_DELL_M44] = "dell-m44", - [STAC_9205_EAPD] = "eapd", +static const struct hda_model_fixup stac9205_models[] = { + { .id = STAC_9205_REF, .name = "ref" }, + { .id = STAC_9205_DELL_M42, .name = "dell-m42" }, + { .id = STAC_9205_DELL_M43, .name = "dell-m43" }, + { .id = STAC_9205_DELL_M44, .name = "dell-m44" }, + { .id = STAC_9205_EAPD, .name = "eapd" }, + {} }; -static const struct snd_pci_quirk stac9205_cfg_tbl[] = { +static const struct snd_pci_quirk stac9205_fixup_tbl[] = { /* SigmaTel reference board */ SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, "DFI LanParty", STAC_9205_REF), @@ -2326,1650 +4134,92 @@ static const struct snd_pci_quirk stac9205_cfg_tbl[] = { {} /* terminator */ }; -static void stac92xx_set_config_regs(struct hda_codec *codec, - const unsigned int *pincfgs) +static void stac92hd95_fixup_hp_led(struct hda_codec *codec, + const struct hda_fixup *fix, int action) { - int i; struct sigmatel_spec *spec = codec->spec; - if (!pincfgs) + if (action != HDA_FIXUP_ACT_PRE_PROBE) return; - for (i = 0; i < spec->num_pins; i++) - if (spec->pin_nids[i] && pincfgs[i]) - snd_hda_codec_set_pincfg(codec, spec->pin_nids[i], - pincfgs[i]); -} - -/* - * Analog playback callbacks - */ -static int stac92xx_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - if (spec->stream_delay) - msleep(spec->stream_delay); - return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); -} - -static int stac92xx_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream); -} - -static int stac92xx_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_analog_cleanup(codec, &spec->multiout); -} - -/* - * Digital playback callbacks - */ -static int stac92xx_dig_playback_pcm_open(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_open(codec, &spec->multiout); -} - -static int stac92xx_dig_playback_pcm_close(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_close(codec, &spec->multiout); -} - -static int stac92xx_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - 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 - */ -static int stac92xx_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->adc_nids[substream->number]; - - if (spec->powerdown_adcs) { - msleep(40); - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D0); - } - snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); - return 0; -} - -static int stac92xx_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = spec->adc_nids[substream->number]; - - snd_hda_codec_cleanup_stream(codec, nid); - if (spec->powerdown_adcs) - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - return 0; + if (find_mute_led_cfg(codec, spec->default_polarity)) + codec_dbg(codec, "mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); } -static const struct hda_pcm_stream stac92xx_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ - .ops = { - .open = stac92xx_dig_playback_pcm_open, - .close = stac92xx_dig_playback_pcm_close, - .prepare = stac92xx_dig_playback_pcm_prepare, - .cleanup = stac92xx_dig_playback_pcm_cleanup +static const struct hda_fixup stac92hd95_fixups[] = { + [STAC_92HD95_HP_LED] = { + .type = HDA_FIXUP_FUNC, + .v.func = stac92hd95_fixup_hp_led, }, -}; - -static const struct hda_pcm_stream stac92xx_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in stac92xx_build_pcms */ -}; - -static const struct hda_pcm_stream stac92xx_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - .nid = 0x02, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup + [STAC_92HD95_HP_BASS] = { + .type = HDA_FIXUP_VERBS, + .v.verbs = (const struct hda_verb[]) { + {0x1a, 0x795, 0x00}, /* HPF to 100Hz */ + {} + }, + .chained = true, + .chain_id = STAC_92HD95_HP_LED, }, }; -static const struct hda_pcm_stream stac92xx_pcm_analog_alt_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - .nid = 0x06, /* NID to query formats and rates */ - .ops = { - .open = stac92xx_playback_pcm_open, - .prepare = stac92xx_playback_pcm_prepare, - .cleanup = stac92xx_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream stac92xx_pcm_analog_capture = { - .channels_min = 2, - .channels_max = 2, - /* NID + .substreams is set in stac92xx_build_pcms */ - .ops = { - .prepare = stac92xx_capture_pcm_prepare, - .cleanup = stac92xx_capture_pcm_cleanup - }, +static const struct snd_pci_quirk stac92hd95_fixup_tbl[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1911, "HP Spectre 13", STAC_92HD95_HP_BASS), + {} /* terminator */ }; -static int stac92xx_build_pcms(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 1; - codec->pcm_info = info; - - 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; - - if (spec->alt_switch) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Analog Alt"; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_analog_alt_playback; - } - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - codec->num_pcms++; - info++; - info->name = "STAC92xx Digital"; - info->pcm_type = spec->autocfg.dig_out_type[0]; - if (spec->multiout.dig_out_nid) { - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = stac92xx_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = stac92xx_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in_nid; - } - } - - return 0; -} - -static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) - -{ - snd_hda_set_pin_ctl_cache(codec, nid, pin_type); -} - -#define stac92xx_hp_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_hp_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = !!spec->hp_switch; - return 0; -} - -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid); - -static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - int nid = kcontrol->private_value; - - spec->hp_switch = ucontrol->value.integer.value[0] ? nid : 0; - - /* check to be sure that the ports are up to date with - * switch changes - */ - stac_issue_unsol_event(codec, nid); - - return 1; -} - -static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - int i; - static const char * const texts[] = { - "Mic In", "Line In", "Line Out" - }; - - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - - if (nid == spec->mic_switch || nid == spec->line_switch) - i = 3; - else - i = 2; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = i; - uinfo->count = 1; - if (uinfo->value.enumerated.item >= i) - uinfo->value.enumerated.item = i-1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = kcontrol->private_value; - unsigned int vref = stac92xx_vref_get(codec, nid); - - if (vref == snd_hda_get_default_vref(codec, nid)) - ucontrol->value.enumerated.item[0] = 0; - else if (vref == AC_PINCTL_VREF_GRD) - ucontrol->value.enumerated.item[0] = 1; - else if (vref == AC_PINCTL_VREF_HIZ) - ucontrol->value.enumerated.item[0] = 2; - - return 0; -} - -static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - unsigned int new_vref = 0; - int error; - hda_nid_t nid = kcontrol->private_value; - - if (ucontrol->value.enumerated.item[0] == 0) - new_vref = snd_hda_get_default_vref(codec, nid); - else if (ucontrol->value.enumerated.item[0] == 1) - new_vref = AC_PINCTL_VREF_GRD; - else if (ucontrol->value.enumerated.item[0] == 2) - new_vref = AC_PINCTL_VREF_HIZ; - else - return 0; - - if (new_vref != stac92xx_vref_get(codec, nid)) { - error = stac92xx_vref_set(codec, nid, new_vref); - return error; - } - - return 0; -} - -static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - char *texts[2]; - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - if (kcontrol->private_value == spec->line_switch) - texts[0] = "Line In"; - else - texts[0] = "Mic In"; - texts[1] = "Line Out"; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->value.enumerated.items = 2; - uinfo->count = 1; - - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; - - ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; - return 0; -} - -static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value; - int io_idx = (nid == spec->mic_switch) ? 1 : 0; - unsigned short val = !!ucontrol->value.enumerated.item[0]; - - spec->io_switch[io_idx] = val; - - if (val) - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - else { - unsigned int pinctl = AC_PINCTL_IN_EN; - if (io_idx) /* set VREF for mic */ - pinctl |= snd_hda_get_default_vref(codec, nid); - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - - /* check the auto-mute again: we need to mute/unmute the speaker - * appropriately according to the pin direction - */ - if (spec->hp_detect) - stac_issue_unsol_event(codec, nid); - - return 1; -} - -#define stac92xx_clfe_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_clfe_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - - ucontrol->value.integer.value[0] = spec->clfe_swap; - return 0; -} - -static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid = kcontrol->private_value & 0xff; - unsigned int val = !!ucontrol->value.integer.value[0]; - - if (spec->clfe_swap == val) - return 0; - - spec->clfe_swap = val; - - snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, - spec->clfe_swap ? 0x4 : 0x0); - - return 1; -} - -#define STAC_CODEC_HP_SWITCH(xname) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_hp_switch_info, \ - .get = stac92xx_hp_switch_get, \ - .put = stac92xx_hp_switch_put, \ - } - -#define STAC_CODEC_IO_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_io_switch_info, \ - .get = stac92xx_io_switch_get, \ - .put = stac92xx_io_switch_put, \ - .private_value = xpval, \ - } - -#define STAC_CODEC_CLFE_SWITCH(xname, xpval) \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .info = stac92xx_clfe_switch_info, \ - .get = stac92xx_clfe_switch_get, \ - .put = stac92xx_clfe_switch_put, \ - .private_value = xpval, \ - } - -enum { - STAC_CTL_WIDGET_VOL, - STAC_CTL_WIDGET_MUTE, - STAC_CTL_WIDGET_MUTE_BEEP, - STAC_CTL_WIDGET_MONO_MUX, - STAC_CTL_WIDGET_HP_SWITCH, - STAC_CTL_WIDGET_IO_SWITCH, - STAC_CTL_WIDGET_CLFE_SWITCH, - STAC_CTL_WIDGET_DC_BIAS -}; - -static const struct snd_kcontrol_new stac92xx_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - HDA_CODEC_MUTE_BEEP(NULL, 0, 0, 0), - STAC_MONO_MUX, - STAC_CODEC_HP_SWITCH(NULL), - STAC_CODEC_IO_SWITCH(NULL, 0), - STAC_CODEC_CLFE_SWITCH(NULL, 0), - DC_BIAS(NULL, 0, 0), -}; - -/* add dynamic controls */ -static struct snd_kcontrol_new * -stac_control_new(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - const char *name, - unsigned int subdev) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *ktemp; - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) { - /* roolback */ - memset(knew, 0, sizeof(*knew)); - spec->kctls.alloced--; - return NULL; - } - knew->subdevice = subdev; - return knew; -} - -static struct snd_kcontrol_new * -add_control_temp(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - int idx, const char *name, - unsigned long val) -{ - struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, - HDA_SUBDEV_AMP_FLAG); - if (!knew) - return NULL; - knew->index = idx; - knew->private_value = val; - return knew; -} - -static int stac92xx_add_control_temp(struct sigmatel_spec *spec, - const struct snd_kcontrol_new *ktemp, - int idx, const char *name, - unsigned long val) -{ - return add_control_temp(spec, ktemp, idx, name, val) ? 0 : -ENOMEM; -} - -static inline int stac92xx_add_control_idx(struct sigmatel_spec *spec, - int type, int idx, const char *name, - unsigned long val) -{ - return stac92xx_add_control_temp(spec, - &stac92xx_control_templates[type], - idx, name, val); -} - - -/* add dynamic controls */ -static inline int stac92xx_add_control(struct sigmatel_spec *spec, int type, - const char *name, unsigned long val) -{ - return stac92xx_add_control_idx(spec, type, 0, name, val); -} - -static const struct snd_kcontrol_new stac_input_src_temp = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Input Source", - .info = stac92xx_mux_enum_info, - .get = stac92xx_mux_enum_get, - .put = stac92xx_mux_enum_put, +static const struct hda_model_fixup stac92hd95_models[] = { + { .id = STAC_92HD95_HP_LED, .name = "hp-led" }, + { .id = STAC_92HD95_HP_BASS, .name = "hp-bass" }, + {} }; -static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, - hda_nid_t nid, int idx) -{ - int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int control = 0; - struct sigmatel_spec *spec = codec->spec; - char name[22]; - - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { - if (spec->headset_jack && snd_hda_get_input_pin_attr(def_conf) - != INPUT_PIN_ATTR_DOCK) - return 0; - if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD - && nid == spec->line_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - else if (snd_hda_query_pin_caps(codec, nid) - & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) - control = STAC_CTL_WIDGET_DC_BIAS; - else if (nid == spec->mic_switch) - control = STAC_CTL_WIDGET_IO_SWITCH; - } - - if (control) { - snd_hda_get_pin_label(codec, nid, &spec->autocfg, - name, sizeof(name), NULL); - return stac92xx_add_control(codec->spec, control, - strcat(name, " Jack Mode"), nid); - } - - return 0; -} - -static int stac92xx_add_input_source(struct sigmatel_spec *spec) -{ - struct snd_kcontrol_new *knew; - struct hda_input_mux *imux = &spec->private_imux; - - if (spec->auto_mic) - return 0; /* no need for input source */ - if (!spec->num_adcs || imux->num_items <= 1) - return 0; /* no need for input source control */ - knew = stac_control_new(spec, &stac_input_src_temp, - stac_input_src_temp.name, 0); - if (!knew) - return -ENOMEM; - knew->count = spec->num_adcs; - return 0; -} - -/* check whether the line-input can be used as line-out */ -static hda_nid_t check_line_out_switch(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t nid; - unsigned int pincap; - int i; - - if (cfg->line_out_type != AUTO_PIN_LINE_OUT) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].type == AUTO_PIN_LINE_IN) { - nid = cfg->inputs[i].pin; - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) - return nid; - } - } - return 0; -} - -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid); - -/* check whether the mic-input can be used as line-out */ -static hda_nid_t check_mic_out_switch(struct hda_codec *codec, hda_nid_t *dac) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int def_conf, pincap; - int i; - - *dac = 0; - if (cfg->line_out_type != AUTO_PIN_LINE_OUT) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - /* some laptops have an internal analog microphone - * which can't be used as a output */ - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_OUT) { - *dac = get_unassigned_dac(codec, nid); - if (*dac) - return nid; - } - } - } - return 0; -} - -static int is_in_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == nid) - return 1; - } - - return 0; -} - -static int check_all_dac_nids(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - if (is_in_dac_nids(spec, nid)) - return 1; - for (i = 0; i < spec->autocfg.hp_outs; i++) - if (spec->hp_dacs[i] == nid) - return 1; - for (i = 0; i < spec->autocfg.speaker_outs; i++) - if (spec->speaker_dacs[i] == nid) - return 1; - return 0; -} - -static hda_nid_t get_unassigned_dac(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int j, conn_len; - hda_nid_t conn[HDA_MAX_CONNECTIONS], fallback_dac; - unsigned int wcaps, wtype; - - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - /* 92HD88: trace back up the link of nids to find the DAC */ - while (conn_len == 1 && (get_wcaps_type(get_wcaps(codec, conn[0])) - != AC_WID_AUD_OUT)) { - nid = conn[0]; - conn_len = snd_hda_get_connections(codec, nid, conn, - HDA_MAX_CONNECTIONS); - } - for (j = 0; j < conn_len; j++) { - wcaps = get_wcaps(codec, conn[j]); - wtype = get_wcaps_type(wcaps); - /* we check only analog outputs */ - if (wtype != AC_WID_AUD_OUT || (wcaps & AC_WCAP_DIGITAL)) - continue; - /* if this route has a free DAC, assign it */ - if (!check_all_dac_nids(spec, conn[j])) { - if (conn_len > 1) { - /* select this DAC in the pin's input mux */ - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); - } - return conn[j]; - } - } - - /* if all DACs are already assigned, connect to the primary DAC, - unless we're assigning a secondary headphone */ - fallback_dac = spec->multiout.dac_nids[0]; - if (spec->multiout.hp_nid) { - for (j = 0; j < cfg->hp_outs; j++) - if (cfg->hp_pins[j] == nid) { - fallback_dac = spec->multiout.hp_nid; - break; - } - } - - if (conn_len > 1) { - for (j = 0; j < conn_len; j++) { - if (conn[j] == fallback_dac) { - snd_hda_codec_write_cache(codec, nid, 0, - AC_VERB_SET_CONNECT_SEL, j); - break; - } - } - } - return 0; -} - -static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid); -static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid); - -/* - * Fill in the dac_nids table from the parsed pin configuration - * This function only works when every pin in line_out_pins[] - * contains atleast one DAC in its connection list. Some 92xx - * codecs are not connected directly to a DAC, such as the 9200 - * and 9202/925x. For those, dac_nids[] must be hard-coded. - */ -static int stac92xx_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - hda_nid_t nid, dac; - - for (i = 0; i < cfg->line_outs; i++) { - nid = cfg->line_out_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (!dac) { - if (spec->multiout.num_dacs > 0) { - /* we have already working output pins, - * so let's drop the broken ones again - */ - cfg->line_outs = spec->multiout.num_dacs; - break; - } - /* error out, no available DAC found */ - snd_printk(KERN_ERR - "%s: No available DAC for pin 0x%x\n", - __func__, nid); - return -ENODEV; - } - add_spec_dacs(spec, dac); - } - - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (dac) { - if (!spec->multiout.hp_nid) - spec->multiout.hp_nid = dac; - else - add_spec_extra_dacs(spec, dac); - } - spec->hp_dacs[i] = dac; - } - - for (i = 0; i < cfg->speaker_outs; i++) { - nid = cfg->speaker_pins[i]; - dac = get_unassigned_dac(codec, nid); - if (dac) - add_spec_extra_dacs(spec, dac); - spec->speaker_dacs[i] = dac; - } - - /* add line-in as output */ - nid = check_line_out_switch(codec); - if (nid) { - dac = get_unassigned_dac(codec, nid); - if (dac) { - snd_printdd("STAC: Add line-in 0x%x as output %d\n", - nid, cfg->line_outs); - cfg->line_out_pins[cfg->line_outs] = nid; - cfg->line_outs++; - spec->line_switch = nid; - add_spec_dacs(spec, dac); - } - } - /* add mic as output */ - nid = check_mic_out_switch(codec, &dac); - if (nid && dac) { - snd_printdd("STAC: Add mic-in 0x%x as output %d\n", - nid, cfg->line_outs); - cfg->line_out_pins[cfg->line_outs] = nid; - cfg->line_outs++; - spec->mic_switch = nid; - add_spec_dacs(spec, dac); - } - - snd_printd("stac92xx: dac_nids=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - spec->multiout.num_dacs, - spec->multiout.dac_nids[0], - spec->multiout.dac_nids[1], - spec->multiout.dac_nids[2], - spec->multiout.dac_nids[3], - spec->multiout.dac_nids[4]); - - return 0; -} - -/* create volume control/switch for the given prefx type */ -static int create_controls_idx(struct hda_codec *codec, const char *pfx, - int idx, hda_nid_t nid, int chs) -{ - struct sigmatel_spec *spec = codec->spec; - char name[32]; - int err; - - if (!spec->check_volume_offset) { - unsigned int caps, step, nums, db_scale; - caps = query_amp_caps(codec, nid, HDA_OUTPUT); - step = (caps & AC_AMPCAP_STEP_SIZE) >> - AC_AMPCAP_STEP_SIZE_SHIFT; - step = (step + 1) * 25; /* in .01dB unit */ - nums = (caps & AC_AMPCAP_NUM_STEPS) >> - AC_AMPCAP_NUM_STEPS_SHIFT; - db_scale = nums * step; - /* if dB scale is over -64dB, and finer enough, - * let's reduce it to half - */ - if (db_scale > 6400 && nums >= 0x1f) - spec->volume_offset = nums / 2; - spec->check_volume_offset = 1; - } - - sprintf(name, "%s Playback Volume", pfx); - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, idx, name, - HDA_COMPOSE_AMP_VAL_OFS(nid, chs, 0, HDA_OUTPUT, - spec->volume_offset)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", pfx); - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_MUTE, idx, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - return 0; -} - -#define create_controls(codec, pfx, nid, chs) \ - create_controls_idx(codec, pfx, 0, nid, chs) - -static int add_spec_dacs(struct sigmatel_spec *spec, hda_nid_t nid) -{ - if (spec->multiout.num_dacs > 4) { - printk(KERN_WARNING "stac92xx: No space for DAC 0x%x\n", nid); - return 1; - } else { - snd_BUG_ON(spec->multiout.dac_nids != spec->dac_nids); - spec->dac_nids[spec->multiout.num_dacs] = nid; - spec->multiout.num_dacs++; - } - return 0; -} - -static int add_spec_extra_dacs(struct sigmatel_spec *spec, hda_nid_t nid) -{ - int i; - for (i = 0; i < ARRAY_SIZE(spec->multiout.extra_out_nid); i++) { - if (!spec->multiout.extra_out_nid[i]) { - spec->multiout.extra_out_nid[i] = nid; - return 0; - } - } - printk(KERN_WARNING "stac92xx: No space for extra DAC 0x%x\n", nid); - return 1; -} - -/* Create output controls - * The mixer elements are named depending on the given type (AUTO_PIN_XXX_OUT) - */ -static int create_multi_out_ctls(struct hda_codec *codec, int num_outs, - const hda_nid_t *pins, - const hda_nid_t *dac_nids, - int type) -{ - struct sigmatel_spec *spec = codec->spec; - static const char * const chname[4] = { - "Front", "Surround", NULL /*CLFE*/, "Side" - }; - hda_nid_t nid; - int i, err; - unsigned int wid_caps; - - for (i = 0; i < num_outs && i < ARRAY_SIZE(chname); i++) { - if (type == AUTO_PIN_HP_OUT && !spec->hp_detect) { - if (is_jack_detectable(codec, pins[i])) - spec->hp_detect = 1; - } - nid = dac_nids[i]; - if (!nid) - continue; - if (type != AUTO_PIN_HP_OUT && i == 2) { - /* Center/LFE */ - err = create_controls(codec, "Center", nid, 1); - if (err < 0) - return err; - err = create_controls(codec, "LFE", nid, 2); - if (err < 0) - return err; - - wid_caps = get_wcaps(codec, nid); - - if (wid_caps & AC_WCAP_LR_SWAP) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_CLFE_SWITCH, - "Swap Center/LFE Playback Switch", nid); - - if (err < 0) - return err; - } - - } else { - const char *name; - int idx; - switch (type) { - case AUTO_PIN_HP_OUT: - name = "Headphone"; - idx = i; - break; - case AUTO_PIN_SPEAKER_OUT: - if (num_outs <= 1) { - name = "Speaker"; - idx = i; - break; - } - /* Fall through in case of multi speaker outs */ - default: - name = chname[i]; - idx = 0; - break; - } - err = create_controls_idx(codec, name, idx, nid, 3); - if (err < 0) - return err; - } - } - return 0; -} - -static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, - unsigned int dir_mask, unsigned int data); - -/* hook for controlling mic-mute LED GPIO */ -static int stac92xx_capture_sw_put_led(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - int err; - bool mute; - err = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - if (err <= 0) - return err; - mute = !(ucontrol->value.integer.value[0] && - ucontrol->value.integer.value[1]); - if (spec->mic_mute_led_on != mute) { - spec->mic_mute_led_on = mute; - if (mute) - spec->gpio_data |= spec->mic_mute_led_gpio; - else - spec->gpio_data &= ~spec->mic_mute_led_gpio; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } - return err; -} - -static int stac92xx_add_capvol_ctls(struct hda_codec *codec, unsigned long vol, - unsigned long sw, int idx) +static int stac_parse_auto_config(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; int err; + int flags = 0; - err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, - "Capture Volume", vol); - if (err < 0) - return err; - - knew = add_control_temp(spec, - &stac92xx_control_templates[STAC_CTL_WIDGET_MUTE], - idx, "Capture Switch", sw); - if (!knew) - return -ENOMEM; - /* add a LED hook for some HP laptops */ - if (spec->mic_mute_led_gpio) - knew->put = stac92xx_capture_sw_put_led; - - return 0; -} - -/* add playback controls from the parsed DAC table */ -static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t nid; - int err; - int idx; + if (spec->headset_jack) + flags |= HDA_PINCFG_HEADSET_MIC; - err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, - spec->multiout.dac_nids, - cfg->line_out_type); + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, flags); if (err < 0) return err; - if (cfg->hp_outs > 1 && cfg->line_out_type == AUTO_PIN_LINE_OUT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_HP_SWITCH, - "Headphone as Line Out Switch", - cfg->hp_pins[cfg->hp_outs - 1]); - if (err < 0) - return err; - } + /* add hooks */ + spec->gen.pcm_playback_hook = stac_playback_pcm_hook; + spec->gen.pcm_capture_hook = stac_capture_pcm_hook; - for (idx = 0; idx < cfg->num_inputs; idx++) { - if (cfg->inputs[idx].type > AUTO_PIN_LINE_IN) - break; - nid = cfg->inputs[idx].pin; - err = stac92xx_add_jack_mode_control(codec, nid, idx); - if (err < 0) - return err; - } - - return 0; -} - -/* add playback controls for Speaker and HP outputs */ -static int stac92xx_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - - err = create_multi_out_ctls(codec, cfg->hp_outs, cfg->hp_pins, - spec->hp_dacs, AUTO_PIN_HP_OUT); - if (err < 0) - return err; + spec->gen.automute_hook = stac_update_outputs; + spec->gen.hp_automute_hook = stac_hp_automute; + spec->gen.line_automute_hook = stac_line_automute; + spec->gen.mic_autoswitch_hook = stac_mic_autoswitch; - err = create_multi_out_ctls(codec, cfg->speaker_outs, cfg->speaker_pins, - spec->speaker_dacs, AUTO_PIN_SPEAKER_OUT); + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); if (err < 0) return err; - return 0; -} - -/* labels for mono mux outputs */ -static const char * const stac92xx_mono_labels[4] = { - "DAC0", "DAC1", "Mixer", "DAC2" -}; - -/* create mono mux for mono out on capable codecs */ -static int stac92xx_auto_create_mono_output_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *mono_mux = &spec->private_mono_mux; - int i, num_cons; - hda_nid_t con_lst[ARRAY_SIZE(stac92xx_mono_labels)]; - - num_cons = snd_hda_get_connections(codec, - spec->mono_nid, - con_lst, - HDA_MAX_NUM_INPUTS); - if (num_cons <= 0 || num_cons > ARRAY_SIZE(stac92xx_mono_labels)) - return -EINVAL; - - for (i = 0; i < num_cons; i++) - snd_hda_add_imux_item(mono_mux, stac92xx_mono_labels[i], i, - NULL); - - return stac92xx_add_control(spec, STAC_CTL_WIDGET_MONO_MUX, - "Mono Mux", spec->mono_nid); -} - -/* create PC beep volume controls */ -static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, - hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); - int err, type = STAC_CTL_WIDGET_MUTE_BEEP; - - if (spec->anabeep_nid == nid) - type = STAC_CTL_WIDGET_MUTE; - - /* check for mute support for the the amp */ - if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { - err = stac92xx_add_control(spec, type, - "Beep Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - - /* check to see if there is volume support for the amp */ - if ((caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT) { - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_VOL, - "Beep Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); - if (err < 0) - return err; - } - return 0; -} - -#ifdef CONFIG_SND_HDA_INPUT_BEEP -#define stac92xx_dig_beep_switch_info snd_ctl_boolean_mono_info - -static int stac92xx_dig_beep_switch_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = codec->beep->enabled; - return 0; -} - -static int stac92xx_dig_beep_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); -} - -static const struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = stac92xx_dig_beep_switch_info, - .get = stac92xx_dig_beep_switch_get, - .put = stac92xx_dig_beep_switch_put, -}; - -static int stac92xx_beep_switch_ctl(struct hda_codec *codec) -{ - return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, - 0, "Beep Playback Switch", 0); -} -#endif - -static int stac92xx_auto_create_mux_input_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i, j, err = 0; - - for (i = 0; i < spec->num_muxes; i++) { - hda_nid_t nid; - unsigned int wcaps; - unsigned long val; - - nid = spec->mux_nids[i]; - wcaps = get_wcaps(codec, nid); - if (!(wcaps & AC_WCAP_OUT_AMP)) - continue; - - /* check whether already the same control was created as - * normal Capture Volume. - */ - val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - for (j = 0; j < spec->num_caps; j++) { - if (spec->capvols[j] == val) - break; - } - if (j < spec->num_caps) - continue; - - err = stac92xx_add_control_idx(spec, STAC_CTL_WIDGET_VOL, i, - "Mux Capture Volume", val); - if (err < 0) - return err; - } - return 0; -}; - -static const char * const stac92xx_spdif_labels[3] = { - "Digital Playback", "Analog Mux 1", "Analog Mux 2", -}; - -static int stac92xx_auto_create_spdif_mux_ctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *spdif_mux = &spec->private_smux; - const char * const *labels = spec->spdif_labels; - int i, num_cons; - hda_nid_t con_lst[HDA_MAX_NUM_INPUTS]; - - num_cons = snd_hda_get_connections(codec, - spec->smux_nids[0], - con_lst, - HDA_MAX_NUM_INPUTS); - if (num_cons <= 0) - return -EINVAL; - - if (!labels) - labels = stac92xx_spdif_labels; - - for (i = 0; i < num_cons; i++) - snd_hda_add_imux_item(spdif_mux, labels[i], i, NULL); - - return 0; -} - -/* labels for dmic mux inputs */ -static const char * const stac92xx_dmic_labels[5] = { - "Analog Inputs", "Digital Mic 1", "Digital Mic 2", - "Digital Mic 3", "Digital Mic 4" -}; - -static hda_nid_t get_connected_node(struct hda_codec *codec, hda_nid_t mux, - int idx) -{ - hda_nid_t conn[HDA_MAX_NUM_INPUTS]; - int nums; - nums = snd_hda_get_connections(codec, mux, conn, ARRAY_SIZE(conn)); - if (idx >= 0 && idx < nums) - return conn[idx]; - return 0; -} - -/* look for NID recursively */ -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 1) - -/* create a volume assigned to the given pin (only if supported) */ -/* return 1 if the volume control is created */ -static int create_elem_capture_vol(struct hda_codec *codec, hda_nid_t nid, - const char *label, int idx, int direction) -{ - unsigned int caps, nums; - char name[32]; - int err; - - if (direction == HDA_OUTPUT) - caps = AC_WCAP_OUT_AMP; - else - caps = AC_WCAP_IN_AMP; - if (!(get_wcaps(codec, nid) & caps)) - return 0; - caps = query_amp_caps(codec, nid, direction); - nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (!nums) - return 0; - snprintf(name, sizeof(name), "%s Capture Volume", label); - err = stac92xx_add_control_idx(codec->spec, STAC_CTL_WIDGET_VOL, idx, name, - HDA_COMPOSE_AMP_VAL(nid, 3, 0, direction)); - if (err < 0) - return err; - return 1; -} - -/* create playback/capture controls for input pins on dmic capable codecs */ -static int stac92xx_auto_create_dmic_input_ctls(struct hda_codec *codec, - const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - struct hda_input_mux *dimux = &spec->private_dimux; - int err, i; - unsigned int def_conf; - - snd_hda_add_imux_item(dimux, stac92xx_dmic_labels[0], 0, NULL); - - for (i = 0; i < spec->num_dmics; i++) { - hda_nid_t nid; - int index, type_idx; - char label[32]; - - nid = spec->dmic_nids[i]; - if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) - continue; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - continue; - - index = get_connection_index(codec, spec->dmux_nids[0], nid); - if (index < 0) - continue; - - snd_hda_get_pin_label(codec, nid, &spec->autocfg, - label, sizeof(label), NULL); - snd_hda_add_imux_item(dimux, label, index, &type_idx); - if (snd_hda_get_bool_hint(codec, "separate_dmux") != 1) - snd_hda_add_imux_item(imux, label, index, &type_idx); - - err = create_elem_capture_vol(codec, nid, label, type_idx, - HDA_INPUT); - if (err < 0) - return err; - if (!err) { - err = create_elem_capture_vol(codec, nid, label, - type_idx, HDA_OUTPUT); - if (err < 0) - return err; - if (!err) { - nid = get_connected_node(codec, - spec->dmux_nids[0], index); - if (nid) - err = create_elem_capture_vol(codec, - nid, label, - type_idx, HDA_INPUT); - if (err < 0) - return err; - } - } - } - - return 0; -} - -static int check_mic_pin(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *fixed, hda_nid_t *ext, hda_nid_t *dock) -{ - unsigned int cfg; - unsigned int type; - - if (!nid) - return 0; - cfg = snd_hda_codec_get_pincfg(codec, nid); - type = get_defcfg_device(cfg); - switch (snd_hda_get_input_pin_attr(cfg)) { - case INPUT_PIN_ATTR_INT: - if (*fixed) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN) - return 1; /* invalid type */ - *fixed = nid; - break; - case INPUT_PIN_ATTR_UNUSED: - break; - case INPUT_PIN_ATTR_DOCK: - if (*dock) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN && type != AC_JACK_LINE_IN) - return 1; /* invalid type */ - *dock = nid; - break; - default: - if (*ext) - return 1; /* already occupied */ - if (type != AC_JACK_MIC_IN) - return 1; /* invalid type */ - *ext = nid; - break; - } - return 0; -} - -static int set_mic_route(struct hda_codec *codec, - struct sigmatel_mic_route *mic, - hda_nid_t pin) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - mic->pin = pin; - if (pin == 0) - return 0; - for (i = 0; i < cfg->num_inputs; i++) { - if (pin == cfg->inputs[i].pin) - break; - } - if (i < cfg->num_inputs && cfg->inputs[i].type == AUTO_PIN_MIC) { - /* analog pin */ - i = get_connection_index(codec, spec->mux_nids[0], pin); - if (i < 0) - return -1; - mic->mux_idx = i; - mic->dmux_idx = -1; - if (spec->dmux_nids) - mic->dmux_idx = get_connection_index(codec, - spec->dmux_nids[0], - spec->mux_nids[0]); - } else if (spec->dmux_nids) { - /* digital pin */ - i = get_connection_index(codec, spec->dmux_nids[0], pin); - if (i < 0) - return -1; - mic->dmux_idx = i; - mic->mux_idx = -1; - if (spec->mux_nids) - mic->mux_idx = get_connection_index(codec, - spec->mux_nids[0], - spec->dmux_nids[0]); - } - return 0; -} - -/* return non-zero if the device is for automatic mic switch */ -static int stac_check_auto_mic(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t fixed, ext, dock; - int i; - - fixed = ext = dock = 0; - for (i = 0; i < cfg->num_inputs; i++) - if (check_mic_pin(codec, cfg->inputs[i].pin, - &fixed, &ext, &dock)) - return 0; - for (i = 0; i < spec->num_dmics; i++) - if (check_mic_pin(codec, spec->dmic_nids[i], - &fixed, &ext, &dock)) - return 0; - if (!fixed || (!ext && !dock)) - return 0; /* no input to switch */ - if (!is_jack_detectable(codec, ext)) - return 0; /* no unsol support */ - if (set_mic_route(codec, &spec->ext_mic, ext) || - set_mic_route(codec, &spec->int_mic, fixed) || - set_mic_route(codec, &spec->dock_mic, dock)) - return 0; /* something is wrong */ - return 1; -} - -/* create playback/capture controls for input pins */ -static int stac92xx_auto_create_analog_input_ctls(struct hda_codec *codec, const struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - struct hda_input_mux *imux = &spec->private_imux; - int i, j; - const char *label; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int index, err, type_idx; - - index = -1; - for (j = 0; j < spec->num_muxes; j++) { - index = get_connection_index(codec, spec->mux_nids[j], - nid); - if (index >= 0) - break; - } - if (index < 0) - continue; - - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, index, &type_idx); - - err = create_elem_capture_vol(codec, nid, - label, type_idx, - HDA_INPUT); - if (err < 0) - return err; - } - spec->num_analog_muxes = imux->num_items; - - if (imux->num_items) { - /* - * Set the current input for the muxes. - * The STAC9221 has two input muxes with identical source - * NID lists. Hopefully this won't get confused. - */ - for (i = 0; i < spec->num_muxes; i++) { - snd_hda_codec_write_cache(codec, spec->mux_nids[i], 0, - AC_VERB_SET_CONNECT_SEL, - imux->items[0].index); - } - } - - return 0; -} - -static void stac92xx_auto_init_multi_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.line_outs; i++) { - hda_nid_t nid = spec->autocfg.line_out_pins[i]; - stac92xx_auto_set_pinctl(codec, nid, AC_PINCTL_OUT_EN); - } -} - -static void stac92xx_auto_init_hp_out(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.hp_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.hp_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - } - for (i = 0; i < spec->autocfg.speaker_outs; i++) { - hda_nid_t pin; - pin = spec->autocfg.speaker_pins[i]; - if (pin) /* connect to front */ - stac92xx_auto_set_pinctl(codec, pin, AC_PINCTL_OUT_EN); - } -} - -static int is_dual_headphones(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int i, valid_hps; - - if (spec->autocfg.line_out_type != AUTO_PIN_SPEAKER_OUT || - spec->autocfg.hp_outs <= 1) - return 0; - valid_hps = 0; - for (i = 0; i < spec->autocfg.hp_outs; i++) { - hda_nid_t nid = spec->autocfg.hp_pins[i]; - unsigned int cfg = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_location(cfg) & AC_JACK_LOC_SEPARATE) - continue; - valid_hps++; - } - return (valid_hps > 1); -} - - -static int stac92xx_parse_auto_config(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t dig_out = 0, dig_in = 0; - int hp_swap = 0; - int i, err; - - if ((err = snd_hda_parse_pin_def_config(codec, - &spec->autocfg, - spec->dmic_nids)) < 0) - return err; - if (! spec->autocfg.line_outs) - return 0; /* can't find valid pin config */ - - /* If we have no real line-out pin and multiple hp-outs, HPs should - * be set up as multi-channel outputs. - */ - if (is_dual_headphones(codec)) { - /* Copy hp_outs to line_outs, backup line_outs in - * speaker_outs so that the following routines can handle - * HP pins as primary outputs. - */ - snd_printdd("stac92xx: Enabling multi-HPs workaround\n"); - memcpy(spec->autocfg.speaker_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.line_out_pins)); - spec->autocfg.speaker_outs = spec->autocfg.line_outs; - memcpy(spec->autocfg.line_out_pins, spec->autocfg.hp_pins, - sizeof(spec->autocfg.hp_pins)); - spec->autocfg.line_outs = spec->autocfg.hp_outs; - spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; - spec->autocfg.hp_outs = 0; - hp_swap = 1; - } - if (spec->autocfg.mono_out_pin) { - int dir = get_wcaps(codec, spec->autocfg.mono_out_pin) & - (AC_WCAP_OUT_AMP | AC_WCAP_IN_AMP); - u32 caps = query_amp_caps(codec, - spec->autocfg.mono_out_pin, dir); - hda_nid_t conn_list[1]; - - /* get the mixer node and then the mono mux if it exists */ - if (snd_hda_get_connections(codec, - spec->autocfg.mono_out_pin, conn_list, 1) && - snd_hda_get_connections(codec, conn_list[0], - conn_list, 1) > 0) { - - int wcaps = get_wcaps(codec, conn_list[0]); - int wid_type = get_wcaps_type(wcaps); - /* LR swap check, some stac925x have a mux that - * changes the DACs output path instead of the - * mono-mux path. - */ - if (wid_type == AC_WID_AUD_SEL && - !(wcaps & AC_WCAP_LR_SWAP)) - spec->mono_nid = conn_list[0]; - } - if (dir) { - hda_nid_t nid = spec->autocfg.mono_out_pin; - - /* most mono outs have a least a mute/unmute switch */ - dir = (dir & AC_WCAP_OUT_AMP) ? HDA_OUTPUT : HDA_INPUT; - err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, - "Mono Playback Switch", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); - if (err < 0) - return err; - /* check for volume support for the amp */ - if ((caps & AC_AMPCAP_NUM_STEPS) - >> AC_AMPCAP_NUM_STEPS_SHIFT) { - err = stac92xx_add_control(spec, - STAC_CTL_WIDGET_VOL, - "Mono Playback Volume", - HDA_COMPOSE_AMP_VAL(nid, 1, 0, dir)); - if (err < 0) - return err; - } - } - - stac92xx_auto_set_pinctl(codec, spec->autocfg.mono_out_pin, - AC_PINCTL_OUT_EN); - } - - if (!spec->multiout.num_dacs) { - 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; - } + /* minimum value is actually mute */ + spec->gen.vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; /* setup analog beep controls */ if (spec->anabeep_nid > 0) { - err = stac92xx_auto_create_beep_ctls(codec, - spec->anabeep_nid); + err = stac_auto_create_beep_ctls(codec, + spec->anabeep_nid); if (err < 0) return err; } /* setup digital beep controls and input device */ #ifdef CONFIG_SND_HDA_INPUT_BEEP - if (spec->digbeep_nid > 0) { - hda_nid_t nid = spec->digbeep_nid; + if (spec->gen.beep_nid) { + hda_nid_t nid = spec->gen.beep_nid; unsigned int caps; - err = stac92xx_auto_create_beep_ctls(codec, nid); - if (err < 0) - return err; - err = snd_hda_attach_beep_device(codec, nid); + err = stac_auto_create_beep_ctls(codec, nid); if (err < 0) return err; if (codec->beep) { @@ -3978,7 +4228,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) /* if no beep switch is available, make its own one */ caps = query_amp_caps(codec, nid, HDA_OUTPUT); if (!(caps & AC_AMPCAP_MUTE)) { - err = stac92xx_beep_switch_ctl(codec); + err = stac_beep_switch_ctl(codec); if (err < 0) return err; } @@ -3986,573 +4236,70 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec) } #endif - err = stac92xx_auto_create_hp_ctls(codec, &spec->autocfg); - if (err < 0) - return err; - - /* All output parsing done, now restore the swapped hp pins */ - if (hp_swap) { - memcpy(spec->autocfg.hp_pins, spec->autocfg.line_out_pins, - sizeof(spec->autocfg.hp_pins)); - spec->autocfg.hp_outs = spec->autocfg.line_outs; - spec->autocfg.line_out_type = AUTO_PIN_HP_OUT; - spec->autocfg.line_outs = 0; - } - - if (stac_check_auto_mic(codec)) { - spec->auto_mic = 1; - /* only one capture for auto-mic */ - spec->num_adcs = 1; - spec->num_caps = 1; - spec->num_muxes = 1; - } - - for (i = 0; i < spec->num_caps; i++) { - err = stac92xx_add_capvol_ctls(codec, spec->capvols[i], - spec->capsws[i], i); - if (err < 0) - return err; - } - - err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg); - if (err < 0) - return err; - - if (spec->mono_nid > 0) { - err = stac92xx_auto_create_mono_output_ctls(codec); - if (err < 0) - return err; - } - if (spec->num_dmics > 0 && !spec->dinput_mux) - if ((err = stac92xx_auto_create_dmic_input_ctls(codec, - &spec->autocfg)) < 0) - return err; - if (spec->num_muxes > 0) { - err = stac92xx_auto_create_mux_input_ctls(codec); - if (err < 0) - return err; - } - if (spec->num_smuxes > 0) { - err = stac92xx_auto_create_spdif_mux_ctls(codec); - if (err < 0) - return err; - } - - err = stac92xx_add_input_source(spec); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - if (spec->multiout.max_channels > 2) - spec->surr_switch = 1; - - /* find digital out and in converters */ - for (i = codec->start_nid; i < codec->start_nid + codec->num_nodes; i++) { - unsigned int wid_caps = get_wcaps(codec, i); - if (wid_caps & AC_WCAP_DIGITAL) { - switch (get_wcaps_type(wid_caps)) { - case AC_WID_AUD_OUT: - if (!dig_out) - dig_out = i; - break; - case AC_WID_AUD_IN: - if (!dig_in) - dig_in = i; - break; - } - } - } - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = dig_out; - if (dig_in && spec->autocfg.dig_in_pin) - spec->dig_in_nid = dig_in; - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->input_mux = &spec->private_imux; - if (!spec->dinput_mux) - spec->dinput_mux = &spec->private_dimux; - spec->sinput_mux = &spec->private_smux; - spec->mono_mux = &spec->private_mono_mux; - return 1; -} - -/* add playback controls for HP output */ -static int stac9200_auto_create_hp_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - hda_nid_t pin = cfg->hp_pins[0]; - - if (! pin) - return 0; - - if (is_jack_detectable(codec, pin)) - spec->hp_detect = 1; - - return 0; -} - -/* add playback controls for LFE output */ -static int stac9200_auto_create_lfe_ctls(struct hda_codec *codec, - struct auto_pin_cfg *cfg) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - hda_nid_t lfe_pin = 0x0; - int i; - - /* - * search speaker outs and line outs for a mono speaker pin - * with an amp. If one is found, add LFE controls - * for it. - */ - for (i = 0; i < spec->autocfg.speaker_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.speaker_pins[i]; - unsigned int wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, must be lfe */ - lfe_pin = pin; - } - - /* if speaker_outs is 0, then speakers may be in line_outs */ - if (lfe_pin == 0 && spec->autocfg.speaker_outs == 0) { - for (i = 0; i < spec->autocfg.line_outs && lfe_pin == 0x0; i++) { - hda_nid_t pin = spec->autocfg.line_out_pins[i]; - unsigned int defcfg; - defcfg = snd_hda_codec_get_pincfg(codec, pin); - if (get_defcfg_device(defcfg) == AC_JACK_SPEAKER) { - unsigned int wcaps = get_wcaps(codec, pin); - wcaps &= (AC_WCAP_STEREO | AC_WCAP_OUT_AMP); - if (wcaps == AC_WCAP_OUT_AMP) - /* found a mono speaker with an amp, - must be lfe */ - lfe_pin = pin; - } - } - } + if (spec->gpio_led) + spec->gen.vmaster_mute.hook = stac_vmaster_hook; - if (lfe_pin) { - err = create_controls(codec, "LFE", lfe_pin, 1); - if (err < 0) - return err; + if (spec->aloopback_ctl && + snd_hda_get_bool_hint(codec, "loopback") == 1) { + if (!snd_hda_gen_add_kctl(&spec->gen, NULL, spec->aloopback_ctl)) + return -ENOMEM; } - return 0; -} - -static int stac9200_parse_auto_config(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - int err; - - if ((err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL)) < 0) - return err; - - if ((err = stac92xx_auto_create_analog_input_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_hp_ctls(codec, &spec->autocfg)) < 0) - return err; - - if ((err = stac9200_auto_create_lfe_ctls(codec, &spec->autocfg)) < 0) - return err; - - if (spec->num_muxes > 0) { - err = stac92xx_auto_create_mux_input_ctls(codec); + if (spec->have_spdif_mux) { + err = stac_create_spdif_mux_ctls(codec); if (err < 0) return err; } - err = stac92xx_add_input_source(spec); - if (err < 0) - return err; - - if (spec->autocfg.dig_outs) - spec->multiout.dig_out_nid = 0x05; - if (spec->autocfg.dig_in_pin) - spec->dig_in_nid = 0x04; - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - spec->input_mux = &spec->private_imux; - spec->dinput_mux = &spec->private_dimux; - - return 1; -} - -/* - * Early 2006 Intel Macintoshes with STAC9220X5 codecs seem to have a - * funky external mute control using GPIO pins. - */ - -static void stac_gpio_set(struct hda_codec *codec, unsigned int mask, - unsigned int dir_mask, unsigned int data) -{ - unsigned int gpiostate, gpiomask, gpiodir; - - snd_printdd("%s msk %x dir %x gpio %x\n", __func__, mask, dir_mask, data); - - gpiostate = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - gpiostate = (gpiostate & ~dir_mask) | (data & dir_mask); - - gpiomask = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_MASK, 0); - gpiomask |= mask; - - gpiodir = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DIRECTION, 0); - gpiodir |= dir_mask; - - /* Configure GPIOx as CMOS */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e7, 0); - - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_SET_GPIO_MASK, gpiomask); - snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DIRECTION, gpiodir); /* sync */ - - msleep(1); - - snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_SET_GPIO_DATA, gpiostate); /* sync */ -} - -static int stac_add_event(struct hda_codec *codec, hda_nid_t nid, - unsigned char type, int data) -{ - struct hda_jack_tbl *event; - - event = snd_hda_jack_tbl_new(codec, nid); - if (!event) - return -ENOMEM; - event->action = type; - event->private_data = data; + stac_init_power_map(codec); return 0; } -static void handle_unsol_event(struct hda_codec *codec, - struct hda_jack_tbl *event); - -/* check if given nid is a valid pin and no other events are assigned - * to it. If OK, assign the event, set the unsol flag, and returns 1. - * Otherwise, returns zero. - */ -static int enable_pin_detect(struct hda_codec *codec, hda_nid_t nid, - unsigned int type) -{ - struct hda_jack_tbl *event; - - if (!is_jack_detectable(codec, nid)) - return 0; - event = snd_hda_jack_tbl_new(codec, nid); - if (!event) - return -ENOMEM; - if (event->action && event->action != type) - return 0; - event->action = type; - event->callback = handle_unsol_event; - snd_hda_jack_detect_enable(codec, nid, 0); - return 1; -} - -static int is_nid_out_jack_pin(struct auto_pin_cfg *cfg, hda_nid_t nid) -{ - int i; - for (i = 0; i < cfg->hp_outs; i++) - if (cfg->hp_pins[i] == nid) - return 1; /* nid is a HP-Out */ - for (i = 0; i < cfg->line_outs; i++) - if (cfg->line_out_pins[i] == nid) - return 1; /* nid is a line-Out */ - return 0; /* nid is not a HP-Out */ -}; - -static void stac92xx_power_down(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - /* power down inactive DACs */ - const hda_nid_t *dac; - for (dac = spec->dac_list; *dac; dac++) - if (!check_all_dac_nids(spec, *dac)) - snd_hda_codec_write(codec, *dac, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); -} - -static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, - int enable); -static inline int get_int_hint(struct hda_codec *codec, const char *key, - int *valp) -{ - const char *p; - p = snd_hda_get_hint(codec, key); - if (p) { - unsigned long val; - if (!strict_strtoul(p, 0, &val)) { - *valp = val; - return 1; - } - } - return 0; -} - -/* override some hints from the hwdep entry */ -static void stac_store_hints(struct hda_codec *codec) +static int stac_init(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - int val; - - val = snd_hda_get_bool_hint(codec, "hp_detect"); - if (val >= 0) - spec->hp_detect = val; - if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { - spec->eapd_mask = spec->gpio_dir = spec->gpio_data = - spec->gpio_mask; - } - if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) - spec->gpio_mask &= spec->gpio_mask; - if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) - spec->gpio_dir &= spec->gpio_mask; - if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) - spec->eapd_mask &= spec->gpio_mask; - if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) - spec->gpio_mute &= spec->gpio_mask; - val = snd_hda_get_bool_hint(codec, "eapd_switch"); - if (val >= 0) - spec->eapd_switch = val; -} - -static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins, - const hda_nid_t *pins) -{ - while (num_pins--) - stac_issue_unsol_event(codec, *pins++); -} - -/* fake event to set up pins */ -static void stac_fake_hp_events(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - if (spec->autocfg.hp_outs) - stac_issue_unsol_events(codec, spec->autocfg.hp_outs, - spec->autocfg.hp_pins); - if (spec->autocfg.line_outs && - spec->autocfg.line_out_pins[0] != spec->autocfg.hp_pins[0]) - stac_issue_unsol_events(codec, spec->autocfg.line_outs, - spec->autocfg.line_out_pins); -} - -static int stac92xx_init(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int gpio; int i; - if (spec->init) - snd_hda_sequence_write(codec, spec->init); - - /* power down adcs initially */ - if (spec->powerdown_adcs) - for (i = 0; i < spec->num_adcs; i++) - snd_hda_codec_write(codec, - spec->adc_nids[i], 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - /* override some hints */ stac_store_hints(codec); /* set up GPIO */ - gpio = spec->gpio_data; /* turn on EAPD statically when spec->eapd_switch isn't set. * otherwise, unsol event will turn it on/off dynamically */ if (!spec->eapd_switch) - gpio |= spec->eapd_mask; - stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, gpio); - - /* set up pins */ - if (spec->hp_detect) { - /* Enable unsolicited responses on the HP widget */ - for (i = 0; i < cfg->hp_outs; i++) { - hda_nid_t nid = cfg->hp_pins[i]; - enable_pin_detect(codec, nid, STAC_HP_EVENT); - } - if (cfg->line_out_type == AUTO_PIN_LINE_OUT && - cfg->speaker_outs > 0) { - /* enable pin-detect for line-outs as well */ - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t nid = cfg->line_out_pins[i]; - enable_pin_detect(codec, nid, STAC_LO_EVENT); - } - } - - /* force to enable the first line-out; the others are set up - * in unsol_event - */ - stac92xx_auto_set_pinctl(codec, spec->autocfg.line_out_pins[0], - AC_PINCTL_OUT_EN); - /* fake event to set up pins */ - stac_fake_hp_events(codec); - } else { - stac92xx_auto_init_multi_out(codec); - stac92xx_auto_init_hp_out(codec); - for (i = 0; i < cfg->hp_outs; i++) - stac_toggle_power_map(codec, cfg->hp_pins[i], 1); - } - if (spec->auto_mic) { - /* initialize connection to analog input */ - if (spec->dmux_nids) - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, 0); - if (enable_pin_detect(codec, spec->ext_mic.pin, STAC_MIC_EVENT)) - stac_issue_unsol_event(codec, spec->ext_mic.pin); - if (enable_pin_detect(codec, spec->dock_mic.pin, - STAC_MIC_EVENT)) - stac_issue_unsol_event(codec, spec->dock_mic.pin); - } - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - int type = cfg->inputs[i].type; - unsigned int pinctl, conf; - if (type == AUTO_PIN_MIC) { - /* for mic pins, force to initialize */ - pinctl = snd_hda_get_default_vref(codec, nid); - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } else { - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - /* if PINCTL already set then skip */ - /* Also, if both INPUT and OUTPUT are set, - * it must be a BIOS bug; need to override, too - */ - if (!(pinctl & AC_PINCTL_IN_EN) || - (pinctl & AC_PINCTL_OUT_EN)) { - pinctl &= ~AC_PINCTL_OUT_EN; - pinctl |= AC_PINCTL_IN_EN; - stac92xx_auto_set_pinctl(codec, nid, pinctl); - } - } - conf = snd_hda_codec_get_pincfg(codec, nid); - if (get_defcfg_connect(conf) != AC_JACK_PORT_FIXED) { - if (enable_pin_detect(codec, nid, STAC_INSERT_EVENT)) - stac_issue_unsol_event(codec, nid); - } - } - for (i = 0; i < spec->num_dmics; i++) - stac92xx_auto_set_pinctl(codec, spec->dmic_nids[i], - AC_PINCTL_IN_EN); - if (cfg->dig_out_pins[0]) - stac92xx_auto_set_pinctl(codec, cfg->dig_out_pins[0], - AC_PINCTL_OUT_EN); - if (cfg->dig_in_pin) - stac92xx_auto_set_pinctl(codec, cfg->dig_in_pin, - AC_PINCTL_IN_EN); - for (i = 0; i < spec->num_pwrs; i++) { - hda_nid_t nid = spec->pwr_nids[i]; - unsigned int pinctl, def_conf; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - def_conf = get_defcfg_connect(def_conf); - if (def_conf == AC_JACK_PORT_NONE) { - /* power off unused ports */ - stac_toggle_power_map(codec, nid, 0); - continue; - } - if (def_conf == AC_JACK_PORT_FIXED) { - /* no need for jack detection for fixed pins */ - stac_toggle_power_map(codec, nid, 1); - continue; - } - /* power on when no jack detection is available */ - /* or when the VREF is used for controlling LED */ - if (!spec->hp_detect || - spec->vref_mute_led_nid == nid || - !is_jack_detectable(codec, nid)) { - stac_toggle_power_map(codec, nid, 1); - continue; - } - - if (is_nid_out_jack_pin(cfg, nid)) - continue; /* already has an unsol event */ - - pinctl = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - /* outputs are only ports capable of power management - * any attempts on powering down a input port cause the - * referenced VREF to act quirky. - */ - if (pinctl & AC_PINCTL_IN_EN) { - stac_toggle_power_map(codec, nid, 1); - continue; - } - if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) { - stac_issue_unsol_event(codec, nid); - continue; - } - /* none of the above, turn the port OFF */ - stac_toggle_power_map(codec, nid, 0); - } + spec->gpio_data |= spec->eapd_mask; + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); - /* sync mute LED */ - if (spec->gpio_led) { - if (spec->vmaster_mute.hook) - snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - else /* the very first init call doesn't have vmaster yet */ - stac92xx_update_led_status(codec, false); - } + snd_hda_gen_init(codec); /* sync the power-map */ if (spec->num_pwrs) snd_hda_codec_write(codec, codec->afg, 0, AC_VERB_IDT_SET_POWER_MAP, spec->power_map_bits); - if (spec->dac_list) - stac92xx_power_down(codec); - return 0; -} -static void stac92xx_free_kctls(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); + /* power down inactive ADCs */ + if (spec->powerdown_adcs) { + for (i = 0; i < spec->gen.num_all_adcs; i++) { + if (spec->active_adcs & (1 << i)) + continue; + snd_hda_codec_write(codec, spec->gen.all_adcs[i], 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + } } - snd_array_free(&spec->kctls); -} -static void stac92xx_shutup_pins(struct hda_codec *codec) -{ - unsigned int i, def_conf; - - if (codec->bus->shutdown) - return; - for (i = 0; i < codec->init_pins.used; i++) { - struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); - def_conf = snd_hda_codec_get_pincfg(codec, pin->nid); - if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) - snd_hda_set_pin_ctl(codec, pin->nid, 0); - } + return 0; } -static void stac92xx_shutup(struct hda_codec *codec) +static void stac_shutup(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; - stac92xx_shutup_pins(codec); + snd_hda_shutup_pins(codec); if (spec->eapd_mask) stac_gpio_set(codec, spec->gpio_mask, @@ -4560,468 +4307,7 @@ static void stac92xx_shutup(struct hda_codec *codec) ~spec->eapd_mask); } -static void stac92xx_free(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - if (! spec) - return; - - stac92xx_shutup(codec); - - kfree(spec); - snd_hda_detach_beep_device(codec); -} - -static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int old_ctl, pin_ctl; - - pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - - if (pin_ctl & AC_PINCTL_IN_EN) { - /* - * we need to check the current set-up direction of - * shared input pins since they can be switched via - * "xxx as Output" mixer switch - */ - struct sigmatel_spec *spec = codec->spec; - if (nid == spec->line_switch || nid == spec->mic_switch) - return; - } - - old_ctl = pin_ctl; - /* if setting pin direction bits, clear the current - direction bits first */ - if (flag & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN)) - pin_ctl &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - - pin_ctl |= flag; - if (old_ctl != pin_ctl) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl); -} - -static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, - unsigned int flag) -{ - unsigned int pin_ctl = snd_hda_codec_read(codec, nid, - 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); - if (pin_ctl & flag) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag); -} - -static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) -{ - if (!nid) - return 0; - return snd_hda_jack_detect(codec, nid); -} - -static void stac92xx_line_out_detect(struct hda_codec *codec, - int presence) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - if (cfg->speaker_outs == 0) - return; - - for (i = 0; i < cfg->line_outs; i++) { - if (presence) - break; - presence = get_pin_presence(codec, cfg->line_out_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, - cfg->line_out_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } - } - - if (presence) { - /* disable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_reset_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); - } else { - /* enable speakers */ - for (i = 0; i < cfg->speaker_outs; i++) - stac92xx_set_pinctl(codec, cfg->speaker_pins[i], - AC_PINCTL_OUT_EN); - if (spec->eapd_mask && spec->eapd_switch) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data | - spec->eapd_mask); - } -} - -/* return non-zero if the hp-pin of the given array index isn't - * a jack-detection target - */ -static int no_hp_sensing(struct sigmatel_spec *spec, int i) -{ - struct auto_pin_cfg *cfg = &spec->autocfg; - - /* ignore sensing of shared line and mic jacks */ - if (cfg->hp_pins[i] == spec->line_switch) - return 1; - if (cfg->hp_pins[i] == spec->mic_switch) - return 1; - /* ignore if the pin is set as line-out */ - if (cfg->hp_pins[i] == spec->hp_switch) - return 1; - return 0; -} - -static void stac92xx_hp_detect(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i, presence; - - presence = 0; - if (spec->gpio_mute) - presence = !(snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0) & spec->gpio_mute); - - for (i = 0; i < cfg->hp_outs; i++) { - if (presence) - break; - if (no_hp_sensing(spec, i)) - continue; - presence = get_pin_presence(codec, cfg->hp_pins[i]); - if (presence) { - unsigned int pinctl; - pinctl = snd_hda_codec_read(codec, cfg->hp_pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (pinctl & AC_PINCTL_IN_EN) - presence = 0; /* mic- or line-input */ - } - } - - if (presence) { - /* disable lineouts */ - if (spec->hp_switch) - stac92xx_reset_pinctl(codec, spec->hp_switch, - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->line_outs; i++) - stac92xx_reset_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - } else { - /* enable lineouts */ - if (spec->hp_switch) - stac92xx_set_pinctl(codec, spec->hp_switch, - AC_PINCTL_OUT_EN); - for (i = 0; i < cfg->line_outs; i++) - stac92xx_set_pinctl(codec, cfg->line_out_pins[i], - AC_PINCTL_OUT_EN); - } - stac92xx_line_out_detect(codec, presence); - /* toggle hp outs */ - for (i = 0; i < cfg->hp_outs; i++) { - unsigned int val = AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN; - if (no_hp_sensing(spec, i)) - continue; - if (1 /*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 */ - } -} - -static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, - int enable) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int idx, val; - - for (idx = 0; idx < spec->num_pwrs; idx++) { - if (spec->pwr_nids[idx] == nid) - break; - } - if (idx >= spec->num_pwrs) - return; - - idx = 1 << idx; - - val = spec->power_map_bits; - if (enable) - val &= ~idx; - else - val |= idx; - - /* power down unused output ports */ - if (val != spec->power_map_bits) { - spec->power_map_bits = val; - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_IDT_SET_POWER_MAP, val); - } -} - -static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) -{ - stac_toggle_power_map(codec, nid, get_pin_presence(codec, nid)); -} - -/* get the pin connection (fixed, none, etc) */ -static unsigned int stac_get_defcfg_connect(struct hda_codec *codec, int idx) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int cfg; - - cfg = snd_hda_codec_get_pincfg(codec, spec->pin_nids[idx]); - return get_defcfg_connect(cfg); -} - -static int stac92xx_connected_ports(struct hda_codec *codec, - const hda_nid_t *nids, int num_nids) -{ - struct sigmatel_spec *spec = codec->spec; - int idx, num; - unsigned int def_conf; - - for (num = 0; num < num_nids; num++) { - for (idx = 0; idx < spec->num_pins; idx++) - if (spec->pin_nids[idx] == nids[num]) - break; - if (idx >= spec->num_pins) - break; - def_conf = stac_get_defcfg_connect(codec, idx); - if (def_conf == AC_JACK_PORT_NONE) - break; - } - return num; -} - -static void stac92xx_mic_detect(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - struct sigmatel_mic_route *mic; - - if (get_pin_presence(codec, spec->ext_mic.pin)) - mic = &spec->ext_mic; - else if (get_pin_presence(codec, spec->dock_mic.pin)) - mic = &spec->dock_mic; - else - mic = &spec->int_mic; - if (mic->dmux_idx >= 0) - snd_hda_codec_write_cache(codec, spec->dmux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - mic->dmux_idx); - if (mic->mux_idx >= 0) - snd_hda_codec_write_cache(codec, spec->mux_nids[0], 0, - AC_VERB_SET_CONNECT_SEL, - mic->mux_idx); -} - -static void handle_unsol_event(struct hda_codec *codec, - struct hda_jack_tbl *event) -{ - struct sigmatel_spec *spec = codec->spec; - int data; - - switch (event->action) { - case STAC_HP_EVENT: - case STAC_LO_EVENT: - stac92xx_hp_detect(codec); - break; - case STAC_MIC_EVENT: - stac92xx_mic_detect(codec); - break; - } - - switch (event->action) { - case STAC_HP_EVENT: - case STAC_LO_EVENT: - case STAC_MIC_EVENT: - case STAC_INSERT_EVENT: - case STAC_PWR_EVENT: - if (spec->num_pwrs > 0) - stac92xx_pin_sense(codec, event->nid); - - switch (codec->subsystem_id) { - case 0x103c308f: - if (event->nid == 0xb) { - int pin = AC_PINCTL_IN_EN; - - if (get_pin_presence(codec, 0xa) - && get_pin_presence(codec, 0xb)) - pin |= AC_PINCTL_VREF_80; - if (!get_pin_presence(codec, 0xb)) - pin |= AC_PINCTL_VREF_80; - - /* toggle VREF state based on mic + hp pin - * status - */ - stac92xx_auto_set_pinctl(codec, 0x0a, pin); - } - } - break; - case STAC_VREF_EVENT: - data = snd_hda_codec_read(codec, codec->afg, 0, - AC_VERB_GET_GPIO_DATA, 0); - /* toggle VREF state based on GPIOx status */ - snd_hda_codec_write(codec, codec->afg, 0, 0x7e0, - !!(data & (1 << event->private_data))); - break; - } -} - -static void stac_issue_unsol_event(struct hda_codec *codec, hda_nid_t nid) -{ - struct hda_jack_tbl *event = snd_hda_jack_tbl_get(codec, nid); - if (!event) - return; - handle_unsol_event(codec, event); -} - -static int hp_blike_system(u32 subsystem_id); - -static void set_hp_led_gpio(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int gpio; - - if (spec->gpio_led) - return; - - gpio = snd_hda_param_read(codec, codec->afg, AC_PAR_GPIO_CAP); - gpio &= AC_GPIO_IO_COUNT; - if (gpio > 3) - spec->gpio_led = 0x08; /* GPIO 3 */ - else - spec->gpio_led = 0x01; /* GPIO 0 */ -} - -/* - * This method searches for the mute LED GPIO configuration - * provided as OEM string in SMBIOS. The format of that string - * is HP_Mute_LED_P_G or HP_Mute_LED_P - * where P can be 0 or 1 and defines mute LED GPIO control state (low/high) - * that corresponds to the NOT muted state of the master volume - * and G is the index of the GPIO to use as the mute LED control (0..9) - * If _G portion is missing it is assigned based on the codec ID - * - * So, HP B-series like systems may have HP_Mute_LED_0 (current models) - * or HP_Mute_LED_0_3 (future models) OEM SMBIOS strings - * - * - * The dv-series laptops don't seem to have the HP_Mute_LED* strings in - * SMBIOS - at least the ones I have seen do not have them - which include - * my own system (HP Pavilion dv6-1110ax) and my cousin's - * HP Pavilion dv9500t CTO. - * Need more information on whether it is true across the entire series. - * -- kunal - */ -static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) -{ - struct sigmatel_spec *spec = codec->spec; - const struct dmi_device *dev = NULL; - - if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { - get_int_hint(codec, "gpio_led_polarity", - &spec->gpio_led_polarity); - return 1; - } - if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, - NULL, dev))) { - if (sscanf(dev->name, "HP_Mute_LED_%d_%x", - &spec->gpio_led_polarity, - &spec->gpio_led) == 2) { - unsigned int max_gpio; - max_gpio = snd_hda_param_read(codec, codec->afg, - AC_PAR_GPIO_CAP); - max_gpio &= AC_GPIO_IO_COUNT; - if (spec->gpio_led < max_gpio) - spec->gpio_led = 1 << spec->gpio_led; - else - spec->vref_mute_led_nid = spec->gpio_led; - return 1; - } - if (sscanf(dev->name, "HP_Mute_LED_%d", - &spec->gpio_led_polarity) == 1) { - set_hp_led_gpio(codec); - return 1; - } - /* BIOS bug: unfilled OEM string */ - if (strstr(dev->name, "HP_Mute_LED_P_G")) { - set_hp_led_gpio(codec); - switch (codec->subsystem_id) { - case 0x103c148a: - spec->gpio_led_polarity = 0; - break; - default: - spec->gpio_led_polarity = 1; - break; - } - return 1; - } - } - - /* - * Fallback case - if we don't find the DMI strings, - * we statically set the GPIO - if not a B-series system - * and default polarity is provided - */ - if (!hp_blike_system(codec->subsystem_id) && - (default_polarity == 0 || default_polarity == 1)) { - set_hp_led_gpio(codec); - spec->gpio_led_polarity = default_polarity; - return 1; - } - } - return 0; -} - -static int hp_blike_system(u32 subsystem_id) -{ - switch (subsystem_id) { - case 0x103c1520: - case 0x103c1521: - case 0x103c1523: - case 0x103c1524: - case 0x103c1525: - case 0x103c1722: - case 0x103c1723: - case 0x103c1724: - case 0x103c1725: - case 0x103c1726: - case 0x103c1727: - case 0x103c1728: - case 0x103c1729: - case 0x103c172a: - case 0x103c172b: - case 0x103c307e: - case 0x103c307f: - case 0x103c3080: - case 0x103c3081: - case 0x103c7007: - case 0x103c7008: - return 1; - } - return 0; -} +#define stac_free snd_hda_gen_free #ifdef CONFIG_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, @@ -5071,148 +4357,69 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, #endif #ifdef CONFIG_PM -static int stac92xx_resume(struct hda_codec *codec) -{ - stac92xx_init(codec); - snd_hda_codec_resume_amp(codec); - snd_hda_codec_resume_cache(codec); - /* fake event to set up pins again to override cached values */ - stac_fake_hp_events(codec); - return 0; -} - -static int stac92xx_suspend(struct hda_codec *codec) +static int stac_suspend(struct hda_codec *codec) { - stac92xx_shutup(codec); + stac_shutup(codec); return 0; } - -static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - unsigned int afg_power_state = power_state; - struct sigmatel_spec *spec = codec->spec; - - if (power_state == AC_PWRST_D3) { - if (spec->vref_mute_led_nid) { - /* with vref-out pin used for mute led control - * codec AFG is prevented from D3 state - */ - afg_power_state = AC_PWRST_D1; - } - /* this delay seems necessary to avoid click noise at power-down */ - msleep(100); - } - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - afg_power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state, true); -} #else -#define stac92xx_suspend NULL -#define stac92xx_resume NULL -#define stac92xx_set_power_state NULL +#define stac_suspend NULL #endif /* CONFIG_PM */ -/* update mute-LED accoring to the master switch */ -static void stac92xx_update_led_status(struct hda_codec *codec, int enabled) -{ - struct sigmatel_spec *spec = codec->spec; - int muted = !enabled; - - if (!spec->gpio_led) - return; - - /* LED state is inverted on these systems */ - if (spec->gpio_led_polarity) - muted = !muted; - - if (!spec->vref_mute_led_nid) { - if (muted) - spec->gpio_data |= spec->gpio_led; - else - spec->gpio_data &= ~spec->gpio_led; - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - } else { - spec->vref_led = muted ? AC_PINCTL_VREF_50 : AC_PINCTL_VREF_GRD; - stac_vrefout_set(codec, spec->vref_mute_led_nid, - spec->vref_led); - } -} - -static const struct hda_codec_ops stac92xx_patch_ops = { - .build_controls = stac92xx_build_controls, - .build_pcms = stac92xx_build_pcms, - .init = stac92xx_init, - .free = stac92xx_free, +static const struct hda_codec_ops stac_patch_ops = { + .build_controls = snd_hda_gen_build_controls, + .build_pcms = snd_hda_gen_build_pcms, + .init = stac_init, + .free = stac_free, .unsol_event = snd_hda_jack_unsol_event, #ifdef CONFIG_PM - .suspend = stac92xx_suspend, - .resume = stac92xx_resume, + .suspend = stac_suspend, #endif - .reboot_notify = stac92xx_shutup, + .reboot_notify = stac_shutup, }; +static int alloc_stac_spec(struct hda_codec *codec) +{ + struct sigmatel_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + snd_hda_gen_spec_init(&spec->gen); + codec->spec = spec; + codec->no_trigger_sense = 1; /* seems common with STAC/IDT codecs */ + return 0; +} + static int patch_stac9200(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9200_pin_nids); - spec->pin_nids = stac9200_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9200_MODELS, - stac9200_models, - stac9200_cfg_tbl); - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9200_brd_tbl[spec->board_config]); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac9200_dac_nids; - spec->adc_nids = stac9200_adc_nids; - spec->mux_nids = stac9200_mux_nids; - spec->num_muxes = 1; - spec->num_dmics = 0; - spec->num_adcs = 1; - spec->num_pwrs = 0; - - 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 - spec->init = stac9200_core_init; - spec->mixer = stac9200_mixer; + spec->gen.own_eapd_ctl = 1; - if (spec->board_config == STAC_9200_PANASONIC) { - spec->gpio_mask = spec->gpio_dir = 0x09; - spec->gpio_data = 0x00; - } + codec->patch_ops = stac_patch_ops; + codec->power_filter = snd_hda_codec_eapd_power_filter; + + snd_hda_add_verbs(codec, stac9200_eapd_init); - err = stac9200_parse_auto_config(codec); + snd_hda_pick_fixup(codec, stac9200_models, stac9200_fixup_tbl, + stac9200_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(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; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -5222,81 +4429,29 @@ static int patch_stac925x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac925x_pin_nids); - spec->pin_nids = stac925x_pin_nids; - - /* 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: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac925x_brd_tbl[spec->board_config]); - - spec->multiout.max_channels = 2; - spec->multiout.num_dacs = 1; - spec->multiout.dac_nids = stac925x_dac_nids; - spec->adc_nids = stac925x_adc_nids; - spec->mux_nids = stac925x_mux_nids; - spec->num_muxes = 1; - spec->num_adcs = 1; - spec->num_pwrs = 0; - switch (codec->vendor_id) { - case 0x83847632: /* STAC9202 */ - case 0x83847633: /* STAC9202D */ - case 0x83847636: /* STAC9251 */ - case 0x83847637: /* STAC9251D */ - spec->num_dmics = STAC925X_NUM_DMICS; - spec->dmic_nids = stac925x_dmic_nids; - spec->num_dmuxes = ARRAY_SIZE(stac925x_dmux_nids); - spec->dmux_nids = stac925x_dmux_nids; - break; - default: - spec->num_dmics = 0; - break; - } + spec->gen.own_eapd_ctl = 1; - spec->init = stac925x_core_init; - spec->mixer = stac925x_mixer; - spec->num_caps = 1; - spec->capvols = stac925x_capvols; - spec->capsws = stac925x_capsws; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_925x_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_add_verbs(codec, stac925x_core_init); + + snd_hda_pick_fixup(codec, stac925x_models, stac925x_fixup_tbl, + stac925x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -5304,471 +4459,195 @@ static int patch_stac925x(struct hda_codec *codec) static int patch_stac92hd73xx(struct hda_codec *codec) { struct sigmatel_spec *spec; - hda_nid_t conn[STAC92HD73_DAC_COUNT + 2]; - int err = 0; + int err; int num_dacs; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; - codec->slave_dig_outs = stac92hd73xx_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac92hd73xx_pin_nids); - spec->pin_nids = stac92hd73xx_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD73XX_MODELS, - stac92hd73xx_models, - stac92hd73xx_cfg_tbl); - /* check codec subsystem id if not found */ - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - STAC_92HD73XX_MODELS, stac92hd73xx_models, - stac92hd73xx_codec_id_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd73xx_brd_tbl[spec->board_config]); - - num_dacs = snd_hda_get_connections(codec, 0x0a, - conn, STAC92HD73_DAC_COUNT + 2) - 1; + spec->gen.mixer_nid = 0x1d; + spec->have_spdif_mux = 1; + num_dacs = snd_hda_get_num_conns(codec, 0x0a) - 1; if (num_dacs < 3 || num_dacs > 5) { - printk(KERN_WARNING "hda_codec: Could not determine " - "number of channels defaulting to DAC count\n"); - num_dacs = STAC92HD73_DAC_COUNT; + codec_warn(codec, + "Could not determine number of channels defaulting to DAC count\n"); + num_dacs = 5; } - spec->init = stac92hd73xx_core_init; + switch (num_dacs) { case 0x3: /* 6 Channel */ - spec->aloopback_ctl = stac92hd73xx_6ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_6ch_loopback; break; case 0x4: /* 8 Channel */ - spec->aloopback_ctl = stac92hd73xx_8ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_8ch_loopback; break; case 0x5: /* 10 Channel */ - spec->aloopback_ctl = stac92hd73xx_10ch_loopback; + spec->aloopback_ctl = &stac92hd73xx_10ch_loopback; break; } - spec->multiout.dac_nids = spec->dac_nids; spec->aloopback_mask = 0x01; spec->aloopback_shift = 8; - spec->digbeep_nid = 0x1c; - spec->mux_nids = stac92hd73xx_mux_nids; - spec->adc_nids = stac92hd73xx_adc_nids; - spec->dmic_nids = stac92hd73xx_dmic_nids; - spec->dmux_nids = stac92hd73xx_dmux_nids; - spec->smux_nids = stac92hd73xx_smux_nids; - - spec->num_muxes = ARRAY_SIZE(stac92hd73xx_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac92hd73xx_adc_nids); - spec->num_dmuxes = ARRAY_SIZE(stac92hd73xx_dmux_nids); - - spec->num_caps = STAC92HD73XX_NUM_CAPS; - spec->capvols = stac92hd73xx_capvols; - spec->capsws = stac92hd73xx_capsws; - - switch (spec->board_config) { - case STAC_DELL_EQ: - spec->init = dell_eq_core_init; - /* fallthru */ - case STAC_DELL_M6_AMIC: - case STAC_DELL_M6_DMIC: - case STAC_DELL_M6_BOTH: - spec->num_smuxes = 0; - spec->eapd_switch = 0; + spec->gen.beep_nid = 0x1c; /* digital beep */ - switch (spec->board_config) { - case STAC_DELL_M6_AMIC: /* Analog Mics */ - snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); - spec->num_dmics = 0; - break; - case STAC_DELL_M6_DMIC: /* Digital Mics */ - snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); - spec->num_dmics = 1; - break; - case STAC_DELL_M6_BOTH: /* Both */ - snd_hda_codec_set_pincfg(codec, 0x0b, 0x90A70170); - snd_hda_codec_set_pincfg(codec, 0x13, 0x90A60160); - spec->num_dmics = 1; - break; - } - break; - case STAC_ALIENWARE_M17X: - spec->num_dmics = STAC92HD73XX_NUM_DMICS; - spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); - spec->eapd_switch = 0; - break; - default: - spec->num_dmics = STAC92HD73XX_NUM_DMICS; - spec->num_smuxes = ARRAY_SIZE(stac92hd73xx_smux_nids); - spec->eapd_switch = 1; - break; - } - if (spec->board_config != STAC_92HD73XX_REF) { - /* GPIO0 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; - spec->gpio_data = 0x01; - } + /* GPIO0 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; + spec->gpio_data = 0x01; + + spec->eapd_switch = 1; spec->num_pwrs = ARRAY_SIZE(stac92hd73xx_pwr_nids); spec->pwr_nids = stac92hd73xx_pwr_nids; - err = stac92xx_parse_auto_config(codec); + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD73XX_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_pick_fixup(codec, stac92hd73xx_models, stac92hd73xx_fixup_tbl, + stac92hd73xx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + if (!spec->volknob_init) + snd_hda_add_verbs(codec, stac92hd73xx_core_init); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - if (spec->board_config == STAC_92HD73XX_NO_JD) - spec->hp_detect = 0; - - codec->patch_ops = stac92xx_patch_ops; + /* Don't GPIO-mute speakers if there are no internal speakers, because + * the GPIO might be necessary for Headphone + */ + if (spec->eapd_switch && !has_builtin_speaker(codec)) + spec->eapd_switch = 0; codec->proc_widget_hook = stac92hd7x_proc_hook; - return 0; -} - -static int hp_bnb2011_with_dock(struct hda_codec *codec) -{ - if (codec->vendor_id != 0x111d7605 && - codec->vendor_id != 0x111d76d1) - return 0; - - switch (codec->subsystem_id) { - case 0x103c1618: - case 0x103c1619: - case 0x103c161a: - case 0x103c161b: - case 0x103c161c: - case 0x103c161d: - case 0x103c161e: - case 0x103c161f: - - case 0x103c162a: - case 0x103c162b: - - case 0x103c1630: - case 0x103c1631: - - case 0x103c1633: - case 0x103c1634: - case 0x103c1635: - - case 0x103c3587: - case 0x103c3588: - case 0x103c3589: - case 0x103c358a: + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - case 0x103c3667: - case 0x103c3668: - case 0x103c3669: - - return 1; - } return 0; } -static void stac92hd8x_add_pin(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int i; - - spec->auto_pin_nids[spec->auto_pin_cnt] = nid; - spec->auto_pin_cnt++; - - if (get_defcfg_device(def_conf) == AC_JACK_MIC_IN && - get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) { - for (i = 0; i < ARRAY_SIZE(stac92hd83xxx_dmic_nids); i++) { - if (nid == stac92hd83xxx_dmic_nids[i]) { - spec->auto_dmic_nids[spec->auto_dmic_cnt] = nid; - spec->auto_dmic_cnt++; - } - } - } -} - -static void stac92hd8x_add_adc(struct hda_codec *codec, hda_nid_t nid) -{ - struct sigmatel_spec *spec = codec->spec; - - spec->auto_adc_nids[spec->auto_adc_cnt] = nid; - spec->auto_adc_cnt++; -} - -static void stac92hd8x_add_mux(struct hda_codec *codec, hda_nid_t nid) +static void stac_setup_gpio(struct hda_codec *codec) { - int i, j; struct sigmatel_spec *spec = codec->spec; - for (i = 0; i < spec->auto_adc_cnt; i++) { - if (get_connection_index(codec, - spec->auto_adc_nids[i], nid) >= 0) { - /* mux and volume for adc_nids[i] */ - if (!spec->auto_mux_nids[i]) { - spec->auto_mux_nids[i] = nid; - /* 92hd codecs capture volume is in mux */ - spec->auto_capvols[i] = HDA_COMPOSE_AMP_VAL(nid, - 3, 0, HDA_OUTPUT); - } - for (j = 0; j < spec->auto_dmic_cnt; j++) { - if (get_connection_index(codec, nid, - spec->auto_dmic_nids[j]) >= 0) { - /* dmux for adc_nids[i] */ - if (!spec->auto_dmux_nids[i]) - spec->auto_dmux_nids[i] = nid; - break; - } - } - break; + spec->gpio_mask |= spec->eapd_mask; + if (spec->gpio_led) { + if (!spec->vref_mute_led_nid) { + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + spec->gpio_data |= spec->gpio_led; + } else { + codec->power_filter = stac_vref_led_power_filter; } } -} - -static void stac92hd8x_fill_auto_spec(struct hda_codec *codec) -{ - hda_nid_t nid, end_nid; - unsigned int wid_caps, wid_type; - struct sigmatel_spec *spec = codec->spec; - - end_nid = codec->start_nid + codec->num_nodes; - - for (nid = codec->start_nid; nid < end_nid; nid++) { - wid_caps = get_wcaps(codec, nid); - wid_type = get_wcaps_type(wid_caps); - - if (wid_type == AC_WID_PIN) - stac92hd8x_add_pin(codec, nid); - - if (wid_type == AC_WID_AUD_IN && !(wid_caps & AC_WCAP_DIGITAL)) - stac92hd8x_add_adc(codec, nid); - } - for (nid = codec->start_nid; nid < end_nid; nid++) { - wid_caps = get_wcaps(codec, nid); - wid_type = get_wcaps_type(wid_caps); + if (spec->mic_mute_led_gpio) { + spec->gpio_mask |= spec->mic_mute_led_gpio; + spec->gpio_dir |= spec->mic_mute_led_gpio; + spec->mic_enabled = 0; + spec->gpio_data |= spec->mic_mute_led_gpio; - if (wid_type == AC_WID_AUD_SEL) - stac92hd8x_add_mux(codec, nid); + spec->gen.cap_sync_hook = stac_capture_led_hook; } - - spec->pin_nids = spec->auto_pin_nids; - spec->num_pins = spec->auto_pin_cnt; - spec->adc_nids = spec->auto_adc_nids; - spec->num_adcs = spec->auto_adc_cnt; - spec->capvols = spec->auto_capvols; - spec->capsws = spec->auto_capvols; - spec->num_caps = spec->auto_adc_cnt; - spec->mux_nids = spec->auto_mux_nids; - spec->num_muxes = spec->auto_adc_cnt; - spec->dmux_nids = spec->auto_dmux_nids; - spec->num_dmuxes = spec->auto_adc_cnt; - spec->dmic_nids = spec->auto_dmic_nids; - spec->num_dmics = spec->auto_dmic_cnt; } static int patch_stac92hd83xxx(struct hda_codec *codec) { struct sigmatel_spec *spec; - int default_polarity = -1; /* no default cfg */ int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - - if (hp_bnb2011_with_dock(codec)) { - snd_hda_codec_set_pincfg(codec, 0xa, 0x2101201f); - snd_hda_codec_set_pincfg(codec, 0xf, 0x2181205e); - } + err = alloc_stac_spec(codec); + if (err < 0) + return err; codec->epss = 0; /* longer delay needed for D3 */ - codec->no_trigger_sense = 1; - codec->spec = spec; - - stac92hd8x_fill_auto_spec(codec); + spec = codec->spec; spec->linear_tone_beep = 0; - codec->slave_dig_outs = stac92hd83xxx_slave_dig_outs; - spec->digbeep_nid = 0x21; + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; + spec->gen.mixer_nid = 0x1b; + + spec->gen.beep_nid = 0x21; /* digital beep */ spec->pwr_nids = stac92hd83xxx_pwr_nids; spec->num_pwrs = ARRAY_SIZE(stac92hd83xxx_pwr_nids); - spec->multiout.dac_nids = spec->dac_nids; - spec->init = stac92hd83xxx_core_init; - - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD83XXX_MODELS, - stac92hd83xxx_models, - stac92hd83xxx_cfg_tbl); - /* check codec subsystem id if not found */ - if (spec->board_config < 0) - spec->board_config = - snd_hda_check_board_codec_sid_config(codec, - STAC_92HD83XXX_MODELS, stac92hd83xxx_models, - stac92hd83xxx_codec_id_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd83xxx_brd_tbl[spec->board_config]); + spec->default_polarity = -1; /* no default cfg */ - codec->patch_ops = stac92xx_patch_ops; + codec->patch_ops = stac_patch_ops; - switch (spec->board_config) { - case STAC_HP_ZEPHYR: - spec->init = stac92hd83xxx_hp_zephyr_init; - break; - case STAC_92HD83XXX_HP_LED: - default_polarity = 0; - break; - case STAC_92HD83XXX_HP_INV_LED: - default_polarity = 1; - break; - case STAC_92HD83XXX_HP_MIC_LED: - spec->mic_mute_led_gpio = 0x08; /* GPIO3 */ - break; - case STAC_92HD83XXX_HEADSET_JACK: - spec->headset_jack = 1; - break; - } + snd_hda_add_verbs(codec, stac92hd83xxx_core_init); - if (find_mute_led_cfg(codec, default_polarity)) - snd_printd("mute LED gpio %d polarity %d\n", - spec->gpio_led, - spec->gpio_led_polarity); + snd_hda_pick_fixup(codec, stac92hd83xxx_models, stac92hd83xxx_fixup_tbl, + stac92hd83xxx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - if (spec->gpio_led) { - if (!spec->vref_mute_led_nid) { - spec->gpio_mask |= spec->gpio_led; - spec->gpio_dir |= spec->gpio_led; - spec->gpio_data |= spec->gpio_led; - } else { - codec->patch_ops.set_power_state = - stac92xx_set_power_state; - } - } - - if (spec->mic_mute_led_gpio) { - spec->gpio_mask |= spec->mic_mute_led_gpio; - spec->gpio_dir |= spec->mic_mute_led_gpio; - spec->mic_mute_led_on = true; - spec->gpio_data |= spec->mic_mute_led_gpio; - } - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD83XXX_REF; - goto again; - } - err = -EINVAL; - } + stac_setup_gpio(codec); + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } codec->proc_widget_hook = stac92hd_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } -static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, - hda_nid_t dig0pin) +static const hda_nid_t stac92hd95_pwr_nids[] = { + 0x0a, 0x0b, 0x0c, 0x0d +}; + +static int patch_stac92hd95(struct hda_codec *codec) { - struct sigmatel_spec *spec = codec->spec; - int idx; + struct sigmatel_spec *spec; + int err; - for (idx = 0; idx < spec->num_pins; idx++) - if (spec->pin_nids[idx] == dig0pin) - break; - if ((idx + 2) >= spec->num_pins) - return 0; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - /* dig1pin case */ - if (stac_get_defcfg_connect(codec, idx + 1) != AC_JACK_PORT_NONE) - return 2; + codec->epss = 0; /* longer delay needed for D3 */ - /* dig0pin + dig2pin case */ - if (stac_get_defcfg_connect(codec, idx + 2) != AC_JACK_PORT_NONE) - return 2; - if (stac_get_defcfg_connect(codec, idx) != AC_JACK_PORT_NONE) - return 1; - else - return 0; -} + spec = codec->spec; + spec->linear_tone_beep = 0; + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; -/* HP dv7 bass switch - GPIO5 */ -#define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info -static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); - return 0; -} + spec->gen.beep_nid = 0x19; /* digital beep */ + spec->pwr_nids = stac92hd95_pwr_nids; + spec->num_pwrs = ARRAY_SIZE(stac92hd95_pwr_nids); + spec->default_polarity = 0; -static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct sigmatel_spec *spec = codec->spec; - unsigned int gpio_data; + codec->patch_ops = stac_patch_ops; - gpio_data = (spec->gpio_data & ~0x20) | - (ucontrol->value.integer.value[0] ? 0x20 : 0); - if (gpio_data == spec->gpio_data) - return 0; - spec->gpio_data = gpio_data; - stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); - return 1; -} + snd_hda_pick_fixup(codec, stac92hd95_models, stac92hd95_fixup_tbl, + stac92hd95_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); -static const struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = stac_hp_bass_gpio_info, - .get = stac_hp_bass_gpio_get, - .put = stac_hp_bass_gpio_put, -}; + stac_setup_gpio(codec); -static int stac_add_hp_bass_switch(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; + err = stac_parse_auto_config(codec); + if (err < 0) { + stac_free(codec); + return err; + } - if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, - "Bass Speaker Playback Switch", 0)) - return -ENOMEM; + codec->proc_widget_hook = stac92hd_proc_hook; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); - spec->gpio_mask |= 0x20; - spec->gpio_dir |= 0x20; - spec->gpio_data |= 0x20; return 0; } @@ -5776,84 +4655,32 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; const struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; - unsigned int pin_cfg; - int err = 0; + int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 0; - codec->patch_ops = stac92xx_patch_ops; - spec->num_pins = STAC92HD71BXX_NUM_PINS; - switch (codec->vendor_id) { - case 0x111d76b6: - case 0x111d76b7: - spec->pin_nids = stac92hd71bxx_pin_nids_4port; - break; - case 0x111d7603: - case 0x111d7608: - /* On 92HD75Bx 0x27 isn't a pin nid */ - spec->num_pins--; - /* fallthrough */ - default: - spec->pin_nids = stac92hd71bxx_pin_nids_6port; - } - spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); - spec->board_config = snd_hda_check_board_config(codec, - STAC_92HD71BXX_MODELS, - stac92hd71bxx_models, - stac92hd71bxx_cfg_tbl); -again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac92hd71bxx_brd_tbl[spec->board_config]); + spec->gen.own_eapd_ctl = 1; + spec->gen.power_down_unused = 1; + spec->gen.mixer_nid = 0x17; + spec->have_spdif_mux = 1; - if (spec->board_config != STAC_92HD71BXX_REF) { - /* GPIO0 = EAPD */ - spec->gpio_mask = 0x01; - spec->gpio_dir = 0x01; - spec->gpio_data = 0x01; - } + codec->patch_ops = stac_patch_ops; - spec->dmic_nids = stac92hd71bxx_dmic_nids; - spec->dmux_nids = stac92hd71bxx_dmux_nids; - - spec->num_caps = STAC92HD71BXX_NUM_CAPS; - spec->capvols = stac92hd71bxx_capvols; - spec->capsws = stac92hd71bxx_capsws; + /* GPIO0 = EAPD */ + spec->gpio_mask = 0x01; + spec->gpio_dir = 0x01; + spec->gpio_data = 0x01; switch (codec->vendor_id) { case 0x111d76b6: /* 4 Port without Analog Mixer */ case 0x111d76b7: unmute_init++; - /* fallthru */ - case 0x111d76b4: /* 6 Port without Analog Mixer */ - case 0x111d76b5: - codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, - STAC92HD71BXX_NUM_DMICS); break; case 0x111d7608: /* 5 Port with Analog Mixer */ - switch (spec->board_config) { - case STAC_HP_M4: - /* Enable VREF power saving on GPIO1 detect */ - err = stac_add_event(codec, codec->afg, - STAC_VREF_EVENT, 0x02); - if (err < 0) - return err; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x02); - snd_hda_jack_detect_enable(codec, codec->afg, 0); - spec->gpio_mask |= 0x02; - break; - } if ((codec->revision_id & 0xf) == 0 || (codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ @@ -5862,158 +4689,45 @@ again: unmute_init++; snd_hda_codec_set_pincfg(codec, 0x0f, 0x40f000f0); snd_hda_codec_set_pincfg(codec, 0x19, 0x40f000f3); - spec->dmic_nids = stac92hd71bxx_dmic_5port_nids; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_5port_nids, - STAC92HD71BXX_NUM_DMICS - 1); break; case 0x111d7603: /* 6 Port with Analog Mixer */ if ((codec->revision_id & 0xf) == 1) spec->stream_delay = 40; /* 40 milliseconds */ - /* fallthru */ - default: - codec->slave_dig_outs = stac92hd71bxx_slave_dig_outs; - spec->num_dmics = stac92xx_connected_ports(codec, - stac92hd71bxx_dmic_nids, - STAC92HD71BXX_NUM_DMICS); break; } if (get_wcaps_type(get_wcaps(codec, 0x28)) == AC_WID_VOL_KNB) - spec->init = stac92hd71bxx_core_init; + snd_hda_add_verbs(codec, stac92hd71bxx_core_init); if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) snd_hda_sequence_write_cache(codec, unmute_init); - spec->aloopback_ctl = stac92hd71bxx_loopback; + spec->aloopback_ctl = &stac92hd71bxx_loopback; spec->aloopback_mask = 0x50; spec->aloopback_shift = 0; spec->powerdown_adcs = 1; - spec->digbeep_nid = 0x26; - spec->mux_nids = stac92hd71bxx_mux_nids; - spec->adc_nids = stac92hd71bxx_adc_nids; - spec->smux_nids = stac92hd71bxx_smux_nids; + spec->gen.beep_nid = 0x26; /* digital beep */ + spec->num_pwrs = ARRAY_SIZE(stac92hd71bxx_pwr_nids); spec->pwr_nids = stac92hd71bxx_pwr_nids; - spec->num_muxes = ARRAY_SIZE(stac92hd71bxx_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac92hd71bxx_adc_nids); - spec->num_dmuxes = ARRAY_SIZE(stac92hd71bxx_dmux_nids); - spec->num_smuxes = stac92hd71bxx_connected_smuxes(codec, 0x1e); - - snd_printdd("Found board config: %d\n", spec->board_config); - - switch (spec->board_config) { - case STAC_HP_M4: - /* enable internal microphone */ - snd_hda_codec_set_pincfg(codec, 0x0e, 0x01813040); - stac92xx_auto_set_pinctl(codec, 0x0e, - AC_PINCTL_IN_EN | AC_PINCTL_VREF_80); - /* fallthru */ - case STAC_DELL_M4_2: - spec->num_dmics = 0; - spec->num_smuxes = 0; - spec->num_dmuxes = 0; - break; - case STAC_DELL_M4_1: - case STAC_DELL_M4_3: - spec->num_dmics = 1; - spec->num_smuxes = 0; - spec->num_dmuxes = 1; - break; - case STAC_HP_DV4_1222NR: - spec->num_dmics = 1; - /* I don't know if it needs 1 or 2 smuxes - will wait for - * bug reports to fix if needed - */ - spec->num_smuxes = 1; - spec->num_dmuxes = 1; - /* fallthrough */ - case STAC_HP_DV4: - spec->gpio_led = 0x01; - /* fallthrough */ - case STAC_HP_DV5: - snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); - stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); - /* HP dv6 gives the headphone pin as a line-out. Thus we - * need to set hp_detect flag here to force to enable HP - * detection. - */ - spec->hp_detect = 1; - break; - case STAC_HP_HDX: - spec->num_dmics = 1; - spec->num_dmuxes = 1; - spec->num_smuxes = 1; - spec->gpio_led = 0x08; - break; - } - - if (hp_blike_system(codec->subsystem_id)) { - pin_cfg = snd_hda_codec_get_pincfg(codec, 0x0f); - if (get_defcfg_device(pin_cfg) == AC_JACK_LINE_OUT || - get_defcfg_device(pin_cfg) == AC_JACK_SPEAKER || - get_defcfg_device(pin_cfg) == AC_JACK_HP_OUT) { - /* It was changed in the BIOS to just satisfy MS DTM. - * Lets turn it back into slaved HP - */ - pin_cfg = (pin_cfg & (~AC_DEFCFG_DEVICE)) - | (AC_JACK_HP_OUT << - AC_DEFCFG_DEVICE_SHIFT); - pin_cfg = (pin_cfg & (~(AC_DEFCFG_DEF_ASSOC - | AC_DEFCFG_SEQUENCE))) - | 0x1f; - snd_hda_codec_set_pincfg(codec, 0x0f, pin_cfg); - } - } - - if (find_mute_led_cfg(codec, 1)) - snd_printd("mute LED gpio %d polarity %d\n", - spec->gpio_led, - spec->gpio_led_polarity); + snd_hda_pick_fixup(codec, stac92hd71bxx_models, stac92hd71bxx_fixup_tbl, + stac92hd71bxx_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - if (spec->gpio_led) { - if (!spec->vref_mute_led_nid) { - spec->gpio_mask |= spec->gpio_led; - spec->gpio_dir |= spec->gpio_led; - spec->gpio_data |= spec->gpio_led; - } else { - codec->patch_ops.set_power_state = - stac92xx_set_power_state; - } - } - - spec->multiout.dac_nids = spec->dac_nids; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_92HD71BXX_REF; - goto again; - } - err = -EINVAL; - } + stac_setup_gpio(codec); + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - /* enable bass on HP dv7 */ - if (spec->board_config == STAC_HP_DV4 || - spec->board_config == STAC_HP_DV5) { - unsigned int cap; - cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); - cap &= AC_GPIO_IO_COUNT; - if (cap >= 6) - stac_add_hp_bass_switch(codec); - } - codec->proc_widget_hook = stac92hd7x_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6022,95 +4736,17 @@ static int patch_stac922x(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac922x_pin_nids); - spec->pin_nids = stac922x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_922X_MODELS, - stac922x_models, - stac922x_cfg_tbl); - if (spec->board_config == STAC_INTEL_MAC_AUTO) { - spec->gpio_mask = spec->gpio_dir = 0x03; - spec->gpio_data = 0x03; - /* Intel Macs have all same PCI SSID, so we need to check - * codec SSID to distinguish the exact models - */ - printk(KERN_INFO "hda_codec: STAC922x, Apple subsys_id=%x\n", codec->subsystem_id); - switch (codec->subsystem_id) { - - case 0x106b0800: - spec->board_config = STAC_INTEL_MAC_V1; - break; - case 0x106b0600: - case 0x106b0700: - spec->board_config = STAC_INTEL_MAC_V2; - break; - case 0x106b0e00: - case 0x106b0f00: - case 0x106b1600: - case 0x106b1700: - case 0x106b0200: - case 0x106b1e00: - spec->board_config = STAC_INTEL_MAC_V3; - break; - case 0x106b1a00: - case 0x00000100: - spec->board_config = STAC_INTEL_MAC_V4; - break; - case 0x106b0a00: - case 0x106b2200: - spec->board_config = STAC_INTEL_MAC_V5; - break; - default: - spec->board_config = STAC_INTEL_MAC_V3; - break; - } - } - - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac922x_brd_tbl[spec->board_config]); - - spec->adc_nids = stac922x_adc_nids; - spec->mux_nids = stac922x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac922x_mux_nids); - spec->num_adcs = ARRAY_SIZE(stac922x_adc_nids); - spec->num_dmics = 0; - spec->num_pwrs = 0; + spec->gen.own_eapd_ctl = 1; - spec->init = stac922x_core_init; + codec->patch_ops = stac_patch_ops; - spec->num_caps = STAC922X_NUM_CAPS; - spec->capvols = stac922x_capvols; - spec->capsws = stac922x_capsws; - - spec->multiout.dac_nids = spec->dac_nids; - - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D945_REF; - goto again; - } - err = -EINVAL; - } - if (err < 0) { - stac92xx_free(codec); - return err; - } - - codec->patch_ops = stac92xx_patch_ops; + snd_hda_add_verbs(codec, stac922x_core_init); /* Fix Mux capture level; max to 2 */ snd_hda_override_amp_caps(codec, 0x12, HDA_OUTPUT, @@ -6119,124 +4755,67 @@ static int patch_stac922x(struct hda_codec *codec) (0x27 << AC_AMPCAP_STEP_SIZE_SHIFT) | (0 << AC_AMPCAP_MUTE_SHIFT)); + snd_hda_pick_fixup(codec, stac922x_models, stac922x_fixup_tbl, + stac922x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); + if (err < 0) { + stac_free(codec); + return err; + } + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } +static const char * const stac927x_spdif_labels[] = { + "Digital Playback", "ADAT", "Analog Mux 1", + "Analog Mux 2", "Analog Mux 3", NULL +}; + static int patch_stac927x(struct hda_codec *codec) { struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - codec->slave_dig_outs = stac927x_slave_dig_outs; - spec->num_pins = ARRAY_SIZE(stac927x_pin_nids); - spec->pin_nids = stac927x_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_927X_MODELS, - stac927x_models, - stac927x_cfg_tbl); - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac927x_brd_tbl[spec->board_config]); - - spec->digbeep_nid = 0x23; - spec->adc_nids = stac927x_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac927x_adc_nids); - spec->mux_nids = stac927x_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac927x_mux_nids); - spec->smux_nids = stac927x_smux_nids; - spec->num_smuxes = ARRAY_SIZE(stac927x_smux_nids); + spec->gen.own_eapd_ctl = 1; + spec->have_spdif_mux = 1; spec->spdif_labels = stac927x_spdif_labels; - spec->dac_list = stac927x_dac_nids; - spec->multiout.dac_nids = spec->dac_nids; - if (spec->board_config != STAC_D965_REF) { - /* GPIO0 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = 0x01; - spec->gpio_dir = spec->gpio_data = 0x01; - } + spec->gen.beep_nid = 0x23; /* digital beep */ - switch (spec->board_config) { - case STAC_D965_3ST: - case STAC_D965_5ST: - /* GPIO0 High = Enable EAPD */ - spec->num_dmics = 0; - spec->init = d965_core_init; - break; - case STAC_DELL_BIOS: - switch (codec->subsystem_id) { - case 0x10280209: - case 0x1028022e: - /* correct the device field to SPDIF out */ - snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); - break; - } - /* configure the analog microphone on some laptops */ - snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); - /* correct the front output jack as a hp out */ - snd_hda_codec_set_pincfg(codec, 0x0f, 0x0227011f); - /* correct the front input jack as a mic */ - snd_hda_codec_set_pincfg(codec, 0x0e, 0x02a79130); - /* fallthru */ - case STAC_DELL_3ST: - if (codec->subsystem_id != 0x1028022f) { - /* GPIO2 High = Enable EAPD */ - spec->eapd_mask = spec->gpio_mask = 0x04; - spec->gpio_dir = spec->gpio_data = 0x04; - } - spec->dmic_nids = stac927x_dmic_nids; - spec->num_dmics = STAC927X_NUM_DMICS; - - spec->init = dell_3st_core_init; - spec->dmux_nids = stac927x_dmux_nids; - spec->num_dmuxes = ARRAY_SIZE(stac927x_dmux_nids); - break; - case STAC_927X_VOLKNOB: - spec->num_dmics = 0; - spec->init = stac927x_volknob_core_init; - break; - default: - spec->num_dmics = 0; - spec->init = stac927x_core_init; - break; - } - - spec->num_caps = STAC927X_NUM_CAPS; - spec->capvols = stac927x_capvols; - spec->capsws = stac927x_capsws; + /* GPIO0 High = Enable EAPD */ + spec->eapd_mask = spec->gpio_mask = 0x01; + spec->gpio_dir = spec->gpio_data = 0x01; - spec->num_pwrs = 0; - spec->aloopback_ctl = stac927x_loopback; + spec->aloopback_ctl = &stac927x_loopback; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; spec->eapd_switch = 1; - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_D965_REF; - goto again; - } - err = -EINVAL; - } + codec->patch_ops = stac_patch_ops; + + snd_hda_pick_fixup(codec, stac927x_models, stac927x_fixup_tbl, + stac927x_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + if (!spec->volknob_init) + snd_hda_add_verbs(codec, stac927x_core_init); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac927x_proc_hook; /* @@ -6251,9 +4830,7 @@ static int patch_stac927x(struct hda_codec *codec) */ codec->bus->needs_damn_long_delay = 1; - /* no jack detecion for ref-no-jd model */ - if (spec->board_config == STAC_D965_REF_NO_JD) - spec->hp_detect = 0; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); return 0; } @@ -6263,105 +4840,46 @@ static int patch_stac9205(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; + err = alloc_stac_spec(codec); + if (err < 0) + return err; - codec->no_trigger_sense = 1; - codec->spec = spec; + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9205_pin_nids); - spec->pin_nids = stac9205_pin_nids; - spec->board_config = snd_hda_check_board_config(codec, STAC_9205_MODELS, - stac9205_models, - stac9205_cfg_tbl); - again: - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9205_brd_tbl[spec->board_config]); - - spec->digbeep_nid = 0x23; - spec->adc_nids = stac9205_adc_nids; - spec->num_adcs = ARRAY_SIZE(stac9205_adc_nids); - spec->mux_nids = stac9205_mux_nids; - spec->num_muxes = ARRAY_SIZE(stac9205_mux_nids); - spec->smux_nids = stac9205_smux_nids; - spec->num_smuxes = ARRAY_SIZE(stac9205_smux_nids); - spec->dmic_nids = stac9205_dmic_nids; - spec->num_dmics = STAC9205_NUM_DMICS; - spec->dmux_nids = stac9205_dmux_nids; - spec->num_dmuxes = ARRAY_SIZE(stac9205_dmux_nids); - spec->num_pwrs = 0; - - spec->init = stac9205_core_init; - spec->aloopback_ctl = stac9205_loopback; - - spec->num_caps = STAC9205_NUM_CAPS; - spec->capvols = stac9205_capvols; - spec->capsws = stac9205_capsws; + spec->gen.own_eapd_ctl = 1; + spec->have_spdif_mux = 1; + + spec->gen.beep_nid = 0x23; /* digital beep */ + + snd_hda_add_verbs(codec, stac9205_core_init); + spec->aloopback_ctl = &stac9205_loopback; spec->aloopback_mask = 0x40; spec->aloopback_shift = 0; - /* Turn on/off EAPD per HP plugging */ - if (spec->board_config != STAC_9205_EAPD) - spec->eapd_switch = 1; - spec->multiout.dac_nids = spec->dac_nids; - switch (spec->board_config){ - case STAC_9205_DELL_M43: - /* Enable SPDIF in/out */ - snd_hda_codec_set_pincfg(codec, 0x1f, 0x01441030); - snd_hda_codec_set_pincfg(codec, 0x20, 0x1c410030); + /* GPIO0 High = EAPD */ + spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; + spec->gpio_data = 0x01; - /* Enable unsol response for GPIO4/Dock HP connection */ - err = stac_add_event(codec, codec->afg, STAC_VREF_EVENT, 0x01); - if (err < 0) - return err; - snd_hda_codec_write_cache(codec, codec->afg, 0, - AC_VERB_SET_GPIO_UNSOLICITED_RSP_MASK, 0x10); - snd_hda_jack_detect_enable(codec, codec->afg, 0); + /* Turn on/off EAPD per HP plugging */ + spec->eapd_switch = 1; - spec->gpio_dir = 0x0b; - spec->eapd_mask = 0x01; - spec->gpio_mask = 0x1b; - spec->gpio_mute = 0x10; - /* GPIO0 High = EAPD, GPIO1 Low = Headphone Mute, - * GPIO3 Low = DRM - */ - spec->gpio_data = 0x01; - break; - case STAC_9205_REF: - /* SPDIF-In enabled */ - break; - default: - /* GPIO0 High = EAPD */ - spec->eapd_mask = spec->gpio_mask = spec->gpio_dir = 0x1; - spec->gpio_data = 0x01; - break; - } + codec->patch_ops = stac_patch_ops; - err = stac92xx_parse_auto_config(codec); - if (!err) { - if (spec->board_config < 0) { - printk(KERN_WARNING "hda_codec: No auto-config is " - "available, default to model=ref\n"); - spec->board_config = STAC_9205_REF; - goto again; - } - err = -EINVAL; - } + snd_hda_pick_fixup(codec, stac9205_models, stac9205_fixup_tbl, + stac9205_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return err; } - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac9205_proc_hook; + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6375,40 +4893,32 @@ static const struct hda_verb stac9872_core_init[] = { {} }; -static const hda_nid_t stac9872_pin_nids[] = { - 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x11, 0x13, 0x14, -}; - -static const hda_nid_t stac9872_adc_nids[] = { - 0x8 /*,0x6*/ -}; - -static const hda_nid_t stac9872_mux_nids[] = { - 0x15 -}; - -static const unsigned long stac9872_capvols[] = { - HDA_COMPOSE_AMP_VAL(0x09, 3, 0, HDA_INPUT), -}; -#define stac9872_capsws stac9872_capvols - -static const unsigned int stac9872_vaio_pin_configs[9] = { - 0x03211020, 0x411111f0, 0x411111f0, 0x03a15030, - 0x411111f0, 0x90170110, 0x411111f0, 0x411111f0, - 0x90a7013e +static const struct hda_pintbl stac9872_vaio_pin_configs[] = { + { 0x0a, 0x03211020 }, + { 0x0b, 0x411111f0 }, + { 0x0c, 0x411111f0 }, + { 0x0d, 0x03a15030 }, + { 0x0e, 0x411111f0 }, + { 0x0f, 0x90170110 }, + { 0x11, 0x411111f0 }, + { 0x13, 0x411111f0 }, + { 0x14, 0x90a7013e }, + {} }; -static const char * const stac9872_models[STAC_9872_MODELS] = { - [STAC_9872_AUTO] = "auto", - [STAC_9872_VAIO] = "vaio", +static const struct hda_model_fixup stac9872_models[] = { + { .id = STAC_9872_VAIO, .name = "vaio" }, + {} }; -static const unsigned int *stac9872_brd_tbl[STAC_9872_MODELS] = { - [STAC_9872_VAIO] = stac9872_vaio_pin_configs, +static const struct hda_fixup stac9872_fixups[] = { + [STAC_9872_VAIO] = { + .type = HDA_FIXUP_PINS, + .v.pins = stac9872_vaio_pin_configs, + }, }; -static const struct snd_pci_quirk stac9872_cfg_tbl[] = { +static const struct snd_pci_quirk stac9872_fixup_tbl[] = { SND_PCI_QUIRK_MASK(0x104d, 0xfff0, 0x81e0, "Sony VAIO F/S", STAC_9872_VAIO), {} /* terminator */ @@ -6419,42 +4929,30 @@ static int patch_stac9872(struct hda_codec *codec) struct sigmatel_spec *spec; int err; - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (spec == NULL) - return -ENOMEM; - codec->no_trigger_sense = 1; - codec->spec = spec; + err = alloc_stac_spec(codec); + if (err < 0) + return err; + + spec = codec->spec; spec->linear_tone_beep = 1; - spec->num_pins = ARRAY_SIZE(stac9872_pin_nids); - spec->pin_nids = stac9872_pin_nids; - - spec->board_config = snd_hda_check_board_config(codec, STAC_9872_MODELS, - stac9872_models, - stac9872_cfg_tbl); - if (spec->board_config < 0) - snd_printdd(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", - codec->chip_name); - else - stac92xx_set_config_regs(codec, - stac9872_brd_tbl[spec->board_config]); - - spec->multiout.dac_nids = spec->dac_nids; - spec->num_adcs = ARRAY_SIZE(stac9872_adc_nids); - spec->adc_nids = stac9872_adc_nids; - spec->num_muxes = ARRAY_SIZE(stac9872_mux_nids); - spec->mux_nids = stac9872_mux_nids; - spec->init = stac9872_core_init; - spec->num_caps = 1; - spec->capvols = stac9872_capvols; - spec->capsws = stac9872_capsws; - - err = stac92xx_parse_auto_config(codec); + spec->gen.own_eapd_ctl = 1; + + codec->patch_ops = stac_patch_ops; + + snd_hda_add_verbs(codec, stac9872_core_init); + + snd_hda_pick_fixup(codec, stac9872_models, stac9872_fixup_tbl, + stac9872_fixups); + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); + + err = stac_parse_auto_config(codec); if (err < 0) { - stac92xx_free(codec); + stac_free(codec); return -EINVAL; } - spec->input_mux = &spec->private_imux; - codec->patch_ops = stac92xx_patch_ops; + + snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PROBE); + return 0; } @@ -6525,6 +5023,7 @@ static const struct hda_codec_preset snd_hda_preset_sigmatel[] = { { .id = 0x111d7674, .name = "92HD73D1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7675, .name = "92HD73C1X5", .patch = patch_stac92hd73xx }, { .id = 0x111d7676, .name = "92HD73E1X5", .patch = patch_stac92hd73xx }, + { .id = 0x111d7695, .name = "92HD95", .patch = patch_stac92hd95 }, { .id = 0x111d76b0, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b1, .name = "92HD71B8X", .patch = patch_stac92hd71bxx }, { .id = 0x111d76b2, .name = "92HD71B7X", .patch = patch_stac92hd71bxx }, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 72a2f60b087..778166259b3 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -56,6 +56,7 @@ #include "hda_local.h" #include "hda_auto_parser.h" #include "hda_jack.h" +#include "hda_generic.h" /* Pin Widget NID */ #define VT1708_HP_PIN_NID 0x20 @@ -76,6 +77,8 @@ enum VIA_HDA_CODEC { VT2002P, VT1812, VT1802, + VT1705CF, + VT1808, CODEC_TYPES, }; @@ -84,39 +87,6 @@ enum VIA_HDA_CODEC { (spec)->codec_type == VT1812 ||\ (spec)->codec_type == VT1802) -#define MAX_NID_PATH_DEPTH 5 - -/* output-path: DAC -> ... -> pin - * idx[] contains the source index number of the next widget; - * e.g. idx[0] is the index of the DAC selected by path[1] widget - * multi[] indicates whether it's a selector widget with multi-connectors - * (i.e. the connection selection is mandatory) - * vol_ctl and mute_ctl contains the NIDs for the assigned mixers - */ -struct nid_path { - int depth; - hda_nid_t path[MAX_NID_PATH_DEPTH]; - unsigned char idx[MAX_NID_PATH_DEPTH]; - unsigned char multi[MAX_NID_PATH_DEPTH]; - unsigned int vol_ctl; - unsigned int mute_ctl; -}; - -/* input-path */ -struct via_input { - hda_nid_t pin; /* input-pin or aa-mix */ - int adc_idx; /* ADC index to be used */ - int mux_idx; /* MUX index (if any) */ - const char *label; /* input-source label */ -}; - -#define VIA_MAX_ADCS 3 - -enum { - STREAM_MULTI_OUT = (1 << 0), - STREAM_INDEP_HP = (1 << 1), -}; - struct via_spec { struct hda_gen_spec gen; @@ -127,77 +97,7 @@ struct via_spec { const struct hda_verb *init_verbs[5]; unsigned int num_iverbs; - char stream_name_analog[32]; - char stream_name_hp[32]; - const struct hda_pcm_stream *stream_analog_playback; - const struct hda_pcm_stream *stream_analog_capture; - - char stream_name_digital[32]; - const struct hda_pcm_stream *stream_digital_playback; - const struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t slave_dig_outs[2]; - hda_nid_t hp_dac_nid; - hda_nid_t speaker_dac_nid; - int hp_indep_shared; /* indep HP-DAC is shared with side ch */ - int opened_streams; /* STREAM_* bits */ - int active_streams; /* STREAM_* bits */ - int aamix_mode; /* loopback is enabled for output-path? */ - - /* Output-paths: - * There are different output-paths depending on the setup. - * out_path, hp_path and speaker_path are primary paths. If both - * direct DAC and aa-loopback routes are available, these contain - * the former paths. Meanwhile *_mix_path contain the paths with - * loopback mixer. (Since the loopback is only for front channel, - * no out_mix_path for surround channels.) - * The HP output has another path, hp_indep_path, which is used in - * the independent-HP mode. - */ - struct nid_path out_path[HDA_SIDE + 1]; - struct nid_path out_mix_path; - struct nid_path hp_path; - struct nid_path hp_mix_path; - struct nid_path hp_indep_path; - struct nid_path speaker_path; - struct nid_path speaker_mix_path; - - /* capture */ - unsigned int num_adc_nids; - hda_nid_t adc_nids[VIA_MAX_ADCS]; - hda_nid_t mux_nids[VIA_MAX_ADCS]; - hda_nid_t aa_mix_nid; - hda_nid_t dig_in_nid; - - /* capture source */ - bool dyn_adc_switch; - int num_inputs; - struct via_input inputs[AUTO_CFG_MAX_INS + 1]; - unsigned int cur_mux[VIA_MAX_ADCS]; - - /* dynamic DAC switching */ - unsigned int cur_dac_stream_tag; - unsigned int cur_dac_format; - unsigned int cur_hp_stream_tag; - unsigned int cur_hp_format; - - /* dynamic ADC switching */ - hda_nid_t cur_adc; - unsigned int cur_adc_stream_tag; - unsigned int cur_adc_format; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - /* HP mode source */ - unsigned int hp_independent_mode; unsigned int dmic_enabled; unsigned int no_pin_power_ctl; enum VIA_HDA_CODEC codec_type; @@ -205,35 +105,22 @@ struct via_spec { /* analog low-power control */ bool alc_mode; - /* smart51 setup */ - unsigned int smart51_nums; - hda_nid_t smart51_pins[2]; - int smart51_idxs[2]; - const char *smart51_labels[2]; - unsigned int smart51_enabled; - /* work to check hp jack state */ - struct hda_codec *codec; - struct delayed_work vt1708_hp_work; int hp_work_active; int vt1708_jack_detect; - int vt1708_hp_present; void (*set_widgets_power_state)(struct hda_codec *codec); - - struct hda_loopback_check loopback; - int num_loopbacks; - struct hda_amp_list loopback_list[8]; - - /* bind capture-volume */ - struct hda_bind_ctls *bind_cap_vol; - struct hda_bind_ctls *bind_cap_sw; - - struct mutex config_mutex; + unsigned int dac_stream_tag[4]; }; static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec); -static struct via_spec * via_new_spec(struct hda_codec *codec) +static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action); +static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl); + +static struct via_spec *via_new_spec(struct hda_codec *codec) { struct via_spec *spec; @@ -241,14 +128,17 @@ static struct via_spec * via_new_spec(struct hda_codec *codec) if (spec == NULL) return NULL; - mutex_init(&spec->config_mutex); codec->spec = spec; - spec->codec = codec; + snd_hda_gen_spec_init(&spec->gen); spec->codec_type = get_codec_type(codec); /* VT1708BCE & VT1708S are almost same */ if (spec->codec_type == VT1708BCE) spec->codec_type = VT1708S; - snd_hda_gen_init(&spec->gen); + spec->no_pin_power_ctl = 1; + spec->gen.indep_hp = 1; + spec->gen.keep_eapd_on = 1; + spec->gen.pcm_playback_hook = via_playback_pcm_hook; + spec->gen.add_stereo_mix_input = 1; return spec; } @@ -295,21 +185,15 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1708S; else if ((dev_id & 0xfff) == 0x446) codec_type = VT1802; + else if (dev_id == 0x4760) + codec_type = VT1705CF; + else if (dev_id == 0x4761 || dev_id == 0x4762) + codec_type = VT1808; else codec_type = UNKNOWN; return codec_type; }; -#define VIA_JACK_EVENT 0x20 -#define VIA_HP_EVENT 0x01 -#define VIA_LINE_EVENT 0x03 - -enum { - VIA_CTL_WIDGET_VOL, - VIA_CTL_WIDGET_MUTE, - VIA_CTL_WIDGET_ANALOG_MUTE, -}; - static void analog_low_current_mode(struct hda_codec *codec); static bool is_aa_path_mute(struct hda_codec *codec); @@ -317,398 +201,93 @@ static bool is_aa_path_mute(struct hda_codec *codec); (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1 && \ !is_aa_path_mute(codec)) -static void vt1708_stop_hp_work(struct via_spec *spec) +static void vt1708_stop_hp_work(struct hda_codec *codec) { - if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + struct via_spec *spec = codec->spec; + if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs) return; if (spec->hp_work_active) { - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 1); - cancel_delayed_work_sync(&spec->vt1708_hp_work); - spec->hp_work_active = 0; + snd_hda_codec_write(codec, 0x1, 0, 0xf81, 1); + codec->jackpoll_interval = 0; + cancel_delayed_work_sync(&codec->jackpoll_work); + spec->hp_work_active = false; } } -static void vt1708_update_hp_work(struct via_spec *spec) +static void vt1708_update_hp_work(struct hda_codec *codec) { - if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + struct via_spec *spec = codec->spec; + if (spec->codec_type != VT1708 || !spec->gen.autocfg.hp_outs) return; - if (spec->vt1708_jack_detect && - (spec->active_streams || hp_detect_with_aa(spec->codec))) { + if (spec->vt1708_jack_detect) { if (!spec->hp_work_active) { - snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, 0); - schedule_delayed_work(&spec->vt1708_hp_work, - msecs_to_jiffies(100)); - spec->hp_work_active = 1; + codec->jackpoll_interval = msecs_to_jiffies(100); + snd_hda_codec_write(codec, 0x1, 0, 0xf81, 0); + queue_delayed_work(codec->bus->workq, + &codec->jackpoll_work, 0); + spec->hp_work_active = true; } - } else if (!hp_detect_with_aa(spec->codec)) - vt1708_stop_hp_work(spec); + } else if (!hp_detect_with_aa(codec)) + vt1708_stop_hp_work(codec); } static void set_widgets_power_state(struct hda_codec *codec) { +#if 0 /* FIXME: the assumed connections don't match always with the + * actual routes by the generic parser, so better to disable + * the control for safety. + */ struct via_spec *spec = codec->spec; if (spec->set_widgets_power_state) spec->set_widgets_power_state(codec); +#endif } -static int analog_input_switch_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - int change = snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - set_widgets_power_state(codec); - analog_low_current_mode(snd_kcontrol_chip(kcontrol)); - vt1708_update_hp_work(codec->spec); - return change; -} - -/* modify .put = snd_hda_mixer_amp_switch_put */ -#define ANALOG_INPUT_MUTE \ - { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = NULL, \ - .index = 0, \ - .info = snd_hda_mixer_amp_switch_info, \ - .get = snd_hda_mixer_amp_switch_get, \ - .put = analog_input_switch_put, \ - .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } - -static const struct snd_kcontrol_new via_control_templates[] = { - HDA_CODEC_VOLUME(NULL, 0, 0, 0), - HDA_CODEC_MUTE(NULL, 0, 0, 0), - ANALOG_INPUT_MUTE, -}; - - -/* add dynamic controls */ -static struct snd_kcontrol_new *__via_clone_ctl(struct via_spec *spec, - const struct snd_kcontrol_new *tmpl, - const char *name) -{ - struct snd_kcontrol_new *knew; - - snd_array_init(&spec->kctls, sizeof(*knew), 32); - knew = snd_array_new(&spec->kctls); - if (!knew) - return NULL; - *knew = *tmpl; - if (!name) - name = tmpl->name; - if (name) { - knew->name = kstrdup(name, GFP_KERNEL); - if (!knew->name) - return NULL; - } - return knew; -} - -static int __via_add_control(struct via_spec *spec, int type, const char *name, - int idx, unsigned long val) -{ - struct snd_kcontrol_new *knew; - - knew = __via_clone_ctl(spec, &via_control_templates[type], name); - if (!knew) - return -ENOMEM; - knew->index = idx; - if (get_amp_nid_(val)) - knew->subdevice = HDA_SUBDEV_AMP_FLAG; - knew->private_value = val; - return 0; -} - -#define via_add_control(spec, type, name, val) \ - __via_add_control(spec, type, name, 0, val) - -#define via_clone_control(spec, tmpl) __via_clone_ctl(spec, tmpl, NULL) - -static void via_free_kctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (spec->kctls.list) { - struct snd_kcontrol_new *kctl = spec->kctls.list; - int i; - for (i = 0; i < spec->kctls.used; i++) - kfree(kctl[i].name); - } - snd_array_free(&spec->kctls); -} - -/* create input playback/capture controls for the given pin */ -static int via_new_analog_input(struct via_spec *spec, const char *ctlname, - int type_idx, int idx, int mix_nid) -{ - char name[32]; - int err; - - sprintf(name, "%s Playback Volume", ctlname); - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - sprintf(name, "%s Playback Switch", ctlname); - err = __via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, type_idx, - HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); - if (err < 0) - return err; - return 0; -} - -#define get_connection_index(codec, mux, nid) \ - snd_hda_get_conn_index(codec, mux, nid, 0) - -static bool check_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, - unsigned int mask) -{ - unsigned int caps; - if (!nid) - return false; - caps = get_wcaps(codec, nid); - if (dir == HDA_INPUT) - caps &= AC_WCAP_IN_AMP; - else - caps &= AC_WCAP_OUT_AMP; - if (!caps) - return false; - if (query_amp_caps(codec, nid, dir) & mask) - return true; - return false; -} - -#define have_mute(codec, nid, dir) \ - check_amp_caps(codec, nid, dir, AC_AMPCAP_MUTE) - -/* enable/disable the output-route mixers */ -static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, - hda_nid_t mix_nid, int idx, bool enable) +static void update_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm) { - int i, num, val; - - if (!path) + if (snd_hda_check_power_state(codec, nid, parm)) return; - num = snd_hda_get_num_conns(codec, mix_nid); - for (i = 0; i < num; i++) { - if (i == idx) - val = AMP_IN_UNMUTE(i); - else - val = AMP_IN_MUTE(i); - snd_hda_codec_write(codec, mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); } -/* enable/disable the output-route */ -static void activate_output_path(struct hda_codec *codec, struct nid_path *path, - bool enable, bool force) +static void update_conv_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int parm, unsigned int index) { struct via_spec *spec = codec->spec; - int i; - for (i = 0; i < path->depth; i++) { - hda_nid_t src, dst; - int idx = path->idx[i]; - src = path->path[i]; - if (i < path->depth - 1) - dst = path->path[i + 1]; - else - dst = 0; - if (enable && path->multi[i]) - snd_hda_codec_write(codec, dst, 0, - AC_VERB_SET_CONNECT_SEL, idx); - if (!force && (dst == spec->aa_mix_nid)) - continue; - if (have_mute(codec, dst, HDA_INPUT)) - activate_output_mix(codec, path, dst, idx, enable); - if (!force && (src == path->vol_ctl || src == path->mute_ctl)) - continue; - if (have_mute(codec, src, HDA_OUTPUT)) { - int val = enable ? AMP_OUT_UNMUTE : AMP_OUT_MUTE; - snd_hda_codec_write(codec, src, 0, - AC_VERB_SET_AMP_GAIN_MUTE, val); - } - } -} - -/* set the given pin as output */ -static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, - int pin_type) -{ - if (!pin) - return; - snd_hda_set_pin_ctl(codec, pin, pin_type); - if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_EAPD_BTLENABLE, 0x02); -} - -static void via_auto_init_output(struct hda_codec *codec, - struct nid_path *path, int pin_type) -{ - unsigned int caps; - hda_nid_t pin; + unsigned int format; - if (!path->depth) + if (snd_hda_check_power_state(codec, nid, parm)) return; - pin = path->path[path->depth - 1]; - - init_output_pin(codec, pin, pin_type); - if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) - caps = query_amp_caps(codec, pin, HDA_OUTPUT); - else - caps = 0; - if (caps & AC_AMPCAP_MUTE) { - unsigned int val; - val = (caps & AC_AMPCAP_OFFSET) >> AC_AMPCAP_OFFSET_SHIFT; - snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AMP_OUT_MUTE | val); - } - activate_output_path(codec, path, true, true); /* force on */ -} - -static void via_auto_init_multi_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - int i; + format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + if (format && (spec->dac_stream_tag[index] != format)) + spec->dac_stream_tag[index] = format; - for (i = 0; i < spec->autocfg.line_outs + spec->smart51_nums; i++) { - path = &spec->out_path[i]; - if (!i && spec->aamix_mode && spec->out_mix_path.depth) - path = &spec->out_mix_path; - via_auto_init_output(codec, path, PIN_OUT); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); + if (parm == AC_PWRST_D0) { + format = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + if (!format && (spec->dac_stream_tag[index] != format)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, + spec->dac_stream_tag[index]); } } -/* deactivate the inactive headphone-paths */ -static void deactivate_hp_paths(struct hda_codec *codec) +static bool smart51_enabled(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - - if (spec->hp_independent_mode) { - activate_output_path(codec, &spec->hp_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - if (shared) - activate_output_path(codec, &spec->out_path[shared], - false, false); - } else if (spec->aamix_mode || !spec->hp_path.depth) { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_path, false, false); - } else { - activate_output_path(codec, &spec->hp_indep_path, false, false); - activate_output_path(codec, &spec->hp_mix_path, false, false); - } + return spec->gen.ext_channel_count > 2; } -static void via_auto_init_hp_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->hp_path.depth) { - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - return; - } - deactivate_hp_paths(codec); - if (spec->hp_independent_mode) - via_auto_init_output(codec, &spec->hp_indep_path, PIN_HP); - else if (spec->aamix_mode) - via_auto_init_output(codec, &spec->hp_mix_path, PIN_HP); - else - via_auto_init_output(codec, &spec->hp_path, PIN_HP); -} - -static void via_auto_init_speaker_out(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!spec->speaker_path.depth) { - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - return; - } - if (!spec->aamix_mode) { - activate_output_path(codec, &spec->speaker_mix_path, - false, false); - via_auto_init_output(codec, &spec->speaker_path, PIN_OUT); - } else { - activate_output_path(codec, &spec->speaker_path, false, false); - via_auto_init_output(codec, &spec->speaker_mix_path, PIN_OUT); - } -} - -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin); -static void via_hp_automute(struct hda_codec *codec); - -static void via_auto_init_analog_input(struct hda_codec *codec) +static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) { struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - hda_nid_t conn[HDA_MAX_CONNECTIONS]; - unsigned int ctl; - int i, num_conns; - - /* init ADCs */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t nid = spec->adc_nids[i]; - if (!(get_wcaps(codec, nid) & AC_WCAP_IN_AMP) || - !(query_amp_caps(codec, nid, HDA_INPUT) & AC_AMPCAP_MUTE)) - continue; - snd_hda_codec_write(codec, spec->adc_nids[i], 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_UNMUTE(0)); - } - - /* init pins */ - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t nid = cfg->inputs[i].pin; - if (spec->smart51_enabled && is_smart51_pins(codec, nid)) - ctl = PIN_OUT; - else { - ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, nid); - } - snd_hda_set_pin_ctl(codec, nid, ctl); - } - - /* init input-src */ - for (i = 0; i < spec->num_adc_nids; i++) { - int adc_idx = spec->inputs[spec->cur_mux[i]].adc_idx; - /* secondary ADCs must have the unique MUX */ - if (i > 0 && !spec->mux_nids[i]) - break; - if (spec->mux_nids[adc_idx]) { - int mux_idx = spec->inputs[spec->cur_mux[i]].mux_idx; - snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, - AC_VERB_SET_CONNECT_SEL, - mux_idx); - } - if (spec->dyn_adc_switch) - break; /* only one input-src */ - } - - /* init aa-mixer */ - if (!spec->aa_mix_nid) - return; - num_conns = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, - ARRAY_SIZE(conn)); - for (i = 0; i < num_conns; i++) { - unsigned int caps = get_wcaps(codec, conn[i]); - if (get_wcaps_type(caps) == AC_WID_PIN) - snd_hda_codec_write(codec, spec->aa_mix_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, - AMP_IN_MUTE(i)); - } -} + int i; -static void update_power_state(struct hda_codec *codec, hda_nid_t nid, - unsigned int parm) -{ - if (snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_POWER_STATE, 0) == parm) - return; - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); + for (i = 0; i < spec->gen.multi_ios; i++) + if (spec->gen.multi_io[i].pin == pin) + return true; + return false; } static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, @@ -725,7 +304,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, no_presence |= spec->no_pin_power_ctl; if (!no_presence) present = snd_hda_jack_detect(codec, nid); - if ((spec->smart51_enabled && is_smart51_pins(codec, nid)) + if ((smart51_enabled(codec) && is_smart51_pins(codec, nid)) || ((no_presence || present) && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { *affected_parm = AC_PWRST_D0; /* if it's connected */ @@ -739,18 +318,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, static int via_pin_power_ctl_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static const char * const texts[] = { - "Disabled", "Enabled" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; + return snd_hda_enum_bool_helper_info(kcontrol, uinfo); } static int via_pin_power_ctl_get(struct snd_kcontrol *kcontrol, @@ -777,277 +345,29 @@ static int via_pin_power_ctl_put(struct snd_kcontrol *kcontrol, return 1; } -static const struct snd_kcontrol_new via_pin_power_ctl_enum = { +static const struct snd_kcontrol_new via_pin_power_ctl_enum[] = { + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Dynamic Power-Control", .info = via_pin_power_ctl_info, .get = via_pin_power_ctl_get, .put = via_pin_power_ctl_put, + }, + {} /* terminator */ }; -static int via_independent_hp_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char * const texts[] = { "OFF", "ON" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= 2) - uinfo->value.enumerated.item = 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - return 0; -} - -static int via_independent_hp_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->hp_independent_mode; - return 0; -} - -/* adjust spec->multiout setup according to the current flags */ -static void setup_playback_multi_pcm(struct via_spec *spec) -{ - const struct auto_pin_cfg *cfg = &spec->autocfg; - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.hp_nid = 0; - if (!spec->hp_independent_mode) { - if (!spec->hp_indep_shared) - spec->multiout.hp_nid = spec->hp_dac_nid; - } else { - if (spec->hp_indep_shared) - spec->multiout.num_dacs = cfg->line_outs - 1; - } -} - -/* update DAC setups according to indep-HP switch; - * this function is called only when indep-HP is modified - */ -static void switch_indep_hp_dacs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int shared = spec->hp_indep_shared; - hda_nid_t shared_dac, hp_dac; - - if (!spec->opened_streams) - return; - - shared_dac = shared ? spec->multiout.dac_nids[shared] : 0; - hp_dac = spec->hp_dac_nid; - if (spec->hp_independent_mode) { - /* switch to indep-HP mode */ - if (spec->active_streams & STREAM_MULTI_OUT) { - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - __snd_hda_codec_cleanup_stream(codec, shared_dac, 1); - } - if (spec->active_streams & STREAM_INDEP_HP) - snd_hda_codec_setup_stream(codec, hp_dac, - spec->cur_hp_stream_tag, 0, - spec->cur_hp_format); - } else { - /* back to HP or shared-DAC */ - if (spec->active_streams & STREAM_INDEP_HP) - __snd_hda_codec_cleanup_stream(codec, hp_dac, 1); - if (spec->active_streams & STREAM_MULTI_OUT) { - hda_nid_t dac; - int ch; - if (shared_dac) { /* reset mutli-ch DAC */ - dac = shared_dac; - ch = shared * 2; - } else { /* reset HP DAC */ - dac = hp_dac; - ch = 0; - } - snd_hda_codec_setup_stream(codec, dac, - spec->cur_dac_stream_tag, ch, - spec->cur_dac_format); - } - } - setup_playback_multi_pcm(spec); -} - -static int via_independent_hp_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int cur, shared; - - mutex_lock(&spec->config_mutex); - cur = !!ucontrol->value.enumerated.item[0]; - if (spec->hp_independent_mode == cur) { - mutex_unlock(&spec->config_mutex); - return 0; - } - spec->hp_independent_mode = cur; - shared = spec->hp_indep_shared; - deactivate_hp_paths(codec); - if (cur) - activate_output_path(codec, &spec->hp_indep_path, true, false); - else { - if (shared) - activate_output_path(codec, &spec->out_path[shared], - true, false); - if (spec->aamix_mode || !spec->hp_path.depth) - activate_output_path(codec, &spec->hp_mix_path, - true, false); - else - activate_output_path(codec, &spec->hp_path, - true, false); - } - - switch_indep_hp_dacs(codec); - mutex_unlock(&spec->config_mutex); - - /* update jack power state */ - set_widgets_power_state(codec); - via_hp_automute(codec); - return 1; -} - -static const struct snd_kcontrol_new via_hp_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Independent HP", - .info = via_independent_hp_info, - .get = via_independent_hp_get, - .put = via_independent_hp_put, -}; - -static int via_hp_build(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - hda_nid_t nid; - - nid = spec->autocfg.hp_pins[0]; - knew = via_clone_control(spec, &via_hp_mixer); - if (knew == NULL) - return -ENOMEM; - - knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; - - return 0; -} - -static void notify_aa_path_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->smart51_nums; i++) { - struct snd_kcontrol *ctl; - struct snd_ctl_elem_id id; - memset(&id, 0, sizeof(id)); - id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; - sprintf(id.name, "%s Playback Volume", spec->smart51_labels[i]); - ctl = snd_hda_find_mixer_ctl(codec, id.name); - if (ctl) - snd_ctl_notify(codec->bus->card, - SNDRV_CTL_EVENT_MASK_VALUE, - &ctl->id); - } -} - -static void mute_aa_path(struct hda_codec *codec, int mute) -{ - struct via_spec *spec = codec->spec; - int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; - int i; - - /* check AA path's mute status */ - for (i = 0; i < spec->smart51_nums; i++) { - if (spec->smart51_idxs[i] < 0) - continue; - snd_hda_codec_amp_stereo(codec, spec->aa_mix_nid, - HDA_INPUT, spec->smart51_idxs[i], - HDA_AMP_MUTE, val); - } -} - -static bool is_smart51_pins(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->smart51_nums; i++) - if (spec->smart51_pins[i] == pin) - return true; - return false; -} - -static int via_smart51_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - *ucontrol->value.integer.value = spec->smart51_enabled; - return 0; -} - -static int via_smart51_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - int out_in = *ucontrol->value.integer.value - ? AC_PINCTL_OUT_EN : AC_PINCTL_IN_EN; - int i; - - for (i = 0; i < spec->smart51_nums; i++) { - hda_nid_t nid = spec->smart51_pins[i]; - unsigned int parm; - - parm = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); - parm |= out_in; - snd_hda_set_pin_ctl(codec, nid, parm); - if (out_in == AC_PINCTL_OUT_EN) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - } - spec->smart51_enabled = *ucontrol->value.integer.value; - set_widgets_power_state(codec); - return 1; -} - -static const struct snd_kcontrol_new via_smart51_mixer = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Smart 5.1", - .count = 1, - .info = snd_ctl_boolean_mono_info, - .get = via_smart51_get, - .put = via_smart51_put, -}; - -static int via_smart51_build(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - - if (!spec->smart51_nums) - return 0; - if (!via_clone_control(spec, &via_smart51_mixer)) - return -ENOMEM; - return 0; -} - /* check AA path's mute status */ static bool is_aa_path_mute(struct hda_codec *codec) { struct via_spec *spec = codec->spec; const struct hda_amp_list *p; - int i, ch, v; + int ch, v; - for (i = 0; i < spec->num_loopbacks; i++) { - p = &spec->loopback_list[i]; + p = spec->gen.loopback.amplist; + if (!p) + return true; + for (; p->nid; p++) { for (ch = 0; ch < 2; ch++) { v = snd_hda_codec_amp_read(codec, p->nid, ch, p->dir, p->idx); @@ -1068,7 +388,7 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) if (spec->no_pin_power_ctl) enable = false; else - enable = is_aa_path_mute(codec) && !spec->opened_streams; + enable = is_aa_path_mute(codec) && !spec->gen.active_streams; if (enable == spec->alc_mode && !force) return; spec->alc_mode = enable; @@ -1096,6 +416,11 @@ static void __analog_low_current_mode(struct hda_codec *codec, bool force) verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; + case VT1705CF: + case VT1808: + verb = 0xf82; + parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ + break; default: return; /* other codecs are not supported */ } @@ -1108,366 +433,17 @@ static void analog_low_current_mode(struct hda_codec *codec) return __analog_low_current_mode(codec, false); } -/* - * generic initialization of ADC, input mixers and output mixers - */ -static const struct hda_verb vt1708_init_verbs[] = { - /* power down jack detect function */ - {0x1, 0xf81, 0x1}, - { } -}; - -static void set_stream_open(struct hda_codec *codec, int bit, bool active) -{ - struct via_spec *spec = codec->spec; - - if (active) - spec->opened_streams |= bit; - else - spec->opened_streams &= ~bit; - analog_low_current_mode(codec); -} - -static int via_playback_multi_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int err; - - spec->multiout.num_dacs = cfg->line_outs + spec->smart51_nums; - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - set_stream_open(codec, STREAM_MULTI_OUT, true); - err = snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, - hinfo); - if (err < 0) { - set_stream_open(codec, STREAM_MULTI_OUT, false); - return err; - } - return 0; -} - -static int via_playback_multi_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_MULTI_OUT, false); - return 0; -} - -static int via_playback_hp_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - if (snd_BUG_ON(!spec->hp_dac_nid)) - return -EINVAL; - set_stream_open(codec, STREAM_INDEP_HP, true); - return 0; -} - -static int via_playback_hp_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - set_stream_open(codec, STREAM_INDEP_HP, false); - return 0; -} - -static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - setup_playback_multi_pcm(spec); - snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, - format, substream); - /* remember for dynamic DAC switch with indep-HP */ - spec->active_streams |= STREAM_MULTI_OUT; - spec->cur_dac_stream_tag = stream_tag; - spec->cur_dac_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, - stream_tag, 0, format); - spec->active_streams |= STREAM_INDEP_HP; - spec->cur_hp_stream_tag = stream_tag; - spec->cur_hp_format = format; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); - spec->active_streams &= ~STREAM_MULTI_OUT; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -static int via_playback_hp_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - if (spec->hp_independent_mode) - snd_hda_codec_setup_stream(codec, spec->hp_dac_nid, 0, 0, 0); - spec->active_streams &= ~STREAM_INDEP_HP; - mutex_unlock(&spec->config_mutex); - vt1708_update_hp_work(spec); - return 0; -} - -/* - * Digital out - */ -static int via_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_open(codec, &spec->multiout); -} - -static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_close(codec, &spec->multiout); -} - -static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); - return 0; -} - -/* - * Analog capture - */ -static int via_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], - stream_tag, 0, format); - return 0; -} - -static int via_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); - return 0; -} - -/* analog capture with dynamic ADC switching */ -static int via_dyn_adc_capture_pcm_prepare(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[spec->cur_mux[0]].adc_idx; - - mutex_lock(&spec->config_mutex); - spec->cur_adc = spec->adc_nids[adc_idx]; - spec->cur_adc_stream_tag = stream_tag; - spec->cur_adc_format = format; - snd_hda_codec_setup_stream(codec, spec->cur_adc, stream_tag, 0, format); - mutex_unlock(&spec->config_mutex); - return 0; -} - -static int via_dyn_adc_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - - mutex_lock(&spec->config_mutex); - snd_hda_codec_cleanup_stream(codec, spec->cur_adc); - spec->cur_adc = 0; - mutex_unlock(&spec->config_mutex); - return 0; -} - -/* re-setup the stream if running; called from input-src put */ -static bool via_dyn_adc_pcm_resetup(struct hda_codec *codec, int cur) -{ - struct via_spec *spec = codec->spec; - int adc_idx = spec->inputs[cur].adc_idx; - hda_nid_t adc = spec->adc_nids[adc_idx]; - bool ret = false; - - mutex_lock(&spec->config_mutex); - if (spec->cur_adc && spec->cur_adc != adc) { - /* stream is running, let's swap the current ADC */ - __snd_hda_codec_cleanup_stream(codec, spec->cur_adc, 1); - spec->cur_adc = adc; - snd_hda_codec_setup_stream(codec, adc, - spec->cur_adc_stream_tag, 0, - spec->cur_adc_format); - ret = true; - } - mutex_unlock(&spec->config_mutex); - return ret; -} - -static const struct hda_pcm_stream via_pcm_analog_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, - .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_hp_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_playback_hp_pcm_open, - .close = via_playback_hp_pcm_close, - .prepare = via_playback_hp_pcm_prepare, - .cleanup = via_playback_hp_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 8, - /* NID is set in via_build_pcms */ - /* We got noisy outputs on the right channel on VT1708 when - * 24bit samples are used. Until any workaround is found, - * disable the 24bit format, so far. - */ - .formats = SNDRV_PCM_FMTBIT_S16_LE, - .ops = { - .open = via_playback_multi_pcm_open, - .close = via_playback_multi_pcm_close, - .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_analog_capture = { - .substreams = 1, /* will be changed in via_build_pcms() */ - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_dyn_adc_analog_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .prepare = via_dyn_adc_capture_pcm_prepare, - .cleanup = via_dyn_adc_capture_pcm_cleanup, - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_playback = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, - /* NID is set in via_build_pcms */ - .ops = { - .open = via_dig_playback_pcm_open, - .close = via_dig_playback_pcm_close, - .prepare = via_dig_playback_pcm_prepare, - .cleanup = via_dig_playback_pcm_cleanup - }, -}; - -static const struct hda_pcm_stream via_pcm_digital_capture = { - .substreams = 1, - .channels_min = 2, - .channels_max = 2, -}; - -/* - * slave controls for virtual master - */ -static const char * const via_slave_pfxs[] = { - "Front", "Surround", "Center", "LFE", "Side", - "Headphone", "Speaker", - NULL, -}; - static int via_build_controls(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct snd_kcontrol *kctl; int err, i; - spec->no_pin_power_ctl = 1; + err = snd_hda_gen_build_controls(codec); + if (err < 0) + return err; + if (spec->set_widgets_power_state) - if (!via_clone_control(spec, &via_pin_power_ctl_enum)) - return -ENOMEM; + spec->mixers[spec->num_mixers++] = via_pin_power_ctl_enum; for (i = 0; i < spec->num_mixers; i++) { err = snd_hda_add_new_ctls(codec, spec->mixers[i]); @@ -1475,231 +451,33 @@ static int via_build_controls(struct hda_codec *codec) return err; } - if (spec->multiout.dig_out_nid) { - err = snd_hda_create_spdif_out_ctls(codec, - spec->multiout.dig_out_nid, - spec->multiout.dig_out_nid); - if (err < 0) - return err; - err = snd_hda_create_spdif_share_sw(codec, - &spec->multiout); - if (err < 0) - return err; - spec->multiout.share_spdif = 1; - } - if (spec->dig_in_nid) { - err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); - if (err < 0) - return err; - } - - /* if we have no master control, let's create it */ - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { - unsigned int vmaster_tlv[4]; - snd_hda_set_vmaster_tlv(codec, spec->multiout.dac_nids[0], - HDA_OUTPUT, vmaster_tlv); - err = snd_hda_add_vmaster(codec, "Master Playback Volume", - vmaster_tlv, via_slave_pfxs, - "Playback Volume"); - if (err < 0) - return err; - } - if (!snd_hda_find_mixer_ctl(codec, "Master Playback Switch")) { - err = snd_hda_add_vmaster(codec, "Master Playback Switch", - NULL, via_slave_pfxs, - "Playback Switch"); - if (err < 0) - return err; - } - - /* assign Capture Source enums to NID */ - kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); - for (i = 0; kctl && i < kctl->count; i++) { - if (!spec->mux_nids[i]) - continue; - err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); - if (err < 0) - return err; - } - - via_free_kctls(codec); /* no longer needed */ - - err = snd_hda_jack_add_kctls(codec, &spec->autocfg); - if (err < 0) - return err; - return 0; } -static int via_build_pcms(struct hda_codec *codec) +static void via_playback_pcm_hook(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream, + int action) { - struct via_spec *spec = codec->spec; - struct hda_pcm *info = spec->pcm_rec; - - codec->num_pcms = 0; - codec->pcm_info = info; - - if (spec->multiout.num_dacs || spec->num_adc_nids) { - snprintf(spec->stream_name_analog, - sizeof(spec->stream_name_analog), - "%s Analog", codec->chip_name); - info->name = spec->stream_name_analog; - - if (spec->multiout.num_dacs) { - if (!spec->stream_analog_playback) - spec->stream_analog_playback = - &via_pcm_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_analog_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dac_nids[0]; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = - spec->multiout.max_channels; - } - - if (!spec->stream_analog_capture) { - if (spec->dyn_adc_switch) - spec->stream_analog_capture = - &via_pcm_dyn_adc_analog_capture; - else - spec->stream_analog_capture = - &via_pcm_analog_capture; - } - if (spec->num_adc_nids) { - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_analog_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->adc_nids[0]; - if (!spec->dyn_adc_switch) - info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = - spec->num_adc_nids; - } - codec->num_pcms++; - info++; - } - - if (spec->multiout.dig_out_nid || spec->dig_in_nid) { - snprintf(spec->stream_name_digital, - sizeof(spec->stream_name_digital), - "%s Digital", codec->chip_name); - info->name = spec->stream_name_digital; - info->pcm_type = HDA_PCM_TYPE_SPDIF; - if (spec->multiout.dig_out_nid) { - if (!spec->stream_digital_playback) - spec->stream_digital_playback = - &via_pcm_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = - *spec->stream_digital_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->multiout.dig_out_nid; - } - if (spec->dig_in_nid) { - if (!spec->stream_digital_capture) - spec->stream_digital_capture = - &via_pcm_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE] = - *spec->stream_digital_capture; - info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = - spec->dig_in_nid; - } - codec->num_pcms++; - info++; - } - - if (spec->hp_dac_nid) { - snprintf(spec->stream_name_hp, sizeof(spec->stream_name_hp), - "%s HP", codec->chip_name); - info->name = spec->stream_name_hp; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = via_pcm_hp_playback; - info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = - spec->hp_dac_nid; - codec->num_pcms++; - info++; - } - return 0; + analog_low_current_mode(codec); + vt1708_update_hp_work(codec); } static void via_free(struct hda_codec *codec) { - struct via_spec *spec = codec->spec; - - if (!spec) - return; - - via_free_kctls(codec); - vt1708_stop_hp_work(spec); - kfree(spec->bind_cap_vol); - kfree(spec->bind_cap_sw); - snd_hda_gen_free(&spec->gen); - kfree(spec); -} - -/* mute/unmute outputs */ -static void toggle_output_mutes(struct hda_codec *codec, int num_pins, - hda_nid_t *pins, bool mute) -{ - int i; - for (i = 0; i < num_pins; i++) { - unsigned int parm = snd_hda_codec_read(codec, pins[i], 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - if (parm & AC_PINCTL_IN_EN) - continue; - if (mute) - parm &= ~AC_PINCTL_OUT_EN; - else - parm |= AC_PINCTL_OUT_EN; - snd_hda_set_pin_ctl(codec, pins[i], parm); - } -} - -/* mute internal speaker if line-out is plugged */ -static void via_line_automute(struct hda_codec *codec, int present) -{ - struct via_spec *spec = codec->spec; - - if (!spec->autocfg.speaker_outs) - return; - if (!present) - present = snd_hda_jack_detect(codec, - spec->autocfg.line_out_pins[0]); - toggle_output_mutes(codec, spec->autocfg.speaker_outs, - spec->autocfg.speaker_pins, - present); -} - -/* mute internal speaker if HP is plugged */ -static void via_hp_automute(struct hda_codec *codec) -{ - int present = 0; - int nums; - struct via_spec *spec = codec->spec; - - if (!spec->hp_independent_mode && spec->autocfg.hp_pins[0] && - (spec->codec_type != VT1708 || spec->vt1708_jack_detect) && - is_jack_detectable(codec, spec->autocfg.hp_pins[0])) - present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); - - if (spec->smart51_enabled) - nums = spec->autocfg.line_outs + spec->smart51_nums; - else - nums = spec->autocfg.line_outs; - toggle_output_mutes(codec, nums, spec->autocfg.line_out_pins, present); - - via_line_automute(codec, present); + vt1708_stop_hp_work(codec); + snd_hda_gen_free(codec); } #ifdef CONFIG_PM static int via_suspend(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - vt1708_stop_hp_work(spec); + vt1708_stop_hp_work(codec); - if (spec->codec_type == VT1802) { - /* Fix pop noise on headphones */ - int i; - for (i = 0; i < spec->autocfg.hp_outs; i++) - snd_hda_set_pin_ctl(codec, spec->autocfg.hp_pins[i], 0); - } + /* Fix pop noise on headphones */ + if (spec->codec_type == VT1802) + snd_hda_shutup_pins(codec); return 0; } @@ -1709,7 +487,10 @@ static int via_suspend(struct hda_codec *codec) static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { struct via_spec *spec = codec->spec; - return snd_hda_check_amp_list_power(codec, &spec->loopback, nid); + set_widgets_power_state(codec); + analog_low_current_mode(codec); + vt1708_update_hp_work(codec); + return snd_hda_check_amp_list_power(codec, &spec->gen.loopback, nid); } #endif @@ -1720,7 +501,7 @@ static int via_init(struct hda_codec *codec); static const struct hda_codec_ops via_patch_ops = { .build_controls = via_build_controls, - .build_pcms = via_build_pcms, + .build_pcms = snd_hda_gen_build_pcms, .init = via_init, .free = via_free, .unsol_event = snd_hda_jack_unsol_event, @@ -1730,843 +511,12 @@ static const struct hda_codec_ops via_patch_ops = { #endif }; -static bool is_empty_dac(struct hda_codec *codec, hda_nid_t dac) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->multiout.num_dacs; i++) { - if (spec->multiout.dac_nids[i] == dac) - return false; - } - if (spec->hp_dac_nid == dac) - return false; - return true; -} - -static bool __parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path, int depth) -{ - struct via_spec *spec = codec->spec; - hda_nid_t conn[8]; - int i, nums; - - if (nid == spec->aa_mix_nid) { - if (!with_aa_mix) - return false; - with_aa_mix = 2; /* mark aa-mix is included */ - } - - nums = snd_hda_get_connections(codec, nid, conn, ARRAY_SIZE(conn)); - for (i = 0; i < nums; i++) { - if (get_wcaps_type(get_wcaps(codec, conn[i])) != AC_WID_AUD_OUT) - continue; - if (conn[i] == target_dac || is_empty_dac(codec, conn[i])) { - /* aa-mix is requested but not included? */ - if (!(spec->aa_mix_nid && with_aa_mix == 1)) - goto found; - } - } - if (depth >= MAX_NID_PATH_DEPTH) - return false; - for (i = 0; i < nums; i++) { - unsigned int type; - type = get_wcaps_type(get_wcaps(codec, conn[i])); - if (type == AC_WID_AUD_OUT) - continue; - if (__parse_output_path(codec, conn[i], target_dac, - with_aa_mix, path, depth + 1)) - goto found; - } - return false; - - found: - path->path[path->depth] = conn[i]; - path->idx[path->depth] = i; - if (nums > 1 && get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_AUD_MIX) - path->multi[path->depth] = 1; - path->depth++; - return true; -} - -static bool parse_output_path(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t target_dac, int with_aa_mix, - struct nid_path *path) -{ - if (__parse_output_path(codec, nid, target_dac, with_aa_mix, path, 1)) { - path->path[path->depth] = nid; - path->depth++; - snd_printdd("output-path: depth=%d, %02x/%02x/%02x/%02x/%02x\n", - path->depth, path->path[0], path->path[1], - path->path[2], path->path[3], path->path[4]); - return true; - } - return false; -} - -static int via_auto_fill_dac_nids(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, dac_num; - hda_nid_t nid; - - spec->multiout.dac_nids = spec->private_dac_nids; - dac_num = 0; - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t dac = 0; - nid = cfg->line_out_pins[i]; - if (!nid) - continue; - if (parse_output_path(codec, nid, 0, 0, &spec->out_path[i])) - dac = spec->out_path[i].path[0]; - if (!i && parse_output_path(codec, nid, dac, 1, - &spec->out_mix_path)) - dac = spec->out_mix_path.path[0]; - if (dac) { - spec->private_dac_nids[i] = dac; - dac_num++; - } - } - if (!spec->out_path[0].depth && spec->out_mix_path.depth) { - spec->out_path[0] = spec->out_mix_path; - spec->out_mix_path.depth = 0; - } - spec->multiout.num_dacs = dac_num; - return 0; -} - -static int create_ch_ctls(struct hda_codec *codec, const char *pfx, - int chs, bool check_dac, struct nid_path *path) -{ - struct via_spec *spec = codec->spec; - char name[32]; - hda_nid_t dac, pin, sel, nid; - int err; - - dac = check_dac ? path->path[0] : 0; - pin = path->path[path->depth - 1]; - sel = path->depth > 1 ? path->path[1] : 0; - - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_NUM_STEPS)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Volume", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->vol_ctl = nid; - } - - if (dac && check_amp_caps(codec, dac, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = dac; - else if (check_amp_caps(codec, pin, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = pin; - else if (check_amp_caps(codec, sel, HDA_OUTPUT, AC_AMPCAP_MUTE)) - nid = sel; - else - nid = 0; - if (nid) { - sprintf(name, "%s Playback Switch", pfx); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); - if (err < 0) - return err; - path->mute_ctl = nid; - } - return 0; -} - -static void mangle_smart51(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct auto_pin_cfg_item *ins = cfg->inputs; - int i, j, nums, attr; - int pins[AUTO_CFG_MAX_INS]; - - for (attr = INPUT_PIN_ATTR_REAR; attr >= INPUT_PIN_ATTR_NORMAL; attr--) { - nums = 0; - for (i = 0; i < cfg->num_inputs; i++) { - unsigned int def; - if (ins[i].type > AUTO_PIN_LINE_IN) - continue; - def = snd_hda_codec_get_pincfg(codec, ins[i].pin); - if (snd_hda_get_input_pin_attr(def) != attr) - continue; - for (j = 0; j < nums; j++) - if (ins[pins[j]].type < ins[i].type) { - memmove(pins + j + 1, pins + j, - (nums - j) * sizeof(int)); - break; - } - pins[j] = i; - nums++; - } - if (cfg->line_outs + nums < 3) - continue; - for (i = 0; i < nums; i++) { - hda_nid_t pin = ins[pins[i]].pin; - spec->smart51_pins[spec->smart51_nums++] = pin; - cfg->line_out_pins[cfg->line_outs++] = pin; - if (cfg->line_outs == 3) - break; - } - return; - } -} - -static void copy_path_mixer_ctls(struct nid_path *dst, struct nid_path *src) -{ - dst->vol_ctl = src->vol_ctl; - dst->mute_ctl = src->mute_ctl; -} - -/* add playback controls from the parsed DAC table */ -static int via_auto_create_multi_out_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct nid_path *path; - static const char * const chname[4] = { - "Front", "Surround", "C/LFE", "Side" - }; - int i, idx, err; - int old_line_outs; - - /* check smart51 */ - old_line_outs = cfg->line_outs; - if (cfg->line_outs == 1) - mangle_smart51(codec); - - err = via_auto_fill_dac_nids(codec); - if (err < 0) - return err; - - if (spec->multiout.num_dacs < 3) { - spec->smart51_nums = 0; - cfg->line_outs = old_line_outs; - } - for (i = 0; i < cfg->line_outs; i++) { - hda_nid_t pin, dac; - pin = cfg->line_out_pins[i]; - dac = spec->multiout.dac_nids[i]; - if (!pin || !dac) - continue; - path = spec->out_path + i; - if (i == HDA_CLFE) { - err = create_ch_ctls(codec, "Center", 1, true, path); - if (err < 0) - return err; - err = create_ch_ctls(codec, "LFE", 2, true, path); - if (err < 0) - return err; - } else { - const char *pfx = chname[i]; - if (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT && - cfg->line_outs == 1) - pfx = "Speaker"; - err = create_ch_ctls(codec, pfx, 3, true, path); - if (err < 0) - return err; - } - if (path != spec->out_path + i) - copy_path_mixer_ctls(&spec->out_path[i], path); - if (path == spec->out_path && spec->out_mix_path.depth) - copy_path_mixer_ctls(&spec->out_mix_path, path); - } - - idx = get_connection_index(codec, spec->aa_mix_nid, - spec->multiout.dac_nids[0]); - if (idx >= 0) { - /* add control to mixer */ - const char *name; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Volume" : "PCM Playback Volume"; - err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - name = spec->out_mix_path.depth ? - "PCM Loopback Playback Switch" : "PCM Playback Switch"; - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(spec->aa_mix_nid, 3, - idx, HDA_INPUT)); - if (err < 0) - return err; - } - - cfg->line_outs = old_line_outs; - - return 0; -} - -static int via_auto_create_hp_ctls(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - int i, err; - - if (!pin) - return 0; - - if (!parse_output_path(codec, pin, 0, 0, &spec->hp_indep_path)) { - for (i = HDA_SIDE; i >= HDA_CLFE; i--) { - if (i < spec->multiout.num_dacs && - parse_output_path(codec, pin, - spec->multiout.dac_nids[i], 0, - &spec->hp_indep_path)) { - spec->hp_indep_shared = i; - break; - } - } - } - if (spec->hp_indep_path.depth) { - spec->hp_dac_nid = spec->hp_indep_path.path[0]; - if (!spec->hp_indep_shared) - spec->hp_path = spec->hp_indep_path; - } - /* optionally check front-path w/o AA-mix */ - if (!spec->hp_path.depth) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->hp_path); - - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->hp_mix_path) && !spec->hp_path.depth) - return 0; - - if (spec->hp_path.depth) { - path = &spec->hp_path; - check_dac = true; - } else { - path = &spec->hp_mix_path; - check_dac = false; - } - err = create_ch_ctls(codec, "Headphone", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->hp_mix_path, path); - else - copy_path_mixer_ctls(&spec->hp_path, path); - if (spec->hp_indep_path.depth) - copy_path_mixer_ctls(&spec->hp_indep_path, path); - return 0; -} - -static int via_auto_create_speaker_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct nid_path *path; - bool check_dac; - hda_nid_t pin, dac = 0; - int err; - - pin = spec->autocfg.speaker_pins[0]; - if (!spec->autocfg.speaker_outs || !pin) - return 0; - - if (parse_output_path(codec, pin, 0, 0, &spec->speaker_path)) - dac = spec->speaker_path.path[0]; - if (!dac) - parse_output_path(codec, pin, - spec->multiout.dac_nids[HDA_FRONT], 0, - &spec->speaker_path); - if (!parse_output_path(codec, pin, spec->multiout.dac_nids[HDA_FRONT], - 1, &spec->speaker_mix_path) && !dac) - return 0; - - /* no AA-path for front? */ - if (!spec->out_mix_path.depth && spec->speaker_mix_path.depth) - dac = 0; - - spec->speaker_dac_nid = dac; - spec->multiout.extra_out_nid[0] = dac; - if (dac) { - path = &spec->speaker_path; - check_dac = true; - } else { - path = &spec->speaker_mix_path; - check_dac = false; - } - err = create_ch_ctls(codec, "Speaker", 3, check_dac, path); - if (err < 0) - return err; - if (check_dac) - copy_path_mixer_ctls(&spec->speaker_mix_path, path); - else - copy_path_mixer_ctls(&spec->speaker_path, path); - return 0; -} - -#define via_aamix_ctl_info via_pin_power_ctl_info - -static int via_aamix_ctl_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - ucontrol->value.enumerated.item[0] = spec->aamix_mode; - return 0; -} - -static void update_aamix_paths(struct hda_codec *codec, int do_mix, - struct nid_path *nomix, struct nid_path *mix) -{ - if (do_mix) { - activate_output_path(codec, nomix, false, false); - activate_output_path(codec, mix, true, false); - } else { - activate_output_path(codec, mix, false, false); - activate_output_path(codec, nomix, true, false); - } -} - -static int via_aamix_ctl_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int val = ucontrol->value.enumerated.item[0]; - - if (val == spec->aamix_mode) - return 0; - spec->aamix_mode = val; - /* update front path */ - update_aamix_paths(codec, val, &spec->out_path[0], &spec->out_mix_path); - /* update HP path */ - if (!spec->hp_independent_mode) { - update_aamix_paths(codec, val, &spec->hp_path, - &spec->hp_mix_path); - } - /* update speaker path */ - update_aamix_paths(codec, val, &spec->speaker_path, - &spec->speaker_mix_path); - return 1; -} - -static const struct snd_kcontrol_new via_aamix_ctl_enum = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Loopback Mixing", - .info = via_aamix_ctl_info, - .get = via_aamix_ctl_get, - .put = via_aamix_ctl_put, -}; - -static int via_auto_create_loopback_switch(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (!spec->aa_mix_nid) - return 0; /* no loopback switching available */ - if (!(spec->out_mix_path.depth || spec->hp_mix_path.depth || - spec->speaker_path.depth)) - return 0; /* no loopback switching available */ - if (!via_clone_control(spec, &via_aamix_ctl_enum)) - return -ENOMEM; - return 0; -} - -/* look for ADCs */ -static int via_fill_adcs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t nid = codec->start_nid; - int i; - - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (wcaps & AC_WCAP_DIGITAL) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - if (spec->num_adc_nids >= ARRAY_SIZE(spec->adc_nids)) - return -ENOMEM; - spec->adc_nids[spec->num_adc_nids++] = nid; - } - return 0; -} - -/* input-src control */ -static int via_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = spec->num_inputs; - if (uinfo->value.enumerated.item >= spec->num_inputs) - uinfo->value.enumerated.item = spec->num_inputs - 1; - strcpy(uinfo->value.enumerated.name, - spec->inputs[uinfo->value.enumerated.item].label); - return 0; -} - -static int via_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - - ucontrol->value.enumerated.item[0] = spec->cur_mux[idx]; - return 0; -} - -static int via_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct via_spec *spec = codec->spec; - unsigned int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); - hda_nid_t mux; - int cur; - - cur = ucontrol->value.enumerated.item[0]; - if (cur < 0 || cur >= spec->num_inputs) - return -EINVAL; - if (spec->cur_mux[idx] == cur) - return 0; - spec->cur_mux[idx] = cur; - if (spec->dyn_adc_switch) { - int adc_idx = spec->inputs[cur].adc_idx; - mux = spec->mux_nids[adc_idx]; - via_dyn_adc_pcm_resetup(codec, cur); - } else { - mux = spec->mux_nids[idx]; - if (snd_BUG_ON(!mux)) - return -EINVAL; - } - - if (mux) { - /* switch to D0 beofre change index */ - update_power_state(codec, mux, AC_PWRST_D0); - snd_hda_codec_write(codec, mux, 0, - AC_VERB_SET_CONNECT_SEL, - spec->inputs[cur].mux_idx); - } - - /* update jack power state */ - set_widgets_power_state(codec); - return 0; -} - -static const struct snd_kcontrol_new via_input_src_ctl = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - /* The multiple "Capture Source" controls confuse alsamixer - * So call somewhat different.. - */ - /* .name = "Capture Source", */ - .name = "Input Source", - .info = via_mux_enum_info, - .get = via_mux_enum_get, - .put = via_mux_enum_put, +static const struct hda_verb vt1708_init_verbs[] = { + /* power down jack detect function */ + {0x1, 0xf81, 0x1}, + { } }; - -static int create_input_src_ctls(struct hda_codec *codec, int count) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - - if (spec->num_inputs <= 1 || !count) - return 0; /* no need for single src */ - - knew = via_clone_control(spec, &via_input_src_ctl); - if (!knew) - return -ENOMEM; - knew->count = count; - return 0; -} - -/* add the powersave loopback-list entry */ -static void add_loopback_list(struct via_spec *spec, hda_nid_t mix, int idx) -{ - struct hda_amp_list *list; - - if (spec->num_loopbacks >= ARRAY_SIZE(spec->loopback_list) - 1) - return; - list = spec->loopback_list + spec->num_loopbacks; - list->nid = mix; - list->dir = HDA_INPUT; - list->idx = idx; - spec->num_loopbacks++; - spec->loopback.amplist = spec->loopback_list; -} - -static bool is_reachable_nid(struct hda_codec *codec, hda_nid_t src, - hda_nid_t dst) -{ - return snd_hda_get_conn_index(codec, src, dst, 1) >= 0; -} - -/* add the input-route to the given pin */ -static bool add_input_route(struct hda_codec *codec, hda_nid_t pin) -{ - struct via_spec *spec = codec->spec; - int c, idx; - - spec->inputs[spec->num_inputs].adc_idx = -1; - spec->inputs[spec->num_inputs].pin = pin; - for (c = 0; c < spec->num_adc_nids; c++) { - if (spec->mux_nids[c]) { - idx = get_connection_index(codec, spec->mux_nids[c], - pin); - if (idx < 0) - continue; - spec->inputs[spec->num_inputs].mux_idx = idx; - } else { - if (!is_reachable_nid(codec, spec->adc_nids[c], pin)) - continue; - } - spec->inputs[spec->num_inputs].adc_idx = c; - /* Can primary ADC satisfy all inputs? */ - if (!spec->dyn_adc_switch && - spec->num_inputs > 0 && spec->inputs[0].adc_idx != c) { - snd_printd(KERN_INFO - "via: dynamic ADC switching enabled\n"); - spec->dyn_adc_switch = 1; - } - return true; - } - return false; -} - -static int get_mux_nids(struct hda_codec *codec); - -/* parse input-routes; fill ADCs, MUXs and input-src entries */ -static int parse_analog_inputs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - int i, err; - - err = via_fill_adcs(codec); - if (err < 0) - return err; - err = get_mux_nids(codec); - if (err < 0) - return err; - - /* fill all input-routes */ - for (i = 0; i < cfg->num_inputs; i++) { - if (add_input_route(codec, cfg->inputs[i].pin)) - spec->inputs[spec->num_inputs++].label = - hda_get_autocfg_input_label(codec, cfg, i); - } - - /* check for internal loopback recording */ - if (spec->aa_mix_nid && - add_input_route(codec, spec->aa_mix_nid)) - spec->inputs[spec->num_inputs++].label = "Stereo Mixer"; - - return 0; -} - -/* create analog-loopback volume/switch controls */ -static int create_loopback_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, j, err, idx; - - if (!spec->aa_mix_nid) - return 0; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - const char *label = hda_get_autocfg_input_label(codec, cfg, i); - - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - idx = get_connection_index(codec, spec->aa_mix_nid, pin); - if (idx >= 0) { - err = via_new_analog_input(spec, label, type_idx, - idx, spec->aa_mix_nid); - if (err < 0) - return err; - add_loopback_list(spec, spec->aa_mix_nid, idx); - } - - /* remember the label for smart51 control */ - for (j = 0; j < spec->smart51_nums; j++) { - if (spec->smart51_pins[j] == pin) { - spec->smart51_idxs[j] = idx; - spec->smart51_labels[j] = label; - break; - } - } - } - return 0; -} - -/* create mic-boost controls (if present) */ -static int create_mic_boost_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - const struct auto_pin_cfg *cfg = &spec->autocfg; - const char *prev_label = NULL; - int type_idx = 0; - int i, err; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int caps; - const char *label; - char name[32]; - - if (cfg->inputs[i].type != AUTO_PIN_MIC) - continue; - caps = query_amp_caps(codec, pin, HDA_INPUT); - if (caps == -1 || !(caps & AC_AMPCAP_NUM_STEPS)) - continue; - label = hda_get_autocfg_input_label(codec, cfg, i); - if (prev_label && !strcmp(label, prev_label)) - type_idx++; - else - type_idx = 0; - prev_label = label; - snprintf(name, sizeof(name), "%s Boost Volume", label); - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, name, type_idx, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT)); - if (err < 0) - return err; - } - return 0; -} - -/* create capture and input-src controls for multiple streams */ -static int create_multi_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i, err; - - /* create capture mixer elements */ - for (i = 0; i < spec->num_adc_nids; i++) { - hda_nid_t adc = spec->adc_nids[i]; - err = __via_add_control(spec, VIA_CTL_WIDGET_VOL, - "Capture Volume", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - err = __via_add_control(spec, VIA_CTL_WIDGET_MUTE, - "Capture Switch", i, - HDA_COMPOSE_AMP_VAL(adc, 3, 0, - HDA_INPUT)); - if (err < 0) - return err; - } - - /* input-source control */ - for (i = 0; i < spec->num_adc_nids; i++) - if (!spec->mux_nids[i]) - break; - err = create_input_src_ctls(codec, i); - if (err < 0) - return err; - return 0; -} - -/* bind capture volume/switch */ -static struct snd_kcontrol_new via_bind_cap_vol_ctl = - HDA_BIND_VOL("Capture Volume", 0); -static struct snd_kcontrol_new via_bind_cap_sw_ctl = - HDA_BIND_SW("Capture Switch", 0); - -static int init_bind_ctl(struct via_spec *spec, struct hda_bind_ctls **ctl_ret, - struct hda_ctl_ops *ops) -{ - struct hda_bind_ctls *ctl; - int i; - - ctl = kzalloc(sizeof(*ctl) + sizeof(long) * 4, GFP_KERNEL); - if (!ctl) - return -ENOMEM; - ctl->ops = ops; - for (i = 0; i < spec->num_adc_nids; i++) - ctl->values[i] = - HDA_COMPOSE_AMP_VAL(spec->adc_nids[i], 3, 0, HDA_INPUT); - *ctl_ret = ctl; - return 0; -} - -/* create capture and input-src controls for dynamic ADC-switch case */ -static int create_dyn_adc_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - struct snd_kcontrol_new *knew; - int err; - - /* set up the bind capture ctls */ - err = init_bind_ctl(spec, &spec->bind_cap_vol, &snd_hda_bind_vol); - if (err < 0) - return err; - err = init_bind_ctl(spec, &spec->bind_cap_sw, &snd_hda_bind_sw); - if (err < 0) - return err; - - /* create capture mixer elements */ - knew = via_clone_control(spec, &via_bind_cap_vol_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_vol; - - knew = via_clone_control(spec, &via_bind_cap_sw_ctl); - if (!knew) - return -ENOMEM; - knew->private_value = (long)spec->bind_cap_sw; - - /* input-source control */ - err = create_input_src_ctls(codec, 1); - if (err < 0) - return err; - return 0; -} - -/* parse and create capture-related stuff */ -static int via_auto_create_analog_input_ctls(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - - err = parse_analog_inputs(codec); - if (err < 0) - return err; - if (spec->dyn_adc_switch) - err = create_dyn_adc_ctls(codec); - else - err = create_multi_adc_ctls(codec); - if (err < 0) - return err; - err = create_loopback_ctls(codec); - if (err < 0) - return err; - err = create_mic_boost_ctls(codec); - if (err < 0) - return err; - return 0; -} - static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) { unsigned int def_conf; @@ -2609,102 +559,32 @@ static int vt1708_jack_detect_put(struct snd_kcontrol *kcontrol, if (spec->vt1708_jack_detect == val) return 0; spec->vt1708_jack_detect = val; - if (spec->vt1708_jack_detect && - snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") != 1) { - mute_aa_path(codec, 1); - notify_aa_path_ctls(codec); - } - via_hp_automute(codec); - vt1708_update_hp_work(spec); + vt1708_update_hp_work(codec); return 1; } -static const struct snd_kcontrol_new vt1708_jack_detect_ctl = { +static const struct snd_kcontrol_new vt1708_jack_detect_ctl[] = { + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Jack Detect", .count = 1, .info = snd_ctl_boolean_mono_info, .get = vt1708_jack_detect_get, .put = vt1708_jack_detect_put, + }, + {} /* terminator */ }; -static void fill_dig_outs(struct hda_codec *codec); -static void fill_dig_in(struct hda_codec *codec); - -static int via_parse_auto_config(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) - return -EINVAL; - - err = via_auto_create_multi_out_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_hp_ctls(codec, spec->autocfg.hp_pins[0]); - if (err < 0) - return err; - err = via_auto_create_speaker_ctls(codec); - if (err < 0) - return err; - err = via_auto_create_loopback_switch(codec); - if (err < 0) - return err; - err = via_auto_create_analog_input_ctls(codec); - if (err < 0) - return err; - - spec->multiout.max_channels = spec->multiout.num_dacs * 2; - - fill_dig_outs(codec); - fill_dig_in(codec); - - if (spec->kctls.list) - spec->mixers[spec->num_mixers++] = spec->kctls.list; - - - if (spec->hp_dac_nid && spec->hp_mix_path.depth) { - err = via_hp_build(codec); - if (err < 0) - return err; - } - - err = via_smart51_build(codec); - if (err < 0) - return err; - - /* assign slave outs */ - if (spec->slave_dig_outs[0]) - codec->slave_dig_outs = spec->slave_dig_outs; - - return 1; -} - -static void via_auto_init_dig_outs(struct hda_codec *codec) +static void via_hp_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { - struct via_spec *spec = codec->spec; - if (spec->multiout.dig_out_nid) - init_output_pin(codec, spec->autocfg.dig_out_pins[0], PIN_OUT); - if (spec->slave_dig_outs[0]) - init_output_pin(codec, spec->autocfg.dig_out_pins[1], PIN_OUT); -} - -static void via_auto_init_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - if (!spec->dig_in_nid) - return; - snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN); + set_widgets_power_state(codec); + snd_hda_gen_hp_automute(codec, tbl); } -static void via_jack_output_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) +static void via_line_automute(struct hda_codec *codec, struct hda_jack_tbl *tbl) { set_widgets_power_state(codec); - via_hp_automute(codec); + snd_hda_gen_line_automute(codec, tbl); } static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_tbl *tbl) @@ -2712,41 +592,75 @@ static void via_jack_powerstate_event(struct hda_codec *codec, struct hda_jack_t set_widgets_power_state(codec); } -/* initialize the unsolicited events */ -static void via_auto_init_unsol_event(struct hda_codec *codec) +#define VIA_JACK_EVENT (HDA_GEN_LAST_EVENT + 1) + +static void via_set_jack_unsol_events(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int ev; + struct auto_pin_cfg *cfg = &spec->gen.autocfg; + hda_nid_t pin; int i; - hda_jack_callback cb; - - if (cfg->hp_pins[0] && is_jack_detectable(codec, cfg->hp_pins[0])) - snd_hda_jack_detect_enable_callback(codec, cfg->hp_pins[0], - VIA_HP_EVENT | VIA_JACK_EVENT, - via_jack_output_event); + spec->gen.hp_automute_hook = via_hp_automute; if (cfg->speaker_pins[0]) - ev = VIA_LINE_EVENT; - else - ev = 0; - cb = ev ? via_jack_output_event : via_jack_powerstate_event; + spec->gen.line_automute_hook = via_line_automute; for (i = 0; i < cfg->line_outs; i++) { - if (cfg->line_out_pins[i] && - is_jack_detectable(codec, cfg->line_out_pins[i])) - snd_hda_jack_detect_enable_callback(codec, cfg->line_out_pins[i], - ev | VIA_JACK_EVENT, cb); + pin = cfg->line_out_pins[i]; + if (pin && !snd_hda_jack_tbl_get(codec, pin) && + is_jack_detectable(codec, pin)) + snd_hda_jack_detect_enable_callback(codec, pin, + VIA_JACK_EVENT, + via_jack_powerstate_event); } for (i = 0; i < cfg->num_inputs; i++) { - if (is_jack_detectable(codec, cfg->inputs[i].pin)) - snd_hda_jack_detect_enable_callback(codec, cfg->inputs[i].pin, + pin = cfg->line_out_pins[i]; + if (pin && !snd_hda_jack_tbl_get(codec, pin) && + is_jack_detectable(codec, pin)) + snd_hda_jack_detect_enable_callback(codec, pin, VIA_JACK_EVENT, via_jack_powerstate_event); } } +static const struct badness_table via_main_out_badness = { + .no_primary_dac = 0x10000, + .no_dac = 0x4000, + .shared_primary = 0x10000, + .shared_surr = 0x20, + .shared_clfe = 0x20, + .shared_surr_main = 0x20, +}; +static const struct badness_table via_extra_out_badness = { + .no_primary_dac = 0x4000, + .no_dac = 0x4000, + .shared_primary = 0x12, + .shared_surr = 0x20, + .shared_clfe = 0x20, + .shared_surr_main = 0x10, +}; + +static int via_parse_auto_config(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int err; + + spec->gen.main_out_badness = &via_main_out_badness; + spec->gen.extra_out_badness = &via_extra_out_badness; + + err = snd_hda_parse_pin_defcfg(codec, &spec->gen.autocfg, NULL, 0); + if (err < 0) + return err; + + err = snd_hda_gen_parse_auto_config(codec, &spec->gen.autocfg); + if (err < 0) + return err; + + via_set_jack_unsol_events(codec); + return 0; +} + static int via_init(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -2759,63 +673,47 @@ static int via_init(struct hda_codec *codec) set_widgets_power_state(codec); __analog_low_current_mode(codec, true); - via_auto_init_multi_out(codec); - via_auto_init_hp_out(codec); - via_auto_init_speaker_out(codec); - via_auto_init_analog_input(codec); - via_auto_init_dig_outs(codec); - via_auto_init_dig_in(codec); - - via_auto_init_unsol_event(codec); + snd_hda_gen_init(codec); - via_hp_automute(codec); - vt1708_update_hp_work(spec); + vt1708_update_hp_work(codec); return 0; } -static void vt1708_update_hp_jack_state(struct work_struct *work) +static int vt1708_build_controls(struct hda_codec *codec) { - struct via_spec *spec = container_of(work, struct via_spec, - vt1708_hp_work.work); - if (spec->codec_type != VT1708) - return; - snd_hda_jack_set_dirty_all(spec->codec); - /* if jack state toggled */ - if (spec->vt1708_hp_present - != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { - spec->vt1708_hp_present ^= 1; - via_hp_automute(spec->codec); - } - if (spec->vt1708_jack_detect) - schedule_delayed_work(&spec->vt1708_hp_work, - msecs_to_jiffies(100)); + /* In order not to create "Phantom Jack" controls, + temporary enable jackpoll */ + int err; + int old_interval = codec->jackpoll_interval; + codec->jackpoll_interval = msecs_to_jiffies(100); + err = via_build_controls(codec); + codec->jackpoll_interval = old_interval; + return err; } -static int get_mux_nids(struct hda_codec *codec) +static int vt1708_build_pcms(struct hda_codec *codec) { struct via_spec *spec = codec->spec; - hda_nid_t nid, conn[8]; - unsigned int type; - int i, n; - - for (i = 0; i < spec->num_adc_nids; i++) { - nid = spec->adc_nids[i]; - while (nid) { - type = get_wcaps_type(get_wcaps(codec, nid)); - if (type == AC_WID_PIN) - break; - n = snd_hda_get_connections(codec, nid, conn, - ARRAY_SIZE(conn)); - if (n <= 0) - break; - if (n > 1) { - spec->mux_nids[i] = nid; - break; - } - nid = conn[0]; - } + int i, err; + + err = snd_hda_gen_build_pcms(codec); + if (err < 0 || codec->vendor_id != 0x11061708) + return err; + + /* We got noisy outputs on the right channel on VT1708 when + * 24bit samples are used. Until any workaround is found, + * disable the 24bit format, so far. + */ + for (i = 0; i < codec->num_pcms; i++) { + struct hda_pcm *info = &spec->gen.pcm_rec[i]; + if (!info->stream[SNDRV_PCM_STREAM_PLAYBACK].substreams || + info->pcm_type != HDA_PCM_TYPE_AUDIO) + continue; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].formats = + SNDRV_PCM_FMTBIT_S16_LE; } + return 0; } @@ -2829,7 +727,17 @@ static int patch_vt1708(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x17; + spec->gen.mixer_nid = 0x17; + + /* set jackpoll_interval while parsing the codec */ + codec->jackpoll_interval = msecs_to_jiffies(100); + spec->vt1708_jack_detect = 1; + + /* don't support the input jack switching due to lack of unsol event */ + /* (it may work with polling, though, but it needs testing) */ + spec->gen.suppress_auto_mic = 1; + /* Some machines show the broken speaker mute */ + spec->gen.auto_mute_via_amp = 1; /* Add HP and CD pin config connect bit re-config action */ vt1708_set_pinconfig_connect(codec, VT1708_HP_PIN_NID); @@ -2843,18 +751,17 @@ static int patch_vt1708(struct hda_codec *codec) } /* add jack detect on/off control */ - if (!via_clone_control(spec, &vt1708_jack_detect_ctl)) - return -ENOMEM; - - /* disable 32bit format on VT1708 */ - if (codec->vendor_id == 0x11061708) - spec->stream_analog_playback = &vt1708_pcm_analog_s16_playback; + spec->mixers[spec->num_mixers++] = vt1708_jack_detect_ctl; spec->init_verbs[spec->num_iverbs++] = vt1708_init_verbs; codec->patch_ops = via_patch_ops; + codec->patch_ops.build_controls = vt1708_build_controls; + codec->patch_ops.build_pcms = vt1708_build_pcms; + + /* clear jackpoll_interval again; it's set dynamically */ + codec->jackpoll_interval = 0; - INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } @@ -2868,7 +775,7 @@ static int patch_vt1709(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x18; + spec->gen.mixer_nid = 0x18; err = via_parse_auto_config(codec); if (err < 0) { @@ -2912,7 +819,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) /* PW0 (19h), SW1 (18h), AOW1 (11h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x19, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1b, &parm); update_power_state(codec, 0x18, parm); update_power_state(codec, 0x11, parm); @@ -2921,7 +828,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (is_8ch) { parm = AC_PWRST_D3; set_pin_power_state(codec, 0x22, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x26, parm); update_power_state(codec, 0x24, parm); @@ -2929,7 +836,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) /* PW7(23h), SW2(27h), AOW2(25h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x27, parm); update_power_state(codec, 0x25, parm); @@ -2949,7 +856,7 @@ static void set_widgets_power_state_vt1708B(struct hda_codec *codec) if (is_8ch) { update_power_state(codec, 0x25, parm); update_power_state(codec, 0x27, parm); - } else if (codec->vendor_id == 0x11064397 && spec->hp_independent_mode) + } else if (codec->vendor_id == 0x11064397 && spec->gen.indep_hp_enabled) update_power_state(codec, 0x25, parm); } @@ -2967,7 +874,7 @@ static int patch_vt1708B(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; /* automatic parse from the BIOS config */ err = via_parse_auto_config(codec); @@ -2992,61 +899,11 @@ static const struct hda_verb vt1708S_init_verbs[] = { { } }; -/* fill out digital output widgets; one for master and one for slave outputs */ -static void fill_dig_outs(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->autocfg.dig_outs; i++) { - hda_nid_t nid; - int conn; - - nid = spec->autocfg.dig_out_pins[i]; - if (!nid) - continue; - conn = snd_hda_get_connections(codec, nid, &nid, 1); - if (conn < 1) - continue; - if (!spec->multiout.dig_out_nid) - spec->multiout.dig_out_nid = nid; - else { - spec->slave_dig_outs[0] = nid; - break; /* at most two dig outs */ - } - } -} - -static void fill_dig_in(struct hda_codec *codec) -{ - struct via_spec *spec = codec->spec; - hda_nid_t dig_nid; - int i, err; - - if (!spec->autocfg.dig_in_pin) - return; - - dig_nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, dig_nid++) { - unsigned int wcaps = get_wcaps(codec, dig_nid); - if (get_wcaps_type(wcaps) != AC_WID_AUD_IN) - continue; - if (!(wcaps & AC_WCAP_DIGITAL)) - continue; - if (!(wcaps & AC_WCAP_CONN_LIST)) - continue; - err = get_connection_index(codec, dig_nid, - spec->autocfg.dig_in_pin); - if (err >= 0) { - spec->dig_in_nid = dig_nid; - break; - } - } -} - static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, int offset, int num_steps, int step_size) { + snd_hda_override_wcaps(codec, pin, + get_wcaps(codec, pin) | AC_WCAP_IN_AMP); snd_hda_override_amp_caps(codec, pin, HDA_INPUT, (offset << AC_AMPCAP_OFFSET_SHIFT) | (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | @@ -3064,21 +921,10 @@ static int patch_vt1708S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); - /* automatic parse from the BIOS config */ - err = via_parse_auto_config(codec); - if (err < 0) { - via_free(codec); - return err; - } - - spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; - - codec->patch_ops = via_patch_ops; - /* correct names for VT1708BCE */ if (get_codec_type(codec) == VT1708BCE) { kfree(codec->chip_name); @@ -3095,6 +941,18 @@ static int patch_vt1708S(struct hda_codec *codec) sizeof(codec->bus->card->mixername), "%s %s", codec->vendor_name, codec->chip_name); } + + /* automatic parse from the BIOS config */ + err = via_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } + + spec->init_verbs[spec->num_iverbs++] = vt1708S_init_verbs; + + codec->patch_ops = via_patch_ops; + spec->set_widgets_power_state = set_widgets_power_state_vt1708B; return 0; } @@ -3149,7 +1007,7 @@ static int patch_vt1702(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x1a; + spec->gen.mixer_nid = 0x1a; /* limit AA path volume to 0 dB */ snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, @@ -3216,17 +1074,17 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) /* PW2 (26h), AOW2 (ah) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x26, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x2b, &parm); update_power_state(codec, 0xa, parm); /* PW0 (24h), AOW0 (8h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); - if (!spec->hp_independent_mode) /* check for redirected HP */ + if (!spec->gen.indep_hp_enabled) /* check for redirected HP */ set_pin_power_state(codec, 0x28, &parm); update_power_state(codec, 0x8, parm); - if (!spec->hp_independent_mode && parm2 != AC_PWRST_D3) + if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3) parm = parm2; update_power_state(codec, 0xb, parm); /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ @@ -3235,11 +1093,11 @@ static void set_widgets_power_state_vt1718S(struct hda_codec *codec) /* PW1 (25h), AOW1 (9h) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x25, &parm); - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x2a, &parm); update_power_state(codec, 0x9, parm); - if (spec->hp_independent_mode) { + if (spec->gen.indep_hp_enabled) { /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ parm = AC_PWRST_D3; set_pin_power_state(codec, 0x28, &parm); @@ -3259,9 +1117,9 @@ static int add_secret_dac_path(struct hda_codec *codec) hda_nid_t conn[8]; hda_nid_t nid; - if (!spec->aa_mix_nid) + if (!spec->gen.mixer_nid) return 0; - nums = snd_hda_get_connections(codec, spec->aa_mix_nid, conn, + nums = snd_hda_get_connections(codec, spec->gen.mixer_nid, conn, ARRAY_SIZE(conn) - 1); for (i = 0; i < nums; i++) { if (get_wcaps_type(get_wcaps(codec, conn[i])) == AC_WID_AUD_OUT) @@ -3276,7 +1134,7 @@ static int add_secret_dac_path(struct hda_codec *codec) !(caps & AC_WCAP_DIGITAL)) { conn[nums++] = nid; return snd_hda_override_conn_list(codec, - spec->aa_mix_nid, + spec->gen.mixer_nid, nums, conn); } } @@ -3294,7 +1152,7 @@ static int patch_vt1718S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); @@ -3425,7 +1283,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x19, &parm); /* Smart 5.1 PW2(1bh) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1b, &parm); update_power_state(codec, 0x18, parm); update_power_state(codec, 0x11, parm); @@ -3434,12 +1292,12 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) parm = AC_PWRST_D3; set_pin_power_state(codec, 0x23, &parm); /* Smart 5.1 PW1(1ah) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1a, &parm); update_power_state(codec, 0x27, parm); /* Smart 5.1 PW5(1eh) */ - if (spec->smart51_enabled) + if (smart51_enabled(codec)) set_pin_power_state(codec, 0x1e, &parm); update_power_state(codec, 0x25, parm); @@ -3451,7 +1309,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) mono_out = 0; else { present = snd_hda_jack_detect(codec, 0x1d); - if (!spec->hp_independent_mode && present) + if (!spec->gen.indep_hp_enabled && present) mono_out = 0; else mono_out = 1; @@ -3466,7 +1324,7 @@ static void set_widgets_power_state_vt1716S(struct hda_codec *codec) set_pin_power_state(codec, 0x1c, &parm); set_pin_power_state(codec, 0x1d, &parm); /* HP Independent Mode, power on AOW3 */ - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x25, parm); /* force to D0 for internal Speaker */ @@ -3485,7 +1343,7 @@ static int patch_vt1716S(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x16; + spec->gen.mixer_nid = 0x16; override_mic_boost(codec, 0x1a, 0, 3, 40); override_mic_boost(codec, 0x1e, 0, 3, 40); @@ -3498,9 +1356,7 @@ static int patch_vt1716S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1716S_init_verbs; - spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; - spec->num_mixers++; - + spec->mixers[spec->num_mixers++] = vt1716s_dmic_mixer; spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; codec->patch_ops = via_patch_ops; @@ -3585,7 +1441,7 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) update_power_state(codec, 0x35, parm); } - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x9, AC_PWRST_D0); /* Class-D */ @@ -3628,6 +1484,7 @@ static void set_widgets_power_state_vt2002P(struct hda_codec *codec) */ enum { VIA_FIXUP_INTMIC_BOOST, + VIA_FIXUP_ASUS_G75, }; static void via_fixup_intmic_boost(struct hda_codec *codec, @@ -3642,13 +1499,35 @@ static const struct hda_fixup via_fixups[] = { .type = HDA_FIXUP_FUNC, .v.func = via_fixup_intmic_boost, }, + [VIA_FIXUP_ASUS_G75] = { + .type = HDA_FIXUP_PINS, + .v.pins = (const struct hda_pintbl[]) { + /* set 0x24 and 0x33 as speakers */ + { 0x24, 0x991301f0 }, + { 0x33, 0x991301f1 }, /* subwoofer */ + { } + } + }, }; static const struct snd_pci_quirk vt2002p_fixups[] = { + SND_PCI_QUIRK(0x1043, 0x1487, "Asus G75", VIA_FIXUP_ASUS_G75), SND_PCI_QUIRK(0x1043, 0x8532, "Asus X202E", VIA_FIXUP_INTMIC_BOOST), {} }; +/* NIDs 0x24 and 0x33 on VT1802 have connections to non-existing NID 0x3e + * Replace this with mixer NID 0x1c + */ +static void fix_vt1802_connections(struct hda_codec *codec) +{ + static hda_nid_t conn_24[] = { 0x14, 0x1c }; + static hda_nid_t conn_33[] = { 0x1c }; + + snd_hda_override_conn_list(codec, 0x24, ARRAY_SIZE(conn_24), conn_24); + snd_hda_override_conn_list(codec, 0x33, ARRAY_SIZE(conn_33), conn_33); +} + /* patch for vt2002P */ static int patch_vt2002P(struct hda_codec *codec) { @@ -3660,9 +1539,11 @@ static int patch_vt2002P(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); + if (spec->codec_type == VT1802) + fix_vt1802_connections(codec); add_secret_dac_path(codec); snd_hda_pick_fixup(codec, NULL, vt2002p_fixups, via_fixups); @@ -3729,7 +1610,7 @@ static void set_widgets_power_state_vt1812(struct hda_codec *codec) set_pin_power_state(codec, 0x25, &parm); update_power_state(codec, 0x15, parm); update_power_state(codec, 0x35, parm); - if (spec->hp_independent_mode) + if (spec->gen.indep_hp_enabled) update_power_state(codec, 0x9, AC_PWRST_D0); /* Internal Speaker */ @@ -3782,7 +1663,7 @@ static int patch_vt1812(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->aa_mix_nid = 0x21; + spec->gen.mixer_nid = 0x21; override_mic_boost(codec, 0x2b, 0, 3, 40); override_mic_boost(codec, 0x29, 0, 3, 40); add_secret_dac_path(codec); @@ -3802,6 +1683,125 @@ static int patch_vt1812(struct hda_codec *codec) return 0; } +/* patch for vt3476 */ + +static const struct hda_verb vt3476_init_verbs[] = { + /* Enable DMic 8/16/32K */ + {0x1, 0xF7B, 0x30}, + /* Enable Boost Volume backdoor */ + {0x1, 0xFB9, 0x20}, + /* Enable AOW-MW9 path */ + {0x1, 0xFB8, 0x10}, + { } +}; + +static void set_widgets_power_state_vt3476(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm, parm2; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = + snd_hda_codec_read(codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 4; + /* inputs */ + /* PW 5/6/7 (29h/2ah/2bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x29, &parm); + set_pin_power_state(codec, 0x2a, &parm); + set_pin_power_state(codec, 0x2b, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* MUX10/11 (1eh/1fh), AIW 0/1 (10h/11h) */ + update_power_state(codec, 0x1e, parm); + update_power_state(codec, 0x1f, parm); + update_power_state(codec, 0x10, parm); + update_power_state(codec, 0x11, parm); + + /* outputs */ + /* PW3 (27h), MW3(37h), AOW3 (bh) */ + if (spec->codec_type == VT1705CF) { + parm = AC_PWRST_D3; + update_power_state(codec, 0x27, parm); + update_power_state(codec, 0x37, parm); + } else { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + update_power_state(codec, 0x37, parm); + } + + /* PW2 (26h), MW2(36h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + update_power_state(codec, 0x36, parm); + if (smart51_enabled(codec)) { + /* PW7(2bh), MW7(3bh), MUX7(1Bh) */ + set_pin_power_state(codec, 0x2b, &parm); + update_power_state(codec, 0x3b, parm); + update_power_state(codec, 0x1b, parm); + } + update_conv_power_state(codec, 0xa, parm, 2); + + /* PW1 (25h), MW1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + update_power_state(codec, 0x35, parm); + if (smart51_enabled(codec)) { + /* PW6(2ah), MW6(3ah), MUX6(1ah) */ + set_pin_power_state(codec, 0x2a, &parm); + update_power_state(codec, 0x3a, parm); + update_power_state(codec, 0x1a, parm); + } + update_conv_power_state(codec, 0x9, parm, 1); + + /* PW4 (28h), MW4 (38h), MUX4(18h), AOW3(bh)/AOW0(8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + update_power_state(codec, 0x38, parm); + update_power_state(codec, 0x18, parm); + if (spec->gen.indep_hp_enabled) + update_conv_power_state(codec, 0xb, parm, 3); + parm2 = parm; /* for pin 0x0b */ + + /* PW0 (24h), MW0(34h), MW9(3fh), AOW0 (8h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + update_power_state(codec, 0x34, parm); + if (!spec->gen.indep_hp_enabled && parm2 != AC_PWRST_D3) + parm = parm2; + update_conv_power_state(codec, 0x8, parm, 0); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + update_power_state(codec, 0x3f, imux_is_smixer ? AC_PWRST_D0 : parm); +} + +static int patch_vt3476(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = via_new_spec(codec); + if (spec == NULL) + return -ENOMEM; + + spec->gen.mixer_nid = 0x3f; + add_secret_dac_path(codec); + + /* automatic parse from the BIOS config */ + err = via_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } + + spec->init_verbs[spec->num_iverbs++] = vt3476_init_verbs; + + codec->patch_ops = via_patch_ops; + + spec->set_widgets_power_state = set_widgets_power_state_vt3476; + + return 0; +} + /* * patch entries */ @@ -3895,6 +1895,12 @@ static const struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt2002P}, { .id = 0x11068446, .name = "VT1802", .patch = patch_vt2002P}, + { .id = 0x11064760, .name = "VT1705CF", + .patch = patch_vt3476}, + { .id = 0x11064761, .name = "VT1708SCE", + .patch = patch_vt3476}, + { .id = 0x11064762, .name = "VT1808", + .patch = patch_vt3476}, {} /* terminator */ }; diff --git a/sound/pci/hda/thinkpad_helper.c b/sound/pci/hda/thinkpad_helper.c new file mode 100644 index 00000000000..6ba0b5517c4 --- /dev/null +++ b/sound/pci/hda/thinkpad_helper.c @@ -0,0 +1,102 @@ +/* Helper functions for Thinkpad LED control; + * to be included from codec driver + */ + +#if IS_ENABLED(CONFIG_THINKPAD_ACPI) + +#include <linux/acpi.h> +#include <linux/thinkpad_acpi.h> + +static int (*led_set_func)(int, bool); +static void (*old_vmaster_hook)(void *, int); + +static acpi_status acpi_check_cb(acpi_handle handle, u32 lvl, void *context, + void **rv) +{ + bool *found = context; + *found = true; + return AE_OK; +} + +static bool is_thinkpad(struct hda_codec *codec) +{ + bool found = false; + if (codec->subsystem_id >> 16 != 0x17aa) + return false; + if (ACPI_SUCCESS(acpi_get_devices("LEN0068", acpi_check_cb, &found, NULL)) && found) + return true; + found = false; + return ACPI_SUCCESS(acpi_get_devices("IBM0068", acpi_check_cb, &found, NULL)) && found; +} + +static void update_tpacpi_mute_led(void *private_data, int enabled) +{ + if (old_vmaster_hook) + old_vmaster_hook(private_data, enabled); + + if (led_set_func) + led_set_func(TPACPI_LED_MUTE, !enabled); +} + +static void update_tpacpi_micmute_led(struct hda_codec *codec, + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + if (!ucontrol || !led_set_func) + return; + if (strcmp("Capture Switch", ucontrol->id.name) == 0 && ucontrol->id.index == 0) { + /* TODO: How do I verify if it's a mono or stereo here? */ + bool val = ucontrol->value.integer.value[0] || ucontrol->value.integer.value[1]; + led_set_func(TPACPI_LED_MICMUTE, !val); + } +} + +static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ + struct hda_gen_spec *spec = codec->spec; + bool removefunc = false; + + if (action == HDA_FIXUP_ACT_PROBE) { + if (!is_thinkpad(codec)) + return; + if (!led_set_func) + led_set_func = symbol_request(tpacpi_led_set); + if (!led_set_func) { + codec_warn(codec, + "Failed to find thinkpad-acpi symbol tpacpi_led_set\n"); + return; + } + + removefunc = true; + if (led_set_func(TPACPI_LED_MUTE, false) >= 0) { + old_vmaster_hook = spec->vmaster_mute.hook; + spec->vmaster_mute.hook = update_tpacpi_mute_led; + removefunc = false; + } + if (led_set_func(TPACPI_LED_MICMUTE, false) >= 0) { + if (spec->num_adc_nids > 1) + codec_dbg(codec, + "Skipping micmute LED control due to several ADCs"); + else { + spec->cap_sync_hook = update_tpacpi_micmute_led; + removefunc = false; + } + } + } + + if (led_set_func && (action == HDA_FIXUP_ACT_FREE || removefunc)) { + symbol_put(tpacpi_led_set); + led_set_func = NULL; + old_vmaster_hook = NULL; + } +} + +#else /* CONFIG_THINKPAD_ACPI */ + +static void hda_fixup_thinkpad_acpi(struct hda_codec *codec, + const struct hda_fixup *fix, int action) +{ +} + +#endif /* CONFIG_THINKPAD_ACPI */ diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index f7ce33f00ea..7e50c132455 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile @@ -5,7 +5,7 @@ snd-ice17xx-ak4xxx-objs := ak4xxx.o snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o -snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o +snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o quartet.o psc724.o wm8766.o wm8776.o # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/amp.c b/sound/pci/ice1712/amp.c index e525da2673b..2f9b9346786 100644 --- a/sound/pci/ice1712/amp.c +++ b/sound/pci/ice1712/amp.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -38,7 +37,7 @@ static void wm_put(struct snd_ice1712 *ice, int reg, unsigned short val) snd_vt1724_write_i2c(ice, WM_DEV, cval >> 8, cval & 0xff); } -static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) +static int snd_vt1724_amp_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits[] = { WM_ATTEN_L, 0x0000, /* 0 db */ @@ -66,7 +65,7 @@ static int __devinit snd_vt1724_amp_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) +static int snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) { if (ice->ac97) /* we use pins 39 and 41 of the VT1616 for left and right @@ -78,7 +77,7 @@ static int __devinit snd_vt1724_amp_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_vt1724_amp_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_amp_cards[] = { { .subvendor = VT1724_SUBDEVICE_AV710, .name = "Chaintech AV-710", diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 20bcddea2ea..3b3cf4ac906 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -46,7 +46,6 @@ * on mixer switch and other coll stuff. */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -203,7 +202,8 @@ static void aureon_pca9554_write(struct snd_ice1712 *ice, unsigned char reg, static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - char *texts[3] = {"Internal Aux", "Wavetable", "Rear Line-In"}; + static const char * const texts[3] = + {"Internal Aux", "Wavetable", "Rear Line-In"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -1433,7 +1433,7 @@ static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl * mixers */ -static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { +static struct snd_kcontrol_new aureon_dac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -1548,7 +1548,7 @@ static struct snd_kcontrol_new aureon_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static struct snd_kcontrol_new wm_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -1614,7 +1614,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new ac97_controls[] __devinitdata = { +static struct snd_kcontrol_new ac97_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1719,7 +1719,7 @@ static struct snd_kcontrol_new ac97_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { +static struct snd_kcontrol_new universe_ac97_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "AC97 Playback Switch", @@ -1851,7 +1851,7 @@ static struct snd_kcontrol_new universe_ac97_controls[] __devinitdata = { }; -static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { +static struct snd_kcontrol_new cs8415_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), @@ -1896,7 +1896,7 @@ static struct snd_kcontrol_new cs8415_controls[] __devinitdata = { } }; -static int __devinit aureon_add_controls(struct snd_ice1712 *ice) +static int aureon_add_controls(struct snd_ice1712 *ice) { unsigned int i, counts; int err; @@ -1937,9 +1937,12 @@ static int __devinit aureon_add_controls(struct snd_ice1712 *ice) snd_ice1712_save_gpio_status(ice); id = aureon_cs8415_get(ice, CS8415_ID); if (id != 0x41) - snd_printk(KERN_INFO "No CS8415 chip. Skipping CS8415 controls.\n"); + dev_info(ice->card->dev, + "No CS8415 chip. Skipping CS8415 controls.\n"); else if ((id & 0x0F) != 0x01) - snd_printk(KERN_INFO "Detected unsupported CS8415 rev. (%c)\n", (char)((id & 0x0F) + 'A' - 1)); + dev_info(ice->card->dev, + "Detected unsupported CS8415 rev. (%c)\n", + (char)((id & 0x0F) + 'A' - 1)); else { for (i = 0; i < ARRAY_SIZE(cs8415_controls); i++) { struct snd_kcontrol *kctl; @@ -2124,7 +2127,7 @@ static int aureon_resume(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit aureon_init(struct snd_ice1712 *ice) +static int aureon_init(struct snd_ice1712 *ice) { struct aureon_spec *spec; int i, err; @@ -2174,7 +2177,7 @@ static int __devinit aureon_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char aureon51_eeprom[] __devinitdata = { +static unsigned char aureon51_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x0a, /* clock 512, spdif-in/ADC, 3DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2190,7 +2193,7 @@ static unsigned char aureon51_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char aureon71_eeprom[] __devinitdata = { +static unsigned char aureon71_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x0b, /* clock 512, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2207,7 +2210,7 @@ static unsigned char aureon71_eeprom[] __devinitdata = { }; #define prodigy71_eeprom aureon71_eeprom -static unsigned char aureon71_universe_eeprom[] __devinitdata = { +static unsigned char aureon71_universe_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/ADC, * 4DACs */ @@ -2225,7 +2228,7 @@ static unsigned char aureon71_universe_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char prodigy71lt_eeprom[] __devinitdata = { +static unsigned char prodigy71lt_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* clock 384, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xfc, /* vol, 96k, 24bit, 192k */ @@ -2243,7 +2246,7 @@ static unsigned char prodigy71lt_eeprom[] __devinitdata = { #define prodigy71xt_eeprom prodigy71lt_eeprom /* entry point */ -struct snd_ice1712_card_info snd_vt1724_aureon_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_aureon_cards[] = { { .subvendor = VT1724_SUBDEVICE_AUREON51_SKY, .name = "Terratec Aureon 5.1-Sky", diff --git a/sound/pci/ice1712/delta.c b/sound/pci/ice1712/delta.c index 20c6b079d0d..496dbd0ad5d 100644 --- a/sound/pci/ice1712/delta.c +++ b/sound/pci/ice1712/delta.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -426,13 +425,14 @@ static int snd_ice1712_delta1010lt_wordclock_status_get(struct snd_kcontrol *kco struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); if (snd_i2c_sendbytes(ice->cs8427, ®, 1) != 1) - snd_printk(KERN_ERR "unable to send register 0x%x byte to CS8427\n", reg); + dev_err(ice->card->dev, + "unable to send register 0x%x byte to CS8427\n", reg); snd_i2c_readbytes(ice->cs8427, ®, 1); ucontrol->value.integer.value[0] = (reg & CS8427_UNLOCK) ? 1 : 0; return 0; } -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status = { .access = (SNDRV_CTL_ELEM_ACCESS_READ), .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -445,7 +445,7 @@ static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_status __devini * initialize the chips on M-Audio cards */ -static struct snd_akm4xxx akm_audiophile __devinitdata = { +static struct snd_akm4xxx akm_audiophile = { .type = SND_AK4528, .num_adcs = 2, .num_dacs = 2, @@ -454,7 +454,7 @@ static struct snd_akm4xxx akm_audiophile __devinitdata = { } }; -static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { +static struct snd_ak4xxx_private akm_audiophile_priv = { .caddr = 2, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -466,7 +466,7 @@ static struct snd_ak4xxx_private akm_audiophile_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta410 __devinitdata = { +static struct snd_akm4xxx akm_delta410 = { .type = SND_AK4529, .num_adcs = 2, .num_dacs = 8, @@ -475,7 +475,7 @@ static struct snd_akm4xxx akm_delta410 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta410_priv = { .caddr = 0, .cif = 0, .data_mask = ICE1712_DELTA_AP_DOUT, @@ -487,7 +487,7 @@ static struct snd_ak4xxx_private akm_delta410_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta1010lt __devinitdata = { +static struct snd_akm4xxx akm_delta1010lt = { .type = SND_AK4524, .num_adcs = 8, .num_dacs = 8, @@ -497,7 +497,7 @@ static struct snd_akm4xxx akm_delta1010lt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta1010lt_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_1010LT_DOUT, @@ -509,7 +509,7 @@ static struct snd_ak4xxx_private akm_delta1010lt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_delta66e __devinitdata = { +static struct snd_akm4xxx akm_delta66e = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -519,7 +519,7 @@ static struct snd_akm4xxx akm_delta66e __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta66e_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_66E_DOUT, @@ -532,7 +532,7 @@ static struct snd_ak4xxx_private akm_delta66e_priv __devinitdata = { }; -static struct snd_akm4xxx akm_delta44 __devinitdata = { +static struct snd_akm4xxx akm_delta44 = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -542,7 +542,7 @@ static struct snd_akm4xxx akm_delta44 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { +static struct snd_ak4xxx_private akm_delta44_priv = { .caddr = 2, .cif = 0, /* the default level of the CIF pin from AK4524 */ .data_mask = ICE1712_DELTA_CODEC_SERIAL_DATA, @@ -554,7 +554,7 @@ static struct snd_ak4xxx_private akm_delta44_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_vx442 __devinitdata = { +static struct snd_akm4xxx akm_vx442 = { .type = SND_AK4524, .num_adcs = 4, .num_dacs = 4, @@ -564,7 +564,7 @@ static struct snd_akm4xxx akm_vx442 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { +static struct snd_ak4xxx_private akm_vx442_priv = { .caddr = 2, .cif = 0, .data_mask = ICE1712_VX442_DOUT, @@ -576,7 +576,56 @@ static struct snd_ak4xxx_private akm_vx442_priv __devinitdata = { .mask_flags = 0, }; -static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) +#ifdef CONFIG_PM_SLEEP +static int snd_ice1712_delta_resume(struct snd_ice1712 *ice) +{ + unsigned char akm_img_bak[AK4XXX_IMAGE_SIZE]; + unsigned char akm_vol_bak[AK4XXX_IMAGE_SIZE]; + + /* init spdif */ + switch (ice->eeprom.subvendor) { + case ICE1712_SUBDEVICE_AUDIOPHILE: + case ICE1712_SUBDEVICE_DELTA410: + case ICE1712_SUBDEVICE_DELTA1010E: + case ICE1712_SUBDEVICE_DELTA1010LT: + case ICE1712_SUBDEVICE_VX442: + case ICE1712_SUBDEVICE_DELTA66E: + snd_cs8427_init(ice->i2c, ice->cs8427); + break; + case ICE1712_SUBDEVICE_DELTA1010: + case ICE1712_SUBDEVICE_MEDIASTATION: + /* nothing */ + break; + case ICE1712_SUBDEVICE_DELTADIO2496: + case ICE1712_SUBDEVICE_DELTA66: + /* Set spdif defaults */ + snd_ice1712_delta_cs8403_spdif_write(ice, ice->spdif.cs8403_bits); + break; + } + + /* init codec and restore registers */ + if (ice->akm_codecs) { + memcpy(akm_img_bak, ice->akm->images, sizeof(akm_img_bak)); + memcpy(akm_vol_bak, ice->akm->volumes, sizeof(akm_vol_bak)); + snd_akm4xxx_init(ice->akm); + memcpy(ice->akm->images, akm_img_bak, sizeof(akm_img_bak)); + memcpy(ice->akm->volumes, akm_vol_bak, sizeof(akm_vol_bak)); + snd_akm4xxx_reset(ice->akm, 0); + } + + return 0; +} + +static int snd_ice1712_delta_suspend(struct snd_ice1712 *ice) +{ + if (ice->akm_codecs) /* reset & mute codec */ + snd_akm4xxx_reset(ice->akm, 1); + + return 0; +} +#endif + +static int snd_ice1712_delta_init(struct snd_ice1712 *ice) { int err; struct snd_akm4xxx *ak; @@ -617,12 +666,16 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) ice->num_total_dacs = 4; /* two AK4324 codecs */ break; case ICE1712_SUBDEVICE_VX442: - case ICE1712_SUBDEVICE_DELTA66E: /* omni not suported yet */ + case ICE1712_SUBDEVICE_DELTA66E: /* omni not supported yet */ ice->num_total_dacs = 4; ice->num_total_adcs = 4; break; } - +#ifdef CONFIG_PM_SLEEP + ice->pm_resume = snd_ice1712_delta_resume; + ice->pm_suspend = snd_ice1712_delta_suspend; + ice->pm_suspend_enabled = 1; +#endif /* initialize the SPI clock to high */ tmp = snd_ice1712_read(ice, ICE1712_IREG_GPIO_DATA); tmp |= ICE1712_DELTA_AP_CCLK; @@ -638,7 +691,7 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) case ICE1712_SUBDEVICE_VX442: case ICE1712_SUBDEVICE_DELTA66E: if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { - snd_printk(KERN_ERR "unable to create I2C bus\n"); + dev_err(ice->card->dev, "unable to create I2C bus\n"); return err; } ice->i2c->private_data = ice; @@ -714,19 +767,19 @@ static int __devinit snd_ice1712_delta_init(struct snd_ice1712 *ice) * additional controls for M-Audio cards */ -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_WORD_CLOCK_SELECT, 1, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010lt_wordclock_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Sync", 0, ICE1712_DELTA_1010LT_WORDCLOCK, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta1010_wordclock_status = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Word Clock Status", 0, ICE1712_DELTA_WORD_CLOCK_STATUS, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); -static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select __devinitdata = +static struct snd_kcontrol_new snd_ice1712_deltadio2496_spdif_in_select = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, ICE1712_DELTA_SPDIF_INPUT_SELECT, 0, 0); -static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status __devinitdata = +static struct snd_kcontrol_new snd_ice1712_delta_spdif_in_status = ICE1712_GPIO(SNDRV_CTL_ELEM_IFACE_MIXER, "Delta IEC958 Input Status", 0, ICE1712_DELTA_SPDIF_IN_STAT, 1, SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE); -static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) +static int snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) { int err; @@ -802,7 +855,7 @@ static int __devinit snd_ice1712_delta_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_delta_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_delta_cards[] = { { .subvendor = ICE1712_SUBDEVICE_DELTA1010, .name = "M Audio Delta 1010", diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c index 6fe35b81204..817a1bc50a6 100644 --- a/sound/pci/ice1712/ews.c +++ b/sound/pci/ice1712/ews.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -164,7 +163,8 @@ static int snd_ice1712_ews88mt_chip_select(struct snd_ice1712 *ice, int chip_mas __error: snd_i2c_unlock(ice->i2c); - snd_printk(KERN_ERR "AK4524 chip select failed, check cable to the front module\n"); + dev_err(ice->card->dev, + "AK4524 chip select failed, check cable to the front module\n"); return -EIO; } @@ -175,7 +175,7 @@ static void ews88mt_ak4524_lock(struct snd_akm4xxx *ak, int chip) unsigned char tmp; /* assert AK4524 CS */ if (snd_ice1712_ews88mt_chip_select(ice, ~(1 << chip) & 0x0f) < 0) - snd_printk(KERN_ERR "fatal error (ews88mt chip select)\n"); + dev_err(ice->card->dev, "fatal error (ews88mt chip select)\n"); snd_ice1712_save_gpio_status(ice); tmp = ICE1712_EWS88_SERIAL_DATA | ICE1712_EWS88_SERIAL_CLOCK | @@ -344,7 +344,7 @@ static void ews88_setup_spdif(struct snd_ice1712 *ice, int rate) /* */ -static struct snd_akm4xxx akm_ews88mt __devinitdata = { +static struct snd_akm4xxx akm_ews88mt = { .num_adcs = 8, .num_dacs = 8, .type = SND_AK4524, @@ -354,7 +354,7 @@ static struct snd_akm4xxx akm_ews88mt __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ews88mt_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -366,7 +366,7 @@ static struct snd_ak4xxx_private akm_ews88mt_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_ewx2496 __devinitdata = { +static struct snd_akm4xxx akm_ewx2496 = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -375,7 +375,7 @@ static struct snd_akm4xxx akm_ewx2496 __devinitdata = { } }; -static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ewx2496_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_EWS88_SERIAL_DATA, @@ -387,7 +387,7 @@ static struct snd_ak4xxx_private akm_ewx2496_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_6fire __devinitdata = { +static struct snd_akm4xxx akm_6fire = { .num_adcs = 6, .num_dacs = 6, .type = SND_AK4524, @@ -396,7 +396,7 @@ static struct snd_akm4xxx akm_6fire __devinitdata = { } }; -static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { +static struct snd_ak4xxx_private akm_6fire_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_6FIRE_SERIAL_DATA, @@ -420,7 +420,7 @@ static struct snd_ak4xxx_private akm_6fire_priv __devinitdata = { static int snd_ice1712_6fire_write_pca(struct snd_ice1712 *ice, unsigned char reg, unsigned char data); -static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) +static int snd_ice1712_ews_init(struct snd_ice1712 *ice) { int err; struct snd_akm4xxx *ak; @@ -457,7 +457,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) /* create i2c */ if ((err = snd_i2c_bus_create(ice->card, "ICE1712 GPIO 1", NULL, &ice->i2c)) < 0) { - snd_printk(KERN_ERR "unable to create I2C bus\n"); + dev_err(ice->card->dev, "unable to create I2C bus\n"); return err; } ice->i2c->private_data = ice; @@ -470,7 +470,8 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) ICE1712_6FIRE_PCF9554_ADDR, &spec->i2cdevs[EWS_I2C_6FIRE]); if (err < 0) { - snd_printk(KERN_ERR "PCF9554 initialization failed\n"); + dev_err(ice->card->dev, + "PCF9554 initialization failed\n"); return err; } snd_ice1712_6fire_write_pca(ice, PCF9554_REG_CONFIG, 0x80); @@ -576,7 +577,7 @@ static int __devinit snd_ice1712_ews_init(struct snd_ice1712 *ice) /* i/o sensitivity - this callback is shared among other devices, too */ static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo){ - static char *texts[2] = { + static const char * const texts[2] = { "+4dBu", "-10dBV", }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -616,7 +617,7 @@ static int snd_ice1712_ewx_io_sense_put(struct snd_kcontrol *kcontrol, struct sn return val != nval; } -static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ewx2496_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", @@ -724,7 +725,7 @@ static int snd_ice1712_ews88mt_input_sense_put(struct snd_kcontrol *kcontrol, st return ndata != data; } -static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Input Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -733,7 +734,7 @@ static struct snd_kcontrol_new snd_ice1712_ews88mt_input_sense __devinitdata = { .count = 8, }; -static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88mt_output_sense = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Output Sensitivity Switch", .info = snd_ice1712_ewx_io_sense_info, @@ -811,7 +812,7 @@ static int snd_ice1712_ews88d_control_put(struct snd_kcontrol *kcontrol, struct .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_ews88d_controls[] = { EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "IEC958 Input Optical", 0, 1, 0), /* inverted */ EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT Output Optical", 1, 0, 0), EWS88D_CONTROL(SNDRV_CTL_ELEM_IFACE_MIXER, "ADAT External Master Clock", 2, 0, 0), @@ -835,7 +836,7 @@ static int snd_ice1712_6fire_read_pca(struct snd_ice1712 *ice, unsigned char reg byte = 0; if (snd_i2c_readbytes(spec->i2cdevs[EWS_I2C_6FIRE], &byte, 1) != 1) { snd_i2c_unlock(ice->i2c); - printk(KERN_ERR "cannot read pca\n"); + dev_err(ice->card->dev, "cannot read pca\n"); return -EIO; } snd_i2c_unlock(ice->i2c); @@ -899,7 +900,7 @@ static int snd_ice1712_6fire_control_put(struct snd_kcontrol *kcontrol, struct s static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[4] = { + static const char * const texts[4] = { "Internal", "Front Input", "Rear Input", "Wave Table" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; @@ -948,7 +949,7 @@ static int snd_ice1712_6fire_select_input_put(struct snd_kcontrol *kcontrol, str .private_value = xshift | (xinvert << 8),\ } -static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_6fire_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Analog Input Select", @@ -964,7 +965,7 @@ static struct snd_kcontrol_new snd_ice1712_6fire_controls[] __devinitdata = { }; -static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) +static int snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) { unsigned int idx; int err; @@ -1030,7 +1031,7 @@ static int __devinit snd_ice1712_ews_add_controls(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_ews_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_ews_cards[] = { { .subvendor = ICE1712_SUBDEVICE_EWX2496, .name = "TerraTec EWX24/96", diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c index 6914189073a..59e37c58169 100644 --- a/sound/pci/ice1712/hoontech.c +++ b/sound/pci/ice1712/hoontech.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -40,7 +39,7 @@ struct hoontech_spec { unsigned short boxconfig[4]; }; -static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) +static void snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, unsigned char byte) { byte |= ICE1712_STDSP24_CLOCK_BIT; udelay(100); @@ -53,7 +52,7 @@ static void __devinit snd_ice1712_stdsp24_gpio_write(struct snd_ice1712 *ice, un snd_ice1712_write(ice, ICE1712_IREG_GPIO_DATA, byte); } -static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -62,7 +61,7 @@ static void __devinit snd_ice1712_stdsp24_darear(struct snd_ice1712 *ice, int ac mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -71,7 +70,7 @@ static void __devinit snd_ice1712_stdsp24_mute(struct snd_ice1712 *ice, int acti mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -80,7 +79,7 @@ static void __devinit snd_ice1712_stdsp24_insel(struct snd_ice1712 *ice, int act mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) +static void snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, int box, int chn, int activate) { struct hoontech_spec *spec = ice->spec; @@ -130,7 +129,7 @@ static void __devinit snd_ice1712_stdsp24_box_channel(struct snd_ice1712 *ice, i mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) +static void snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int box, int master) { struct hoontech_spec *spec = ice->spec; @@ -158,7 +157,7 @@ static void __devinit snd_ice1712_stdsp24_box_midi(struct snd_ice1712 *ice, int mutex_unlock(&ice->gpio_mutex); } -static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) +static void snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int activate) { struct hoontech_spec *spec = ice->spec; mutex_lock(&ice->gpio_mutex); @@ -167,7 +166,7 @@ static void __devinit snd_ice1712_stdsp24_midi2(struct snd_ice1712 *ice, int act mutex_unlock(&ice->gpio_mutex); } -static int __devinit snd_ice1712_hoontech_init(struct snd_ice1712 *ice) +static int snd_ice1712_hoontech_init(struct snd_ice1712 *ice) { struct hoontech_spec *spec; int box, chn; @@ -267,10 +266,10 @@ static void stdsp24_ak4524_lock(struct snd_akm4xxx *ak, int chip) snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, ~tmp); } -static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) +static int snd_ice1712_value_init(struct snd_ice1712 *ice) { /* Hoontech STDSP24 with modified hardware */ - static struct snd_akm4xxx akm_stdsp24_mv __devinitdata = { + static struct snd_akm4xxx akm_stdsp24_mv = { .num_adcs = 2, .num_dacs = 2, .type = SND_AK4524, @@ -279,7 +278,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) } }; - static struct snd_ak4xxx_private akm_stdsp24_mv_priv __devinitdata = { + static struct snd_ak4xxx_private akm_stdsp24_mv_priv = { .caddr = 2, .cif = 1, /* CIF high */ .data_mask = ICE1712_STDSP24_SERIAL_DATA, @@ -317,7 +316,7 @@ static int __devinit snd_ice1712_value_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) +static int snd_ice1712_ez8_init(struct snd_ice1712 *ice) { ice->gpio.write_mask = ice->eeprom.gpiomask; ice->gpio.direction = ice->eeprom.gpiodir; @@ -329,7 +328,7 @@ static int __devinit snd_ice1712_ez8_init(struct snd_ice1712 *ice) /* entry point */ -struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_ice1712_hoontech_cards[] = { { .subvendor = ICE1712_SUBDEVICE_STDSP24, .name = "Hoontech SoundTrack Audio DSP24", diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index 5be2e120a14..d9b9e4595f1 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -47,7 +47,6 @@ */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -280,7 +279,7 @@ static int snd_ice1712_digmix_route_ac97_put(struct snd_kcontrol *kcontrol, stru return val != nval; } -static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_digmix_route_ac97 = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Digital Mixer To AC97", .info = snd_ice1712_digmix_route_ac97_info, @@ -388,14 +387,14 @@ static void setup_cs8427(struct snd_ice1712 *ice, int rate) /* * create and initialize callbacks for cs8427 interface */ -int __devinit snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) +int snd_ice1712_init_cs8427(struct snd_ice1712 *ice, int addr) { int err; err = snd_cs8427_create(ice->i2c, addr, (ice->cs8427_timeout * HZ) / 1000, &ice->cs8427); if (err < 0) { - snd_printk(KERN_ERR "CS8427 initialization failed\n"); + dev_err(ice->card->dev, "CS8427 initialization failed\n"); return err; } ice->spdif.ops.open = open_cs8427; @@ -468,7 +467,7 @@ static irqreturn_t snd_ice1712_interrupt(int irq, void *dev_id) u16 pbkstatus; struct snd_pcm_substream *substream; pbkstatus = inw(ICEDS(ice, INTSTAT)); - /* printk(KERN_DEBUG "pbkstatus = 0x%x\n", pbkstatus); */ + /* dev_dbg(ice->card->dev, "pbkstatus = 0x%x\n", pbkstatus); */ for (idx = 0; idx < 6; idx++) { if ((pbkstatus & (3 << (idx * 2))) == 0) continue; @@ -686,9 +685,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pointer(struct snd_pcm_substream * if (!(snd_ice1712_read(ice, ICE1712_IREG_PBK_CTRL) & 1)) return 0; ptr = runtime->buffer_size - inw(ice->ddma_port + 4); + ptr = bytes_to_frames(substream->runtime, ptr); if (ptr == runtime->buffer_size) ptr = 0; - return bytes_to_frames(substream->runtime, ptr); + return ptr; } static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substream *substream) @@ -705,9 +705,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_ds_pointer(struct snd_pcm_substrea addr = ICE1712_DSC_ADDR0; ptr = snd_ice1712_ds_read(ice, substream->number * 2, addr) - ice->playback_con_virt_addr[substream->number]; + ptr = bytes_to_frames(substream->runtime, ptr); if (ptr == substream->runtime->buffer_size) ptr = 0; - return bytes_to_frames(substream->runtime, ptr); + return ptr; } static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *substream) @@ -718,9 +719,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pointer(struct snd_pcm_substream *s if (!(snd_ice1712_read(ice, ICE1712_IREG_CAP_CTRL) & 1)) return 0; ptr = inl(ICEREG(ice, CONCAP_ADDR)) - ice->capture_con_virt_addr; + ptr = bytes_to_frames(substream->runtime, ptr); if (ptr == substream->runtime->buffer_size) ptr = 0; - return bytes_to_frames(substream->runtime, ptr); + return ptr; } static const struct snd_pcm_hardware snd_ice1712_playback = { @@ -879,7 +881,7 @@ static struct snd_pcm_ops snd_ice1712_capture_ops = { .pointer = snd_ice1712_capture_pointer, }; -static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -904,12 +906,13 @@ static int __devinit snd_ice1712_pcm(struct snd_ice1712 *ice, int device, struct if (rpcm) *rpcm = pcm; - printk(KERN_WARNING "Consumer PCM code does not work well at the moment --jk\n"); + dev_warn(ice->card->dev, + "Consumer PCM code does not work well at the moment --jk\n"); return 0; } -static int __devinit snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_ds(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1048,6 +1051,8 @@ __out: old = inb(ICEMT(ice, RATE)); if (!force && old == val) goto __out; + + ice->cur_rate = rate; outb(val, ICEMT(ice, RATE)); spin_unlock_irqrestore(&ice->reg_lock, flags); @@ -1114,9 +1119,10 @@ static snd_pcm_uframes_t snd_ice1712_playback_pro_pointer(struct snd_pcm_substre if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_PLAYBACK_START)) return 0; ptr = ice->playback_pro_size - (inw(ICEMT(ice, PLAYBACK_SIZE)) << 2); + ptr = bytes_to_frames(substream->runtime, ptr); if (ptr == substream->runtime->buffer_size) ptr = 0; - return bytes_to_frames(substream->runtime, ptr); + return ptr; } static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substream *substream) @@ -1127,9 +1133,10 @@ static snd_pcm_uframes_t snd_ice1712_capture_pro_pointer(struct snd_pcm_substrea if (!(inl(ICEMT(ice, PLAYBACK_CONTROL)) & ICE1712_CAPTURE_START_SHADOW)) return 0; ptr = ice->capture_pro_size - (inw(ICEMT(ice, CAPTURE_SIZE)) << 2); + ptr = bytes_to_frames(substream->runtime, ptr); if (ptr == substream->runtime->buffer_size) ptr = 0; - return bytes_to_frames(substream->runtime, ptr); + return ptr; } static const struct snd_pcm_hardware snd_ice1712_playback_pro = { @@ -1254,7 +1261,7 @@ static struct snd_pcm_ops snd_ice1712_capture_pro_ops = { .pointer = snd_ice1712_capture_pro_pointer, }; -static int __devinit snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) +static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1388,7 +1395,7 @@ static int snd_ice1712_pro_mixer_volume_put(struct snd_kcontrol *kcontrol, struc static const DECLARE_TLV_DB_SCALE(db_scale_playback, -14400, 150, 0); -static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Playback Switch", @@ -1412,7 +1419,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_playback_ctrls[] __devinitdata }, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Multi Capture Switch", .info = snd_ice1712_pro_mixer_switch_info, @@ -1421,7 +1428,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_switch __devinit .private_value = 10, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, SWITCH), .info = snd_ice1712_pro_mixer_switch_info, @@ -1431,7 +1438,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_switch __devinitd .count = 2, }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -1443,7 +1450,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_analog_volume __devinit .tlv = { .p = db_scale_playback } }; -static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("Multi ", CAPTURE, VOLUME), .info = snd_ice1712_pro_mixer_volume_info, @@ -1453,7 +1460,7 @@ static struct snd_kcontrol_new snd_ice1712_multi_capture_spdif_volume __devinitd .count = 2, }; -static int __devinit snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice) +static int snd_ice1712_build_pro_mixer(struct snd_ice1712 *ice) { struct snd_card *card = ice->card; unsigned int idx; @@ -1512,7 +1519,7 @@ static void snd_ice1712_mixer_free_ac97(struct snd_ac97 *ac97) ice->ac97 = NULL; } -static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) +static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) { int err, bus_num = 0; struct snd_ac97_template ac97; @@ -1535,7 +1542,8 @@ static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) ac97.private_free = snd_ice1712_mixer_free_ac97; err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); if (err < 0) - printk(KERN_WARNING "ice1712: cannot initialize ac97 for consumer, skipped\n"); + dev_warn(ice->card->dev, + "cannot initialize ac97 for consumer, skipped\n"); else { err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice)); if (err < 0) @@ -1553,7 +1561,8 @@ static int __devinit snd_ice1712_ac97_mixer(struct snd_ice1712 *ice) ac97.private_free = snd_ice1712_mixer_free_ac97; err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); if (err < 0) - printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); + dev_warn(ice->card->dev, + "cannot initialize pro ac97, skipped\n"); else return 0; } @@ -1611,7 +1620,7 @@ static void snd_ice1712_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, " GPIO_DIRECTION : 0x%02x\n", (unsigned)snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION)); } -static void __devinit snd_ice1712_proc_init(struct snd_ice1712 *ice) +static void snd_ice1712_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; @@ -1640,7 +1649,7 @@ static int snd_ice1712_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_eeprom __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_eeprom = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1712 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1676,7 +1685,7 @@ static int snd_ice1712_spdif_default_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), @@ -1727,7 +1736,7 @@ static int snd_ice1712_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_maskc = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1736,7 +1745,7 @@ static struct snd_kcontrol_new snd_ice1712_spdif_maskc __devinitdata = .get = snd_ice1712_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_ice1712_spdif_maskp __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_maskp = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1763,7 +1772,7 @@ static int snd_ice1712_spdif_stream_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_ice1712_spdif_stream = { .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE), @@ -1894,7 +1903,7 @@ static int snd_ice1712_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_internal_clock = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_ice1712_pro_internal_clock_info, @@ -1965,7 +1974,7 @@ static int snd_ice1712_pro_internal_clock_default_put(struct snd_kcontrol *kcont return change; } -static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_internal_clock_default = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock Default", .info = snd_ice1712_pro_internal_clock_default_info, @@ -1996,7 +2005,7 @@ static int snd_ice1712_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_locking __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_rate_locking = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_ice1712_pro_rate_locking_info, @@ -2027,7 +2036,7 @@ static int snd_ice1712_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_pro_rate_reset __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_pro_rate_reset = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_ice1712_pro_rate_reset_info, @@ -2194,7 +2203,7 @@ static int snd_ice1712_pro_route_spdif_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", .info = snd_ice1712_pro_route_info, @@ -2202,7 +2211,7 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_analog_route __devinitdata .put = snd_ice1712_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_spdif_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", .info = snd_ice1712_pro_route_info, @@ -2244,7 +2253,7 @@ static int snd_ice1712_pro_volume_rate_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_volume_rate = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Volume Rate", .info = snd_ice1712_pro_volume_rate_info, @@ -2277,7 +2286,7 @@ static int snd_ice1712_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { +static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -2292,16 +2301,16 @@ static struct snd_kcontrol_new snd_ice1712_mixer_pro_peak __devinitdata = { /* * list of available boards */ -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static struct snd_ice1712_card_info *card_tables[] = { snd_ice1712_hoontech_cards, snd_ice1712_delta_cards, snd_ice1712_ews_cards, NULL, }; -static unsigned char __devinit snd_ice1712_read_i2c(struct snd_ice1712 *ice, - unsigned char dev, - unsigned char addr) +static unsigned char snd_ice1712_read_i2c(struct snd_ice1712 *ice, + unsigned char dev, + unsigned char addr) { long t = 0x10000; @@ -2311,8 +2320,8 @@ static unsigned char __devinit snd_ice1712_read_i2c(struct snd_ice1712 *ice, return inb(ICEREG(ice, I2C_DATA)); } -static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, - const char *modelname) +static int snd_ice1712_read_eeprom(struct snd_ice1712 *ice, + const char *modelname) { int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; @@ -2333,7 +2342,8 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, pci_read_config_word(ice->pci, PCI_SUBSYSTEM_ID, &device); ice->eeprom.subvendor = ((unsigned int)swab16(vendor) << 16) | swab16(device); if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) { - printk(KERN_ERR "ice1712: No valid ID is found\n"); + dev_err(ice->card->dev, + "No valid ID is found\n"); return -ENXIO; } } @@ -2341,21 +2351,22 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, for (tbl = card_tables; *tbl; tbl++) { for (c = *tbl; c->subvendor; c++) { if (modelname && c->model && !strcmp(modelname, c->model)) { - printk(KERN_INFO "ice1712: Using board model %s\n", c->name); + dev_info(ice->card->dev, + "Using board model %s\n", c->name); ice->eeprom.subvendor = c->subvendor; } else if (c->subvendor != ice->eeprom.subvendor) continue; if (!c->eeprom_size || !c->eeprom_data) goto found; /* if the EEPROM is given by the driver, use it */ - snd_printdd("using the defined eeprom..\n"); + dev_dbg(ice->card->dev, "using the defined eeprom..\n"); ice->eeprom.version = 1; ice->eeprom.size = c->eeprom_size + 6; memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size); goto read_skipped; } } - printk(KERN_WARNING "ice1712: No matching model found for ID 0x%x\n", + dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n", ice->eeprom.subvendor); found: @@ -2363,12 +2374,13 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, if (ice->eeprom.size < 6) ice->eeprom.size = 32; /* FIXME: any cards without the correct size? */ else if (ice->eeprom.size > 32) { - snd_printk(KERN_ERR "invalid EEPROM (size = %i)\n", ice->eeprom.size); + dev_err(ice->card->dev, + "invalid EEPROM (size = %i)\n", ice->eeprom.size); return -EIO; } ice->eeprom.version = snd_ice1712_read_i2c(ice, dev, 0x05); if (ice->eeprom.version != 1) { - snd_printk(KERN_ERR "invalid EEPROM version %i\n", + dev_err(ice->card->dev, "invalid EEPROM version %i\n", ice->eeprom.version); /* return -EIO; */ } @@ -2386,7 +2398,7 @@ static int __devinit snd_ice1712_read_eeprom(struct snd_ice1712 *ice, -static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) +static int snd_ice1712_chip_init(struct snd_ice1712 *ice) { outb(ICE1712_RESET | ICE1712_NATIVE, ICEREG(ice, CONTROL)); udelay(200); @@ -2429,11 +2441,18 @@ static int __devinit snd_ice1712_chip_init(struct snd_ice1712 *ice) snd_ice1712_write(ice, ICE1712_IREG_CONSUMER_POWERDOWN, 0); } snd_ice1712_set_pro_rate(ice, 48000, 1); + /* unmask used interrupts */ + outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ? + ICE1712_IRQ_MPU2 : 0) | + ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ? + ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0), + ICEREG(ice, IRQMASK)); + outb(0x00, ICEMT(ice, IRQ)); return 0; } -int __devinit snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) +int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) { int err; struct snd_kcontrol *kctl; @@ -2461,7 +2480,7 @@ int __devinit snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice) } -static int __devinit snd_ice1712_build_controls(struct snd_ice1712 *ice) +static int snd_ice1712_build_controls(struct snd_ice1712 *ice) { int err; @@ -2531,13 +2550,13 @@ static int snd_ice1712_dev_free(struct snd_device *device) return snd_ice1712_free(ice); } -static int __devinit snd_ice1712_create(struct snd_card *card, - struct pci_dev *pci, - const char *modelname, - int omni, - int cs8427_timeout, - int dxr_enable, - struct snd_ice1712 **r_ice1712) +static int snd_ice1712_create(struct snd_card *card, + struct pci_dev *pci, + const char *modelname, + int omni, + int cs8427_timeout, + int dxr_enable, + struct snd_ice1712 **r_ice1712) { struct snd_ice1712 *ice; int err; @@ -2554,7 +2573,8 @@ static int __devinit snd_ice1712_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { - snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2590,11 +2610,14 @@ static int __devinit snd_ice1712_create(struct snd_card *card, ice->pci = pci; ice->irq = -1; pci_set_master(pci); + /* disable legacy emulation */ pci_write_config_word(ice->pci, 0x40, 0x807f); pci_write_config_word(ice->pci, 0x42, 0x0006); snd_ice1712_proc_init(ice); synchronize_irq(pci->irq); + card->private_data = ice; + err = pci_request_regions(pci, "ICE1712"); if (err < 0) { kfree(ice); @@ -2608,7 +2631,7 @@ static int __devinit snd_ice1712_create(struct snd_card *card, if (request_irq(pci->irq, snd_ice1712_interrupt, IRQF_SHARED, KBUILD_MODNAME, ice)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_ice1712_free(ice); return -EIO; } @@ -2624,22 +2647,12 @@ static int __devinit snd_ice1712_create(struct snd_card *card, return -EIO; } - /* unmask used interrupts */ - outb(((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_2xMPU401) == 0 ? - ICE1712_IRQ_MPU2 : 0) | - ((ice->eeprom.data[ICE_EEP1_CODEC] & ICE1712_CFG_NO_CON_AC97) ? - ICE1712_IRQ_PBKDS | ICE1712_IRQ_CONCAP | ICE1712_IRQ_CONPBK : 0), - ICEREG(ice, IRQMASK)); - outb(0x00, ICEMT(ice, IRQ)); - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, ice, &ops); if (err < 0) { snd_ice1712_free(ice); return err; } - snd_card_set_dev(card, &pci->dev); - *r_ice1712 = ice; return 0; } @@ -2651,10 +2664,10 @@ static int __devinit snd_ice1712_create(struct snd_card *card, * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static struct snd_ice1712_card_info no_matched; -static int __devinit snd_ice1712_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_ice1712_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2669,7 +2682,8 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2686,6 +2700,7 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, for (tbl = card_tables; *tbl; tbl++) { for (c = *tbl; c->subvendor; c++) { if (c->subvendor == ice->eeprom.subvendor) { + ice->card_info = c; strcpy(card->shortname, c->name); if (c->driver) /* specific driver? */ strcpy(card->driver, c->driver); @@ -2797,17 +2812,120 @@ static int __devinit snd_ice1712_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_ice1712_remove(struct pci_dev *pci) +static void snd_ice1712_remove(struct pci_dev *pci) +{ + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (ice->card_info && ice->card_info->chip_exit) + ice->card_info->chip_exit(ice); + snd_card_free(card); +} + +#ifdef CONFIG_PM_SLEEP +static int snd_ice1712_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); + struct snd_ice1712 *ice = card->private_data; + + if (!ice->pm_suspend_enabled) + return 0; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + + snd_pcm_suspend_all(ice->pcm); + snd_pcm_suspend_all(ice->pcm_pro); + snd_pcm_suspend_all(ice->pcm_ds); + snd_ac97_suspend(ice->ac97); + + spin_lock_irq(&ice->reg_lock); + ice->pm_saved_is_spdif_master = is_spdif_master(ice); + ice->pm_saved_spdif_ctrl = inw(ICEMT(ice, ROUTE_SPDOUT)); + ice->pm_saved_route = inw(ICEMT(ice, ROUTE_PSDOUT03)); + spin_unlock_irq(&ice->reg_lock); + + if (ice->pm_suspend) + ice->pm_suspend(ice); + + pci_disable_device(pci); + pci_save_state(pci); + pci_set_power_state(pci, PCI_D3hot); + return 0; +} + +static int snd_ice1712_resume(struct device *dev) { - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); + struct snd_ice1712 *ice = card->private_data; + int rate; + + if (!ice->pm_suspend_enabled) + return 0; + + pci_set_power_state(pci, PCI_D0); + pci_restore_state(pci); + + if (pci_enable_device(pci) < 0) { + snd_card_disconnect(card); + return -EIO; + } + + pci_set_master(pci); + + if (ice->cur_rate) + rate = ice->cur_rate; + else + rate = PRO_RATE_DEFAULT; + + if (snd_ice1712_chip_init(ice) < 0) { + snd_card_disconnect(card); + return -EIO; + } + + ice->cur_rate = rate; + + if (ice->pm_resume) + ice->pm_resume(ice); + + if (ice->pm_saved_is_spdif_master) { + /* switching to external clock via SPDIF */ + spin_lock_irq(&ice->reg_lock); + outb(inb(ICEMT(ice, RATE)) | ICE1712_SPDIF_MASTER, + ICEMT(ice, RATE)); + spin_unlock_irq(&ice->reg_lock); + snd_ice1712_set_input_clock_source(ice, 1); + } else { + /* internal on-card clock */ + snd_ice1712_set_pro_rate(ice, rate, 1); + snd_ice1712_set_input_clock_source(ice, 0); + } + + outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT)); + outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03)); + + if (ice->ac97) + snd_ac97_resume(ice->ac97); + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + return 0; } +static SIMPLE_DEV_PM_OPS(snd_ice1712_pm, snd_ice1712_suspend, snd_ice1712_resume); +#define SND_VT1712_PM_OPS &snd_ice1712_pm +#else +#define SND_VT1712_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static struct pci_driver ice1712_driver = { .name = KBUILD_MODNAME, .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, - .remove = __devexit_p(snd_ice1712_remove), + .remove = snd_ice1712_remove, + .driver = { + .pm = SND_VT1712_PM_OPS, + }, }; module_pci_driver(ice1712_driver); diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index d0e7d87f09f..b209fc30b33 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -22,6 +22,7 @@ * */ +#include <linux/io.h> #include <sound/control.h> #include <sound/ac97_codec.h> #include <sound/rawmidi.h> @@ -288,6 +289,7 @@ struct snd_ice1712_spdif { } ops; }; +struct snd_ice1712_card_info; struct snd_ice1712 { unsigned long conp_dma_size; @@ -324,6 +326,7 @@ struct snd_ice1712 { struct snd_info_entry *proc_entry; struct snd_ice1712_eeprom eeprom; + struct snd_ice1712_card_info *card_info; unsigned int pro_volumes[20]; unsigned int omni:1; /* Delta Omni I/O */ @@ -381,7 +384,7 @@ struct snd_ice1712 { unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate); int (*set_spdif_clock)(struct snd_ice1712 *ice, int type); int (*get_spdif_master_type)(struct snd_ice1712 *ice); - char **ext_clock_names; + const char * const *ext_clock_names; int ext_clock_count; void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *); #ifdef CONFIG_PM_SLEEP @@ -513,10 +516,11 @@ static inline u8 snd_ice1712_read(struct snd_ice1712 *ice, u8 addr) struct snd_ice1712_card_info { unsigned int subvendor; - char *name; - char *model; - char *driver; + const char *name; + const char *model; + const char *driver; int (*chip_init)(struct snd_ice1712 *); + void (*chip_exit)(struct snd_ice1712 *); int (*build_controls)(struct snd_ice1712 *); unsigned int no_mpu401:1; unsigned int mpu401_1_info_flags; diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3050a527925..5e7948f3efe 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -22,7 +22,6 @@ * */ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -54,6 +53,7 @@ #include "wtm.h" #include "se.h" #include "quartet.h" +#include "psc724.h" MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>"); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); @@ -106,7 +106,7 @@ static int PRO_RATE_LOCKED; static int PRO_RATE_RESET = 1; static unsigned int PRO_RATE_DEFAULT = 44100; -static char *ext_clock_names[1] = { "IEC958 In" }; +static const char * const ext_clock_names[1] = { "IEC958 In" }; /* * Basic I/O @@ -146,7 +146,7 @@ static unsigned char snd_vt1724_ac97_ready(struct snd_ice1712 *ice) continue; return old_cmd; } - snd_printd(KERN_ERR "snd_vt1724_ac97_ready: timeout\n"); + dev_dbg(ice->card->dev, "snd_vt1724_ac97_ready: timeout\n"); return old_cmd; } @@ -156,7 +156,7 @@ static int snd_vt1724_ac97_wait_bit(struct snd_ice1712 *ice, unsigned char bit) for (tm = 0; tm < 0x10000; tm++) if ((inb(ICEMT1724(ice, AC97_CMD)) & bit) == 0) return 0; - snd_printd(KERN_ERR "snd_vt1724_ac97_wait_bit: timeout\n"); + dev_dbg(ice->card->dev, "snd_vt1724_ac97_wait_bit: timeout\n"); return -EIO; } @@ -430,10 +430,10 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id) spin_lock(&ice->reg_lock); if (++timeout > 10) { status = inb(ICEREG1724(ice, IRQSTAT)); - printk(KERN_ERR "ice1724: Too long irq loop, " - "status = 0x%x\n", status); + dev_err(ice->card->dev, + "Too long irq loop, status = 0x%x\n", status); if (status & VT1724_IRQ_MPU_TX) { - printk(KERN_ERR "ice1724: Disabling MPU_TX\n"); + dev_err(ice->card->dev, "Disabling MPU_TX\n"); enable_midi_irq(ice, VT1724_IRQ_MPU_TX, 0); } spin_unlock(&ice->reg_lock); @@ -801,7 +801,7 @@ static int snd_vt1724_playback_pro_prepare(struct snd_pcm_substream *substream) spin_unlock_irq(&ice->reg_lock); /* - printk(KERN_DEBUG "pro prepare: ch = %d, addr = 0x%x, " + dev_dbg(ice->card->dev, "pro prepare: ch = %d, addr = 0x%x, " "buffer = 0x%x, period = 0x%x\n", substream->runtime->channels, (unsigned int)substream->runtime->dma_addr, @@ -821,13 +821,13 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea #if 0 /* read PLAYBACK_ADDR */ ptr = inl(ICEMT1724(ice, PLAYBACK_ADDR)); if (ptr < substream->runtime->dma_addr) { - snd_printd("ice1724: invalid negative ptr\n"); + dev_dbg(ice->card->dev, "invalid negative ptr\n"); return 0; } ptr -= substream->runtime->dma_addr; ptr = bytes_to_frames(substream->runtime, ptr); if (ptr >= substream->runtime->buffer_size) { - snd_printd("ice1724: invalid ptr %d (size=%d)\n", + dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->period_size); return 0; } @@ -840,7 +840,7 @@ static snd_pcm_uframes_t snd_vt1724_playback_pro_pointer(struct snd_pcm_substrea else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { - snd_printd("ice1724: invalid ptr %d (size=%d)\n", + dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); ptr = 0; } @@ -884,7 +884,7 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr else if (ptr <= substream->runtime->buffer_size) ptr = substream->runtime->buffer_size - ptr; else { - snd_printd("ice1724: invalid ptr %d (size=%d)\n", + dev_dbg(ice->card->dev, "invalid ptr %d (size=%d)\n", (int)ptr, (int)substream->runtime->buffer_size); ptr = 0; } @@ -1135,7 +1135,7 @@ static struct snd_pcm_ops snd_vt1724_capture_pro_ops = { .pointer = snd_vt1724_pcm_pointer, }; -static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int capt, err; @@ -1315,7 +1315,7 @@ static struct snd_pcm_ops snd_vt1724_capture_spdif_ops = { }; -static int __devinit snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_spdif(struct snd_ice1712 *ice, int device) { char *name; struct snd_pcm *pcm; @@ -1449,7 +1449,7 @@ static struct snd_pcm_ops snd_vt1724_playback_indep_ops = { }; -static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) +static int snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) { struct snd_pcm *pcm; int play; @@ -1484,7 +1484,7 @@ static int __devinit snd_vt1724_pcm_indep(struct snd_ice1712 *ice, int device) * Mixer section */ -static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) +static int snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) { int err; @@ -1508,7 +1508,8 @@ static int __devinit snd_vt1724_ac97_mixer(struct snd_ice1712 *ice) ac97.private_data = ice; err = snd_ac97_mixer(pbus, &ac97, &ice->ac97); if (err < 0) - printk(KERN_WARNING "ice1712: cannot initialize pro ac97, skipped\n"); + dev_warn(ice->card->dev, + "cannot initialize pro ac97, skipped\n"); else return 0; } @@ -1570,7 +1571,7 @@ static void snd_vt1724_proc_read(struct snd_info_entry *entry, idx, inb(ice->profi_port+idx)); } -static void __devinit snd_vt1724_proc_init(struct snd_ice1712 *ice) +static void snd_vt1724_proc_init(struct snd_ice1712 *ice) { struct snd_info_entry *entry; @@ -1599,7 +1600,7 @@ static int snd_vt1724_eeprom_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_eeprom __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_eeprom = { .iface = SNDRV_CTL_ELEM_IFACE_CARD, .name = "ICE1724 EEPROM", .access = SNDRV_CTL_ELEM_ACCESS_READ, @@ -1712,7 +1713,7 @@ static int snd_vt1724_spdif_default_put(struct snd_kcontrol *kcontrol, return val != old; } -static struct snd_kcontrol_new snd_vt1724_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), @@ -1744,7 +1745,7 @@ static int snd_vt1724_spdif_maskp_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_maskc = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1753,7 +1754,7 @@ static struct snd_kcontrol_new snd_vt1724_spdif_maskc __devinitdata = .get = snd_vt1724_spdif_maskc_get, }; -static struct snd_kcontrol_new snd_vt1724_spdif_maskp __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_maskp = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1790,7 +1791,7 @@ static int snd_vt1724_spdif_sw_put(struct snd_kcontrol *kcontrol, return old != val; } -static struct snd_kcontrol_new snd_vt1724_spdif_switch __devinitdata = +static struct snd_kcontrol_new snd_vt1724_spdif_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* FIXME: the following conflict with IEC958 Playback Route */ @@ -1965,7 +1966,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, return old_rate != new_rate; } -static struct snd_kcontrol_new snd_vt1724_pro_internal_clock __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_internal_clock = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Internal Clock", .info = snd_vt1724_pro_internal_clock_info, @@ -1996,7 +1997,7 @@ static int snd_vt1724_pro_rate_locking_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_locking __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_rate_locking = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Locking", .info = snd_vt1724_pro_rate_locking_info, @@ -2027,7 +2028,7 @@ static int snd_vt1724_pro_rate_reset_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_pro_rate_reset = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Multi Track Rate Reset", .info = snd_vt1724_pro_rate_reset_info, @@ -2042,7 +2043,7 @@ static struct snd_kcontrol_new snd_vt1724_pro_rate_reset __devinitdata = { static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM Out", /* 0 */ "H/W In 0", "H/W In 1", /* 1-2 */ "IEC958 In L", "IEC958 In R", /* 3-4 */ @@ -2149,7 +2150,7 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, digital_route_shift(idx)); } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = +static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "H/W Playback Route", @@ -2158,7 +2159,7 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = .put = snd_vt1724_pro_route_analog_put, }; -static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_mixer_pro_spdif_route = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, NONE) "Route", .info = snd_vt1724_pro_route_info, @@ -2194,7 +2195,7 @@ static int snd_vt1724_pro_peak_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { +static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "Multi Track Peak", .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, @@ -2206,13 +2207,13 @@ static struct snd_kcontrol_new snd_vt1724_mixer_pro_peak __devinitdata = { * */ -static struct snd_ice1712_card_info no_matched __devinitdata; +static struct snd_ice1712_card_info no_matched; /* ooAoo cards with no controls */ -static unsigned char ooaoo_sq210_eeprom[] __devinitdata = { +static unsigned char ooaoo_sq210_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4c, /* 49MHz crystal, no mpu401, no ADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -2232,7 +2233,7 @@ static unsigned char ooaoo_sq210_eeprom[] __devinitdata = { }; -struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] __devinitdata = { +static struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] = { { .name = "ooAoo SQ210a", .model = "sq210a", @@ -2242,7 +2243,7 @@ struct snd_ice1712_card_info snd_vt1724_ooaoo_cards[] __devinitdata = { { } /* terminator */ }; -static struct snd_ice1712_card_info *card_tables[] __devinitdata = { +static struct snd_ice1712_card_info *card_tables[] = { snd_vt1724_revo_cards, snd_vt1724_amp_cards, snd_vt1724_aureon_cards, @@ -2257,6 +2258,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_se_cards, snd_vt1724_qtet_cards, snd_vt1724_ooaoo_cards, + snd_vt1724_psc724_cards, NULL, }; @@ -2270,7 +2272,7 @@ static void wait_i2c_busy(struct snd_ice1712 *ice) while ((inb(ICEREG1724(ice, I2C_CTRL)) & VT1724_I2C_BUSY) && t--) ; if (t == -1) - printk(KERN_ERR "ice1724: i2c busy timeout\n"); + dev_err(ice->card->dev, "i2c busy timeout\n"); } unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, @@ -2286,7 +2288,7 @@ unsigned char snd_vt1724_read_i2c(struct snd_ice1712 *ice, val = inb(ICEREG1724(ice, I2C_DATA)); mutex_unlock(&ice->i2c_mutex); /* - printk(KERN_DEBUG "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); + dev_dbg(ice->card->dev, "i2c_read: [0x%x,0x%x] = 0x%x\n", dev, addr, val); */ return val; } @@ -2297,7 +2299,7 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice, mutex_lock(&ice->i2c_mutex); wait_i2c_busy(ice); /* - printk(KERN_DEBUG "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); + dev_dbg(ice->card->dev, "i2c_write: [0x%x,0x%x] = 0x%x\n", dev, addr, data); */ outb(addr, ICEREG1724(ice, I2C_BYTE_ADDR)); outb(data, ICEREG1724(ice, I2C_DATA)); @@ -2306,8 +2308,8 @@ void snd_vt1724_write_i2c(struct snd_ice1712 *ice, mutex_unlock(&ice->i2c_mutex); } -static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, - const char *modelname) +static int snd_vt1724_read_eeprom(struct snd_ice1712 *ice, + const char *modelname) { const int dev = 0xa0; /* EEPROM device address */ unsigned int i, size; @@ -2334,7 +2336,8 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, ((unsigned int)swab16(vendor) << 16) | swab16(device); if (ice->eeprom.subvendor == 0 || ice->eeprom.subvendor == (unsigned int)-1) { - printk(KERN_ERR "ice1724: No valid ID is found\n"); + dev_err(ice->card->dev, + "No valid ID is found\n"); return -ENXIO; } } @@ -2343,36 +2346,42 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, for (c = *tbl; c->name; c++) { if (modelname && c->model && !strcmp(modelname, c->model)) { - printk(KERN_INFO "ice1724: Using board model %s\n", + dev_info(ice->card->dev, + "Using board model %s\n", c->name); ice->eeprom.subvendor = c->subvendor; } else if (c->subvendor != ice->eeprom.subvendor) continue; + ice->card_info = c; if (!c->eeprom_size || !c->eeprom_data) goto found; /* if the EEPROM is given by the driver, use it */ - snd_printdd("using the defined eeprom..\n"); + dev_dbg(ice->card->dev, "using the defined eeprom..\n"); ice->eeprom.version = 2; ice->eeprom.size = c->eeprom_size + 6; memcpy(ice->eeprom.data, c->eeprom_data, c->eeprom_size); goto read_skipped; } } - printk(KERN_WARNING "ice1724: No matching model found for ID 0x%x\n", + dev_warn(ice->card->dev, "No matching model found for ID 0x%x\n", ice->eeprom.subvendor); +#ifdef CONFIG_PM_SLEEP + /* assume AC97-only card which can suspend without additional code */ + ice->pm_suspend_enabled = 1; +#endif found: ice->eeprom.size = snd_vt1724_read_i2c(ice, dev, 0x04); if (ice->eeprom.size < 6) ice->eeprom.size = 32; else if (ice->eeprom.size > 32) { - printk(KERN_ERR "ice1724: Invalid EEPROM (size = %i)\n", + dev_err(ice->card->dev, "Invalid EEPROM (size = %i)\n", ice->eeprom.size); return -EIO; } ice->eeprom.version = snd_vt1724_read_i2c(ice, dev, 0x05); - if (ice->eeprom.version != 2) - printk(KERN_WARNING "ice1724: Invalid EEPROM version %i\n", + if (ice->eeprom.version != 1 && ice->eeprom.version != 2) + dev_warn(ice->card->dev, "Invalid EEPROM version %i\n", ice->eeprom.version); size = ice->eeprom.size - 6; for (i = 0; i < size; i++) @@ -2424,7 +2433,7 @@ static int snd_vt1724_chip_init(struct snd_ice1712 *ice) return 0; } -static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) +static int snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) { int err; struct snd_kcontrol *kctl; @@ -2466,7 +2475,7 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) } -static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice) +static int snd_vt1724_build_controls(struct snd_ice1712 *ice) { int err; @@ -2526,10 +2535,10 @@ static int snd_vt1724_dev_free(struct snd_device *device) return snd_vt1724_free(ice); } -static int __devinit snd_vt1724_create(struct snd_card *card, - struct pci_dev *pci, - const char *modelname, - struct snd_ice1712 **r_ice1712) +static int snd_vt1724_create(struct snd_card *card, + struct pci_dev *pci, + const char *modelname, + struct snd_ice1712 **r_ice1712) { struct snd_ice1712 *ice; int err; @@ -2580,7 +2589,7 @@ static int __devinit snd_vt1724_create(struct snd_card *card, if (request_irq(pci->irq, snd_vt1724_interrupt, IRQF_SHARED, KBUILD_MODNAME, ice)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_vt1724_free(ice); return -EIO; } @@ -2603,8 +2612,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *r_ice1712 = ice; return 0; } @@ -2616,8 +2623,8 @@ static int __devinit snd_vt1724_create(struct snd_card *card, * */ -static int __devinit snd_vt1724_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_vt1724_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -2632,7 +2639,8 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2786,10 +2794,14 @@ __found: return 0; } -static void __devexit snd_vt1724_remove(struct pci_dev *pci) +static void snd_vt1724_remove(struct pci_dev *pci) { - snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); + struct snd_card *card = pci_get_drvdata(pci); + struct snd_ice1712 *ice = card->private_data; + + if (ice->card_info && ice->card_info->chip_exit) + ice->card_info->chip_exit(ice); + snd_card_free(card); } #ifdef CONFIG_PM_SLEEP @@ -2859,7 +2871,12 @@ static int snd_vt1724_resume(struct device *dev) ice->set_spdif_clock(ice, 0); } else { /* internal on-card clock */ - snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); + int rate; + if (ice->cur_rate) + rate = ice->cur_rate; + else + rate = ice->pro_rate_default; + snd_vt1724_set_pro_rate(ice, rate, 1); } update_spdif_bits(ice, ice->pm_saved_spdif_ctrl); @@ -2884,7 +2901,7 @@ static struct pci_driver vt1724_driver = { .name = KBUILD_MODNAME, .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, - .remove = __devexit_p(snd_vt1724_remove), + .remove = snd_vt1724_remove, .driver = { .pm = SND_VT1724_PM_OPS, }, diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 14fd536b645..7a6c0786c55 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -23,7 +23,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -245,7 +244,7 @@ static void juli_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) /* AK5385 first, since it requires cold reset affecting both codecs */ old_gpio = ice->gpio.get_data(ice); new_gpio = (old_gpio & ~GPIO_AK5385A_MASK) | ak5385_pins; - /* printk(KERN_DEBUG "JULI - ak5385 set_rate_val: new gpio 0x%x\n", + /* dev_dbg(ice->card->dev, "JULI - ak5385 set_rate_val: new gpio 0x%x\n", new_gpio); */ ice->gpio.set_data(ice, new_gpio); @@ -283,7 +282,7 @@ static const struct snd_akm4xxx_dac_channel juli_dac[] = { }; -static struct snd_akm4xxx akm_juli_dac __devinitdata = { +static struct snd_akm4xxx akm_juli_dac = { .type = SND_AK4358, .num_dacs = 8, /* DAC1 - analog out DAC2 - analog in monitor @@ -345,7 +344,7 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol, new_gpio = old_gpio & ~((unsigned int) kcontrol->private_value); } - /* printk(KERN_DEBUG + /* dev_dbg(ice->card->dev, "JULI - mute/unmute: control_value: 0x%x, old_gpio: 0x%x, " "new_gpio 0x%x\n", (unsigned int)ucontrol->value.integer.value[0], old_gpio, @@ -358,7 +357,7 @@ static int juli_mute_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { +static struct snd_kcontrol_new juli_mute_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -412,7 +411,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { }, }; -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { PCM_VOLUME, MONITOR_AN_IN_VOLUME, MONITOR_DIG_IN_VOLUME, @@ -420,11 +419,11 @@ static char *slave_vols[] __devinitdata = { NULL }; -static __devinitdata +static DECLARE_TLV_DB_SCALE(juli_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, - const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, + const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -434,20 +433,21 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, return snd_ctl_find_id(card, &sid); } -static void __devinit add_slaves(struct snd_card *card, - struct snd_kcontrol *master, char **list) +static void add_slaves(struct snd_card *card, + struct snd_kcontrol *master, + char * const *list) { for (; *list; list++) { struct snd_kcontrol *slave = ctl_find(card, *list); - /* printk(KERN_DEBUG "add_slaves - %s\n", *list); */ + /* dev_dbg(card->dev, "add_slaves - %s\n", *list); */ if (slave) { - /* printk(KERN_DEBUG "slave %s found\n", *list); */ + /* dev_dbg(card->dev, "slave %s found\n", *list); */ snd_ctl_add_slave(master, slave); } } } -static int __devinit juli_add_controls(struct snd_ice1712 *ice) +static int juli_add_controls(struct snd_ice1712 *ice) { struct juli_spec *spec = ice->spec; int err; @@ -536,7 +536,7 @@ static void juli_set_rate(struct snd_ice1712 *ice, unsigned int rate) old = ice->gpio.get_data(ice); new = (old & ~GPIO_RATE_MASK) | get_gpio_val(rate); - /* printk(KERN_DEBUG "JULI - set_rate: old %x, new %x\n", + /* dev_dbg(ice->card->dev, "JULI - set_rate: old %x, new %x\n", old & GPIO_RATE_MASK, new & GPIO_RATE_MASK); */ @@ -573,13 +573,13 @@ static void juli_ak4114_change(struct ak4114 *ak4114, unsigned char c0, if (ice->is_spdif_master(ice) && c1) { /* only for SPDIF master mode, rate was changed */ rate = snd_ak4114_external_rate(ak4114); - /* printk(KERN_DEBUG "ak4114 - input rate changed to %d\n", + /* dev_dbg(ice->card->dev, "ak4114 - input rate changed to %d\n", rate); */ juli_akm_set_rate_val(ice->akm, rate); } } -static int __devinit juli_init(struct snd_ice1712 *ice) +static int juli_init(struct snd_ice1712 *ice) { static const unsigned char ak4114_init_vals[] = { /* AK4117_REG_PWRDN */ AK4114_RST | AK4114_PWN | @@ -628,7 +628,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) #endif if (spec->analog) { - printk(KERN_INFO "juli@: analog I/O detected\n"); + dev_info(ice->card->dev, "juli@: analog I/O detected\n"); ice->num_total_dacs = 2; ice->num_total_adcs = 2; @@ -667,7 +667,7 @@ static int __devinit juli_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char juli_eeprom[] __devinitdata = { +static unsigned char juli_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, 1xADC, 1xDACs, SPDIF in */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -686,7 +686,7 @@ static unsigned char juli_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_juli_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_juli_cards[] = { { .subvendor = VT1724_SUBDEVICE_JULI, .name = "ESI Juli@", diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c index 726fd4b92e1..63aa39f06f0 100644 --- a/sound/pci/ice1712/maya44.c +++ b/sound/pci/ice1712/maya44.c @@ -24,7 +24,6 @@ #include <linux/init.h> #include <linux/slab.h> -#include <linux/io.h> #include <sound/core.h> #include <sound/control.h> #include <sound/pcm.h> @@ -358,7 +357,7 @@ static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) static int maya_rec_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Line", "Mic" }; + static const char * const texts[] = { "Line", "Mic" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -407,7 +406,7 @@ static int maya_rec_src_put(struct snd_kcontrol *kcontrol, static int maya_pb_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { + static const char * const texts[] = { "PCM Out", /* 0 */ "Input 1", "Input 2", "Input 3", "Input 4" }; @@ -455,7 +454,7 @@ static int maya_pb_route_put(struct snd_kcontrol *kcontrol, * controls to be added */ -static struct snd_kcontrol_new maya_controls[] __devinitdata = { +static struct snd_kcontrol_new maya_controls[] = { { .name = "Crossmix Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -545,7 +544,7 @@ static struct snd_kcontrol_new maya_controls[] __devinitdata = { }, }; -static int __devinit maya44_add_controls(struct snd_ice1712 *ice) +static int maya44_add_controls(struct snd_ice1712 *ice) { int err, i; @@ -562,8 +561,8 @@ static int __devinit maya44_add_controls(struct snd_ice1712 *ice) /* * initialize a wm8776 chip */ -static void __devinit wm8776_init(struct snd_ice1712 *ice, - struct snd_wm8776 *wm, unsigned int addr) +static void wm8776_init(struct snd_ice1712 *ice, + struct snd_wm8776 *wm, unsigned int addr) { static const unsigned short inits_wm8776[] = { 0x02, 0x100, /* R2: headphone L+R muted + update */ @@ -693,14 +692,14 @@ static struct snd_pcm_hw_constraint_list dac_rates = { /* * chip addresses on I2C bus */ -static unsigned char wm8776_addr[2] __devinitdata = { +static unsigned char wm8776_addr[2] = { 0x34, 0x36, /* codec 0 & 1 */ }; /* * initialize the chip */ -static int __devinit maya44_init(struct snd_ice1712 *ice) +static int maya44_init(struct snd_ice1712 *ice) { int i; struct snd_maya44 *chip; @@ -743,7 +742,7 @@ static int __devinit maya44_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char maya44_eeprom[] __devinitdata = { +static unsigned char maya44_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x45, /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ [ICE_EEP2_ACLINK] = 0x80, @@ -765,7 +764,7 @@ static unsigned char maya44_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_maya44_cards[] = { { .subvendor = VT1724_SUBDEVICE_MAYA44, .name = "ESI Maya44", diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c index de29be8c965..0011e04f36a 100644 --- a/sound/pci/ice1712/phase.c +++ b/sound/pci/ice1712/phase.c @@ -42,7 +42,6 @@ * Digital receiver: CS8414-CS (supported in this release) */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -103,13 +102,13 @@ static const unsigned char wm_vol[256] = { #define WM_VOL_MAX (sizeof(wm_vol) - 1) #define WM_VOL_MUTE 0x8000 -static struct snd_akm4xxx akm_phase22 __devinitdata = { +static struct snd_akm4xxx akm_phase22 = { .type = SND_AK4524, .num_dacs = 2, .num_adcs = 2, }; -static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { +static struct snd_ak4xxx_private akm_phase22_priv = { .caddr = 2, .cif = 1, .data_mask = 1 << 4, @@ -121,7 +120,7 @@ static struct snd_ak4xxx_private akm_phase22_priv __devinitdata = { .mask_flags = 0, }; -static int __devinit phase22_init(struct snd_ice1712 *ice) +static int phase22_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; int err; @@ -158,7 +157,7 @@ static int __devinit phase22_init(struct snd_ice1712 *ice) return 0; } -static int __devinit phase22_add_controls(struct snd_ice1712 *ice) +static int phase22_add_controls(struct snd_ice1712 *ice) { int err = 0; @@ -172,7 +171,7 @@ static int __devinit phase22_add_controls(struct snd_ice1712 *ice) return 0; } -static unsigned char phase22_eeprom[] __devinitdata = { +static unsigned char phase22_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x28, /* clock 512, mpu 401, spdif-in/1xADC, 1xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -189,7 +188,7 @@ static unsigned char phase22_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, }; -static unsigned char phase28_eeprom[] __devinitdata = { +static unsigned char phase28_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x2b, /* clock 512, mpu401, spdif-in/1xADC, 4xDACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -379,7 +378,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol, return change; } -static int __devinit phase28_init(struct snd_ice1712 *ice) +static int phase28_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits_phase28[] = { /* These come first to reduce init pop noise */ @@ -722,7 +721,7 @@ static int phase28_deemp_put(struct snd_kcontrol *kcontrol, static int phase28_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "128x", "64x" }; + static const char * const texts[2] = { "128x", "64x" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -770,7 +769,7 @@ static int phase28_oversampling_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); -static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { +static struct snd_kcontrol_new phase28_dac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -885,7 +884,7 @@ static struct snd_kcontrol_new phase28_dac_controls[] __devinitdata = { } }; -static struct snd_kcontrol_new wm_controls[] __devinitdata = { +static struct snd_kcontrol_new wm_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", @@ -919,7 +918,7 @@ static struct snd_kcontrol_new wm_controls[] __devinitdata = { } }; -static int __devinit phase28_add_controls(struct snd_ice1712 *ice) +static int phase28_add_controls(struct snd_ice1712 *ice) { unsigned int i, counts; int err; @@ -943,7 +942,7 @@ static int __devinit phase28_add_controls(struct snd_ice1712 *ice) return 0; } -struct snd_ice1712_card_info snd_vt1724_phase_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_phase_cards[] = { { .subvendor = VT1724_SUBDEVICE_PHASE22, .name = "Terratec PHASE 22", diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 92c1160d7ab..5555eb4b240 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -550,7 +549,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_volume, -6400, 50, 1); * mixers */ -static struct snd_kcontrol_new pontis_controls[] __devinitdata = { +static struct snd_kcontrol_new pontis_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -697,7 +696,7 @@ static void cs_proc_init(struct snd_ice1712 *ice) } -static int __devinit pontis_add_controls(struct snd_ice1712 *ice) +static int pontis_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -718,7 +717,7 @@ static int __devinit pontis_add_controls(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit pontis_init(struct snd_ice1712 *ice) +static int pontis_init(struct snd_ice1712 *ice) { static const unsigned short wm_inits[] = { /* These come first to reduce init pop noise */ @@ -805,7 +804,7 @@ static int __devinit pontis_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char pontis_eeprom[] __devinitdata = { +static unsigned char pontis_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x08, /* clock 256, mpu401, spdif-in/ADC, 1DAC */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0xf8, /* vol, 96k, 24bit, 192k */ @@ -822,7 +821,7 @@ static unsigned char pontis_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1720_pontis_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1720_pontis_cards[] = { { .subvendor = VT1720_SUBDEVICE_PONTIS_MS300, .name = "Pontis MS300", diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index e36ddb94c38..f3b491aa3e2 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c @@ -54,7 +54,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -99,7 +98,7 @@ static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, new = (~mute << 7 & 0x80) | (old & ~0x80); change = (new != old); if (change) - /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/ + /* dev_dbg(ice->card->dev, "Volume register 0x%02x: 0x%02x\n", idx, new);*/ stac9460_put(ice, idx, new); return change; } @@ -134,7 +133,7 @@ static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e /* due to possible conflicts with stac9460_set_rate_val, mutexing */ mutex_lock(&spec->mute_mutex); /* - printk(KERN_DEBUG "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, + dev_dbg(ice->card->dev, "Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, ucontrol->value.integer.value[0]); */ change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); @@ -188,7 +187,7 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el if (change) { ovol = (0x7f - nvol) | (tmp & 0x80); /* - printk(KERN_DEBUG "DAC Volume: reg 0x%02x: 0x%02x\n", + dev_dbg(ice->card->dev, "DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol); */ stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); @@ -283,7 +282,7 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Line In", "Mic" }; + static const char * const texts[2] = { "Line In", "Mic" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -349,7 +348,7 @@ static void stac9460_set_rate_val(struct snd_ice1712 *ice, unsigned int rate) for (idx = 0; idx < 7 ; ++idx) changed[idx] = stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 0); - /*printk(KERN_DEBUG "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ + /*dev_dbg(ice->card->dev, "Rate change: %d, new MC: 0x%02x\n", rate, new);*/ stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); udelay(10); /* unmuting - only originally unmuted dacs - @@ -369,7 +368,7 @@ static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); * mixers */ -static struct snd_kcontrol_new stac_controls[] __devinitdata = { +static struct snd_kcontrol_new stac_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -562,7 +561,7 @@ static unsigned char prodigy192_ak4114_read(void *private_data, static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[2] = { "Toslink", "Coax" }; + static const char * const texts[2] = { "Toslink", "Coax" }; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; @@ -607,7 +606,7 @@ static int ak4114_input_sw_put(struct snd_kcontrol *kcontrol, } -static struct snd_kcontrol_new ak4114_controls[] __devinitdata = { +static struct snd_kcontrol_new ak4114_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "MIODIO IEC958 Capture Input", @@ -672,7 +671,7 @@ static void stac9460_proc_init(struct snd_ice1712 *ice) } -static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) +static int prodigy192_add_controls(struct snd_ice1712 *ice) { struct prodigy192_spec *spec = ice->spec; unsigned int i; @@ -728,7 +727,7 @@ static int prodigy192_miodio_exists(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit prodigy192_init(struct snd_ice1712 *ice) +static int prodigy192_init(struct snd_ice1712 *ice) { static const unsigned short stac_inits_prodigy[] = { STAC946X_RESET, 0, @@ -769,9 +768,10 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) /* from this moment if err = 0 then * spec->ak4114 should not be null */ - snd_printdd("AK4114 initialized with status %d\n", err); + dev_dbg(ice->card->dev, + "AK4114 initialized with status %d\n", err); } else - snd_printdd("AK4114 not found\n"); + dev_dbg(ice->card->dev, "AK4114 not found\n"); if (err < 0) return err; @@ -784,7 +784,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) * hence the driver needs to sets up it properly. */ -static unsigned char prodigy71_eeprom[] __devinitdata = { +static unsigned char prodigy71_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x6a, /* 49MHz crystal, mpu401, * spdif-in+ 1 stereo ADC, * 3 stereo DACs @@ -808,7 +808,7 @@ static unsigned char prodigy71_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] = { { .subvendor = VT1724_SUBDEVICE_PRODIGY192VE, .name = "Audiotrak Prodigy 192", diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 7bf093c51ce..2261d1e4915 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -25,7 +25,6 @@ */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -299,7 +298,7 @@ static int ak4396_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); -static struct snd_kcontrol_new prodigy_hd2_controls[] __devinitdata = { +static struct snd_kcontrol_new prodigy_hd2_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -782,7 +781,7 @@ static int wm_chswap_put(struct snd_kcontrol *kcontrol, * mixers */ -static struct snd_kcontrol_new prodigy_hifi_controls[] __devinitdata = { +static struct snd_kcontrol_new prodigy_hifi_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -939,7 +938,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) } } -static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) +static int prodigy_hifi_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -956,7 +955,7 @@ static int __devinit prodigy_hifi_add_controls(struct snd_ice1712 *ice) return 0; } -static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) +static int prodigy_hd2_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -977,7 +976,7 @@ static int __devinit prodigy_hd2_add_controls(struct snd_ice1712 *ice) /* * initialize the chip */ -static int __devinit prodigy_hifi_init(struct snd_ice1712 *ice) +static int prodigy_hifi_init(struct snd_ice1712 *ice) { static unsigned short wm_inits[] = { /* These come first to reduce init pop noise */ @@ -1115,7 +1114,7 @@ static int prodigy_hd2_resume(struct snd_ice1712 *ice) } #endif -static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) +static int prodigy_hd2_init(struct snd_ice1712 *ice) { struct prodigy_hifi_spec *spec; @@ -1152,7 +1151,7 @@ static int __devinit prodigy_hd2_init(struct snd_ice1712 *ice) } -static unsigned char prodigy71hifi_eeprom[] __devinitdata = { +static unsigned char prodigy71hifi_eeprom[] = { 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1168,7 +1167,7 @@ static unsigned char prodigy71hifi_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; -static unsigned char prodigyhd2_eeprom[] __devinitdata = { +static unsigned char prodigyhd2_eeprom[] = { 0x4b, /* SYSCONF: clock 512, spdif-in/ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1184,7 +1183,7 @@ static unsigned char prodigyhd2_eeprom[] __devinitdata = { 0x00, /* GPIO_STATE2 */ }; -static unsigned char fortissimo4_eeprom[] __devinitdata = { +static unsigned char fortissimo4_eeprom[] = { 0x43, /* SYSCONF: clock 512, ADC, 4DACs */ 0x80, /* ACLINK: I2S */ 0xfc, /* I2S: vol, 96k, 24bit, 192k */ @@ -1201,7 +1200,7 @@ static unsigned char fortissimo4_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_prodigy_hifi_cards[] = { { .subvendor = VT1724_SUBDEVICE_PRODIGY_HIFI, .name = "Audiotrak Prodigy 7.1 HiFi", diff --git a/sound/pci/ice1712/psc724.c b/sound/pci/ice1712/psc724.c new file mode 100644 index 00000000000..4019cf27d11 --- /dev/null +++ b/sound/pci/ice1712/psc724.c @@ -0,0 +1,464 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for Philips PSC724 Ultimate Edge + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <sound/core.h> + +#include "ice1712.h" +#include "envy24ht.h" +#include "psc724.h" +#include "wm8766.h" +#include "wm8776.h" + +struct psc724_spec { + struct snd_wm8766 wm8766; + struct snd_wm8776 wm8776; + bool mute_all, jack_detect; + struct snd_ice1712 *ice; + struct delayed_work hp_work; + bool hp_connected; +}; + +/****************************************************************************/ +/* PHILIPS PSC724 ULTIMATE EDGE */ +/****************************************************************************/ +/* + * VT1722 (Envy24GT) - 6 outputs, 4 inputs (only 2 used), 24-bit/96kHz + * + * system configuration ICE_EEP2_SYSCONF=0x42 + * XIN1 49.152MHz + * no MPU401 + * one stereo ADC, no S/PDIF receiver + * three stereo DACs (FRONT, REAR, CENTER+LFE) + * + * AC-Link configuration ICE_EEP2_ACLINK=0x80 + * use I2S, not AC97 + * + * I2S converters feature ICE_EEP2_I2S=0x30 + * I2S codec has no volume/mute control feature (bug!) + * I2S codec does not support 96KHz or 192KHz (bug!) + * I2S codec 24bits + * + * S/PDIF configuration ICE_EEP2_SPDIF=0xc1 + * Enable integrated S/PDIF transmitter + * internal S/PDIF out implemented + * No S/PDIF input + * External S/PDIF out implemented + * + * + * ** connected chips ** + * + * WM8776 + * 2-channel DAC used for main output and stereo ADC (with 10-channel MUX) + * AIN1: LINE IN, AIN2: CD/VIDEO, AIN3: AUX, AIN4: Front MIC, AIN5: Rear MIC + * Controlled by I2C using VT1722 I2C interface: + * MODE (pin16) -- GND + * CE (pin17) -- GND I2C mode (address=0x34) + * DI (pin18) -- SDA (VT1722 pin70) + * CL (pin19) -- SCLK (VT1722 pin71) + * + * WM8766 + * 6-channel DAC used for rear & center/LFE outputs (only 4 channels used) + * Controlled by SPI using VT1722 GPIO pins: + * MODE (pin 1) -- GPIO19 (VT1722 pin99) + * ML/I2S (pin11) -- GPIO18 (VT1722 pin98) + * MC/IWL (pin12) -- GPIO17 (VT1722 pin97) + * MD/DM (pin13) -- GPIO16 (VT1722 pin96) + * MUTE (pin14) -- GPIO20 (VT1722 pin101) + * + * GPIO14 is used as input for headphone jack detection (1 = connected) + * GPIO22 is used as MUTE ALL output, grounding all 6 channels + * + * ** output pins and device names ** + * + * 5.1ch name -- output connector color -- device (-D option) + * + * FRONT 2ch -- green -- plughw:0,0 + * CENTER(Lch) SUBWOOFER(Rch) -- orange -- plughw:0,2,0 + * REAR 2ch -- black -- plughw:0,2,1 + */ + +/* codec access low-level functions */ + +#define GPIO_HP_JACK (1 << 14) +#define GPIO_MUTE_SUR (1 << 20) +#define GPIO_MUTE_ALL (1 << 22) + +#define JACK_INTERVAL 1000 + +#define PSC724_SPI_DELAY 1 + +#define PSC724_SPI_DATA (1 << 16) +#define PSC724_SPI_CLK (1 << 17) +#define PSC724_SPI_LOAD (1 << 18) +#define PSC724_SPI_MASK (PSC724_SPI_DATA | PSC724_SPI_CLK | PSC724_SPI_LOAD) + +static void psc724_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data) +{ + struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8766); + struct snd_ice1712 *ice = spec->ice; + u32 st, bits; + int i; + + snd_ice1712_save_gpio_status(ice); + + st = ((addr & 0x7f) << 9) | (data & 0x1ff); + snd_ice1712_gpio_set_dir(ice, ice->gpio.direction | PSC724_SPI_MASK); + snd_ice1712_gpio_set_mask(ice, ice->gpio.write_mask & ~PSC724_SPI_MASK); + bits = snd_ice1712_gpio_read(ice) & ~PSC724_SPI_MASK; + snd_ice1712_gpio_write(ice, bits); + + for (i = 0; i < 16; i++) { + udelay(PSC724_SPI_DELAY); + bits &= ~PSC724_SPI_CLK; + /* MSB first */ + st <<= 1; + if (st & 0x10000) + bits |= PSC724_SPI_DATA; + else + bits &= ~PSC724_SPI_DATA; + snd_ice1712_gpio_write(ice, bits); + /* CLOCK high */ + udelay(PSC724_SPI_DELAY); + bits |= PSC724_SPI_CLK; + snd_ice1712_gpio_write(ice, bits); + } + /* LOAD high */ + udelay(PSC724_SPI_DELAY); + bits |= PSC724_SPI_LOAD; + snd_ice1712_gpio_write(ice, bits); + /* LOAD low, DATA and CLOCK high */ + udelay(PSC724_SPI_DELAY); + bits |= (PSC724_SPI_DATA | PSC724_SPI_CLK); + snd_ice1712_gpio_write(ice, bits); + + snd_ice1712_restore_gpio_status(ice); +} + +static void psc724_wm8776_write(struct snd_wm8776 *wm, u8 addr, u8 data) +{ + struct psc724_spec *spec = container_of(wm, struct psc724_spec, wm8776); + + snd_vt1724_write_i2c(spec->ice, 0x34, addr, data); +} + +/* mute all */ + +static void psc724_set_master_switch(struct snd_ice1712 *ice, bool on) +{ + unsigned int bits = snd_ice1712_gpio_read(ice); + struct psc724_spec *spec = ice->spec; + + spec->mute_all = !on; + if (on) + bits &= ~(GPIO_MUTE_ALL | GPIO_MUTE_SUR); + else + bits |= GPIO_MUTE_ALL | GPIO_MUTE_SUR; + snd_ice1712_gpio_write(ice, bits); +} + +static bool psc724_get_master_switch(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + return !spec->mute_all; +} + +/* jack detection */ + +static void psc724_set_jack_state(struct snd_ice1712 *ice, bool hp_connected) +{ + struct psc724_spec *spec = ice->spec; + struct snd_ctl_elem_id elem_id; + struct snd_kcontrol *kctl; + u16 power = spec->wm8776.regs[WM8776_REG_PWRDOWN] & ~WM8776_PWR_HPPD; + + psc724_set_master_switch(ice, !hp_connected); + if (!hp_connected) + power |= WM8776_PWR_HPPD; + snd_wm8776_set_power(&spec->wm8776, power); + spec->hp_connected = hp_connected; + /* notify about master speaker mute change */ + memset(&elem_id, 0, sizeof(elem_id)); + elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strlcpy(elem_id.name, "Master Speakers Playback Switch", + sizeof(elem_id.name)); + kctl = snd_ctl_find_id(ice->card, &elem_id); + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); + /* and headphone mute change */ + strlcpy(elem_id.name, spec->wm8776.ctl[WM8776_CTL_HP_SW].name, + sizeof(elem_id.name)); + kctl = snd_ctl_find_id(ice->card, &elem_id); + snd_ctl_notify(ice->card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); +} + +static void psc724_update_hp_jack_state(struct work_struct *work) +{ + struct psc724_spec *spec = container_of(work, struct psc724_spec, + hp_work.work); + struct snd_ice1712 *ice = spec->ice; + bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK; + + schedule_delayed_work(&spec->hp_work, msecs_to_jiffies(JACK_INTERVAL)); + if (hp_connected == spec->hp_connected) + return; + psc724_set_jack_state(ice, hp_connected); +} + +static void psc724_set_jack_detection(struct snd_ice1712 *ice, bool on) +{ + struct psc724_spec *spec = ice->spec; + + if (spec->jack_detect == on) + return; + + spec->jack_detect = on; + if (on) { + bool hp_connected = snd_ice1712_gpio_read(ice) & GPIO_HP_JACK; + psc724_set_jack_state(ice, hp_connected); + schedule_delayed_work(&spec->hp_work, + msecs_to_jiffies(JACK_INTERVAL)); + } else + cancel_delayed_work_sync(&spec->hp_work); +} + +static bool psc724_get_jack_detection(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + return spec->jack_detect; +} + +/* mixer controls */ + +struct psc724_control { + const char *name; + void (*set)(struct snd_ice1712 *ice, bool on); + bool (*get)(struct snd_ice1712 *ice); +}; + +static const struct psc724_control psc724_cont[] = { + { + .name = "Master Speakers Playback Switch", + .set = psc724_set_master_switch, + .get = psc724_get_master_switch, + }, + { + .name = "Headphone Jack Detection Playback Switch", + .set = psc724_set_jack_detection, + .get = psc724_get_jack_detection, + }, +}; + +static int psc724_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + ucontrol->value.integer.value[0] = psc724_cont[n].get(ice); + + return 0; +} + +static int psc724_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + psc724_cont[n].set(ice, ucontrol->value.integer.value[0]); + + return 0; +} + +static const char *front_volume = "Front Playback Volume"; +static const char *front_switch = "Front Playback Switch"; +static const char *front_zc = "Front Zero Cross Detect Playback Switch"; +static const char *front_izd = "Front Infinite Zero Detect Playback Switch"; +static const char *front_phase = "Front Phase Invert Playback Switch"; +static const char *front_deemph = "Front Deemphasis Playback Switch"; +static const char *ain1_switch = "Line Capture Switch"; +static const char *ain2_switch = "CD Capture Switch"; +static const char *ain3_switch = "AUX Capture Switch"; +static const char *ain4_switch = "Front Mic Capture Switch"; +static const char *ain5_switch = "Rear Mic Capture Switch"; +static const char *rear_volume = "Surround Playback Volume"; +static const char *clfe_volume = "CLFE Playback Volume"; +static const char *rear_switch = "Surround Playback Switch"; +static const char *clfe_switch = "CLFE Playback Switch"; +static const char *rear_phase = "Surround Phase Invert Playback Switch"; +static const char *clfe_phase = "CLFE Phase Invert Playback Switch"; +static const char *rear_deemph = "Surround Deemphasis Playback Switch"; +static const char *clfe_deemph = "CLFE Deemphasis Playback Switch"; +static const char *rear_clfe_izd = "Rear Infinite Zero Detect Playback Switch"; +static const char *rear_clfe_zc = "Rear Zero Cross Detect Playback Switch"; + +static int psc724_add_controls(struct snd_ice1712 *ice) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + int err, i; + struct psc724_spec *spec = ice->spec; + + spec->wm8776.ctl[WM8776_CTL_DAC_VOL].name = front_volume; + spec->wm8776.ctl[WM8776_CTL_DAC_SW].name = front_switch; + spec->wm8776.ctl[WM8776_CTL_DAC_ZC_SW].name = front_zc; + spec->wm8776.ctl[WM8776_CTL_AUX_SW].name = NULL; + spec->wm8776.ctl[WM8776_CTL_DAC_IZD_SW].name = front_izd; + spec->wm8776.ctl[WM8776_CTL_PHASE_SW].name = front_phase; + spec->wm8776.ctl[WM8776_CTL_DEEMPH_SW].name = front_deemph; + spec->wm8776.ctl[WM8776_CTL_INPUT1_SW].name = ain1_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT2_SW].name = ain2_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT3_SW].name = ain3_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT4_SW].name = ain4_switch; + spec->wm8776.ctl[WM8776_CTL_INPUT5_SW].name = ain5_switch; + snd_wm8776_build_controls(&spec->wm8776); + spec->wm8766.ctl[WM8766_CTL_CH1_VOL].name = rear_volume; + spec->wm8766.ctl[WM8766_CTL_CH2_VOL].name = clfe_volume; + spec->wm8766.ctl[WM8766_CTL_CH3_VOL].name = NULL; + spec->wm8766.ctl[WM8766_CTL_CH1_SW].name = rear_switch; + spec->wm8766.ctl[WM8766_CTL_CH2_SW].name = clfe_switch; + spec->wm8766.ctl[WM8766_CTL_CH3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_PHASE1_SW].name = rear_phase; + spec->wm8766.ctl[WM8766_CTL_PHASE2_SW].name = clfe_phase; + spec->wm8766.ctl[WM8766_CTL_PHASE3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_DEEMPH1_SW].name = rear_deemph; + spec->wm8766.ctl[WM8766_CTL_DEEMPH2_SW].name = clfe_deemph; + spec->wm8766.ctl[WM8766_CTL_DEEMPH3_SW].name = NULL; + spec->wm8766.ctl[WM8766_CTL_IZD_SW].name = rear_clfe_izd; + spec->wm8766.ctl[WM8766_CTL_ZC_SW].name = rear_clfe_zc; + snd_wm8766_build_controls(&spec->wm8766); + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + for (i = 0; i < ARRAY_SIZE(psc724_cont); i++) { + cont.private_value = i; + cont.name = psc724_cont[i].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + cont.info = snd_ctl_boolean_mono_info; + cont.get = psc724_ctl_get; + cont.put = psc724_ctl_put; + ctl = snd_ctl_new1(&cont, ice); + if (!ctl) + return -ENOMEM; + err = snd_ctl_add(ice->card, ctl); + if (err < 0) + return err; + } + + return 0; +} + +static void psc724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) +{ + struct psc724_spec *spec = ice->spec; + /* restore codec volume settings after rate change (PMCLK stop) */ + snd_wm8776_volume_restore(&spec->wm8776); + snd_wm8766_volume_restore(&spec->wm8766); +} + +/* power management */ + +#ifdef CONFIG_PM_SLEEP +static int psc724_resume(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + snd_wm8776_resume(&spec->wm8776); + snd_wm8766_resume(&spec->wm8766); + + return 0; +} +#endif + +/* init */ + +static int psc724_init(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + ice->spec = spec; + spec->ice = ice; + + ice->num_total_dacs = 6; + ice->num_total_adcs = 2; + spec->wm8776.ops.write = psc724_wm8776_write; + spec->wm8776.card = ice->card; + snd_wm8776_init(&spec->wm8776); + spec->wm8766.ops.write = psc724_wm8766_write; + spec->wm8766.card = ice->card; +#ifdef CONFIG_PM_SLEEP + ice->pm_resume = psc724_resume; + ice->pm_suspend_enabled = 1; +#endif + snd_wm8766_init(&spec->wm8766); + snd_wm8766_set_if(&spec->wm8766, + WM8766_IF_FMT_I2S | WM8766_IF_IWL_24BIT); + ice->gpio.set_pro_rate = psc724_set_pro_rate; + INIT_DELAYED_WORK(&spec->hp_work, psc724_update_hp_jack_state); + psc724_set_jack_detection(ice, true); + return 0; +} + +static void psc724_exit(struct snd_ice1712 *ice) +{ + struct psc724_spec *spec = ice->spec; + + cancel_delayed_work_sync(&spec->hp_work); +} + +/* PSC724 has buggy EEPROM (no 96&192kHz, all FFh GPIOs), so override it here */ +static unsigned char psc724_eeprom[] = { + [ICE_EEP2_SYSCONF] = 0x42, /* 49.152MHz, 1 ADC, 3 DACs */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0xf0, /* I2S volume, 96kHz, 24bit */ + [ICE_EEP2_SPDIF] = 0xc1, /* spdif out-en, out-int, no input */ + /* GPIO outputs */ + [ICE_EEP2_GPIO_DIR2] = 0x5f, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */ + /* GPIO write enable */ + [ICE_EEP2_GPIO_MASK] = 0xff, /* read-only */ + [ICE_EEP2_GPIO_MASK1] = 0xff, /* read-only */ + [ICE_EEP2_GPIO_MASK2] = 0xa0, /* MUTE_ALL,WM8766 MUTE/MODE/ML/MC/MD */ + /* GPIO initial state */ + [ICE_EEP2_GPIO_STATE2] = 0x20, /* unmuted, all WM8766 pins low */ +}; + +struct snd_ice1712_card_info snd_vt1724_psc724_cards[] = { + { + .subvendor = VT1724_SUBDEVICE_PSC724, + .name = "Philips PSC724 Ultimate Edge", + .model = "psc724", + .chip_init = psc724_init, + .chip_exit = psc724_exit, + .build_controls = psc724_add_controls, + .eeprom_size = sizeof(psc724_eeprom), + .eeprom_data = psc724_eeprom, + }, + {} /*terminator*/ +}; diff --git a/sound/pci/ice1712/psc724.h b/sound/pci/ice1712/psc724.h new file mode 100644 index 00000000000..858e5fd0eeb --- /dev/null +++ b/sound/pci/ice1712/psc724.h @@ -0,0 +1,13 @@ +#ifndef __SOUND_PSC724_H +#define __SOUND_PSC724_H + +/* ID */ +#define PSC724_DEVICE_DESC \ + "{Philips,PSC724 Ultimate Edge}," + +#define VT1724_SUBDEVICE_PSC724 0xab170619 + +/* entry struct */ +extern struct snd_ice1712_card_info snd_vt1724_psc724_cards[]; + +#endif /* __SOUND_PSC724_H */ diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c index 1948632787e..2c2df4b74e0 100644 --- a/sound/pci/ice1712/quartet.c +++ b/sound/pci/ice1712/quartet.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -47,7 +46,7 @@ struct qtet_kcontrol_private { unsigned int bit; void (*set_register)(struct snd_ice1712 *ice, unsigned int val); unsigned int (*get_register)(struct snd_ice1712 *ice); - unsigned char *texts[2]; + unsigned char * const texts[2]; }; enum { @@ -63,7 +62,7 @@ enum { OUT34_MON12, }; -static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", +static const char * const ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", "Word Clock 256xFS"}; /* chip address on I2C bus */ @@ -204,6 +203,7 @@ static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", #define AK4620_DEEMVOL_REG 0x03 #define AK4620_SMUTE (1<<7) +#ifdef CONFIG_PROC_FS /* * Conversion from int value to its binary form. Used for debugging. * The output buffer must be allocated prior to calling the function. @@ -228,6 +228,7 @@ static char *get_binary(char *buffer, int value) buffer[pos] = '\0'; return buffer; } +#endif /* CONFIG_PROC_FS */ /* * Initial setup of the conversion array GPIO <-> rate @@ -279,7 +280,7 @@ static void qtet_akm_write(struct snd_akm4xxx *ak, int chip, if (snd_BUG_ON(chip < 0 || chip >= 4)) return; - /*printk(KERN_DEBUG "Writing to AK4620: chip=%d, addr=0x%x, + /*dev_dbg(ice->card->dev, "Writing to AK4620: chip=%d, addr=0x%x, data=0x%x\n", chip, addr, data);*/ orig_dir = ice->gpio.get_dir(ice); ice->gpio.set_dir(ice, orig_dir | GPIO_SPI_ALL); @@ -387,7 +388,7 @@ static const struct snd_akm4xxx_adc_channel qtet_adc[] = { AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), }; -static struct snd_akm4xxx akm_qtet_dac __devinitdata = { +static struct snd_akm4xxx akm_qtet_dac = { .type = SND_AK4620, .num_dacs = 4, /* DAC1 - Output 12 */ @@ -551,7 +552,8 @@ static int qtet_mute_put(struct snd_kcontrol *kcontrol, static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[3] = {"Line In 1/2", "Mic", "Mic + Low-cut"}; + static const char * const texts[3] = + {"Line In 1/2", "Mic", "Mic + Low-cut"}; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; uinfo->value.enumerated.items = ARRAY_SIZE(texts); @@ -758,7 +760,7 @@ static int qtet_sw_put(struct snd_kcontrol *kcontrol, .put = qtet_sw_put,\ .private_value = xpriv } -static struct snd_kcontrol_new qtet_controls[] __devinitdata = { +static struct snd_kcontrol_new qtet_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -795,17 +797,17 @@ static struct snd_kcontrol_new qtet_controls[] __devinitdata = { QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), }; -static char *slave_vols[] __devinitdata = { +static char *slave_vols[] = { PCM_12_PLAYBACK_VOLUME, PCM_34_PLAYBACK_VOLUME, NULL }; -static __devinitdata +static DECLARE_TLV_DB_SCALE(qtet_master_db_scale, -6350, 50, 1); -static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, - const char *name) +static struct snd_kcontrol *ctl_find(struct snd_card *card, + const char *name) { struct snd_ctl_elem_id sid; memset(&sid, 0, sizeof(sid)); @@ -815,8 +817,8 @@ static struct snd_kcontrol __devinit *ctl_find(struct snd_card *card, return snd_ctl_find_id(card, &sid); } -static void __devinit add_slaves(struct snd_card *card, - struct snd_kcontrol *master, char **list) +static void add_slaves(struct snd_card *card, + struct snd_kcontrol *master, char * const *list) { for (; *list; list++) { struct snd_kcontrol *slave = ctl_find(card, *list); @@ -825,7 +827,7 @@ static void __devinit add_slaves(struct snd_card *card, } } -static int __devinit qtet_add_controls(struct snd_ice1712 *ice) +static int qtet_add_controls(struct snd_ice1712 *ice) { struct qtet_spec *spec = ice->spec; int err, i; @@ -896,7 +898,7 @@ static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate) new = (get_cpld(ice) & ~CPLD_CKS_MASK) | get_cks_val(rate); /* switch to internal clock, drop CPLD_SYNC_SEL */ new &= ~CPLD_SYNC_SEL; - /* printk(KERN_DEBUG "QT - set_rate: old %x, new %x\n", + /* dev_dbg(ice->card->dev, "QT - set_rate: old %x, new %x\n", get_cpld(ice), new); */ set_cpld(ice, new); } @@ -976,7 +978,7 @@ static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0, c1) { /* only for SPDIF master mode, rate was changed */ rate = snd_ak4113_external_rate(ak4113); - /* printk(KERN_DEBUG "ak4113 - input rate changed to %d\n", + /* dev_dbg(ice->card->dev, "ak4113 - input rate changed to %d\n", rate); */ qtet_akm_set_rate_val(ice->akm, rate); } @@ -1007,7 +1009,7 @@ static void qtet_spdif_in_open(struct snd_ice1712 *ice, /* * initialize the chip */ -static int __devinit qtet_init(struct snd_ice1712 *ice) +static int qtet_init(struct snd_ice1712 *ice) { static const unsigned char ak4113_init_vals[] = { /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | @@ -1095,7 +1097,7 @@ static int __devinit qtet_init(struct snd_ice1712 *ice) return 0; } -static unsigned char qtet_eeprom[] __devinitdata = { +static unsigned char qtet_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, 1xDACs, SPDIF in */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ @@ -1116,7 +1118,7 @@ static unsigned char qtet_eeprom[] __devinitdata = { }; /* entry point */ -struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_qtet_cards[] = { { .subvendor = VT1724_SUBDEVICE_QTET, .name = "Infrasonic Quartet", diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c index b508bb360b9..1112ec1953b 100644 --- a/sound/pci/ice1712/revo.c +++ b/sound/pci/ice1712/revo.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -36,6 +35,7 @@ struct revo51_spec { struct snd_i2c_device *dev; struct snd_pt2258 *pt2258; + struct ak4114 *ak4114; }; static void revo_i2s_mclk_changed(struct snd_ice1712 *ice) @@ -235,7 +235,7 @@ static const struct snd_akm4xxx_adc_channel revo51_adc[] = { }, }; -static struct snd_akm4xxx akm_revo_front __devinitdata = { +static struct snd_akm4xxx akm_revo_front = { .type = SND_AK4381, .num_dacs = 2, .ops = { @@ -244,7 +244,7 @@ static struct snd_akm4xxx akm_revo_front __devinitdata = { .dac_info = revo71_front, }; -static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo_front_priv = { .caddr = 1, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -256,7 +256,7 @@ static struct snd_ak4xxx_private akm_revo_front_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo_surround __devinitdata = { +static struct snd_akm4xxx akm_revo_surround = { .type = SND_AK4355, .idx_offset = 1, .num_dacs = 6, @@ -266,7 +266,7 @@ static struct snd_akm4xxx akm_revo_surround __devinitdata = { .dac_info = revo71_surround, }; -static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo_surround_priv = { .caddr = 3, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -278,7 +278,7 @@ static struct snd_ak4xxx_private akm_revo_surround_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51 __devinitdata = { +static struct snd_akm4xxx akm_revo51 = { .type = SND_AK4358, .num_dacs = 8, .ops = { @@ -287,7 +287,7 @@ static struct snd_akm4xxx akm_revo51 __devinitdata = { .dac_info = revo51_dac, }; -static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo51_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -299,13 +299,13 @@ static struct snd_ak4xxx_private akm_revo51_priv __devinitdata = { .mask_flags = 0, }; -static struct snd_akm4xxx akm_revo51_adc __devinitdata = { +static struct snd_akm4xxx akm_revo51_adc = { .type = SND_AK5365, .num_adcs = 2, .adc_info = revo51_adc, }; -static struct snd_ak4xxx_private akm_revo51_adc_priv __devinitdata = { +static struct snd_ak4xxx_private akm_revo51_adc_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, @@ -346,7 +346,7 @@ static const struct snd_akm4xxx_dac_channel ap192_dac[] = { AK_DAC("PCM Playback Volume", 2) }; -static struct snd_akm4xxx akm_ap192 __devinitdata = { +static struct snd_akm4xxx akm_ap192 = { .type = SND_AK4358, .num_dacs = 2, .ops = { @@ -355,14 +355,14 @@ static struct snd_akm4xxx akm_ap192 __devinitdata = { .dac_info = ap192_dac, }; -static struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { +static struct snd_ak4xxx_private akm_ap192_priv = { .caddr = 2, .cif = 0, .data_mask = VT1724_REVO_CDOUT, .clk_mask = VT1724_REVO_CCLK, - .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS1, - .cs_addr = VT1724_REVO_CS1, - .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS1, + .cs_mask = VT1724_REVO_CS0 | VT1724_REVO_CS3, + .cs_addr = VT1724_REVO_CS3, + .cs_none = VT1724_REVO_CS0 | VT1724_REVO_CS3, .add_flags = VT1724_REVO_CCLK, /* high at init */ .mask_flags = 0, }; @@ -373,7 +373,7 @@ static struct snd_ak4xxx_private akm_ap192_priv __devinitdata = { * CCLK (pin 34) -- GPIO1 pin 51 (shared with AK4358) * CSN (pin 35) -- GPIO7 pin 59 */ -#define AK4114_ADDR 0x02 +#define AK4114_ADDR 0x00 static void write_data(struct snd_ice1712 *ice, unsigned int gpio, unsigned int data, int idx) @@ -427,7 +427,7 @@ static unsigned int ap192_4wire_start(struct snd_ice1712 *ice) tmp = snd_ice1712_gpio_read(ice); tmp |= VT1724_REVO_CCLK; /* high at init */ tmp |= VT1724_REVO_CS0; - tmp &= ~VT1724_REVO_CS1; + tmp &= ~VT1724_REVO_CS3; snd_ice1712_gpio_write(ice, tmp); udelay(1); return tmp; @@ -435,7 +435,7 @@ static unsigned int ap192_4wire_start(struct snd_ice1712 *ice) static void ap192_4wire_finish(struct snd_ice1712 *ice, unsigned int tmp) { - tmp |= VT1724_REVO_CS1; + tmp |= VT1724_REVO_CS3; tmp |= VT1724_REVO_CS0; snd_ice1712_gpio_write(ice, tmp); udelay(1); @@ -468,35 +468,40 @@ static unsigned char ap192_ak4114_read(void *private_data, unsigned char addr) return data; } -static int __devinit ap192_ak4114_init(struct snd_ice1712 *ice) +static int ap192_ak4114_init(struct snd_ice1712 *ice) { static const unsigned char ak4114_init_vals[] = { - AK4114_RST | AK4114_PWN | AK4114_OCKS0 | AK4114_OCKS1, + AK4114_RST | AK4114_PWN | AK4114_OCKS0, AK4114_DIF_I24I2S, AK4114_TX1E, - AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(1), + AK4114_EFH_1024 | AK4114_DIT | AK4114_IPS(0), 0, 0 }; static const unsigned char ak4114_init_txcsb[] = { 0x41, 0x02, 0x2c, 0x00, 0x00 }; - struct ak4114 *ak; int err; + struct revo51_spec *spec; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + ice->spec = spec; + err = snd_ak4114_create(ice->card, ap192_ak4114_read, ap192_ak4114_write, ak4114_init_vals, ak4114_init_txcsb, - ice, &ak); + ice, &spec->ak4114); /* AK4114 in Revo cannot detect external rate correctly. * No reason to stop capture stream due to incorrect checks */ - ak->check_flags = AK4114_CHECK_NO_RATE; + spec->ak4114->check_flags = AK4114_CHECK_NO_RATE; return 0; /* error ignored; it's no fatal error */ } -static int __devinit revo_init(struct snd_ice1712 *ice) +static int revo_init(struct snd_ice1712 *ice) { struct snd_akm4xxx *ak; int err; @@ -563,6 +568,9 @@ static int __devinit revo_init(struct snd_ice1712 *ice) ice); if (err < 0) return err; + err = ap192_ak4114_init(ice); + if (err < 0) + return err; /* unmute all codecs */ snd_ice1712_gpio_write_bits(ice, VT1724_REVO_MUTE, @@ -574,9 +582,9 @@ static int __devinit revo_init(struct snd_ice1712 *ice) } -static int __devinit revo_add_controls(struct snd_ice1712 *ice) +static int revo_add_controls(struct snd_ice1712 *ice) { - struct revo51_spec *spec; + struct revo51_spec *spec = ice->spec; int err; switch (ice->eeprom.subvendor) { @@ -598,7 +606,9 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) err = snd_ice1712_akm4xxx_build_controls(ice); if (err < 0) return err; - err = ap192_ak4114_init(ice); + /* only capture SPDIF over AK4114 */ + err = snd_ak4114_build(spec->ak4114, NULL, + ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); if (err < 0) return err; break; @@ -607,7 +617,7 @@ static int __devinit revo_add_controls(struct snd_ice1712 *ice) } /* entry point */ -struct snd_ice1712_card_info snd_vt1724_revo_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_revo_cards[] = { { .subvendor = VT1724_SUBDEVICE_REVOLUTION71, .name = "M Audio Revolution-7.1", diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c index 69673b95869..ffd894bb450 100644 --- a/sound/pci/ice1712/se.c +++ b/sound/pci/ice1712/se.c @@ -22,7 +22,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -114,7 +113,7 @@ struct se_spec { /* WM8740 interface */ /****************************************************************************/ -static void __devinit se200pci_WM8740_init(struct snd_ice1712 *ice) +static void se200pci_WM8740_init(struct snd_ice1712 *ice) { /* nothing to do */ } @@ -196,7 +195,7 @@ static void se200pci_WM8766_set_volume(struct snd_ice1712 *ice, int ch, } } -static void __devinit se200pci_WM8766_init(struct snd_ice1712 *ice) +static void se200pci_WM8766_init(struct snd_ice1712 *ice) { se200pci_WM8766_write(ice, 0x1f, 0x000); /* RESET ALL */ udelay(10); @@ -253,7 +252,7 @@ static void se200pci_WM8776_set_input_volume(struct snd_ice1712 *ice, se200pci_WM8776_write(ice, 0x0f, vol2 | 0x100); } -static const char *se200pci_sel[] = { +static const char * const se200pci_sel[] = { "LINE-IN", "CD-IN", "MIC-IN", "ALL-MIX", NULL }; @@ -278,7 +277,7 @@ static void se200pci_WM8776_set_afl(struct snd_ice1712 *ice, unsigned int afl) se200pci_WM8776_write(ice, 0x16, 0x001); } -static const char *se200pci_agc[] = { +static const char * const se200pci_agc[] = { "Off", "LimiterMode", "ALCMode", NULL }; @@ -300,10 +299,10 @@ static void se200pci_WM8776_set_agc(struct snd_ice1712 *ice, unsigned int agc) } } -static void __devinit se200pci_WM8776_init(struct snd_ice1712 *ice) +static void se200pci_WM8776_init(struct snd_ice1712 *ice) { int i; - static unsigned short __devinitdata default_values[] = { + static unsigned short default_values[] = { 0x100, 0x100, 0x100, 0x100, 0x100, 0x100, 0x000, 0x090, 0x000, 0x000, @@ -352,7 +351,7 @@ static void se200pci_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate) } struct se200pci_control { - char *name; + const char *name; enum { WM8766, WM8776in, @@ -363,7 +362,7 @@ struct se200pci_control { } target; enum { VOLUME1, VOLUME2, BOOLEAN, ENUM } type; int ch; - const char **member; + const char * const *member; const char *comment; }; @@ -421,7 +420,7 @@ static const struct se200pci_control se200pci_cont[] = { static int se200pci_get_enum_count(int n) { - const char **member; + const char * const *member; int c; member = se200pci_cont[n].member; @@ -600,7 +599,7 @@ static int se200pci_cont_enum_put(struct snd_kcontrol *kc, static const DECLARE_TLV_DB_SCALE(db_scale_gain1, -12750, 50, 1); static const DECLARE_TLV_DB_SCALE(db_scale_gain2, -10350, 50, 1); -static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) +static int se200pci_add_controls(struct snd_ice1712 *ice) { int i; struct snd_kcontrol_new cont; @@ -678,7 +677,7 @@ static int __devinit se200pci_add_controls(struct snd_ice1712 *ice) /* probe/initialize/setup */ /****************************************************************************/ -static int __devinit se_init(struct snd_ice1712 *ice) +static int se_init(struct snd_ice1712 *ice) { struct se_spec *spec; @@ -706,7 +705,7 @@ static int __devinit se_init(struct snd_ice1712 *ice) return -ENOENT; } -static int __devinit se_add_controls(struct snd_ice1712 *ice) +static int se_add_controls(struct snd_ice1712 *ice) { int err; @@ -723,7 +722,7 @@ static int __devinit se_add_controls(struct snd_ice1712 *ice) /* entry point */ /****************************************************************************/ -static unsigned char se200pci_eeprom[] __devinitdata = { +static unsigned char se200pci_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ @@ -742,7 +741,7 @@ static unsigned char se200pci_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x07, /* WM8766 ML/MC/MD */ }; -static unsigned char se90pci_eeprom[] __devinitdata = { +static unsigned char se90pci_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x4b, /* 49.152Hz, spdif-in/ADC, 4DACs */ [ICE_EEP2_ACLINK] = 0x80, /* I2S */ [ICE_EEP2_I2S] = 0x78, /* 96k-ok, 24bit, 192k-ok */ @@ -751,7 +750,7 @@ static unsigned char se90pci_eeprom[] __devinitdata = { /* ALL GPIO bits are in input mode */ }; -struct snd_ice1712_card_info snd_vt1724_se_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_se_cards[] = { { .subvendor = VT1724_SUBDEVICE_SE200PCI, .name = "ONKYO SE200PCI", diff --git a/sound/pci/ice1712/vt1720_mobo.c b/sound/pci/ice1712/vt1720_mobo.c index 4c551e147c0..5dbb867e642 100644 --- a/sound/pci/ice1712/vt1720_mobo.c +++ b/sound/pci/ice1712/vt1720_mobo.c @@ -21,7 +21,6 @@ * */ -#include <asm/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -32,7 +31,7 @@ #include "vt1720_mobo.h" -static int __devinit k8x800_init(struct snd_ice1712 *ice) +static int k8x800_init(struct snd_ice1712 *ice) { ice->vt1720 = 1; @@ -46,7 +45,7 @@ static int __devinit k8x800_init(struct snd_ice1712 *ice) return 0; } -static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) +static int k8x800_add_controls(struct snd_ice1712 *ice) { /* FIXME: needs some quirks for VT1616? */ return 0; @@ -54,7 +53,7 @@ static int __devinit k8x800_add_controls(struct snd_ice1712 *ice) /* EEPROM image */ -static unsigned char k8x800_eeprom[] __devinitdata = { +static unsigned char k8x800_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -70,7 +69,7 @@ static unsigned char k8x800_eeprom[] __devinitdata = { [ICE_EEP2_GPIO_STATE2] = 0x00, /* - */ }; -static unsigned char sn25p_eeprom[] __devinitdata = { +static unsigned char sn25p_eeprom[] = { [ICE_EEP2_SYSCONF] = 0x01, /* clock 256, 1ADC, 2DACs */ [ICE_EEP2_ACLINK] = 0x02, /* ACLINK, packed */ [ICE_EEP2_I2S] = 0x00, /* - */ @@ -88,7 +87,7 @@ static unsigned char sn25p_eeprom[] __devinitdata = { /* entry point */ -struct snd_ice1712_card_info snd_vt1720_mobo_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1720_mobo_cards[] = { { .subvendor = VT1720_SUBDEVICE_K8X800, .name = "Albatron K8X800 Pro II", diff --git a/sound/pci/ice1712/wm8766.c b/sound/pci/ice1712/wm8766.c new file mode 100644 index 00000000000..21b373b2e26 --- /dev/null +++ b/sound/pci/ice1712/wm8766.c @@ -0,0 +1,362 @@ +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8766 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/tlv.h> +#include "wm8766.h" + +/* low-level access */ + +static void snd_wm8766_write(struct snd_wm8766 *wm, u16 addr, u16 data) +{ + if (addr < WM8766_REG_COUNT) + wm->regs[addr] = data; + wm->ops.write(wm, addr, data); +} + +/* mixer controls */ + +static const DECLARE_TLV_DB_SCALE(wm8766_tlv, -12750, 50, 1); + +static struct snd_wm8766_ctl snd_wm8766_default_ctl[WM8766_CTL_COUNT] = { + [WM8766_CTL_CH1_VOL] = { + .name = "Channel 1 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL1, + .reg2 = WM8766_REG_DACR1, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH2_VOL] = { + .name = "Channel 2 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL2, + .reg2 = WM8766_REG_DACR2, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH3_VOL] = { + .name = "Channel 3 Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8766_tlv, + .reg1 = WM8766_REG_DACL3, + .reg2 = WM8766_REG_DACR3, + .mask1 = WM8766_VOL_MASK, + .mask2 = WM8766_VOL_MASK, + .max = 0xff, + .flags = WM8766_FLAG_STEREO | WM8766_FLAG_VOL_UPDATE, + }, + [WM8766_CTL_CH1_SW] = { + .name = "Channel 1 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE1, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_CH2_SW] = { + .name = "Channel 2 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE2, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_CH3_SW] = { + .name = "Channel 3 Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_MUTE3, + .flags = WM8766_FLAG_INVERT, + }, + [WM8766_CTL_PHASE1_SW] = { + .name = "Channel 1 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT1, + }, + [WM8766_CTL_PHASE2_SW] = { + .name = "Channel 2 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT2, + }, + [WM8766_CTL_PHASE3_SW] = { + .name = "Channel 3 Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_IFCTRL, + .mask1 = WM8766_PHASE_INVERT3, + }, + [WM8766_CTL_DEEMPH1_SW] = { + .name = "Channel 1 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP1, + }, + [WM8766_CTL_DEEMPH2_SW] = { + .name = "Channel 2 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP2, + }, + [WM8766_CTL_DEEMPH3_SW] = { + .name = "Channel 3 Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_DEEMP3, + }, + [WM8766_CTL_IZD_SW] = { + .name = "Infinite Zero Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL1, + .mask1 = WM8766_DAC_IZD, + }, + [WM8766_CTL_ZC_SW] = { + .name = "Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8766_REG_DACCTRL2, + .mask1 = WM8766_DAC2_ZCD, + .flags = WM8766_FLAG_INVERT, + }, +}; + +/* exported functions */ + +void snd_wm8766_init(struct snd_wm8766 *wm) +{ + int i; + static const u16 default_values[] = { + 0x000, 0x100, + 0x120, 0x000, + 0x000, 0x100, 0x000, 0x100, 0x000, + 0x000, 0x080, + }; + + memcpy(wm->ctl, snd_wm8766_default_ctl, sizeof(wm->ctl)); + + snd_wm8766_write(wm, WM8766_REG_RESET, 0x00); /* reset */ + udelay(10); + /* load defaults */ + for (i = 0; i < ARRAY_SIZE(default_values); i++) + snd_wm8766_write(wm, i, default_values[i]); +} + +void snd_wm8766_resume(struct snd_wm8766 *wm) +{ + int i; + + for (i = 0; i < WM8766_REG_COUNT; i++) + snd_wm8766_write(wm, i, wm->regs[i]); +} + +void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac) +{ + u16 val = wm->regs[WM8766_REG_IFCTRL] & ~WM8766_IF_MASK; + + dac &= WM8766_IF_MASK; + snd_wm8766_write(wm, WM8766_REG_IFCTRL, val | dac); +} + +void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode) +{ + u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_MSTR_MASK; + + mode &= WM8766_DAC3_MSTR_MASK; + snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | mode); +} + +void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power) +{ + u16 val = wm->regs[WM8766_REG_DACCTRL3] & ~WM8766_DAC3_POWER_MASK; + + power &= WM8766_DAC3_POWER_MASK; + snd_wm8766_write(wm, WM8766_REG_DACCTRL3, val | power); +} + +void snd_wm8766_volume_restore(struct snd_wm8766 *wm) +{ + u16 val = wm->regs[WM8766_REG_DACR1]; + /* restore volume after MCLK stopped */ + snd_wm8766_write(wm, WM8766_REG_DACR1, val | WM8766_VOL_UPDATE); +} + +/* mixer callbacks */ + +static int snd_wm8766_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (wm->ctl[n].flags & WM8766_FLAG_STEREO) ? 2 : 1; + uinfo->value.integer.min = wm->ctl[n].min; + uinfo->value.integer.max = wm->ctl[n].max; + + return 0; +} + +static int snd_wm8766_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, + wm->ctl[n].enum_names); +} + +static int snd_wm8766_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val1, val2; + + if (wm->ctl[n].get) + wm->ctl[n].get(wm, &val1, &val2); + else { + val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; + val1 >>= __ffs(wm->ctl[n].mask1); + if (wm->ctl[n].flags & WM8766_FLAG_STEREO) { + val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; + val2 >>= __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) + val2 &= ~WM8766_VOL_UPDATE; + } + } + if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { + val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); + if (wm->ctl[n].flags & WM8766_FLAG_STEREO) + val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); + } + ucontrol->value.integer.value[0] = val1; + if (wm->ctl[n].flags & WM8766_FLAG_STEREO) + ucontrol->value.integer.value[1] = val2; + + return 0; +} + +static int snd_wm8766_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8766 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val, regval1, regval2; + + /* this also works for enum because value is an union */ + regval1 = ucontrol->value.integer.value[0]; + regval2 = ucontrol->value.integer.value[1]; + if (wm->ctl[n].flags & WM8766_FLAG_INVERT) { + regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); + regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); + } + if (wm->ctl[n].set) + wm->ctl[n].set(wm, regval1, regval2); + else { + val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; + val |= regval1 << __ffs(wm->ctl[n].mask1); + /* both stereo controls in one register */ + if (wm->ctl[n].flags & WM8766_FLAG_STEREO && + wm->ctl[n].reg1 == wm->ctl[n].reg2) { + val &= ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + } + snd_wm8766_write(wm, wm->ctl[n].reg1, val); + /* stereo controls in different registers */ + if (wm->ctl[n].flags & WM8766_FLAG_STEREO && + wm->ctl[n].reg1 != wm->ctl[n].reg2) { + val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8766_FLAG_VOL_UPDATE) + val |= WM8766_VOL_UPDATE; + snd_wm8766_write(wm, wm->ctl[n].reg2, val); + } + } + + return 0; +} + +static int snd_wm8766_add_control(struct snd_wm8766 *wm, int num) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cont.private_value = num; + cont.name = wm->ctl[num].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (wm->ctl[num].flags & WM8766_FLAG_LIM || + wm->ctl[num].flags & WM8766_FLAG_ALC) + cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + cont.tlv.p = NULL; + cont.get = snd_wm8766_ctl_get; + cont.put = snd_wm8766_ctl_put; + + switch (wm->ctl[num].type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + cont.info = snd_wm8766_volume_info; + cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + cont.tlv.p = wm->ctl[num].tlv; + break; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + wm->ctl[num].max = 1; + if (wm->ctl[num].flags & WM8766_FLAG_STEREO) + cont.info = snd_ctl_boolean_stereo_info; + else + cont.info = snd_ctl_boolean_mono_info; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + cont.info = snd_wm8766_enum_info; + break; + default: + return -EINVAL; + } + ctl = snd_ctl_new1(&cont, wm); + if (!ctl) + return -ENOMEM; + wm->ctl[num].kctl = ctl; + + return snd_ctl_add(wm->card, ctl); +} + +int snd_wm8766_build_controls(struct snd_wm8766 *wm) +{ + int err, i; + + for (i = 0; i < WM8766_CTL_COUNT; i++) + if (wm->ctl[i].name) { + err = snd_wm8766_add_control(wm, i); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/pci/ice1712/wm8766.h b/sound/pci/ice1712/wm8766.h new file mode 100644 index 00000000000..c119f84bd2c --- /dev/null +++ b/sound/pci/ice1712/wm8766.h @@ -0,0 +1,163 @@ +#ifndef __SOUND_WM8766_H +#define __SOUND_WM8766_H + +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8766 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define WM8766_REG_DACL1 0x00 +#define WM8766_REG_DACR1 0x01 +#define WM8766_VOL_MASK 0x1ff /* incl. update bit */ +#define WM8766_VOL_UPDATE (1 << 8) /* update volume */ +#define WM8766_REG_DACCTRL1 0x02 +#define WM8766_DAC_MUTEALL (1 << 0) +#define WM8766_DAC_DEEMPALL (1 << 1) +#define WM8766_DAC_PDWN (1 << 2) +#define WM8766_DAC_ATC (1 << 3) +#define WM8766_DAC_IZD (1 << 4) +#define WM8766_DAC_PL_MASK 0x1e0 +#define WM8766_DAC_PL_LL (1 << 5) /* L chan: L signal */ +#define WM8766_DAC_PL_LR (2 << 5) /* L chan: R signal */ +#define WM8766_DAC_PL_LB (3 << 5) /* L chan: both */ +#define WM8766_DAC_PL_RL (1 << 7) /* R chan: L signal */ +#define WM8766_DAC_PL_RR (2 << 7) /* R chan: R signal */ +#define WM8766_DAC_PL_RB (3 << 7) /* R chan: both */ +#define WM8766_REG_IFCTRL 0x03 +#define WM8766_IF_FMT_RIGHTJ (0 << 0) +#define WM8766_IF_FMT_LEFTJ (1 << 0) +#define WM8766_IF_FMT_I2S (2 << 0) +#define WM8766_IF_FMT_DSP (3 << 0) +#define WM8766_IF_DSP_LATE (1 << 2) /* in DSP mode */ +#define WM8766_IF_LRC_INVERTED (1 << 2) /* in other modes */ +#define WM8766_IF_BCLK_INVERTED (1 << 3) +#define WM8766_IF_IWL_16BIT (0 << 4) +#define WM8766_IF_IWL_20BIT (1 << 4) +#define WM8766_IF_IWL_24BIT (2 << 4) +#define WM8766_IF_IWL_32BIT (3 << 4) +#define WM8766_IF_MASK 0x3f +#define WM8766_PHASE_INVERT1 (1 << 6) +#define WM8766_PHASE_INVERT2 (1 << 7) +#define WM8766_PHASE_INVERT3 (1 << 8) +#define WM8766_REG_DACL2 0x04 +#define WM8766_REG_DACR2 0x05 +#define WM8766_REG_DACL3 0x06 +#define WM8766_REG_DACR3 0x07 +#define WM8766_REG_MASTDA 0x08 +#define WM8766_REG_DACCTRL2 0x09 +#define WM8766_DAC2_ZCD (1 << 0) +#define WM8766_DAC2_ZFLAG_ALL (0 << 1) +#define WM8766_DAC2_ZFLAG_1 (1 << 1) +#define WM8766_DAC2_ZFLAG_2 (2 << 1) +#define WM8766_DAC2_ZFLAG_3 (3 << 1) +#define WM8766_DAC2_MUTE1 (1 << 3) +#define WM8766_DAC2_MUTE2 (1 << 4) +#define WM8766_DAC2_MUTE3 (1 << 5) +#define WM8766_DAC2_DEEMP1 (1 << 6) +#define WM8766_DAC2_DEEMP2 (1 << 7) +#define WM8766_DAC2_DEEMP3 (1 << 8) +#define WM8766_REG_DACCTRL3 0x0a +#define WM8766_DAC3_DACPD1 (1 << 1) +#define WM8766_DAC3_DACPD2 (1 << 2) +#define WM8766_DAC3_DACPD3 (1 << 3) +#define WM8766_DAC3_PWRDNALL (1 << 4) +#define WM8766_DAC3_POWER_MASK 0x1e +#define WM8766_DAC3_MASTER (1 << 5) +#define WM8766_DAC3_DAC128FS (0 << 6) +#define WM8766_DAC3_DAC192FS (1 << 6) +#define WM8766_DAC3_DAC256FS (2 << 6) +#define WM8766_DAC3_DAC384FS (3 << 6) +#define WM8766_DAC3_DAC512FS (4 << 6) +#define WM8766_DAC3_DAC768FS (5 << 6) +#define WM8766_DAC3_MSTR_MASK 0x1e0 +#define WM8766_REG_MUTE1 0x0c +#define WM8766_MUTE1_MPD (1 << 6) +#define WM8766_REG_MUTE2 0x0f +#define WM8766_MUTE2_MPD (1 << 5) +#define WM8766_REG_RESET 0x1f + +#define WM8766_REG_COUNT 0x10 /* don't cache the RESET register */ + +struct snd_wm8766; + +struct snd_wm8766_ops { + void (*write)(struct snd_wm8766 *wm, u16 addr, u16 data); +}; + +enum snd_wm8766_ctl_id { + WM8766_CTL_CH1_VOL, + WM8766_CTL_CH2_VOL, + WM8766_CTL_CH3_VOL, + WM8766_CTL_CH1_SW, + WM8766_CTL_CH2_SW, + WM8766_CTL_CH3_SW, + WM8766_CTL_PHASE1_SW, + WM8766_CTL_PHASE2_SW, + WM8766_CTL_PHASE3_SW, + WM8766_CTL_DEEMPH1_SW, + WM8766_CTL_DEEMPH2_SW, + WM8766_CTL_DEEMPH3_SW, + WM8766_CTL_IZD_SW, + WM8766_CTL_ZC_SW, + + WM8766_CTL_COUNT, +}; + +#define WM8766_ENUM_MAX 16 + +#define WM8766_FLAG_STEREO (1 << 0) +#define WM8766_FLAG_VOL_UPDATE (1 << 1) +#define WM8766_FLAG_INVERT (1 << 2) +#define WM8766_FLAG_LIM (1 << 3) +#define WM8766_FLAG_ALC (1 << 4) + +struct snd_wm8766_ctl { + struct snd_kcontrol *kctl; + const char *name; + snd_ctl_elem_type_t type; + const char *const enum_names[WM8766_ENUM_MAX]; + const unsigned int *tlv; + u16 reg1, reg2, mask1, mask2, min, max, flags; + void (*set)(struct snd_wm8766 *wm, u16 ch1, u16 ch2); + void (*get)(struct snd_wm8766 *wm, u16 *ch1, u16 *ch2); +}; + +enum snd_wm8766_agc_mode { WM8766_AGC_OFF, WM8766_AGC_LIM, WM8766_AGC_ALC }; + +struct snd_wm8766 { + struct snd_card *card; + struct snd_wm8766_ctl ctl[WM8766_CTL_COUNT]; + enum snd_wm8766_agc_mode agc_mode; + struct snd_wm8766_ops ops; + u16 regs[WM8766_REG_COUNT]; /* 9-bit registers */ +}; + + + +void snd_wm8766_init(struct snd_wm8766 *wm); +void snd_wm8766_resume(struct snd_wm8766 *wm); +void snd_wm8766_set_if(struct snd_wm8766 *wm, u16 dac); +void snd_wm8766_set_master_mode(struct snd_wm8766 *wm, u16 mode); +void snd_wm8766_set_power(struct snd_wm8766 *wm, u16 power); +void snd_wm8766_volume_restore(struct snd_wm8766 *wm); +int snd_wm8766_build_controls(struct snd_wm8766 *wm); + +#endif /* __SOUND_WM8766_H */ diff --git a/sound/pci/ice1712/wm8776.c b/sound/pci/ice1712/wm8776.c new file mode 100644 index 00000000000..e66c0da6201 --- /dev/null +++ b/sound/pci/ice1712/wm8776.c @@ -0,0 +1,634 @@ +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8776 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <linux/delay.h> +#include <sound/core.h> +#include <sound/control.h> +#include <sound/tlv.h> +#include "wm8776.h" + +/* low-level access */ + +static void snd_wm8776_write(struct snd_wm8776 *wm, u16 addr, u16 data) +{ + u8 bus_addr = addr << 1 | data >> 8; /* addr + 9th data bit */ + u8 bus_data = data & 0xff; /* remaining 8 data bits */ + + if (addr < WM8776_REG_RESET) + wm->regs[addr] = data; + wm->ops.write(wm, bus_addr, bus_data); +} + +/* register-level functions */ + +static void snd_wm8776_activate_ctl(struct snd_wm8776 *wm, + const char *ctl_name, + bool active) +{ + struct snd_card *card = wm->card; + struct snd_kcontrol *kctl; + struct snd_kcontrol_volatile *vd; + struct snd_ctl_elem_id elem_id; + unsigned int index_offset; + + memset(&elem_id, 0, sizeof(elem_id)); + strlcpy(elem_id.name, ctl_name, sizeof(elem_id.name)); + elem_id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kctl = snd_ctl_find_id(card, &elem_id); + if (!kctl) + return; + index_offset = snd_ctl_get_ioff(kctl, &kctl->id); + vd = &kctl->vd[index_offset]; + if (active) + vd->access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + else + vd->access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &kctl->id); +} + +static void snd_wm8776_update_agc_ctl(struct snd_wm8776 *wm) +{ + int i, flags_on = 0, flags_off = 0; + + switch (wm->agc_mode) { + case WM8776_AGC_OFF: + flags_off = WM8776_FLAG_LIM | WM8776_FLAG_ALC; + break; + case WM8776_AGC_LIM: + flags_off = WM8776_FLAG_ALC; + flags_on = WM8776_FLAG_LIM; + break; + case WM8776_AGC_ALC_R: + case WM8776_AGC_ALC_L: + case WM8776_AGC_ALC_STEREO: + flags_off = WM8776_FLAG_LIM; + flags_on = WM8776_FLAG_ALC; + break; + } + + for (i = 0; i < WM8776_CTL_COUNT; i++) + if (wm->ctl[i].flags & flags_off) + snd_wm8776_activate_ctl(wm, wm->ctl[i].name, false); + else if (wm->ctl[i].flags & flags_on) + snd_wm8776_activate_ctl(wm, wm->ctl[i].name, true); +} + +static void snd_wm8776_set_agc(struct snd_wm8776 *wm, u16 agc, u16 nothing) +{ + u16 alc1 = wm->regs[WM8776_REG_ALCCTRL1] & ~WM8776_ALC1_LCT_MASK; + u16 alc2 = wm->regs[WM8776_REG_ALCCTRL2] & ~WM8776_ALC2_LCEN; + + switch (agc) { + case 0: /* Off */ + wm->agc_mode = WM8776_AGC_OFF; + break; + case 1: /* Limiter */ + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_LIM; + break; + case 2: /* ALC Right */ + alc1 |= WM8776_ALC1_LCSEL_ALCR; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_R; + break; + case 3: /* ALC Left */ + alc1 |= WM8776_ALC1_LCSEL_ALCL; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_L; + break; + case 4: /* ALC Stereo */ + alc1 |= WM8776_ALC1_LCSEL_ALCSTEREO; + alc2 |= WM8776_ALC2_LCEN; + wm->agc_mode = WM8776_AGC_ALC_STEREO; + break; + } + snd_wm8776_write(wm, WM8776_REG_ALCCTRL1, alc1); + snd_wm8776_write(wm, WM8776_REG_ALCCTRL2, alc2); + snd_wm8776_update_agc_ctl(wm); +} + +static void snd_wm8776_get_agc(struct snd_wm8776 *wm, u16 *mode, u16 *nothing) +{ + *mode = wm->agc_mode; +} + +/* mixer controls */ + +static const DECLARE_TLV_DB_SCALE(wm8776_hp_tlv, -7400, 100, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_dac_tlv, -12750, 50, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_adc_tlv, -10350, 50, 1); +static const DECLARE_TLV_DB_SCALE(wm8776_lct_tlv, -1600, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_tlv, 0, 400, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_ngth_tlv, -7800, 600, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_tlv, -1200, 100, 0); +static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_tlv, -2100, 400, 0); + +static struct snd_wm8776_ctl snd_wm8776_default_ctl[WM8776_CTL_COUNT] = { + [WM8776_CTL_DAC_VOL] = { + .name = "Master Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_dac_tlv, + .reg1 = WM8776_REG_DACLVOL, + .reg2 = WM8776_REG_DACRVOL, + .mask1 = WM8776_DACVOL_MASK, + .mask2 = WM8776_DACVOL_MASK, + .max = 0xff, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_DAC_SW] = { + .name = "Master Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .reg2 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_PL_LL, + .mask2 = WM8776_DAC_PL_RR, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_DAC_ZC_SW] = { + .name = "Master Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_DZCEN, + }, + [WM8776_CTL_HP_VOL] = { + .name = "Headphone Playback Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_hp_tlv, + .reg1 = WM8776_REG_HPLVOL, + .reg2 = WM8776_REG_HPRVOL, + .mask1 = WM8776_HPVOL_MASK, + .mask2 = WM8776_HPVOL_MASK, + .min = 0x2f, + .max = 0x7f, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_HP_SW] = { + .name = "Headphone Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_PWRDOWN, + .mask1 = WM8776_PWR_HPPD, + .flags = WM8776_FLAG_INVERT, + }, + [WM8776_CTL_HP_ZC_SW] = { + .name = "Headphone Zero Cross Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_HPLVOL, + .reg2 = WM8776_REG_HPRVOL, + .mask1 = WM8776_VOL_HPZCEN, + .mask2 = WM8776_VOL_HPZCEN, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_AUX_SW] = { + .name = "AUX Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_OUTMUX, + .mask1 = WM8776_OUTMUX_AUX, + }, + [WM8776_CTL_BYPASS_SW] = { + .name = "Bypass Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_OUTMUX, + .mask1 = WM8776_OUTMUX_BYPASS, + }, + [WM8776_CTL_DAC_IZD_SW] = { + .name = "Infinite Zero Detect Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL1, + .mask1 = WM8776_DAC_IZD, + }, + [WM8776_CTL_PHASE_SW] = { + .name = "Phase Invert Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_PHASESWAP, + .reg2 = WM8776_REG_PHASESWAP, + .mask1 = WM8776_PHASE_INVERTL, + .mask2 = WM8776_PHASE_INVERTR, + .flags = WM8776_FLAG_STEREO, + }, + [WM8776_CTL_DEEMPH_SW] = { + .name = "Deemphasis Playback Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_DACCTRL2, + .mask1 = WM8776_DAC2_DEEMPH, + }, + [WM8776_CTL_ADC_VOL] = { + .name = "Input Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_adc_tlv, + .reg1 = WM8776_REG_ADCLVOL, + .reg2 = WM8776_REG_ADCRVOL, + .mask1 = WM8776_ADC_GAIN_MASK, + .mask2 = WM8776_ADC_GAIN_MASK, + .max = 0xff, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_VOL_UPDATE, + }, + [WM8776_CTL_ADC_SW] = { + .name = "Input Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .reg2 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUTEL, + .mask2 = WM8776_ADC_MUTER, + .flags = WM8776_FLAG_STEREO | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_INPUT1_SW] = { + .name = "AIN1 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN1, + }, + [WM8776_CTL_INPUT2_SW] = { + .name = "AIN2 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN2, + }, + [WM8776_CTL_INPUT3_SW] = { + .name = "AIN3 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN3, + }, + [WM8776_CTL_INPUT4_SW] = { + .name = "AIN4 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN4, + }, + [WM8776_CTL_INPUT5_SW] = { + .name = "AIN5 Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_ADCMUX, + .mask1 = WM8776_ADC_MUX_AIN5, + }, + [WM8776_CTL_AGC_SEL] = { + .name = "AGC Select Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "Off", "Limiter", "ALC Right", "ALC Left", + "ALC Stereo" }, + .max = 5, /* .enum_names item count */ + .set = snd_wm8776_set_agc, + .get = snd_wm8776_get_agc, + }, + [WM8776_CTL_LIM_THR] = { + .name = "Limiter Threshold Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_lct_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_LCT_MASK, + .max = 15, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_ATK] = { + .name = "Limiter Attack Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0.25 ms", "0.5 ms", "1 ms", "2 ms", "4 ms", + "8 ms", "16 ms", "32 ms", "64 ms", "128 ms", "256 ms" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_ATK_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_DCY] = { + .name = "Limiter Decay Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", + "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", "307 ms", + "614 ms", "1.23 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_DCY_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_TRANWIN] = { + .name = "Limiter Transient Window Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0 us", "62.5 us", "125 us", "250 us", "500 us", + "1 ms", "2 ms", "4 ms" }, + .max = 8, /* .enum_names item count */ + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_TRANWIN_MASK, + .flags = WM8776_FLAG_LIM, + }, + [WM8776_CTL_LIM_MAXATTN] = { + .name = "Limiter Maximum Attenuation Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxatten_lim_tlv, + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_MAXATTEN_MASK, + .min = 3, + .max = 12, + .flags = WM8776_FLAG_LIM | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_ALC_TGT] = { + .name = "ALC Target Level Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_lct_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_LCT_MASK, + .max = 15, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_ATK] = { + .name = "ALC Attack Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", + "134 ms", "269 ms", "538 ms", "1.08 s", "2.15 s", + "4.3 s", "8.6 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_ATK_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_DCY] = { + .name = "ALC Decay Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "33.5 ms", "67.0 ms", "134 ms", "268 ms", + "536 ms", "1.07 s", "2.14 s", "4.29 s", "8.58 s", + "17.2 s", "34.3 s" }, + .max = 11, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL3, + .mask1 = WM8776_ALC3_DCY_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_MAXGAIN] = { + .name = "ALC Maximum Gain Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxgain_tlv, + .reg1 = WM8776_REG_ALCCTRL1, + .mask1 = WM8776_ALC1_MAXGAIN_MASK, + .min = 1, + .max = 7, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_ALC_MAXATTN] = { + .name = "ALC Maximum Attenuation Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_maxatten_alc_tlv, + .reg1 = WM8776_REG_LIMITER, + .mask1 = WM8776_LIM_MAXATTEN_MASK, + .min = 10, + .max = 15, + .flags = WM8776_FLAG_ALC | WM8776_FLAG_INVERT, + }, + [WM8776_CTL_ALC_HLD] = { + .name = "ALC Hold Time Capture Enum", + .type = SNDRV_CTL_ELEM_TYPE_ENUMERATED, + .enum_names = { "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", + "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", "341 ms", + "683 ms", "1.37 s", "2.73 s", "5.46 s", "10.9 s", + "21.8 s", "43.7 s" }, + .max = 16, /* .enum_names item count */ + .reg1 = WM8776_REG_ALCCTRL2, + .mask1 = WM8776_ALC2_HOLD_MASK, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_NGT_SW] = { + .name = "Noise Gate Capture Switch", + .type = SNDRV_CTL_ELEM_TYPE_BOOLEAN, + .reg1 = WM8776_REG_NOISEGATE, + .mask1 = WM8776_NGAT_ENABLE, + .flags = WM8776_FLAG_ALC, + }, + [WM8776_CTL_NGT_THR] = { + .name = "Noise Gate Threshold Capture Volume", + .type = SNDRV_CTL_ELEM_TYPE_INTEGER, + .tlv = wm8776_ngth_tlv, + .reg1 = WM8776_REG_NOISEGATE, + .mask1 = WM8776_NGAT_THR_MASK, + .max = 7, + .flags = WM8776_FLAG_ALC, + }, +}; + +/* exported functions */ + +void snd_wm8776_init(struct snd_wm8776 *wm) +{ + int i; + static const u16 default_values[] = { + 0x000, 0x100, 0x000, + 0x000, 0x100, 0x000, + 0x000, 0x090, 0x000, 0x000, + 0x022, 0x022, 0x022, + 0x008, 0x0cf, 0x0cf, 0x07b, 0x000, + 0x032, 0x000, 0x0a6, 0x001, 0x001 + }; + + memcpy(wm->ctl, snd_wm8776_default_ctl, sizeof(wm->ctl)); + + snd_wm8776_write(wm, WM8776_REG_RESET, 0x00); /* reset */ + udelay(10); + /* load defaults */ + for (i = 0; i < ARRAY_SIZE(default_values); i++) + snd_wm8776_write(wm, i, default_values[i]); +} + +void snd_wm8776_resume(struct snd_wm8776 *wm) +{ + int i; + + for (i = 0; i < WM8776_REG_COUNT; i++) + snd_wm8776_write(wm, i, wm->regs[i]); +} + +void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac) +{ + snd_wm8776_write(wm, WM8776_REG_DACIFCTRL, dac); +} + +void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc) +{ + snd_wm8776_write(wm, WM8776_REG_ADCIFCTRL, adc); +} + +void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode) +{ + snd_wm8776_write(wm, WM8776_REG_MSTRCTRL, mode); +} + +void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power) +{ + snd_wm8776_write(wm, WM8776_REG_PWRDOWN, power); +} + +void snd_wm8776_volume_restore(struct snd_wm8776 *wm) +{ + u16 val = wm->regs[WM8776_REG_DACRVOL]; + /* restore volume after MCLK stopped */ + snd_wm8776_write(wm, WM8776_REG_DACRVOL, val | WM8776_VOL_UPDATE); +} + +/* mixer callbacks */ + +static int snd_wm8776_volume_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = (wm->ctl[n].flags & WM8776_FLAG_STEREO) ? 2 : 1; + uinfo->value.integer.min = wm->ctl[n].min; + uinfo->value.integer.max = wm->ctl[n].max; + + return 0; +} + +static int snd_wm8776_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + + return snd_ctl_enum_info(uinfo, 1, wm->ctl[n].max, + wm->ctl[n].enum_names); +} + +static int snd_wm8776_ctl_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val1, val2; + + if (wm->ctl[n].get) + wm->ctl[n].get(wm, &val1, &val2); + else { + val1 = wm->regs[wm->ctl[n].reg1] & wm->ctl[n].mask1; + val1 >>= __ffs(wm->ctl[n].mask1); + if (wm->ctl[n].flags & WM8776_FLAG_STEREO) { + val2 = wm->regs[wm->ctl[n].reg2] & wm->ctl[n].mask2; + val2 >>= __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE) + val2 &= ~WM8776_VOL_UPDATE; + } + } + if (wm->ctl[n].flags & WM8776_FLAG_INVERT) { + val1 = wm->ctl[n].max - (val1 - wm->ctl[n].min); + if (wm->ctl[n].flags & WM8776_FLAG_STEREO) + val2 = wm->ctl[n].max - (val2 - wm->ctl[n].min); + } + ucontrol->value.integer.value[0] = val1; + if (wm->ctl[n].flags & WM8776_FLAG_STEREO) + ucontrol->value.integer.value[1] = val2; + + return 0; +} + +static int snd_wm8776_ctl_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_wm8776 *wm = snd_kcontrol_chip(kcontrol); + int n = kcontrol->private_value; + u16 val, regval1, regval2; + + /* this also works for enum because value is an union */ + regval1 = ucontrol->value.integer.value[0]; + regval2 = ucontrol->value.integer.value[1]; + if (wm->ctl[n].flags & WM8776_FLAG_INVERT) { + regval1 = wm->ctl[n].max - (regval1 - wm->ctl[n].min); + regval2 = wm->ctl[n].max - (regval2 - wm->ctl[n].min); + } + if (wm->ctl[n].set) + wm->ctl[n].set(wm, regval1, regval2); + else { + val = wm->regs[wm->ctl[n].reg1] & ~wm->ctl[n].mask1; + val |= regval1 << __ffs(wm->ctl[n].mask1); + /* both stereo controls in one register */ + if (wm->ctl[n].flags & WM8776_FLAG_STEREO && + wm->ctl[n].reg1 == wm->ctl[n].reg2) { + val &= ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + } + snd_wm8776_write(wm, wm->ctl[n].reg1, val); + /* stereo controls in different registers */ + if (wm->ctl[n].flags & WM8776_FLAG_STEREO && + wm->ctl[n].reg1 != wm->ctl[n].reg2) { + val = wm->regs[wm->ctl[n].reg2] & ~wm->ctl[n].mask2; + val |= regval2 << __ffs(wm->ctl[n].mask2); + if (wm->ctl[n].flags & WM8776_FLAG_VOL_UPDATE) + val |= WM8776_VOL_UPDATE; + snd_wm8776_write(wm, wm->ctl[n].reg2, val); + } + } + + return 0; +} + +static int snd_wm8776_add_control(struct snd_wm8776 *wm, int num) +{ + struct snd_kcontrol_new cont; + struct snd_kcontrol *ctl; + + memset(&cont, 0, sizeof(cont)); + cont.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + cont.private_value = num; + cont.name = wm->ctl[num].name; + cont.access = SNDRV_CTL_ELEM_ACCESS_READWRITE; + if (wm->ctl[num].flags & WM8776_FLAG_LIM || + wm->ctl[num].flags & WM8776_FLAG_ALC) + cont.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + cont.tlv.p = NULL; + cont.get = snd_wm8776_ctl_get; + cont.put = snd_wm8776_ctl_put; + + switch (wm->ctl[num].type) { + case SNDRV_CTL_ELEM_TYPE_INTEGER: + cont.info = snd_wm8776_volume_info; + cont.access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; + cont.tlv.p = wm->ctl[num].tlv; + break; + case SNDRV_CTL_ELEM_TYPE_BOOLEAN: + wm->ctl[num].max = 1; + if (wm->ctl[num].flags & WM8776_FLAG_STEREO) + cont.info = snd_ctl_boolean_stereo_info; + else + cont.info = snd_ctl_boolean_mono_info; + break; + case SNDRV_CTL_ELEM_TYPE_ENUMERATED: + cont.info = snd_wm8776_enum_info; + break; + default: + return -EINVAL; + } + ctl = snd_ctl_new1(&cont, wm); + if (!ctl) + return -ENOMEM; + + return snd_ctl_add(wm->card, ctl); +} + +int snd_wm8776_build_controls(struct snd_wm8776 *wm) +{ + int err, i; + + for (i = 0; i < WM8776_CTL_COUNT; i++) + if (wm->ctl[i].name) { + err = snd_wm8776_add_control(wm, i); + if (err < 0) + return err; + } + + return 0; +} diff --git a/sound/pci/ice1712/wm8776.h b/sound/pci/ice1712/wm8776.h new file mode 100644 index 00000000000..93a2d697115 --- /dev/null +++ b/sound/pci/ice1712/wm8776.h @@ -0,0 +1,226 @@ +#ifndef __SOUND_WM8776_H +#define __SOUND_WM8776_H + +/* + * ALSA driver for ICEnsemble VT17xx + * + * Lowlevel functions for WM8776 codec + * + * Copyright (c) 2012 Ondrej Zary <linux@rainbow-software.org> + * + * 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 Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#define WM8776_REG_HPLVOL 0x00 +#define WM8776_REG_HPRVOL 0x01 +#define WM8776_REG_HPMASTER 0x02 +#define WM8776_HPVOL_MASK 0x17f /* incl. update bit */ +#define WM8776_VOL_HPZCEN (1 << 7) /* zero cross detect */ +#define WM8776_VOL_UPDATE (1 << 8) /* update volume */ +#define WM8776_REG_DACLVOL 0x03 +#define WM8776_REG_DACRVOL 0x04 +#define WM8776_REG_DACMASTER 0x05 +#define WM8776_DACVOL_MASK 0x1ff /* incl. update bit */ +#define WM8776_REG_PHASESWAP 0x06 +#define WM8776_PHASE_INVERTL (1 << 0) +#define WM8776_PHASE_INVERTR (1 << 1) +#define WM8776_REG_DACCTRL1 0x07 +#define WM8776_DAC_DZCEN (1 << 0) +#define WM8776_DAC_ATC (1 << 1) +#define WM8776_DAC_IZD (1 << 2) +#define WM8776_DAC_TOD (1 << 3) +#define WM8776_DAC_PL_MASK 0xf0 +#define WM8776_DAC_PL_LL (1 << 4) /* L chan: L signal */ +#define WM8776_DAC_PL_LR (2 << 4) /* L chan: R signal */ +#define WM8776_DAC_PL_LB (3 << 4) /* L chan: both */ +#define WM8776_DAC_PL_RL (1 << 6) /* R chan: L signal */ +#define WM8776_DAC_PL_RR (2 << 6) /* R chan: R signal */ +#define WM8776_DAC_PL_RB (3 << 6) /* R chan: both */ +#define WM8776_REG_DACMUTE 0x08 +#define WM8776_DACMUTE (1 << 0) +#define WM8776_REG_DACCTRL2 0x09 +#define WM8776_DAC2_DEEMPH (1 << 0) +#define WM8776_DAC2_ZFLAG_DISABLE (0 << 1) +#define WM8776_DAC2_ZFLAG_OWN (1 << 1) +#define WM8776_DAC2_ZFLAG_BOTH (2 << 1) +#define WM8776_DAC2_ZFLAG_EITHER (3 << 1) +#define WM8776_REG_DACIFCTRL 0x0a +#define WM8776_FMT_RIGHTJ (0 << 0) +#define WM8776_FMT_LEFTJ (1 << 0) +#define WM8776_FMT_I2S (2 << 0) +#define WM8776_FMT_DSP (3 << 0) +#define WM8776_FMT_DSP_LATE (1 << 2) /* in DSP mode */ +#define WM8776_FMT_LRC_INVERTED (1 << 2) /* in other modes */ +#define WM8776_FMT_BCLK_INVERTED (1 << 3) +#define WM8776_FMT_16BIT (0 << 4) +#define WM8776_FMT_20BIT (1 << 4) +#define WM8776_FMT_24BIT (2 << 4) +#define WM8776_FMT_32BIT (3 << 4) +#define WM8776_REG_ADCIFCTRL 0x0b +#define WM8776_FMT_ADCMCLK_INVERTED (1 << 6) +#define WM8776_FMT_ADCHPD (1 << 8) +#define WM8776_REG_MSTRCTRL 0x0c +#define WM8776_IF_ADC256FS (2 << 0) +#define WM8776_IF_ADC384FS (3 << 0) +#define WM8776_IF_ADC512FS (4 << 0) +#define WM8776_IF_ADC768FS (5 << 0) +#define WM8776_IF_OVERSAMP64 (1 << 3) +#define WM8776_IF_DAC128FS (0 << 4) +#define WM8776_IF_DAC192FS (1 << 4) +#define WM8776_IF_DAC256FS (2 << 4) +#define WM8776_IF_DAC384FS (3 << 4) +#define WM8776_IF_DAC512FS (4 << 4) +#define WM8776_IF_DAC768FS (5 << 4) +#define WM8776_IF_DAC_MASTER (1 << 7) +#define WM8776_IF_ADC_MASTER (1 << 8) +#define WM8776_REG_PWRDOWN 0x0d +#define WM8776_PWR_PDWN (1 << 0) +#define WM8776_PWR_ADCPD (1 << 1) +#define WM8776_PWR_DACPD (1 << 2) +#define WM8776_PWR_HPPD (1 << 3) +#define WM8776_PWR_AINPD (1 << 6) +#define WM8776_REG_ADCLVOL 0x0e +#define WM8776_REG_ADCRVOL 0x0f +#define WM8776_ADC_GAIN_MASK 0xff +#define WM8776_ADC_ZCEN (1 << 8) +#define WM8776_REG_ALCCTRL1 0x10 +#define WM8776_ALC1_LCT_MASK 0x0f /* 0=-16dB, 1=-15dB..15=-1dB */ +#define WM8776_ALC1_MAXGAIN_MASK 0x70 /* 0,1=0dB, 2=+4dB...7=+24dB */ +#define WM8776_ALC1_LCSEL_MASK 0x180 +#define WM8776_ALC1_LCSEL_LIMITER (0 << 7) +#define WM8776_ALC1_LCSEL_ALCR (1 << 7) +#define WM8776_ALC1_LCSEL_ALCL (2 << 7) +#define WM8776_ALC1_LCSEL_ALCSTEREO (3 << 7) +#define WM8776_REG_ALCCTRL2 0x11 +#define WM8776_ALC2_HOLD_MASK 0x0f /*0=0ms, 1=2.67ms, 2=5.33ms.. */ +#define WM8776_ALC2_ZCEN (1 << 7) +#define WM8776_ALC2_LCEN (1 << 8) +#define WM8776_REG_ALCCTRL3 0x12 +#define WM8776_ALC3_ATK_MASK 0x0f +#define WM8776_ALC3_DCY_MASK 0xf0 +#define WM8776_ALC3_FDECAY (1 << 8) +#define WM8776_REG_NOISEGATE 0x13 +#define WM8776_NGAT_ENABLE (1 << 0) +#define WM8776_NGAT_THR_MASK 0x1c /*0=-78dB, 1=-72dB...7=-36dB */ +#define WM8776_REG_LIMITER 0x14 +#define WM8776_LIM_MAXATTEN_MASK 0x0f +#define WM8776_LIM_TRANWIN_MASK 0x70 /*0=0us, 1=62.5us, 2=125us.. */ +#define WM8776_REG_ADCMUX 0x15 +#define WM8776_ADC_MUX_AIN1 (1 << 0) +#define WM8776_ADC_MUX_AIN2 (1 << 1) +#define WM8776_ADC_MUX_AIN3 (1 << 2) +#define WM8776_ADC_MUX_AIN4 (1 << 3) +#define WM8776_ADC_MUX_AIN5 (1 << 4) +#define WM8776_ADC_MUTER (1 << 6) +#define WM8776_ADC_MUTEL (1 << 7) +#define WM8776_ADC_LRBOTH (1 << 8) +#define WM8776_REG_OUTMUX 0x16 +#define WM8776_OUTMUX_DAC (1 << 0) +#define WM8776_OUTMUX_AUX (1 << 1) +#define WM8776_OUTMUX_BYPASS (1 << 2) +#define WM8776_REG_RESET 0x17 + +#define WM8776_REG_COUNT 0x17 /* don't cache the RESET register */ + +struct snd_wm8776; + +struct snd_wm8776_ops { + void (*write)(struct snd_wm8776 *wm, u8 addr, u8 data); +}; + +enum snd_wm8776_ctl_id { + WM8776_CTL_DAC_VOL, + WM8776_CTL_DAC_SW, + WM8776_CTL_DAC_ZC_SW, + WM8776_CTL_HP_VOL, + WM8776_CTL_HP_SW, + WM8776_CTL_HP_ZC_SW, + WM8776_CTL_AUX_SW, + WM8776_CTL_BYPASS_SW, + WM8776_CTL_DAC_IZD_SW, + WM8776_CTL_PHASE_SW, + WM8776_CTL_DEEMPH_SW, + WM8776_CTL_ADC_VOL, + WM8776_CTL_ADC_SW, + WM8776_CTL_INPUT1_SW, + WM8776_CTL_INPUT2_SW, + WM8776_CTL_INPUT3_SW, + WM8776_CTL_INPUT4_SW, + WM8776_CTL_INPUT5_SW, + WM8776_CTL_AGC_SEL, + WM8776_CTL_LIM_THR, + WM8776_CTL_LIM_ATK, + WM8776_CTL_LIM_DCY, + WM8776_CTL_LIM_TRANWIN, + WM8776_CTL_LIM_MAXATTN, + WM8776_CTL_ALC_TGT, + WM8776_CTL_ALC_ATK, + WM8776_CTL_ALC_DCY, + WM8776_CTL_ALC_MAXGAIN, + WM8776_CTL_ALC_MAXATTN, + WM8776_CTL_ALC_HLD, + WM8776_CTL_NGT_SW, + WM8776_CTL_NGT_THR, + + WM8776_CTL_COUNT, +}; + +#define WM8776_ENUM_MAX 16 + +#define WM8776_FLAG_STEREO (1 << 0) +#define WM8776_FLAG_VOL_UPDATE (1 << 1) +#define WM8776_FLAG_INVERT (1 << 2) +#define WM8776_FLAG_LIM (1 << 3) +#define WM8776_FLAG_ALC (1 << 4) + +struct snd_wm8776_ctl { + const char *name; + snd_ctl_elem_type_t type; + const char *const enum_names[WM8776_ENUM_MAX]; + const unsigned int *tlv; + u16 reg1, reg2, mask1, mask2, min, max, flags; + void (*set)(struct snd_wm8776 *wm, u16 ch1, u16 ch2); + void (*get)(struct snd_wm8776 *wm, u16 *ch1, u16 *ch2); +}; + +enum snd_wm8776_agc_mode { + WM8776_AGC_OFF, + WM8776_AGC_LIM, + WM8776_AGC_ALC_R, + WM8776_AGC_ALC_L, + WM8776_AGC_ALC_STEREO +}; + +struct snd_wm8776 { + struct snd_card *card; + struct snd_wm8776_ctl ctl[WM8776_CTL_COUNT]; + enum snd_wm8776_agc_mode agc_mode; + struct snd_wm8776_ops ops; + u16 regs[WM8776_REG_COUNT]; /* 9-bit registers */ +}; + + + +void snd_wm8776_init(struct snd_wm8776 *wm); +void snd_wm8776_resume(struct snd_wm8776 *wm); +void snd_wm8776_set_dac_if(struct snd_wm8776 *wm, u16 dac); +void snd_wm8776_set_adc_if(struct snd_wm8776 *wm, u16 adc); +void snd_wm8776_set_master_mode(struct snd_wm8776 *wm, u16 mode); +void snd_wm8776_set_power(struct snd_wm8776 *wm, u16 power); +void snd_wm8776_volume_restore(struct snd_wm8776 *wm); +int snd_wm8776_build_controls(struct snd_wm8776 *wm); + +#endif /* __SOUND_WM8776_H */ diff --git a/sound/pci/ice1712/wtm.c b/sound/pci/ice1712/wtm.c index e618f789026..bcf30a387b8 100644 --- a/sound/pci/ice1712/wtm.c +++ b/sound/pci/ice1712/wtm.c @@ -25,7 +25,6 @@ -#include <linux/io.h> #include <linux/delay.h> #include <linux/interrupt.h> #include <linux/init.h> @@ -384,7 +383,7 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, /* * Control tabs */ -static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { +static struct snd_kcontrol_new stac9640_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Master Playback Switch", @@ -448,7 +447,7 @@ static struct snd_kcontrol_new stac9640_controls[] __devinitdata = { /*INIT*/ -static int __devinit wtm_add_controls(struct snd_ice1712 *ice) +static int wtm_add_controls(struct snd_ice1712 *ice) { unsigned int i; int err; @@ -462,7 +461,7 @@ static int __devinit wtm_add_controls(struct snd_ice1712 *ice) return 0; } -static int __devinit wtm_init(struct snd_ice1712 *ice) +static int wtm_init(struct snd_ice1712 *ice) { static unsigned short stac_inits_prodigy[] = { STAC946X_RESET, 0, @@ -485,7 +484,7 @@ static int __devinit wtm_init(struct snd_ice1712 *ice) } -static unsigned char wtm_eeprom[] __devinitdata = { +static unsigned char wtm_eeprom[] = { 0x47, /*SYSCONF: clock 192KHz, 4ADC, 8DAC */ 0x80, /* ACLINK : I2S */ 0xf8, /* I2S: vol; 96k, 24bit, 192k */ @@ -503,7 +502,7 @@ static unsigned char wtm_eeprom[] __devinitdata = { /*entry point*/ -struct snd_ice1712_card_info snd_vt1724_wtm_cards[] __devinitdata = { +struct snd_ice1712_card_info snd_vt1724_wtm_cards[] = { { .subvendor = VT1724_SUBDEVICE_WTM, .name = "ESI Waveterminal 192M", diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index ea4b706c8d6..c91860e0a28 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -547,7 +547,8 @@ static int snd_intel8x0_codec_semaphore(struct intel8x0 *chip, unsigned int code /* access to some forbidden (non existent) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ - snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + dev_err(chip->card->dev, + "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); iagetword(chip, 0); /* clear semaphore flag */ /* I don't care about the semaphore */ @@ -562,7 +563,9 @@ static void snd_intel8x0_codec_write(struct snd_ac97 *ac97, if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_write %d: semaphore is not ready for register 0x%x\n", + ac97->num, reg); } iaputword(chip, reg + ac97->num * 0x80, val); } @@ -576,7 +579,9 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, if (snd_intel8x0_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_read %d: semaphore is not ready for register 0x%x\n", + ac97->num, reg); res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); @@ -585,15 +590,17 @@ static unsigned short snd_intel8x0_codec_read(struct snd_ac97 *ac97, iputdword(chip, ICHREG(GLOB_STA), tmp & ~(chip->codec_ready_bits | ICH_GSCI)); if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_read %d: read timeout for register 0x%x\n", + ac97->num, reg); res = 0xffff; } } return res; } -static void __devinit snd_intel8x0_codec_read_test(struct intel8x0 *chip, - unsigned int codec) +static void snd_intel8x0_codec_read_test(struct intel8x0 *chip, + unsigned int codec) { unsigned int tmp; @@ -619,7 +626,7 @@ static int snd_intel8x0_ali_codec_ready(struct intel8x0 *chip, int mask) return 0; } if (! chip->in_ac97_init) - snd_printd(KERN_WARNING "intel8x0: AC97 codec ready timeout.\n"); + dev_warn(chip->card->dev, "AC97 codec ready timeout.\n"); return -EBUSY; } @@ -631,7 +638,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip) 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"); + dev_warn(chip->card->dev, "ali_codec_semaphore timeout\n"); return snd_intel8x0_ali_codec_ready(chip, ALI_CSPSR_CODEC_READY); } @@ -700,7 +707,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ ichdev->fragsize >> ichdev->pos_shift); #if 0 - printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n", + dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); #endif } @@ -712,8 +719,8 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; ichdev->position = 0; #if 0 - printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, " - "period_size1 = 0x%x\n", + dev_dbg(chip->card->dev, + "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); #endif @@ -781,8 +788,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich ichdev->lvi_frag %= ichdev->frags; ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); #if 0 - printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, " - "all = 0x%x, 0x%x\n", + dev_dbg(chip->card->dev, + "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); @@ -1507,8 +1514,8 @@ struct ich_pcm_table { int ac97_idx; }; -static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, - struct ich_pcm_table *rec) +static int snd_intel8x0_pcm1(struct intel8x0 *chip, int device, + struct ich_pcm_table *rec) { struct snd_pcm *pcm; int err; @@ -1541,17 +1548,16 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, snd_dma_pci_data(chip->pci), rec->prealloc_size, rec->prealloc_max_size); - if (rec->ac97_idx == ICHD_PCMOUT && rec->playback_ops) { + if (rec->playback_ops && + rec->playback_ops->open == snd_intel8x0_playback_open) { struct snd_pcm_chmap *chmap; int chs = 2; - if (rec->ac97_idx == ICHD_PCMOUT) { - if (chip->multi8) - chs = 8; - else if (chip->multi6) - chs = 6; - else if (chip->multi4) - chs = 4; - } + if (chip->multi8) + chs = 8; + else if (chip->multi6) + chs = 6; + else if (chip->multi4) + chs = 4; err = snd_pcm_add_chmap_ctls(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_pcm_alt_chmaps, chs, 0, &chmap); @@ -1564,7 +1570,7 @@ static int __devinit snd_intel8x0_pcm1(struct intel8x0 *chip, int device, return 0; } -static struct ich_pcm_table intel_pcms[] __devinitdata = { +static struct ich_pcm_table intel_pcms[] = { { .playback_ops = &snd_intel8x0_playback_ops, .capture_ops = &snd_intel8x0_capture_ops, @@ -1601,7 +1607,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = { }, }; -static struct ich_pcm_table nforce_pcms[] __devinitdata = { +static struct ich_pcm_table nforce_pcms[] = { { .playback_ops = &snd_intel8x0_playback_ops, .capture_ops = &snd_intel8x0_capture_ops, @@ -1624,7 +1630,7 @@ static struct ich_pcm_table nforce_pcms[] __devinitdata = { }, }; -static struct ich_pcm_table ali_pcms[] __devinitdata = { +static struct ich_pcm_table ali_pcms[] = { { .playback_ops = &snd_intel8x0_ali_playback_ops, .capture_ops = &snd_intel8x0_ali_capture_ops, @@ -1656,7 +1662,7 @@ static struct ich_pcm_table ali_pcms[] __devinitdata = { #endif }; -static int __devinit snd_intel8x0_pcm(struct intel8x0 *chip) +static int snd_intel8x0_pcm(struct intel8x0 *chip) { int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec; @@ -1719,7 +1725,7 @@ static void snd_intel8x0_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97[ac97->num] = NULL; } -static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { +static struct ac97_pcm ac97_pcm_defs[] = { /* front PCM */ { .exclusive = 1, @@ -1789,7 +1795,7 @@ static struct ac97_pcm ac97_pcm_defs[] __devinitdata = { }, }; -static struct ac97_quirk ac97_quirks[] __devinitdata = { +static struct ac97_quirk ac97_quirks[] = { { .subvendor = 0x0e11, .subdevice = 0x000e, @@ -2196,8 +2202,8 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { { } /* terminator */ }; -static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, - const char *quirk_override) +static int snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, + const char *quirk_override) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2290,7 +2296,8 @@ static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, ac97.num = i; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { if (err != -EACCES) - snd_printk(KERN_ERR "Unable to initialize codec #%d\n", i); + dev_err(chip->card->dev, + "Unable to initialize codec #%d\n", i); if (i == 0) goto __err; } @@ -2442,7 +2449,7 @@ static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip) return 0; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", + dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); return -EIO; } @@ -2484,7 +2491,8 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) } while (time_after_eq(end_time, jiffies)); if (! status) { /* no codec is found */ - snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", + dev_err(chip->card->dev, + "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA))); return -EIO; } @@ -2548,7 +2556,7 @@ static int snd_intel8x0_ali_chip_init(struct intel8x0 *chip, int probing) goto __ok; schedule_timeout_uninterruptible(1); } - snd_printk(KERN_ERR "AC'97 reset failed.\n"); + dev_err(chip->card->dev, "AC'97 reset failed.\n"); if (probing) return -EIO; @@ -2592,7 +2600,7 @@ static int snd_intel8x0_chip_init(struct intel8x0 *chip, int probing) break; } if (timeout == 0) - printk(KERN_ERR "intel8x0: reset of registers failed?\n"); + dev_err(chip->card->dev, "reset of registers failed?\n"); } /* initialize Buffer Descriptor Lists */ for (i = 0; i < chip->bdbars_count; i++) @@ -2693,8 +2701,7 @@ static int intel8x0_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "intel8x0: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2702,8 +2709,8 @@ static int intel8x0_resume(struct device *dev) snd_intel8x0_chip_init(chip, 0); if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR "intel8x0: unable to grab IRQ %d, " - "disabling device\n", pci->irq); + dev_err(dev, "unable to grab IRQ %d, disabling device\n", + pci->irq); snd_card_disconnect(card); return -EIO; } @@ -2765,14 +2772,14 @@ static SIMPLE_DEV_PM_OPS(intel8x0_pm, intel8x0_suspend, intel8x0_resume); #define INTEL8X0_TESTBUF_SIZE 32768 /* enough large for one shot */ -static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) +static void intel8x0_measure_ac97_clock(struct intel8x0 *chip) { struct snd_pcm_substream *subs; struct ichdev *ichdev; unsigned long port; unsigned long pos, pos1, t; int civ, timeout = 1000, attempt = 1; - struct timespec start_time, stop_time; + ktime_t start_time, stop_time; if (chip->ac97_bus->clock != 48000) return; /* specified in module option */ @@ -2780,7 +2787,8 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) __again: subs = chip->pcm[0]->streams[0].substream; if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { - snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); + dev_warn(chip->card->dev, + "no playback buffer allocated - aborting measure ac97 clock\n"); return; } ichdev = &chip->ichd[ICHD_PCMOUT]; @@ -2790,7 +2798,8 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) /* set rate */ if (snd_ac97_set_rate(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 48000) < 0) { - snd_printk(KERN_ERR "cannot set ac97 rate: clock = %d\n", chip->ac97_bus->clock); + dev_err(chip->card->dev, "cannot set ac97 rate: clock = %d\n", + chip->ac97_bus->clock); return; } snd_intel8x0_setup_periods(chip, ichdev); @@ -2804,7 +2813,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); } - do_posix_clock_monotonic_gettime(&start_time); + start_time = ktime_get(); spin_unlock_irq(&chip->reg_lock); msleep(50); spin_lock_irq(&chip->reg_lock); @@ -2828,7 +2837,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) pos += ichdev->position; } chip->in_measurement = 0; - do_posix_clock_monotonic_gettime(&stop_time); + stop_time = ktime_get(); /* stop */ if (chip->device_type == DEVICE_ALI) { iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); @@ -2844,7 +2853,8 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) spin_unlock_irq(&chip->reg_lock); if (pos == 0) { - snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n"); + dev_err(chip->card->dev, + "measure - unreliable DMA position..\n"); __retry: if (attempt < 3) { msleep(300); @@ -2855,19 +2865,18 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) } pos /= 4; - t = stop_time.tv_sec - start_time.tv_sec; - t *= 1000000; - t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000; - printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos); + t = ktime_us_delta(stop_time, start_time); + dev_info(chip->card->dev, + "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos); if (t == 0) { - snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n"); + dev_err(chip->card->dev, "?? calculation error..\n"); goto __retry; } pos *= 1000; pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; if (pos < 40000 || pos >= 60000) { /* abnormal value. hw problem? */ - printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); + dev_info(chip->card->dev, "measured clock %ld rejected\n", pos); goto __retry; } else if (pos > 40500 && pos < 41500) /* first exception - 41000Hz reference clock */ @@ -2879,11 +2888,11 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) /* not 48000Hz, tuning the clock.. */ chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; __end: - printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); + dev_info(chip->card->dev, "clocking to %d\n", chip->ac97_bus->clock); snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); } -static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = { +static struct snd_pci_quirk intel8x0_clock_list[] = { SND_PCI_QUIRK(0x0e11, 0x008a, "AD1885", 41000), SND_PCI_QUIRK(0x1028, 0x00be, "AD1885", 44100), SND_PCI_QUIRK(0x1028, 0x0177, "AD1980", 48000), @@ -2892,7 +2901,7 @@ static struct snd_pci_quirk intel8x0_clock_list[] __devinitdata = { { } /* terminator */ }; -static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip) +static int intel8x0_in_clock_list(struct intel8x0 *chip) { struct pci_dev *pci = chip->pci; const struct snd_pci_quirk *wl; @@ -2900,7 +2909,7 @@ static int __devinit intel8x0_in_clock_list(struct intel8x0 *chip) wl = snd_pci_quirk_lookup(pci, intel8x0_clock_list); if (!wl) return 0; - printk(KERN_INFO "intel8x0: white list rate for %04x:%04x is %i\n", + dev_info(chip->card->dev, "white list rate for %04x:%04x is %i\n", pci->subsystem_vendor, pci->subsystem_device, wl->value); chip->ac97_bus->clock = wl->value; return 1; @@ -2941,7 +2950,7 @@ static void snd_intel8x0_proc_read(struct snd_info_entry * entry, chip->ac97_sdin[2]); } -static void __devinit snd_intel8x0_proc_init(struct intel8x0 * chip) +static void snd_intel8x0_proc_init(struct intel8x0 *chip) { struct snd_info_entry *entry; @@ -2970,7 +2979,7 @@ static unsigned int sis_codec_bits[3] = { ICH_PCR, ICH_SCR, ICH_SIS_TCR }; -static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci) +static int snd_intel8x0_inside_vm(struct pci_dev *pci) { int result = inside_vm; char *msg = NULL; @@ -3004,15 +3013,15 @@ static int __devinit snd_intel8x0_inside_vm(struct pci_dev *pci) fini: if (msg != NULL) - printk(KERN_INFO "intel8x0: %s optimization\n", msg); + dev_info(&pci->dev, "%s optimization\n", msg); return result; } -static int __devinit snd_intel8x0_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0 ** r_intel8x0) +static int snd_intel8x0_create(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type, + struct intel8x0 **r_intel8x0) { struct intel8x0 *chip; int err; @@ -3099,7 +3108,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, else chip->addr = pci_iomap(pci, 0, 0); if (!chip->addr) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + dev_err(card->dev, "AC'97 space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -3108,7 +3117,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, else chip->bmaddr = pci_iomap(pci, 1, 0); if (!chip->bmaddr) { - snd_printk(KERN_ERR "Controller space ioremap problem\n"); + dev_err(card->dev, "Controller space ioremap problem\n"); snd_intel8x0_free(chip); return -EIO; } @@ -3153,7 +3162,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, chip->bdbars_count * sizeof(u32) * ICH_MAX_FRAGS * 2, &chip->bdbars) < 0) { snd_intel8x0_free(chip); - snd_printk(KERN_ERR "intel8x0: cannot allocate buffer descriptors\n"); + dev_err(card->dev, "cannot allocate buffer descriptors\n"); return -ENOMEM; } /* tables must be aligned to 8 bytes here, but the kernel pages @@ -3207,7 +3216,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, /* request irq after initializaing int_sta_mask, etc */ if (request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_intel8x0_free(chip); return -EBUSY; } @@ -3218,8 +3227,6 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *r_intel8x0 = chip; return 0; } @@ -3227,7 +3234,7 @@ static int __devinit snd_intel8x0_create(struct snd_card *card, static struct shortname_table { unsigned int id; const char *s; -} shortnames[] __devinitdata = { +} shortnames[] = { { PCI_DEVICE_ID_INTEL_82801AA_5, "Intel 82801AA-ICH" }, { PCI_DEVICE_ID_INTEL_82801AB_5, "Intel 82901AB-ICH0" }, { PCI_DEVICE_ID_INTEL_82801BA_4, "Intel 82801BA-ICH2" }, @@ -3253,38 +3260,40 @@ static struct shortname_table { { 0, NULL }, }; -static struct snd_pci_quirk spdif_aclink_defaults[] __devinitdata = { +static struct snd_pci_quirk spdif_aclink_defaults[] = { SND_PCI_QUIRK(0x147b, 0x1c1a, "ASUS KN8", 1), { } /* end */ }; /* look up white/black list for SPDIF over ac-link */ -static int __devinit check_default_spdif_aclink(struct pci_dev *pci) +static int check_default_spdif_aclink(struct pci_dev *pci) { const struct snd_pci_quirk *w; w = snd_pci_quirk_lookup(pci, spdif_aclink_defaults); if (w) { if (w->value) - snd_printdd(KERN_INFO "intel8x0: Using SPDIF over " - "AC-Link for %s\n", w->name); + dev_dbg(&pci->dev, + "Using SPDIF over AC-Link for %s\n", + snd_pci_quirk_name(w)); else - snd_printdd(KERN_INFO "intel8x0: Using integrated " - "SPDIF DMA for %s\n", w->name); + dev_dbg(&pci->dev, + "Using integrated SPDIF DMA for %s\n", + snd_pci_quirk_name(w)); return w->value; } return 0; } -static int __devinit snd_intel8x0_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_intel8x0_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct intel8x0 *chip; int err; struct shortname_table *name; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -3359,17 +3368,16 @@ static int __devinit snd_intel8x0_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_intel8x0_remove(struct pci_dev *pci) +static void snd_intel8x0_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver intel8x0_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, - .remove = __devexit_p(snd_intel8x0_remove), + .remove = snd_intel8x0_remove, .driver = { .pm = INTEL8X0_PM_OPS, }, diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 4d551736531..b54d3e93cab 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c @@ -334,7 +334,8 @@ static int snd_intel8x0m_codec_semaphore(struct intel8x0m *chip, unsigned int co /* access to some forbidden (non existent) ac97 registers will not * reset the semaphore. So even if you don't get the semaphore, still * continue the access. We don't need the semaphore anyway. */ - snd_printk(KERN_ERR "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", + dev_err(chip->card->dev, + "codec_semaphore: semaphore is not ready [0x%x][0x%x]\n", igetbyte(chip, ICHREG(ACC_SEMA)), igetdword(chip, ICHREG(GLOB_STA))); iagetword(chip, 0); /* clear semaphore flag */ /* I don't care about the semaphore */ @@ -349,7 +350,9 @@ static void snd_intel8x0m_codec_write(struct snd_ac97 *ac97, if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_write %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_write %d: semaphore is not ready for register 0x%x\n", + ac97->num, reg); } iaputword(chip, reg + ac97->num * 0x80, val); } @@ -363,7 +366,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97, if (snd_intel8x0m_codec_semaphore(chip, ac97->num) < 0) { if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_read %d: semaphore is not ready for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_read %d: semaphore is not ready for register 0x%x\n", + ac97->num, reg); res = 0xffff; } else { res = iagetword(chip, reg + ac97->num * 0x80); @@ -372,7 +377,9 @@ static unsigned short snd_intel8x0m_codec_read(struct snd_ac97 *ac97, iputdword(chip, ICHREG(GLOB_STA), tmp & ~(ICH_SRI|ICH_PRI|ICH_TRI|ICH_GSCI)); if (! chip->in_ac97_init) - snd_printk(KERN_ERR "codec_read %d: read timeout for register 0x%x\n", ac97->num, reg); + dev_err(chip->card->dev, + "codec_read %d: read timeout for register 0x%x\n", + ac97->num, reg); res = 0xffff; } } @@ -412,7 +419,7 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ ichdev->fragsize >> chip->pcm_pos_shift); /* - printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n", + dev_dbg(chip->card->dev, "bdbar[%i] = 0x%x [0x%x]\n", idx + 0, bdbar[idx + 0], bdbar[idx + 1]); */ } @@ -424,8 +431,8 @@ static void snd_intel8x0m_setup_periods(struct intel8x0m *chip, struct ichdev *i ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; ichdev->position = 0; #if 0 - printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, " - "period_size1 = 0x%x\n", + dev_dbg(chip->card->dev, + "lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); #endif @@ -470,8 +477,8 @@ static inline void snd_intel8x0m_update(struct intel8x0m *chip, struct ichdev *i ichdev->lvi_frag * ichdev->fragsize1); #if 0 - printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], " - "prefetch = %i, all = 0x%x, 0x%x\n", + dev_dbg(chip->card->dev, + "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), inl(port + 4), inb(port + ICH_REG_OFF_CR)); @@ -710,8 +717,8 @@ struct ich_pcm_table { int ac97_idx; }; -static int __devinit snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, - struct ich_pcm_table *rec) +static int snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, + struct ich_pcm_table *rec) { struct snd_pcm *pcm; int err; @@ -749,7 +756,7 @@ static int __devinit snd_intel8x0m_pcm1(struct intel8x0m *chip, int device, return 0; } -static struct ich_pcm_table intel_pcms[] __devinitdata = { +static struct ich_pcm_table intel_pcms[] = { { .suffix = "Modem", .playback_ops = &snd_intel8x0m_playback_ops, @@ -759,7 +766,7 @@ static struct ich_pcm_table intel_pcms[] __devinitdata = { }, }; -static int __devinit snd_intel8x0m_pcm(struct intel8x0m *chip) +static int snd_intel8x0m_pcm(struct intel8x0m *chip) { int i, tblsize, device, err; struct ich_pcm_table *tbl, *rec; @@ -819,7 +826,7 @@ static void snd_intel8x0m_mixer_free_ac97(struct snd_ac97 *ac97) } -static int __devinit snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) +static int snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -850,7 +857,8 @@ static int __devinit snd_intel8x0m_mixer(struct intel8x0m *chip, int ac97_clock) ac97.pci = chip->pci; ac97.num = glob_sta & ICH_SCR ? 1 : 0; if ((err = snd_ac97_mixer(pbus, &ac97, &x97)) < 0) { - snd_printk(KERN_ERR "Unable to initialize codec #%d\n", ac97.num); + dev_err(chip->card->dev, + "Unable to initialize codec #%d\n", ac97.num); if (ac97.num == 0) goto __err; return err; @@ -901,7 +909,7 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing) goto __ok; schedule_timeout_uninterruptible(1); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", + dev_err(chip->card->dev, "AC'97 warm reset still in progress? [0x%x]\n", igetdword(chip, ICHREG(GLOB_CNT))); return -EIO; @@ -921,7 +929,8 @@ static int snd_intel8x0m_ich_chip_init(struct intel8x0m *chip, int probing) } while (time_after_eq(end_time, jiffies)); if (! status) { /* no codec is found */ - snd_printk(KERN_ERR "codec_ready: codec is not ready [0x%x]\n", + dev_err(chip->card->dev, + "codec_ready: codec is not ready [0x%x]\n", igetdword(chip, ICHREG(GLOB_STA))); return -EIO; } @@ -1042,16 +1051,15 @@ static int intel8x0m_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "intel8x0m: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR "intel8x0m: unable to grab IRQ %d, " - "disabling device\n", pci->irq); + dev_err(dev, "unable to grab IRQ %d, disabling device\n", + pci->irq); snd_card_disconnect(card); return -EIO; } @@ -1090,7 +1098,7 @@ static void snd_intel8x0m_proc_read(struct snd_info_entry * entry, (tmp & (ICH_PCR | ICH_SCR | ICH_TCR)) == 0 ? " none" : ""); } -static void __devinit snd_intel8x0m_proc_init(struct intel8x0m * chip) +static void snd_intel8x0m_proc_init(struct intel8x0m *chip) { struct snd_info_entry *entry; @@ -1113,10 +1121,10 @@ struct ich_reg_info { unsigned int offset; }; -static int __devinit snd_intel8x0m_create(struct snd_card *card, - struct pci_dev *pci, - unsigned long device_type, - struct intel8x0m **r_intel8x0m) +static int snd_intel8x0m_create(struct snd_card *card, + struct pci_dev *pci, + unsigned long device_type, + struct intel8x0m **r_intel8x0m) { struct intel8x0m *chip; int err; @@ -1165,7 +1173,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, else chip->addr = pci_iomap(pci, 0, 0); if (!chip->addr) { - snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); + dev_err(card->dev, "AC'97 space ioremap problem\n"); snd_intel8x0m_free(chip); return -EIO; } @@ -1174,7 +1182,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, else chip->bmaddr = pci_iomap(pci, 1, 0); if (!chip->bmaddr) { - snd_printk(KERN_ERR "Controller space ioremap problem\n"); + dev_err(card->dev, "Controller space ioremap problem\n"); snd_intel8x0m_free(chip); return -EIO; } @@ -1182,7 +1190,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, port_inited: if (request_irq(pci->irq, snd_intel8x0m_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_intel8x0m_free(chip); return -EBUSY; } @@ -1243,8 +1251,6 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, return err; } - snd_card_set_dev(card, &pci->dev); - *r_intel8x0m = chip; return 0; } @@ -1252,7 +1258,7 @@ static int __devinit snd_intel8x0m_create(struct snd_card *card, static struct shortname_table { unsigned int id; const char *s; -} shortnames[] __devinitdata = { +} shortnames[] = { { PCI_DEVICE_ID_INTEL_82801AA_6, "Intel 82801AA-ICH" }, { PCI_DEVICE_ID_INTEL_82801AB_6, "Intel 82901AB-ICH0" }, { PCI_DEVICE_ID_INTEL_82801BA_6, "Intel 82801BA-ICH2" }, @@ -1275,15 +1281,15 @@ static struct shortname_table { { 0 }, }; -static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_intel8x0m_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct intel8x0m *chip; int err; struct shortname_table *name; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -1325,17 +1331,16 @@ static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) +static void snd_intel8x0m_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver intel8x0m_driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, - .remove = __devexit_p(snd_intel8x0m_remove), + .remove = snd_intel8x0m_remove, .driver = { .pm = INTEL8X0M_PM_OPS, }, diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 8a67ce95f24..8f36d77f01e 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c @@ -2083,7 +2083,7 @@ static void snd_korg1212_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, " Error count: %ld\n", korg1212->totalerrorcnt); } -static void __devinit snd_korg1212_proc_init(struct snd_korg1212 *korg1212) +static void snd_korg1212_proc_init(struct snd_korg1212 *korg1212) { struct snd_info_entry *entry; @@ -2154,8 +2154,8 @@ static int snd_korg1212_dev_free(struct snd_device *device) return snd_korg1212_free(korg1212); } -static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, - struct snd_korg1212 ** rchip) +static int snd_korg1212_create(struct snd_card *card, struct pci_dev *pci, + struct snd_korg1212 **rchip) { int err, rc; @@ -2418,8 +2418,6 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * snd_korg1212_proc_init(korg1212); - snd_card_set_dev(card, &pci->dev); - * rchip = korg1212; return 0; @@ -2429,7 +2427,7 @@ static int __devinit snd_korg1212_create(struct snd_card *card, struct pci_dev * * Card initialisation */ -static int __devinit +static int snd_korg1212_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2445,7 +2443,8 @@ snd_korg1212_probe(struct pci_dev *pci, dev++; return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2470,17 +2469,16 @@ snd_korg1212_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_korg1212_remove(struct pci_dev *pci) +static void snd_korg1212_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver korg1212_driver = { .name = KBUILD_MODNAME, .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, - .remove = __devexit_p(snd_korg1212_remove), + .remove = snd_korg1212_remove, }; module_pci_driver(korg1212_driver); diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c index ac15166bee6..68824cdd137 100644 --- a/sound/pci/lola/lola.c +++ b/sound/pci/lola/lola.c @@ -75,7 +75,7 @@ MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); static int debug; module_param(debug, int, 0644); #define verbose_debug(fmt, args...) \ - do { if (debug > 1) printk(KERN_DEBUG SFX fmt, ##args); } while (0) + do { if (debug > 1) pr_debug(SFX fmt, ##args); } while (0) #else #define verbose_debug(fmt, args...) #endif @@ -168,7 +168,7 @@ static int rirb_get_response(struct lola *chip, unsigned int *val, verbose_debug("get_response: %x, %x\n", chip->res, chip->res_ex); if (chip->res_ex & LOLA_RIRB_EX_ERROR) { - printk(KERN_WARNING SFX "RIRB ERROR: " + dev_warn(chip->card->dev, "RIRB ERROR: " "NID=%x, verb=%x, data=%x, ext=%x\n", chip->last_cmd_nid, chip->last_verb, chip->last_data, @@ -182,9 +182,9 @@ static int rirb_get_response(struct lola *chip, unsigned int *val, udelay(20); cond_resched(); } - printk(KERN_WARNING SFX "RIRB response error\n"); + dev_warn(chip->card->dev, "RIRB response error\n"); if (!chip->polling_mode) { - printk(KERN_WARNING SFX "switching to polling mode\n"); + dev_warn(chip->card->dev, "switching to polling mode\n"); chip->polling_mode = 1; goto again; } @@ -327,7 +327,7 @@ static int reset_controller(struct lola *chip) break; } while (time_before(jiffies, end_time)); if (!gctl) { - printk(KERN_ERR SFX "cannot reset controller\n"); + dev_err(chip->card->dev, "cannot reset controller\n"); return -EIO; } return 0; @@ -445,47 +445,47 @@ static void lola_reset_setups(struct lola *chip) lola_setup_all_analog_gains(chip, PLAY, false); /* output, update */ } -static int __devinit lola_parse_tree(struct lola *chip) +static int lola_parse_tree(struct lola *chip) { unsigned int val; int nid, err; err = lola_read_param(chip, 0, LOLA_PAR_VENDOR_ID, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read VENDOR_ID\n"); + dev_err(chip->card->dev, "Can't read VENDOR_ID\n"); return err; } val >>= 16; if (val != 0x1369) { - printk(KERN_ERR SFX "Unknown codec vendor 0x%x\n", val); + dev_err(chip->card->dev, "Unknown codec vendor 0x%x\n", val); return -EINVAL; } err = lola_read_param(chip, 1, LOLA_PAR_FUNCTION_TYPE, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read FUNCTION_TYPE for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read FUNCTION_TYPE\n"); return err; } if (val != 1) { - printk(KERN_ERR SFX "Unknown function type %d\n", val); + dev_err(chip->card->dev, "Unknown function type %d\n", val); return -EINVAL; } err = lola_read_param(chip, 1, LOLA_PAR_SPECIFIC_CAPS, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read SPECCAPS\n"); + dev_err(chip->card->dev, "Can't read SPECCAPS\n"); return err; } chip->lola_caps = val; chip->pin[CAPT].num_pins = LOLA_AFG_INPUT_PIN_COUNT(chip->lola_caps); chip->pin[PLAY].num_pins = LOLA_AFG_OUTPUT_PIN_COUNT(chip->lola_caps); - snd_printdd(SFX "speccaps=0x%x, pins in=%d, out=%d\n", + dev_dbg(chip->card->dev, "speccaps=0x%x, pins in=%d, out=%d\n", chip->lola_caps, chip->pin[CAPT].num_pins, chip->pin[PLAY].num_pins); if (chip->pin[CAPT].num_pins > MAX_AUDIO_INOUT_COUNT || chip->pin[PLAY].num_pins > MAX_AUDIO_INOUT_COUNT) { - printk(KERN_ERR SFX "Invalid Lola-spec caps 0x%x\n", val); + dev_err(chip->card->dev, "Invalid Lola-spec caps 0x%x\n", val); return -EINVAL; } @@ -568,8 +568,8 @@ static int lola_dev_free(struct snd_device *device) return 0; } -static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, - int dev, struct lola **rchip) +static int lola_create(struct snd_card *card, struct pci_dev *pci, + int dev, struct lola **rchip) { struct lola *chip; int err; @@ -586,7 +586,6 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (!chip) { - snd_printk(KERN_ERR SFX "cannot allocate chip\n"); pci_disable_device(pci); return -ENOMEM; } @@ -609,7 +608,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, chip->sample_rate_max = 192000; break; default: - snd_printk(KERN_WARNING SFX + dev_warn(chip->card->dev, "Invalid granularity %d, reset to %d\n", chip->granularity, LOLA_GRANULARITY_MAX); chip->granularity = LOLA_GRANULARITY_MAX; @@ -618,7 +617,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, } chip->sample_rate_min = sample_rate_min[dev]; if (chip->sample_rate_min > chip->sample_rate_max) { - snd_printk(KERN_WARNING SFX + dev_warn(chip->card->dev, "Invalid sample_rate_min %d, reset to 16000\n", chip->sample_rate_min); chip->sample_rate_min = 16000; @@ -636,7 +635,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, chip->bar[1].addr = pci_resource_start(pci, 2); chip->bar[1].remap_addr = pci_ioremap_bar(pci, 2); if (!chip->bar[0].remap_addr || !chip->bar[1].remap_addr) { - snd_printk(KERN_ERR SFX "ioremap error\n"); + dev_err(chip->card->dev, "ioremap error\n"); err = -ENXIO; goto errout; } @@ -649,7 +648,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, if (request_irq(pci->irq, lola_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - printk(KERN_ERR SFX "unable to grab IRQ %d\n", pci->irq); + dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq); err = -EBUSY; goto errout; } @@ -660,7 +659,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, chip->pcm[CAPT].num_streams = (dever >> 0) & 0x3ff; chip->pcm[PLAY].num_streams = (dever >> 10) & 0x3ff; chip->version = (dever >> 24) & 0xff; - snd_printdd(SFX "streams in=%d, out=%d, version=0x%x\n", + dev_dbg(chip->card->dev, "streams in=%d, out=%d, version=0x%x\n", chip->pcm[CAPT].num_streams, chip->pcm[PLAY].num_streams, chip->version); @@ -669,7 +668,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, chip->pcm[PLAY].num_streams > MAX_STREAM_OUT_COUNT || (!chip->pcm[CAPT].num_streams && !chip->pcm[PLAY].num_streams)) { - printk(KERN_ERR SFX "invalid DEVER = %x\n", dever); + dev_err(chip->card->dev, "invalid DEVER = %x\n", dever); err = -EINVAL; goto errout; } @@ -680,7 +679,7 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating device [card]!\n"); + dev_err(chip->card->dev, "Error creating device [card]!\n"); goto errout; } @@ -702,8 +701,8 @@ static int __devinit lola_create(struct snd_card *card, struct pci_dev *pci, return err; } -static int __devinit lola_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int lola_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -717,14 +716,13 @@ static int __devinit lola_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) { - snd_printk(KERN_ERR SFX "Error creating card!\n"); + dev_err(card->dev, "Error creating card!\n"); return err; } - snd_card_set_dev(card, &pci->dev); - err = lola_create(card, pci, dev, &chip); if (err < 0) goto out_free; @@ -756,10 +754,9 @@ out_free: return err; } -static void __devexit lola_remove(struct pci_dev *pci) +static void lola_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } /* PCI IDs */ @@ -774,7 +771,7 @@ static struct pci_driver lola_driver = { .name = KBUILD_MODNAME, .id_table = lola_ids, .probe = lola_probe, - .remove = __devexit_p(lola_remove), + .remove = lola_remove, }; module_pci_driver(lola_driver); diff --git a/sound/pci/lola/lola_clock.c b/sound/pci/lola/lola_clock.c index 72f8ef0ac86..2bef6b412ae 100644 --- a/sound/pci/lola/lola_clock.c +++ b/sound/pci/lola/lola_clock.c @@ -120,7 +120,7 @@ int lola_set_granularity(struct lola *chip, unsigned int val, bool force) * Clock widget handling */ -int __devinit lola_init_clock_widget(struct lola *chip, int nid) +int lola_init_clock_widget(struct lola *chip, int nid) { unsigned int val; int i, j, nitems, nb_verbs, idx, idx_list; @@ -128,21 +128,21 @@ int __devinit lola_init_clock_widget(struct lola *chip, int nid) err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid); return err; } if ((val & 0xfff00000) != 0x01f00000) { /* test SubType and Type */ - snd_printdd("No valid clock widget\n"); + dev_dbg(chip->card->dev, "No valid clock widget\n"); return 0; } chip->clock.nid = nid; chip->clock.items = val & 0xff; - snd_printdd("clock_list nid=%x, entries=%d\n", nid, + dev_dbg(chip->card->dev, "clock_list nid=%x, entries=%d\n", nid, chip->clock.items); if (chip->clock.items > MAX_SAMPLE_CLOCK_COUNT) { - printk(KERN_ERR SFX "CLOCK_LIST too big: %d\n", + dev_err(chip->card->dev, "CLOCK_LIST too big: %d\n", chip->clock.items); return -EINVAL; } @@ -158,7 +158,7 @@ int __devinit lola_init_clock_widget(struct lola *chip, int nid) err = lola_codec_read(chip, nid, LOLA_VERB_GET_CLOCK_LIST, idx, 0, &val, &res_ex); if (err < 0) { - printk(KERN_ERR SFX "Can't read CLOCK_LIST\n"); + dev_err(chip->card->dev, "Can't read CLOCK_LIST\n"); return -EINVAL; } @@ -223,7 +223,7 @@ int lola_enable_clock_events(struct lola *chip) if (err < 0) return err; if (res) { - printk(KERN_WARNING SFX "error in enable_clock_events %d\n", + dev_warn(chip->card->dev, "error in enable_clock_events %d\n", res); return -EINVAL; } @@ -242,7 +242,7 @@ int lola_set_clock_index(struct lola *chip, unsigned int idx) if (err < 0) return err; if (res) { - printk(KERN_WARNING SFX "error in set_clock %d\n", res); + dev_warn(chip->card->dev, "error in set_clock %d\n", res); return -EINVAL; } return 0; diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c index 6b8d6481295..782f4d8299a 100644 --- a/sound/pci/lola/lola_mixer.c +++ b/sound/pci/lola/lola_mixer.c @@ -28,8 +28,8 @@ #include <sound/tlv.h> #include "lola.h" -static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, - int dir, int nid) +static int lola_init_pin(struct lola *chip, struct lola_pin *pin, + int dir, int nid) { unsigned int val; int err; @@ -37,7 +37,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, pin->nid = nid; err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid); return err; } val &= 0x00f00fff; /* test TYPE and bits 0..11 */ @@ -48,7 +48,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, else if (val == 0x0040000c && dir == PLAY) /* Dig=0, OutAmp/ovrd */ pin->is_analog = true; else { - printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", val, nid); + dev_err(chip->card->dev, "Invalid wcaps 0x%x for 0x%x\n", val, nid); return -EINVAL; } @@ -62,7 +62,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, else err = lola_read_param(chip, nid, LOLA_PAR_AMP_IN_CAP, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read AMP-caps for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read AMP-caps for 0x%x\n", nid); return err; } @@ -79,7 +79,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, err = lola_codec_read(chip, nid, LOLA_VERB_GET_MAX_LEVEL, 0, 0, &val, NULL); if (err < 0) { - printk(KERN_ERR SFX "Can't get MAX_LEVEL 0x%x\n", nid); + dev_err(chip->card->dev, "Can't get MAX_LEVEL 0x%x\n", nid); return err; } pin->max_level = val & 0x3ff; /* 10 bits */ @@ -91,7 +91,7 @@ static int __devinit lola_init_pin(struct lola *chip, struct lola_pin *pin, return 0; } -int __devinit lola_init_pins(struct lola *chip, int dir, int *nidp) +int lola_init_pins(struct lola *chip, int dir, int *nidp) { int i, err, nid; nid = *nidp; @@ -112,19 +112,19 @@ void lola_free_mixer(struct lola *chip) vfree(chip->mixer.array_saved); } -int __devinit lola_init_mixer_widget(struct lola *chip, int nid) +int lola_init_mixer_widget(struct lola *chip, int nid) { unsigned int val; int err; err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid); return err; } if ((val & 0xfff00000) != 0x02f00000) { /* test SubType and Type */ - snd_printdd("No valid mixer widget\n"); + dev_dbg(chip->card->dev, "No valid mixer widget\n"); return 0; } @@ -202,7 +202,7 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) */ if (chip->mixer.src_stream_out_ofs > MAX_AUDIO_INOUT_COUNT || chip->mixer.dest_phys_out_ofs > MAX_STREAM_IN_COUNT) { - printk(KERN_ERR SFX "Invalid mixer widget size\n"); + dev_err(chip->card->dev, "Invalid mixer widget size\n"); return -EINVAL; } @@ -213,7 +213,7 @@ int __devinit lola_init_mixer_widget(struct lola *chip, int nid) (((1U << chip->mixer.dest_phys_outs) - 1) << chip->mixer.dest_phys_out_ofs); - snd_printdd("Mixer src_mask=%x, dest_mask=%x\n", + dev_dbg(chip->card->dev, "Mixer src_mask=%x, dest_mask=%x\n", chip->mixer.src_mask, chip->mixer.dest_mask); return 0; @@ -236,7 +236,8 @@ static int lola_mixer_set_src_gain(struct lola *chip, unsigned int id, (gain == readw(&chip->mixer.array->src_gain[id]))) return 0; - snd_printdd("lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n", + dev_dbg(chip->card->dev, + "lola_mixer_set_src_gain (id=%d, gain=%d) enable=%x\n", id, gain, val); writew(gain, &chip->mixer.array->src_gain[id]); writel(val, &chip->mixer.array->src_gain_enable); @@ -409,7 +410,8 @@ static int set_analog_volume(struct lola *chip, int dir, return 0; if (external_call) lola_codec_flush(chip); - snd_printdd("set_analog_volume (dir=%d idx=%d, volume=%d)\n", + dev_dbg(chip->card->dev, + "set_analog_volume (dir=%d idx=%d, volume=%d)\n", dir, idx, val); err = lola_codec_write(chip, pin->nid, LOLA_VERB_SET_AMP_GAIN_MUTE, val, 0); @@ -579,7 +581,7 @@ static int lola_analog_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, return 0; } -static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { +static struct snd_kcontrol_new lola_analog_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ | @@ -590,7 +592,7 @@ static struct snd_kcontrol_new lola_analog_mixer __devinitdata = { .tlv.c = lola_analog_vol_tlv, }; -static int __devinit create_analog_mixer(struct lola *chip, int dir, char *name) +static int create_analog_mixer(struct lola *chip, int dir, char *name) { if (!chip->pin[dir].num_pins) return 0; @@ -644,7 +646,7 @@ static int lola_input_src_put(struct snd_kcontrol *kcontrol, return lola_set_src_config(chip, mask, true); } -static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { +static struct snd_kcontrol_new lola_input_src_mixer = { .name = "Digital SRC Capture Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = lola_input_src_info, @@ -656,7 +658,7 @@ static struct snd_kcontrol_new lola_input_src_mixer __devinitdata = { * Lola16161 or Lola881 can have Hardware sample rate converters * on its digital input pins */ -static int __devinit create_input_src_mixer(struct lola *chip) +static int create_input_src_mixer(struct lola *chip) { if (!chip->input_src_caps_mask) return 0; @@ -726,7 +728,7 @@ static int lola_src_gain_put(struct snd_kcontrol *kcontrol, /* raw value: 0 = -84dB, 336 = 0dB, 408=18dB, incremented 1 for mute */ static const DECLARE_TLV_DB_SCALE(lola_src_gain_tlv, -8425, 25, 1); -static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { +static struct snd_kcontrol_new lola_src_gain_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -736,8 +738,8 @@ static struct snd_kcontrol_new lola_src_gain_mixer __devinitdata = { .tlv.p = lola_src_gain_tlv, }; -static int __devinit create_src_gain_mixer(struct lola *chip, - int num, int ofs, char *name) +static int create_src_gain_mixer(struct lola *chip, + int num, int ofs, char *name) { lola_src_gain_mixer.name = name; lola_src_gain_mixer.private_value = ofs + (num << 8); @@ -813,7 +815,7 @@ static int lola_dest_gain_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(lola_dest_gain_tlv, -8425, 25, 1); -static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { +static struct snd_kcontrol_new lola_dest_gain_mixer = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ), @@ -823,9 +825,9 @@ static struct snd_kcontrol_new lola_dest_gain_mixer __devinitdata = { .tlv.p = lola_dest_gain_tlv, }; -static int __devinit create_dest_gain_mixer(struct lola *chip, - int src_num, int src_ofs, - int num, int ofs, char *name) +static int create_dest_gain_mixer(struct lola *chip, + int src_num, int src_ofs, + int num, int ofs, char *name) { lola_dest_gain_mixer.count = num; lola_dest_gain_mixer.name = name; @@ -838,7 +840,7 @@ static int __devinit create_dest_gain_mixer(struct lola *chip, /* */ -int __devinit lola_create_mixer(struct lola *chip) +int lola_create_mixer(struct lola *chip) { int err; diff --git a/sound/pci/lola/lola_pcm.c b/sound/pci/lola/lola_pcm.c index c44db68eecb..3bd6985430e 100644 --- a/sound/pci/lola/lola_pcm.c +++ b/sound/pci/lola/lola_pcm.c @@ -103,7 +103,7 @@ static void wait_for_srst_clear(struct lola *chip, struct lola_stream *str) return; msleep(1); } - printk(KERN_WARNING SFX "SRST not clear (stream %d)\n", str->dsd); + dev_warn(chip->card->dev, "SRST not clear (stream %d)\n", str->dsd); } static int lola_stream_wait_for_fifo(struct lola *chip, @@ -118,7 +118,7 @@ static int lola_stream_wait_for_fifo(struct lola *chip, return 0; msleep(1); } - printk(KERN_WARNING SFX "FIFO not ready (stream %d)\n", str->dsd); + dev_warn(chip->card->dev, "FIFO not ready (stream %d)\n", str->dsd); return -EIO; } @@ -156,7 +156,7 @@ static int lola_sync_wait_for_fifo(struct lola *chip, return 0; msleep(1); } - printk(KERN_WARNING SFX "FIFO not ready (pending %d)\n", pending - 1); + dev_warn(chip->card->dev, "FIFO not ready (pending %d)\n", pending - 1); return -EIO; } @@ -373,7 +373,7 @@ static int lola_setup_periods(struct lola *chip, struct lola_pcm *pcm, return 0; error: - snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", + dev_err(chip->card->dev, "Too many BDL entries: buffer=%d, period=%d\n", str->bufsize, period_bytes); return -EINVAL; } @@ -415,7 +415,7 @@ static int lola_set_stream_config(struct lola *chip, err = lola_codec_read(chip, str->nid, LOLA_VERB_SET_STREAM_FORMAT, str->format_verb, 0, &val, NULL); if (err < 0) { - printk(KERN_ERR SFX "Cannot set stream format 0x%x\n", + dev_err(chip->card->dev, "Cannot set stream format 0x%x\n", str->format_verb); return err; } @@ -427,7 +427,8 @@ static int lola_set_stream_config(struct lola *chip, LOLA_VERB_SET_CHANNEL_STREAMID, 0, verb, &val, NULL); if (err < 0) { - printk(KERN_ERR SFX "Cannot set stream channel %d\n", i); + dev_err(chip->card->dev, + "Cannot set stream channel %d\n", i); return err; } } @@ -597,7 +598,7 @@ static struct snd_pcm_ops lola_pcm_ops = { .page = snd_pcm_sgbuf_ops_page, }; -int __devinit lola_create_pcm(struct lola *chip) +int lola_create_pcm(struct lola *chip) { struct snd_pcm *pcm; int i, err; @@ -651,13 +652,14 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str, str->dsd += MAX_STREAM_IN_COUNT; err = lola_read_param(chip, nid, LOLA_PAR_AUDIO_WIDGET_CAP, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read wcaps for 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read wcaps for 0x%x\n", nid); return err; } if (dir == PLAY) { /* test TYPE and bits 0..11 (no test bit9 : Digital = 0/1) */ if ((val & 0x00f00dff) != 0x00000010) { - printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + dev_err(chip->card->dev, + "Invalid wcaps 0x%x for 0x%x\n", val, nid); return -EINVAL; } @@ -666,7 +668,8 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str, * (bug : ignore bit8: Conn list = 0/1) */ if ((val & 0x00f00cff) != 0x00100010) { - printk(KERN_ERR SFX "Invalid wcaps 0x%x for 0x%x\n", + dev_err(chip->card->dev, + "Invalid wcaps 0x%x for 0x%x\n", val, nid); return -EINVAL; } @@ -677,20 +680,21 @@ static int lola_init_stream(struct lola *chip, struct lola_stream *str, err = lola_read_param(chip, nid, LOLA_PAR_STREAM_FORMATS, &val); if (err < 0) { - printk(KERN_ERR SFX "Can't read FORMATS 0x%x\n", nid); + dev_err(chip->card->dev, "Can't read FORMATS 0x%x\n", nid); return err; } val &= 3; if (val == 3) str->can_float = true; if (!(val & 1)) { - printk(KERN_ERR SFX "Invalid formats 0x%x for 0x%x", val, nid); + dev_err(chip->card->dev, + "Invalid formats 0x%x for 0x%x", val, nid); return -EINVAL; } return 0; } -int __devinit lola_init_pcm(struct lola *chip, int dir, int *nidp) +int lola_init_pcm(struct lola *chip, int dir, int *nidp) { struct lola_pcm *pcm = &chip->pcm[dir]; int i, nid, err; diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c index 9d7daf897c9..c241dc06dd9 100644 --- a/sound/pci/lola/lola_proc.c +++ b/sound/pci/lola/lola_proc.c @@ -151,7 +151,7 @@ static void lola_proc_codec_rw_write(struct snd_info_entry *entry, char line[64]; unsigned int id, verb, data, extdata; while (!snd_info_get_line(buffer, line, sizeof(line))) { - if (sscanf(line, "%i %i %i %i", &id, &verb, &data, &extdata) != 4) + if (sscanf(line, "%u %u %u %u", &id, &verb, &data, &extdata) != 4) continue; lola_codec_read(chip, id, verb, data, extdata, &chip->debug_res, @@ -206,7 +206,7 @@ static void lola_proc_regs_read(struct snd_info_entry *entry, } } -void __devinit lola_proc_debug_new(struct lola *chip) +void lola_proc_debug_new(struct lola *chip) { struct snd_info_entry *entry; diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 5579b08bb35..27f60ce8a55 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c @@ -112,16 +112,16 @@ static int lx_hardware_open(struct lx6464es *chip, snd_pcm_uframes_t period_size = runtime->period_size; - snd_printd(LXP "allocating pipe for %d channels\n", channels); + dev_dbg(chip->card->dev, "allocating pipe for %d channels\n", channels); err = lx_pipe_allocate(chip, 0, is_capture, channels); if (err < 0) { - snd_printk(KERN_ERR LXP "allocating pipe failed\n"); + dev_err(chip->card->dev, LXP "allocating pipe failed\n"); return err; } err = lx_set_granularity(chip, period_size); if (err < 0) { - snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", + dev_err(chip->card->dev, "setting granularity to %ld failed\n", period_size); return err; } @@ -136,24 +136,24 @@ static int lx_hardware_start(struct lx6464es *chip, struct snd_pcm_runtime *runtime = substream->runtime; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - snd_printd(LXP "setting stream format\n"); + dev_dbg(chip->card->dev, "setting stream format\n"); err = lx_stream_set_format(chip, runtime, 0, is_capture); if (err < 0) { - snd_printk(KERN_ERR LXP "setting stream format failed\n"); + dev_err(chip->card->dev, "setting stream format failed\n"); return err; } - snd_printd(LXP "starting pipe\n"); + dev_dbg(chip->card->dev, "starting pipe\n"); err = lx_pipe_start(chip, 0, is_capture); if (err < 0) { - snd_printk(KERN_ERR LXP "starting pipe failed\n"); + dev_err(chip->card->dev, "starting pipe failed\n"); return err; } - snd_printd(LXP "waiting for pipe to start\n"); + dev_dbg(chip->card->dev, "waiting for pipe to start\n"); err = lx_pipe_wait_for_start(chip, 0, is_capture); if (err < 0) { - snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); + dev_err(chip->card->dev, "waiting for pipe failed\n"); return err; } @@ -167,24 +167,24 @@ static int lx_hardware_stop(struct lx6464es *chip, int err = 0; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - snd_printd(LXP "pausing pipe\n"); + dev_dbg(chip->card->dev, "pausing pipe\n"); err = lx_pipe_pause(chip, 0, is_capture); if (err < 0) { - snd_printk(KERN_ERR LXP "pausing pipe failed\n"); + dev_err(chip->card->dev, "pausing pipe failed\n"); return err; } - snd_printd(LXP "waiting for pipe to become idle\n"); + dev_dbg(chip->card->dev, "waiting for pipe to become idle\n"); err = lx_pipe_wait_for_idle(chip, 0, is_capture); if (err < 0) { - snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); + dev_err(chip->card->dev, "waiting for pipe failed\n"); return err; } - snd_printd(LXP "stopping pipe\n"); + dev_dbg(chip->card->dev, "stopping pipe\n"); err = lx_pipe_stop(chip, 0, is_capture); if (err < 0) { - snd_printk(LXP "stopping pipe failed\n"); + dev_err(chip->card->dev, "stopping pipe failed\n"); return err; } @@ -198,10 +198,10 @@ static int lx_hardware_close(struct lx6464es *chip, int err = 0; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - snd_printd(LXP "releasing pipe\n"); + dev_dbg(chip->card->dev, "releasing pipe\n"); err = lx_pipe_release(chip, 0, is_capture); if (err < 0) { - snd_printk(LXP "releasing pipe failed\n"); + dev_err(chip->card->dev, "releasing pipe failed\n"); return err; } @@ -216,7 +216,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) int err = 0; int board_rate; - snd_printdd("->lx_pcm_open\n"); + dev_dbg(chip->card->dev, "->lx_pcm_open\n"); mutex_lock(&chip->setup_mutex); /* copy the struct snd_pcm_hardware struct */ @@ -227,7 +227,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); if (err < 0) { - snd_printk(KERN_WARNING LXP "could not constrain periods\n"); + dev_warn(chip->card->dev, "could not constrain periods\n"); goto exit; } #endif @@ -238,7 +238,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) board_rate, board_rate); if (err < 0) { - snd_printk(KERN_WARNING LXP "could not constrain periods\n"); + dev_warn(chip->card->dev, "could not constrain periods\n"); goto exit; } @@ -248,7 +248,7 @@ static int lx_pcm_open(struct snd_pcm_substream *substream) MICROBLAZE_IBL_MIN, MICROBLAZE_IBL_MAX); if (err < 0) { - snd_printk(KERN_WARNING LXP + dev_warn(chip->card->dev, "could not constrain period size\n"); goto exit; } @@ -263,14 +263,14 @@ exit: runtime->private_data = chip; mutex_unlock(&chip->setup_mutex); - snd_printdd("<-lx_pcm_open, %d\n", err); + dev_dbg(chip->card->dev, "<-lx_pcm_open, %d\n", err); return err; } static int lx_pcm_close(struct snd_pcm_substream *substream) { int err = 0; - snd_printdd("->lx_pcm_close\n"); + dev_dbg(substream->pcm->card->dev, "->lx_pcm_close\n"); return err; } @@ -285,13 +285,13 @@ static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : &chip->playback_stream; - snd_printdd("->lx_pcm_stream_pointer\n"); + dev_dbg(chip->card->dev, "->lx_pcm_stream_pointer\n"); spin_lock_irqsave(&chip->lock, flags); pos = lx_stream->frame_pos * substream->runtime->period_size; spin_unlock_irqrestore(&chip->lock, flags); - snd_printdd(LXP "stream_pointer at %ld\n", pos); + dev_dbg(chip->card->dev, "stream_pointer at %ld\n", pos); return pos; } @@ -301,37 +301,37 @@ static int lx_pcm_prepare(struct snd_pcm_substream *substream) int err = 0; const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - snd_printdd("->lx_pcm_prepare\n"); + dev_dbg(chip->card->dev, "->lx_pcm_prepare\n"); mutex_lock(&chip->setup_mutex); if (chip->hardware_running[is_capture]) { err = lx_hardware_stop(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to stop hardware. " + dev_err(chip->card->dev, "failed to stop hardware. " "Error code %d\n", err); goto exit; } err = lx_hardware_close(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to close hardware. " + dev_err(chip->card->dev, "failed to close hardware. " "Error code %d\n", err); goto exit; } } - snd_printd(LXP "opening hardware\n"); + dev_dbg(chip->card->dev, "opening hardware\n"); err = lx_hardware_open(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to open hardware. " + dev_err(chip->card->dev, "failed to open hardware. " "Error code %d\n", err); goto exit; } err = lx_hardware_start(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to start hardware. " + dev_err(chip->card->dev, "failed to start hardware. " "Error code %d\n", err); goto exit; } @@ -354,7 +354,7 @@ static int lx_pcm_hw_params(struct snd_pcm_substream *substream, struct lx6464es *chip = snd_pcm_substream_chip(substream); int err = 0; - snd_printdd("->lx_pcm_hw_params\n"); + dev_dbg(chip->card->dev, "->lx_pcm_hw_params\n"); mutex_lock(&chip->setup_mutex); @@ -389,20 +389,20 @@ static int lx_pcm_hw_free(struct snd_pcm_substream *substream) int err = 0; int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); - snd_printdd("->lx_pcm_hw_free\n"); + dev_dbg(chip->card->dev, "->lx_pcm_hw_free\n"); mutex_lock(&chip->setup_mutex); if (chip->hardware_running[is_capture]) { err = lx_hardware_stop(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to stop hardware. " + dev_err(chip->card->dev, "failed to stop hardware. " "Error code %d\n", err); goto exit; } err = lx_hardware_close(chip, substream); if (err < 0) { - snd_printk(KERN_ERR LXP "failed to close hardware. " + dev_err(chip->card->dev, "failed to close hardware. " "Error code %d\n", err); goto exit; } @@ -446,25 +446,25 @@ static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); - snd_printdd(LXP "starting: needed %d, freed %d\n", + dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", needed, freed); err = lx_buffer_give(chip, 0, is_capture, period_bytes, lower_32_bits(buf), upper_32_bits(buf), &buffer_index); - snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", - buffer_index, (void *)buf, period_bytes); + dev_dbg(chip->card->dev, "starting: buffer index %x on 0x%lx (%d bytes)\n", + buffer_index, (unsigned long)buf, period_bytes); buf += period_bytes; } err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); - snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); + dev_dbg(chip->card->dev, "starting: needed %d, freed %d\n", needed, freed); - snd_printd(LXP "starting: starting stream\n"); + dev_dbg(chip->card->dev, "starting: starting stream\n"); err = lx_stream_start(chip, 0, is_capture); if (err < 0) - snd_printk(KERN_ERR LXP "couldn't start stream\n"); + dev_err(chip->card->dev, "couldn't start stream\n"); else lx_stream->status = LX_STREAM_STATUS_RUNNING; @@ -476,10 +476,10 @@ static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) const unsigned int is_capture = lx_stream->is_capture; int err; - snd_printd(LXP "stopping: stopping stream\n"); + dev_dbg(chip->card->dev, "stopping: stopping stream\n"); err = lx_stream_stop(chip, 0, is_capture); if (err < 0) - snd_printk(KERN_ERR LXP "couldn't stop stream\n"); + dev_err(chip->card->dev, "couldn't stop stream\n"); else lx_stream->status = LX_STREAM_STATUS_FREE; @@ -507,7 +507,7 @@ static void lx_trigger_tasklet(unsigned long data) struct lx6464es *chip = (struct lx6464es *)data; unsigned long flags; - snd_printdd("->lx_trigger_tasklet\n"); + dev_dbg(chip->card->dev, "->lx_trigger_tasklet\n"); spin_lock_irqsave(&chip->lock, flags); lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); @@ -547,14 +547,14 @@ static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) struct lx_stream *stream = is_capture ? &chip->capture_stream : &chip->playback_stream; - snd_printdd("->lx_pcm_trigger\n"); + dev_dbg(chip->card->dev, "->lx_pcm_trigger\n"); return lx_pcm_trigger_dispatch(chip, stream, cmd); } static int snd_lx6464es_free(struct lx6464es *chip) { - snd_printdd("->snd_lx6464es_free\n"); + dev_dbg(chip->card->dev, "->snd_lx6464es_free\n"); lx_irq_disable(chip); @@ -578,12 +578,12 @@ static int snd_lx6464es_dev_free(struct snd_device *device) } /* reset the dsp during initialization */ -static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) +static int lx_init_xilinx_reset(struct lx6464es *chip) { int i; u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); - snd_printdd("->lx_init_xilinx_reset\n"); + dev_dbg(chip->card->dev, "->lx_init_xilinx_reset\n"); /* activate reset of xilinx */ plx_reg &= ~CHIPSC_RESET_XILINX; @@ -603,8 +603,8 @@ static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) msleep(10); reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); if (reg_mbox3) { - snd_printd(LXP "xilinx reset done\n"); - snd_printdd(LXP "xilinx took %d loops\n", i); + dev_dbg(chip->card->dev, "xilinx reset done\n"); + dev_dbg(chip->card->dev, "xilinx took %d loops\n", i); break; } } @@ -620,11 +620,11 @@ static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) return 0; } -static int __devinit lx_init_xilinx_test(struct lx6464es *chip) +static int lx_init_xilinx_test(struct lx6464es *chip) { u32 reg; - snd_printdd("->lx_init_xilinx_test\n"); + dev_dbg(chip->card->dev, "->lx_init_xilinx_test\n"); /* TEST if we have access to Xilinx/MicroBlaze */ lx_dsp_reg_write(chip, eReg_CSM, 0); @@ -632,25 +632,25 @@ static int __devinit lx_init_xilinx_test(struct lx6464es *chip) reg = lx_dsp_reg_read(chip, eReg_CSM); if (reg) { - snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); + dev_err(chip->card->dev, "Problem: Reg_CSM %x.\n", reg); /* PCI9056_SPACE0_REMAP */ lx_plx_reg_write(chip, ePLX_PCICR, 1); reg = lx_dsp_reg_read(chip, eReg_CSM); if (reg) { - snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); + dev_err(chip->card->dev, "Error: Reg_CSM %x.\n", reg); return -EAGAIN; /* seems to be appropriate */ } } - snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); + dev_dbg(chip->card->dev, "Xilinx/MicroBlaze access test successful\n"); return 0; } /* initialize ethersound */ -static int __devinit lx_init_ethersound_config(struct lx6464es *chip) +static int lx_init_ethersound_config(struct lx6464es *chip) { int i; u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); @@ -661,7 +661,7 @@ static int __devinit lx_init_ethersound_config(struct lx6464es *chip) (64 << IOCR_OUTPUTS_OFFSET) | (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); - snd_printdd("->lx_init_ethersound\n"); + dev_dbg(chip->card->dev, "->lx_init_ethersound\n"); chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; @@ -675,35 +675,35 @@ static int __devinit lx_init_ethersound_config(struct lx6464es *chip) for (i = 0; i != 1000; ++i) { if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { - snd_printd(LXP "ethersound initialized after %dms\n", + dev_dbg(chip->card->dev, "ethersound initialized after %dms\n", i); goto ethersound_initialized; } msleep(1); } - snd_printk(KERN_WARNING LXP + dev_warn(chip->card->dev, "ethersound could not be initialized after %dms\n", i); return -ETIMEDOUT; ethersound_initialized: - snd_printd(LXP "ethersound initialized\n"); + dev_dbg(chip->card->dev, "ethersound initialized\n"); return 0; } -static int __devinit lx_init_get_version_features(struct lx6464es *chip) +static int lx_init_get_version_features(struct lx6464es *chip) { u32 dsp_version; int err; - snd_printdd("->lx_init_get_version_features\n"); + dev_dbg(chip->card->dev, "->lx_init_get_version_features\n"); err = lx_dsp_get_version(chip, &dsp_version); if (err == 0) { u32 freq; - snd_printk(LXP "DSP version: V%02d.%02d #%d\n", + dev_info(chip->card->dev, "DSP version: V%02d.%02d #%d\n", (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, dsp_version & 0xff); @@ -718,9 +718,9 @@ static int __devinit lx_init_get_version_features(struct lx6464es *chip) err = lx_dsp_get_clock_frequency(chip, &freq); if (err == 0) chip->board_sample_rate = freq; - snd_printd(LXP "actual clock frequency %d\n", freq); + dev_dbg(chip->card->dev, "actual clock frequency %d\n", freq); } else { - snd_printk(KERN_ERR LXP "DSP corrupted \n"); + dev_err(chip->card->dev, "DSP corrupted \n"); err = -EAGAIN; } @@ -732,7 +732,7 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran) int err = 0; u32 snapped_gran = MICROBLAZE_IBL_MIN; - snd_printdd("->lx_set_granularity\n"); + dev_dbg(chip->card->dev, "->lx_set_granularity\n"); /* blocksize is a power of 2 */ while ((snapped_gran < gran) && @@ -745,38 +745,38 @@ static int lx_set_granularity(struct lx6464es *chip, u32 gran) err = lx_dsp_set_granularity(chip, snapped_gran); if (err < 0) { - snd_printk(KERN_WARNING LXP "could not set granularity\n"); + dev_warn(chip->card->dev, "could not set granularity\n"); err = -EAGAIN; } if (snapped_gran != gran) - snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); + dev_err(chip->card->dev, "snapped blocksize to %d\n", snapped_gran); - snd_printd(LXP "set blocksize on board %d\n", snapped_gran); + dev_dbg(chip->card->dev, "set blocksize on board %d\n", snapped_gran); chip->pcm_granularity = snapped_gran; return err; } /* initialize and test the xilinx dsp chip */ -static int __devinit lx_init_dsp(struct lx6464es *chip) +static int lx_init_dsp(struct lx6464es *chip) { int err; int i; - snd_printdd("->lx_init_dsp\n"); + dev_dbg(chip->card->dev, "->lx_init_dsp\n"); - snd_printd(LXP "initialize board\n"); + dev_dbg(chip->card->dev, "initialize board\n"); err = lx_init_xilinx_reset(chip); if (err) return err; - snd_printd(LXP "testing board\n"); + dev_dbg(chip->card->dev, "testing board\n"); err = lx_init_xilinx_test(chip); if (err) return err; - snd_printd(LXP "initialize ethersound configuration\n"); + dev_dbg(chip->card->dev, "initialize ethersound configuration\n"); err = lx_init_ethersound_config(chip); if (err) return err; @@ -797,8 +797,9 @@ static int __devinit lx_init_dsp(struct lx6464es *chip) return -ETIMEDOUT; mac_ready: - snd_printd(LXP "mac address ready read after: %dms\n", i); - snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", + dev_dbg(chip->card->dev, "mac address ready read after: %dms\n", i); + dev_info(chip->card->dev, + "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", chip->mac_address[0], chip->mac_address[1], chip->mac_address[2], chip->mac_address[3], chip->mac_address[4], chip->mac_address[5]); @@ -835,7 +836,7 @@ static struct snd_pcm_ops lx_ops_capture = { .pointer = lx_pcm_stream_pointer, }; -static int __devinit lx_pcm_create(struct lx6464es *chip) +static int lx_pcm_create(struct lx6464es *chip) { int err; struct snd_pcm *pcm; @@ -907,7 +908,7 @@ static int lx_control_playback_put(struct snd_kcontrol *kcontrol, return changed; } -static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { +static struct snd_kcontrol_new lx_control_playback_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Playback Switch", .index = 0, @@ -954,7 +955,7 @@ static void lx_proc_levels_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) +static int lx_proc_create(struct snd_card *card, struct lx6464es *chip) { struct snd_info_entry *entry; int err = snd_card_proc_new(card, "levels", &entry); @@ -966,9 +967,9 @@ static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip } -static int __devinit snd_lx6464es_create(struct snd_card *card, - struct pci_dev *pci, - struct lx6464es **rchip) +static int snd_lx6464es_create(struct snd_card *card, + struct pci_dev *pci, + struct lx6464es **rchip) { struct lx6464es *chip; int err; @@ -977,7 +978,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, .dev_free = snd_lx6464es_dev_free, }; - snd_printdd("->snd_lx6464es_create\n"); + dev_dbg(card->dev, "->snd_lx6464es_create\n"); *rchip = NULL; @@ -991,8 +992,8 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, /* check if we can restrict PCI DMA transfers to 32 bits */ err = pci_set_dma_mask(pci, DMA_BIT_MASK(32)); if (err < 0) { - snd_printk(KERN_ERR "architecture does not support " - "32bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1034,7 +1035,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip); if (err) { - snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); goto request_irq_failed; } chip->irq = pci->irq; @@ -1045,7 +1046,7 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, err = lx_init_dsp(chip); if (err < 0) { - snd_printk(KERN_ERR LXP "error during DSP initialization\n"); + dev_err(card->dev, "error during DSP initialization\n"); return err; } @@ -1062,8 +1063,6 @@ static int __devinit snd_lx6464es_create(struct snd_card *card, if (err < 0) return err; - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; @@ -1082,15 +1081,15 @@ alloc_failed: return err; } -static int __devinit snd_lx6464es_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_lx6464es_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; struct lx6464es *chip; int err; - snd_printdd("->snd_lx6464es_probe\n"); + dev_dbg(&pci->dev, "->snd_lx6464es_probe\n"); if (dev >= SNDRV_CARDS) return -ENODEV; @@ -1099,13 +1098,14 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; err = snd_lx6464es_create(card, pci, &chip); if (err < 0) { - snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); + dev_err(card->dev, "error during snd_lx6464es_create\n"); goto out_free; } @@ -1125,7 +1125,7 @@ static int __devinit snd_lx6464es_probe(struct pci_dev *pci, if (err < 0) goto out_free; - snd_printdd(LXP "initialization successful\n"); + dev_dbg(chip->card->dev, "initialization successful\n"); pci_set_drvdata(pci, card); dev++; return 0; @@ -1136,10 +1136,9 @@ out_free: } -static void __devexit snd_lx6464es_remove(struct pci_dev *pci) +static void snd_lx6464es_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -1147,7 +1146,7 @@ static struct pci_driver lx6464es_driver = { .name = KBUILD_MODNAME, .id_table = snd_lx6464es_ids, .probe = snd_lx6464es_probe, - .remove = __devexit_p(snd_lx6464es_remove), + .remove = snd_lx6464es_remove, }; module_pci_driver(lx6464es_driver); diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c index 8c3e7fcefd9..e8f38e5df10 100644 --- a/sound/pci/lx6464es/lx_core.c +++ b/sound/pci/lx6464es/lx_core.c @@ -24,6 +24,7 @@ /* #define RMH_DEBUG 1 */ +#include <linux/bitops.h> #include <linux/module.h> #include <linux/pci.h> #include <linux/delay.h> @@ -141,63 +142,6 @@ void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) iowrite32(data, address); } -u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) -{ - int index; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 2: - index = ePLX_MBOX2; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - snd_BUG(); - default: - return 0xdeadbeef; - } - - return lx_plx_reg_read(chip, index); -} - -int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) -{ - int index = -1; - - switch (mbox_nr) { - case 1: - index = ePLX_MBOX1; break; - case 3: - index = ePLX_MBOX3; break; - case 4: - index = ePLX_MBOX4; break; - case 5: - index = ePLX_MBOX5; break; - case 6: - index = ePLX_MBOX6; break; - case 7: - index = ePLX_MBOX7; break; - case 0: /* reserved for HF flags */ - case 2: /* reserved for Pipe States - * the DSP keeps an image of it */ - snd_BUG(); - return -EBADRQC; - } - - lx_plx_reg_write(chip, index, value); - return 0; -} - - /* rmh */ #ifdef CONFIG_SND_DEBUG @@ -330,7 +274,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) int dwloop; if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { - snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); + dev_err(chip->card->dev, "PIOSendMessage eReg_CSM %x\n", reg); return -EBUSY; } @@ -351,7 +295,7 @@ static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) } else udelay(1); } - snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " + dev_warn(chip->card->dev, "TIMEOUT lx_message_send_atomic! " "polling failed\n"); polling_successful: @@ -363,18 +307,18 @@ polling_successful: rmh->stat_len); } } else - snd_printk(LXP "rmh error: %08x\n", reg); + dev_err(chip->card->dev, "rmh error: %08x\n", reg); /* clear Reg_CSM_MR */ lx_dsp_reg_write(chip, eReg_CSM, 0); switch (reg) { case ED_DSP_TIMED_OUT: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); + dev_warn(chip->card->dev, "lx_message_send: dsp timeout\n"); return -ETIMEDOUT; case ED_DSP_CRASHED: - snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); + dev_warn(chip->card->dev, "lx_message_send: dsp crashed\n"); return -EAGAIN; } @@ -385,7 +329,7 @@ polling_successful: /* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) +int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) { u16 ret; unsigned long flags; @@ -486,38 +430,6 @@ int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) return ret; } -#define CSES_TIMEOUT 100 /* microseconds */ -#define CSES_CE 0x0001 -#define CSES_BROADCAST 0x0002 -#define CSES_UPDATE_LDSV 0x0004 - -int lx_dsp_es_check_pipeline(struct lx6464es *chip) -{ - int i; - - for (i = 0; i != CSES_TIMEOUT; ++i) { - /* - * le bit CSES_UPDATE_LDSV est à1 dés que le macprog - * est pret. il re-passe à0 lorsque le premier read a - * été fait. pour l'instant on retire le test car ce bit - * passe a 1 environ 200 à400 ms aprés que le registre - * confES àété écrit (kick du xilinx ES). - * - * On ne teste que le bit CE. - * */ - - u32 cses = lx_dsp_reg_read(chip, eReg_CSES); - - if ((cses & CSES_CE) == 0) - return 0; - - udelay(1); - } - - return -ETIMEDOUT; -} - - #define PIPE_INFO_TO_CMD(capture, pipe) \ ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) @@ -542,7 +454,7 @@ int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, spin_unlock_irqrestore(&chip->msg_lock, flags); if (err != 0) - snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); + dev_err(chip->card->dev, "could not allocate pipe\n"); return err; } @@ -603,16 +515,16 @@ int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, *r_needed += 1; } -#if 0 - snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", + dev_dbg(chip->card->dev, + "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", *r_needed, *r_freed); for (i = 0; i < MAX_STREAM_BUFFER; ++i) { for (i = 0; i != chip->rmh.stat_len; ++i) - snd_printdd(" stat[%d]: %x, %x\n", i, + dev_dbg(chip->card->dev, + " stat[%d]: %x, %x\n", i, chip->rmh.stat[i], chip->rmh.stat[i] & MASK_DATA_SIZE); } -#endif } spin_unlock_irqrestore(&chip->msg_lock, flags); @@ -701,8 +613,8 @@ int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ if (err != 0) - snd_printk(KERN_ERR - "lx6464es: could not query pipe's sample count\n"); + dev_err(chip->card->dev, + "could not query pipe's sample count\n"); else { *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) << 24) /* hi part */ @@ -728,7 +640,7 @@ int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) err = lx_message_send_atomic(chip, &chip->rmh); if (err != 0) - snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); + dev_err(chip->card->dev, "could not query pipe's state\n"); else *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; @@ -801,7 +713,7 @@ int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, u32 channels = runtime->channels; if (runtime->channels != channels) - snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", + dev_err(chip->card->dev, "channel count mismatch: %d vs %d", runtime->channels, channels); spin_lock_irqsave(&chip->msg_lock, flags); @@ -904,13 +816,16 @@ int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, } if (err == EB_RBUFFERS_TABLE_OVERFLOW) - snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); + dev_err(chip->card->dev, + "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); if (err == EB_INVALID_STREAM) - snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); + dev_err(chip->card->dev, + "lx_buffer_give EB_INVALID_STREAM\n"); if (err == EB_CMD_REFUSED) - snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); + dev_err(chip->card->dev, + "lx_buffer_give EB_CMD_REFUSED\n"); done: spin_unlock_irqrestore(&chip->msg_lock, flags); @@ -983,7 +898,8 @@ int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ - snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], + dev_dbg(chip->card->dev, + "mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], chip->rmh.cmd[2]); err = lx_message_send_atomic(chip, &chip->rmh); @@ -1049,9 +965,9 @@ int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, /* interrupt handling */ #define PCX_IRQ_NONE 0 -#define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ -#define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ -#define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ +#define IRQCS_ACTIVE_PCIDB BIT(13) +#define IRQCS_ENABLE_PCIIRQ BIT(8) +#define IRQCS_ENABLE_PCIDB BIT(9) static u32 lx_interrupt_test_ack(struct lx6464es *chip) { @@ -1093,7 +1009,7 @@ static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, } if (irq_async) { - /* snd_printd("interrupt: async event pending\n"); */ + /* dev_dbg(chip->card->dev, "interrupt: async event pending\n"); */ *r_async_pending = 1; } @@ -1108,25 +1024,21 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, int err; u32 stat[9]; /* answer from CMD_04_GET_EVENT */ - /* On peut optimiser pour ne pas lire les evenements vides - * les mots de réponse sont dans l'ordre suivant : - * Stat[0] mot de status général - * Stat[1] fin de buffer OUT pF - * Stat[2] fin de buffer OUT pf - * Stat[3] fin de buffer IN pF - * Stat[4] fin de buffer IN pf - * Stat[5] underrun poid fort - * Stat[6] underrun poid faible - * Stat[7] overrun poid fort - * Stat[8] overrun poid faible + /* We can optimize this to not read dumb events. + * Answer words are in the following order: + * Stat[0] general status + * Stat[1] end of buffer OUT pF + * Stat[2] end of buffer OUT pf + * Stat[3] end of buffer IN pF + * Stat[4] end of buffer IN pf + * Stat[5] MSB underrun + * Stat[6] LSB underrun + * Stat[7] MSB overrun + * Stat[8] LSB overrun * */ u64 orun_mask; u64 urun_mask; -#if 0 - int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; - int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; -#endif int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; @@ -1139,13 +1051,13 @@ static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, if (eb_pending_in) { *r_notified_in_pipe_mask = ((u64)stat[3] << 32) + stat[4]; - snd_printdd(LXP "interrupt: EOBI pending %llx\n", + dev_dbg(chip->card->dev, "interrupt: EOBI pending %llx\n", *r_notified_in_pipe_mask); } if (eb_pending_out) { *r_notified_out_pipe_mask = ((u64)stat[1] << 32) + stat[2]; - snd_printdd(LXP "interrupt: EOBO pending %llx\n", + dev_dbg(chip->card->dev, "interrupt: EOBO pending %llx\n", *r_notified_out_pipe_mask); } @@ -1181,18 +1093,20 @@ static int lx_interrupt_request_new_buffer(struct lx6464es *chip, u32 needed, freed; u32 size_array[MAX_STREAM_BUFFER]; - snd_printdd("->lx_interrupt_request_new_buffer\n"); + dev_dbg(chip->card->dev, "->lx_interrupt_request_new_buffer\n"); spin_lock_irqsave(&chip->lock, flags); err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); - snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); + dev_dbg(chip->card->dev, + "interrupt: needed %d, freed %d\n", needed, freed); unpack_pointer(buf, &buf_lo, &buf_hi); err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, &buffer_index); - snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", - buffer_index, (void *)buf, period_bytes); + dev_dbg(chip->card->dev, + "interrupt: gave buffer index %x on 0x%lx (%d bytes)\n", + buffer_index, (unsigned long)buf, period_bytes); lx_stream->frame_pos = next_pos; spin_unlock_irqrestore(&chip->lock, flags); @@ -1206,11 +1120,11 @@ void lx_tasklet_playback(unsigned long data) struct lx_stream *lx_stream = &chip->playback_stream; int err; - snd_printdd("->lx_tasklet_playback\n"); + dev_dbg(chip->card->dev, "->lx_tasklet_playback\n"); err = lx_interrupt_request_new_buffer(chip, lx_stream); if (err < 0) - snd_printk(KERN_ERR LXP + dev_err(chip->card->dev, "cannot request new buffer for playback\n"); snd_pcm_period_elapsed(lx_stream->stream); @@ -1222,10 +1136,10 @@ void lx_tasklet_capture(unsigned long data) struct lx_stream *lx_stream = &chip->capture_stream; int err; - snd_printdd("->lx_tasklet_capture\n"); + dev_dbg(chip->card->dev, "->lx_tasklet_capture\n"); err = lx_interrupt_request_new_buffer(chip, lx_stream); if (err < 0) - snd_printk(KERN_ERR LXP + dev_err(chip->card->dev, "cannot request new buffer for capture\n"); snd_pcm_period_elapsed(lx_stream->stream); @@ -1240,12 +1154,14 @@ static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, int err = 0; if (notified_in_pipe_mask) { - snd_printdd(LXP "requesting audio transfer for capture\n"); + dev_dbg(chip->card->dev, + "requesting audio transfer for capture\n"); tasklet_hi_schedule(&chip->tasklet_capture); } if (notified_out_pipe_mask) { - snd_printdd(LXP "requesting audio transfer for playback\n"); + dev_dbg(chip->card->dev, + "requesting audio transfer for playback\n"); tasklet_hi_schedule(&chip->tasklet_playback); } @@ -1261,30 +1177,29 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) spin_lock(&chip->lock); - snd_printdd("**************************************************\n"); + dev_dbg(chip->card->dev, + "**************************************************\n"); if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { spin_unlock(&chip->lock); - snd_printdd("IRQ_NONE\n"); + dev_dbg(chip->card->dev, "IRQ_NONE\n"); return IRQ_NONE; /* this device did not cause the interrupt */ } if (irqsrc & MASK_SYS_STATUS_CMD_DONE) goto exit; -#if 0 if (irqsrc & MASK_SYS_STATUS_EOBI) - snd_printdd(LXP "interrupt: EOBI\n"); + dev_dbg(chip->card->dev, "interrupt: EOBI\n"); if (irqsrc & MASK_SYS_STATUS_EOBO) - snd_printdd(LXP "interrupt: EOBO\n"); + dev_dbg(chip->card->dev, "interrupt: EOBO\n"); if (irqsrc & MASK_SYS_STATUS_URUN) - snd_printdd(LXP "interrupt: URUN\n"); + dev_dbg(chip->card->dev, "interrupt: URUN\n"); if (irqsrc & MASK_SYS_STATUS_ORUN) - snd_printdd(LXP "interrupt: ORUN\n"); -#endif + dev_dbg(chip->card->dev, "interrupt: ORUN\n"); if (async_pending) { u64 notified_in_pipe_mask = 0; @@ -1298,7 +1213,7 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) ¬ified_in_pipe_mask, ¬ified_out_pipe_mask); if (err) - snd_printk(KERN_ERR LXP + dev_err(chip->card->dev, "error handling async events\n"); err = lx_interrupt_handle_audio_transfer(chip, @@ -1306,20 +1221,18 @@ irqreturn_t lx_interrupt(int irq, void *dev_id) notified_out_pipe_mask ); if (err) - snd_printk(KERN_ERR LXP + dev_err(chip->card->dev, "error during audio transfer\n"); } if (async_escmd) { -#if 0 /* backdoor for ethersound commands * * for now, we do not need this * * */ - snd_printdd("lx6464es: interrupt requests escmd handling\n"); -#endif + dev_dbg(chip->card->dev, "interrupt requests escmd handling\n"); } exit: @@ -1346,12 +1259,12 @@ static void lx_irq_set(struct lx6464es *chip, int enable) void lx_irq_enable(struct lx6464es *chip) { - snd_printdd("->lx_irq_enable\n"); + dev_dbg(chip->card->dev, "->lx_irq_enable\n"); lx_irq_set(chip, 1); } void lx_irq_disable(struct lx6464es *chip) { - snd_printdd("->lx_irq_disable\n"); + dev_dbg(chip->card->dev, "->lx_irq_disable\n"); lx_irq_set(chip, 0); } diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h index 4d7ff797a64..5ec5e04da1a 100644 --- a/sound/pci/lx6464es/lx_core.h +++ b/sound/pci/lx6464es/lx_core.h @@ -109,7 +109,7 @@ struct lx_rmh { /* low-level dsp access */ -int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); +int lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index eb3cd3a4315..0d3ea3e7995 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c @@ -822,7 +822,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { MODULE_DEVICE_TABLE(pci, snd_m3_ids); -static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_amp_quirk_list[] = { SND_PCI_QUIRK(0x0E11, 0x0094, "Compaq Evo N600c", 0x0c), SND_PCI_QUIRK(0x10f7, 0x833e, "Panasonic CF-28", 0x0d), SND_PCI_QUIRK(0x10f7, 0x833d, "Panasonic CF-72", 0x0d), @@ -831,7 +831,7 @@ static struct snd_pci_quirk m3_amp_quirk_list[] __devinitdata = { { } /* END */ }; -static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_irda_quirk_list[] = { SND_PCI_QUIRK(0x1028, 0x00b0, "Dell Inspiron 4000", 1), SND_PCI_QUIRK(0x1028, 0x00a4, "Dell Inspiron 8000", 1), SND_PCI_QUIRK(0x1028, 0x00e6, "Dell Inspiron 8100", 1), @@ -839,7 +839,7 @@ static struct snd_pci_quirk m3_irda_quirk_list[] __devinitdata = { }; /* hardware volume quirks */ -static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_hv_quirk_list[] = { /* Allegro chips */ SND_PCI_QUIRK(0x0E11, 0x002E, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), SND_PCI_QUIRK(0x0E11, 0x0094, NULL, HV_CTRL_ENABLE | HV_BUTTON_FROM_GD), @@ -917,7 +917,7 @@ static struct snd_pci_quirk m3_hv_quirk_list[] __devinitdata = { }; /* HP Omnibook quirks */ -static struct snd_pci_quirk m3_omnibook_quirk_list[] __devinitdata = { +static struct snd_pci_quirk m3_omnibook_quirk_list[] = { SND_PCI_QUIRK_ID(0x103c, 0x0010), /* HP OmniBook 6000 */ SND_PCI_QUIRK_ID(0x103c, 0x0011), /* HP OmniBook 500 */ { } /* END */ @@ -1403,7 +1403,7 @@ static int snd_m3_pcm_hw_params(struct snd_pcm_substream *substream, /* set buffer address */ s->buffer_addr = substream->runtime->dma_addr; if (s->buffer_addr & 0x3) { - snd_printk(KERN_ERR "oh my, not aligned\n"); + dev_err(substream->pcm->card->dev, "oh my, not aligned\n"); s->buffer_addr = s->buffer_addr & ~0x3; } return 0; @@ -1856,7 +1856,7 @@ static struct snd_pcm_ops snd_m3_capture_ops = { .pointer = snd_m3_pcm_pointer, }; -static int __devinit +static int snd_m3_pcm(struct snd_m3 * chip, int device) { struct snd_pcm *pcm; @@ -1900,7 +1900,7 @@ static int snd_m3_ac97_wait(struct snd_m3 *chip) cpu_relax(); } while (i-- > 0); - snd_printk(KERN_ERR "ac97 serial bus busy\n"); + dev_err(chip->card->dev, "ac97 serial bus busy\n"); return 1; } @@ -2015,7 +2015,8 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip) delay1 += 10; delay2 += 100; - snd_printd("maestro3: retrying codec reset with delays of %d and %d ms\n", + dev_dbg(chip->card->dev, + "retrying codec reset with delays of %d and %d ms\n", delay1, delay2); } @@ -2031,7 +2032,7 @@ static void snd_m3_ac97_reset(struct snd_m3 *chip) #endif } -static int __devinit snd_m3_mixer(struct snd_m3 *chip) +static int snd_m3_mixer(struct snd_m3 *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2173,7 +2174,7 @@ static void snd_m3_assp_init(struct snd_m3 *chip) } -static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index) +static int snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma *s, int index) { int data_bytes = 2 * ( MINISRC_TMP_BUFFER_SIZE / 2 + MINISRC_IN_BUFFER_SIZE / 2 + @@ -2194,7 +2195,8 @@ static int __devinit snd_m3_assp_client_init(struct snd_m3 *chip, struct m3_dma address = 0x1100 + ((data_bytes/2) * index); if ((address + (data_bytes/2)) >= 0x1c00) { - snd_printk(KERN_ERR "no memory for %d bytes at ind %d (addr 0x%x)\n", + dev_err(chip->card->dev, + "no memory for %d bytes at ind %d (addr 0x%x)\n", data_bytes, index, address); return -ENOMEM; } @@ -2439,8 +2441,7 @@ static int m3_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "maestor3: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2488,7 +2489,7 @@ static SIMPLE_DEV_PM_OPS(m3_pm, m3_suspend, m3_resume); #endif /* CONFIG_PM_SLEEP */ #ifdef CONFIG_SND_MAESTRO3_INPUT -static int __devinit snd_m3_input_register(struct snd_m3 *chip) +static int snd_m3_input_register(struct snd_m3 *chip) { struct input_dev *input_dev; int err; @@ -2532,7 +2533,7 @@ static int snd_m3_dev_free(struct snd_device *device) return snd_m3_free(chip); } -static int __devinit +static int snd_m3_create(struct snd_card *card, struct pci_dev *pci, int enable_amp, int amp_gpio, @@ -2553,7 +2554,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, /* check, if we can restrict PCI DMA transfers to 28 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(28)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(28)) < 0) { - snd_printk(KERN_ERR "architecture does not support 28bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 28bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -2586,8 +2588,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, else { quirk = snd_pci_quirk_lookup(pci, m3_amp_quirk_list); if (quirk) { - snd_printdd(KERN_INFO "maestro3: set amp-gpio " - "for '%s'\n", quirk->name); + dev_info(card->dev, "set amp-gpio for '%s'\n", + snd_pci_quirk_name(quirk)); chip->amp_gpio = quirk->value; } else if (chip->allegro_flag) chip->amp_gpio = GPO_EXT_AMP_ALLEGRO; @@ -2597,8 +2599,8 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, quirk = snd_pci_quirk_lookup(pci, m3_irda_quirk_list); if (quirk) { - snd_printdd(KERN_INFO "maestro3: enabled irda workaround " - "for '%s'\n", quirk->name); + dev_info(card->dev, "enabled irda workaround for '%s'\n", + snd_pci_quirk_name(quirk)); chip->irda_workaround = 1; } quirk = snd_pci_quirk_lookup(pci, m3_hv_quirk_list); @@ -2650,7 +2652,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, if (request_irq(pci->irq, snd_m3_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_m3_free(chip); return -ENOMEM; } @@ -2659,7 +2661,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, #ifdef CONFIG_PM_SLEEP chip->suspend_mem = vmalloc(sizeof(u16) * (REV_B_CODE_MEMORY_LENGTH + REV_B_DATA_MEMORY_LENGTH)); if (chip->suspend_mem == NULL) - snd_printk(KERN_WARNING "can't allocate apm buffer\n"); + dev_warn(card->dev, "can't allocate apm buffer\n"); #endif if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { @@ -2683,16 +2685,15 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, if (chip->hv_config & HV_CTRL_ENABLE) { err = snd_m3_input_register(chip); if (err) - snd_printk(KERN_WARNING "Input device registration " - "failed with error %i", err); + dev_warn(card->dev, + "Input device registration failed with error %i", + err); } #endif snd_m3_enable_ints(chip); snd_m3_assp_continue(chip); - snd_card_set_dev(card, &pci->dev); - *chip_ret = chip; return 0; @@ -2700,7 +2701,7 @@ snd_m3_create(struct snd_card *card, struct pci_dev *pci, /* */ -static int __devinit +static int snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2719,7 +2720,8 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -2762,7 +2764,7 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi); if (err < 0) - printk(KERN_WARNING "maestro3: no MIDI support.\n"); + dev_warn(card->dev, "no MIDI support.\n"); #endif pci_set_drvdata(pci, card); @@ -2770,17 +2772,16 @@ snd_m3_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return 0; } -static void __devexit snd_m3_remove(struct pci_dev *pci) +static void snd_m3_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver m3_driver = { .name = KBUILD_MODNAME, .id_table = snd_m3_ids, .probe = snd_m3_probe, - .remove = __devexit_p(snd_m3_remove), + .remove = snd_m3_remove, .driver = { .pm = M3_PM_OPS, }, diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index 0762610c99c..a93e7af51ee 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c @@ -87,7 +87,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, if(!start) return 0; /* already stopped */ break; default: - snd_printk(KERN_ERR "error mixart_set_pipe_state called with wrong pipe->status!\n"); + dev_err(&mgr->pci->dev, + "error mixart_set_pipe_state called with wrong pipe->status!\n"); return -EINVAL; /* function called with wrong pipe status */ } @@ -102,7 +103,8 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, err = snd_mixart_send_msg_wait_notif(mgr, &request, system_msg_uid); if(err) { - snd_printk(KERN_ERR "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n"); + dev_err(&mgr->pci->dev, + "error : MSG_SYSTEM_WAIT_SYNCHRO_CMD was not notified !\n"); return err; } @@ -123,7 +125,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); if (err < 0 || group_state_resp.txx_status != 0) { - snd_printk(KERN_ERR "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); + dev_err(&mgr->pci->dev, + "error MSG_STREAM_ST***_STREAM_GRP_PACKET err=%x stat=%x !\n", + err, group_state_resp.txx_status); return -EINVAL; } @@ -134,7 +138,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, err = snd_mixart_send_msg(mgr, &request, sizeof(group_state_resp), &group_state_resp); if (err < 0 || group_state_resp.txx_status != 0) { - snd_printk(KERN_ERR "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", err, group_state_resp.txx_status); + dev_err(&mgr->pci->dev, + "error MSG_STREAM_START_STREAM_GRP_PACKET err=%x stat=%x !\n", + err, group_state_resp.txx_status); return -EINVAL; } @@ -147,7 +153,9 @@ static int mixart_set_pipe_state(struct mixart_mgr *mgr, err = snd_mixart_send_msg(mgr, &request, sizeof(stat), &stat); if (err < 0 || stat != 0) { - snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", err, stat); + dev_err(&mgr->pci->dev, + "error MSG_SYSTEM_SEND_SYNCHRO_CMD err=%x stat=%x !\n", + err, stat); return -EINVAL; } @@ -178,7 +186,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr, if(rate == 0) return 0; /* nothing to do */ else { - snd_printk(KERN_ERR "error mixart_set_clock(%d) called with wrong pipe->status !\n", rate); + dev_err(&mgr->pci->dev, + "error mixart_set_clock(%d) called with wrong pipe->status !\n", + rate); return -EINVAL; } } @@ -190,7 +200,7 @@ static int mixart_set_clock(struct mixart_mgr *mgr, clock_properties.nb_callers = 1; /* only one entry in uid_caller ! */ clock_properties.uid_caller[0] = pipe->group_uid; - snd_printdd("mixart_set_clock to %d kHz\n", rate); + dev_dbg(&mgr->pci->dev, "mixart_set_clock to %d kHz\n", rate); request.message_id = MSG_CLOCK_SET_PROPERTIES; request.uid = mgr->uid_console_manager; @@ -199,7 +209,9 @@ static int mixart_set_clock(struct mixart_mgr *mgr, err = snd_mixart_send_msg(mgr, &request, sizeof(clock_prop_resp), &clock_prop_resp); if (err < 0 || clock_prop_resp.status != 0 || clock_prop_resp.clock_mode != CM_STANDALONE) { - snd_printk(KERN_ERR "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", err, clock_prop_resp.status, clock_prop_resp.clock_mode); + dev_err(&mgr->pci->dev, + "error MSG_CLOCK_SET_PROPERTIES err=%x stat=%x mod=%x !\n", + err, clock_prop_resp.status, clock_prop_resp.clock_mode); return -EINVAL; } @@ -252,7 +264,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture, struct mixart_streaming_group sgroup_resp; } *buf; - snd_printdd("add_ref_pipe audio chip(%d) pcm(%d)\n", chip->chip_idx, pcm_number); + dev_dbg(chip->card->dev, + "add_ref_pipe audio chip(%d) pcm(%d)\n", + chip->chip_idx, pcm_number); buf = kmalloc(sizeof(*buf), GFP_KERNEL); if (!buf) @@ -302,7 +316,9 @@ snd_mixart_add_ref_pipe(struct snd_mixart *chip, int pcm_number, int capture, err = snd_mixart_send_msg(chip->mgr, &request, sizeof(buf->sgroup_resp), &buf->sgroup_resp); if((err < 0) || (buf->sgroup_resp.status != 0)) { - snd_printk(KERN_ERR "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", err, buf->sgroup_resp.status); + dev_err(chip->card->dev, + "error MSG_STREAM_ADD_**PUT_GROUP err=%x stat=%x !\n", + err, buf->sgroup_resp.status); kfree(buf); return NULL; } @@ -343,13 +359,14 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr, /* release the clock */ err = mixart_set_clock( mgr, pipe, 0); if( err < 0 ) { - snd_printk(KERN_ERR "mixart_set_clock(0) return error!\n"); + dev_err(&mgr->pci->dev, + "mixart_set_clock(0) return error!\n"); } /* stop the pipe */ err = mixart_set_pipe_state(mgr, pipe, 0); if( err < 0 ) { - snd_printk(KERN_ERR "error stopping pipe!\n"); + dev_err(&mgr->pci->dev, "error stopping pipe!\n"); } request.message_id = MSG_STREAM_DELETE_GROUP; @@ -360,7 +377,9 @@ int snd_mixart_kill_ref_pipe(struct mixart_mgr *mgr, /* delete the pipe */ err = snd_mixart_send_msg(mgr, &request, sizeof(delete_resp), &delete_resp); if ((err < 0) || (delete_resp.status != 0)) { - snd_printk(KERN_ERR "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", err, delete_resp.status); + dev_err(&mgr->pci->dev, + "error MSG_STREAM_DELETE_GROUP err(%x), status(%x)\n", + err, delete_resp.status); } pipe->group_uid = (struct mixart_uid){0,0}; @@ -414,7 +433,7 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd) switch (cmd) { case SNDRV_PCM_TRIGGER_START: - snd_printdd("SNDRV_PCM_TRIGGER_START\n"); + dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_START\n"); /* START_STREAM */ if( mixart_set_stream_state(stream, 1) ) @@ -431,19 +450,19 @@ static int snd_mixart_trigger(struct snd_pcm_substream *subs, int cmd) stream->status = MIXART_STREAM_STATUS_OPEN; - snd_printdd("SNDRV_PCM_TRIGGER_STOP\n"); + dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_TRIGGER_STOP\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* TODO */ stream->status = MIXART_STREAM_STATUS_PAUSE; - snd_printdd("SNDRV_PCM_PAUSE_PUSH\n"); + dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_PUSH\n"); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* TODO */ stream->status = MIXART_STREAM_STATUS_RUNNING; - snd_printdd("SNDRV_PCM_PAUSE_RELEASE\n"); + dev_dbg(subs->pcm->card->dev, "SNDRV_PCM_PAUSE_RELEASE\n"); break; default: return -EINVAL; @@ -456,7 +475,8 @@ static int mixart_sync_nonblock_events(struct mixart_mgr *mgr) unsigned long timeout = jiffies + HZ; while (atomic_read(&mgr->msg_processed) > 0) { if (time_after(jiffies, timeout)) { - snd_printk(KERN_ERR "mixart: cannot process nonblock events!\n"); + dev_err(&mgr->pci->dev, + "mixart: cannot process nonblock events!\n"); return -EBUSY; } schedule_timeout_uninterruptible(1); @@ -474,7 +494,7 @@ static int snd_mixart_prepare(struct snd_pcm_substream *subs) /* TODO de façon non bloquante, réappliquer les hw_params (rate, bits, codec) */ - snd_printdd("snd_mixart_prepare\n"); + dev_dbg(chip->card->dev, "snd_mixart_prepare\n"); mixart_sync_nonblock_events(chip->mgr); @@ -542,11 +562,13 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form stream_param.sample_size = 32; break; default: - snd_printk(KERN_ERR "error mixart_set_format() : unknown format\n"); + dev_err(chip->card->dev, + "error mixart_set_format() : unknown format\n"); return -EINVAL; } - snd_printdd("set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", + dev_dbg(chip->card->dev, + "set SNDRV_PCM_FORMAT sample_type(%d) sample_size(%d) freq(%d) channels(%d)\n", stream_param.sample_type, stream_param.sample_size, stream_param.sampling_freq, stream->channels); /* TODO: what else to configure ? */ @@ -566,7 +588,9 @@ static int mixart_set_format(struct mixart_stream *stream, snd_pcm_format_t form err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err < 0) || resp.error_code) { - snd_printk(KERN_ERR "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", err, resp.error_code); + dev_err(chip->card->dev, + "MSG_STREAM_SET_INPUT_STAGE_PARAM err=%x; resp=%x\n", + err, resp.error_code); return -EINVAL; } return 0; @@ -627,8 +651,9 @@ static int snd_mixart_hw_params(struct snd_pcm_substream *subs, bufferinfo[i].available_length = subs->runtime->dma_bytes; /* bufferinfo[i].buffer_id is already defined */ - snd_printdd("snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", i, - bufferinfo[i].buffer_address, + dev_dbg(chip->card->dev, + "snd_mixart_hw_params(pcm %d) : dma_addr(%x) dma_bytes(%x) subs-number(%d)\n", + i, bufferinfo[i].buffer_address, bufferinfo[i].available_length, subs->number); } @@ -714,14 +739,18 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) pcm_number = MIXART_PCM_DIGITAL; runtime->hw = snd_mixart_digital_caps; } - snd_printdd("snd_mixart_playback_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); + dev_dbg(chip->card->dev, + "snd_mixart_playback_open C%d/P%d/Sub%d\n", + chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->playback_stream[pcm_number][subs->number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ - snd_printk(KERN_ERR "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); + dev_err(chip->card->dev, + "snd_mixart_playback_open C%d/P%d/Sub%d in use\n", + chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } @@ -737,7 +766,7 @@ static int snd_mixart_playback_open(struct snd_pcm_substream *subs) /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { - snd_printk(KERN_ERR "error starting pipe!\n"); + dev_err(chip->card->dev, "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; @@ -792,14 +821,17 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) runtime->hw.channels_min = 2; /* for instance, no mono */ - snd_printdd("snd_mixart_capture_open C%d/P%d/Sub%d\n", chip->chip_idx, pcm_number, subs->number); + dev_dbg(chip->card->dev, "snd_mixart_capture_open C%d/P%d/Sub%d\n", + chip->chip_idx, pcm_number, subs->number); /* get stream info */ stream = &(chip->capture_stream[pcm_number]); if (stream->status != MIXART_STREAM_STATUS_FREE){ /* streams in use */ - snd_printk(KERN_ERR "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", chip->chip_idx, pcm_number, subs->number); + dev_err(chip->card->dev, + "snd_mixart_capture_open C%d/P%d/Sub%d in use\n", + chip->chip_idx, pcm_number, subs->number); err = -EBUSY; goto _exit_open; } @@ -815,7 +847,7 @@ static int snd_mixart_capture_open(struct snd_pcm_substream *subs) /* start the pipe if necessary */ err = mixart_set_pipe_state(chip->mgr, pipe, 1); if( err < 0 ) { - snd_printk(KERN_ERR "error starting pipe!\n"); + dev_err(chip->card->dev, "error starting pipe!\n"); snd_mixart_kill_ref_pipe(chip->mgr, pipe, 0); err = -EINVAL; goto _exit_open; @@ -855,7 +887,8 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) mutex_lock(&mgr->setup_mutex); - snd_printdd("snd_mixart_close C%d/P%d/Sub%d\n", chip->chip_idx, stream->pcm_number, subs->number); + dev_dbg(chip->card->dev, "snd_mixart_close C%d/P%d/Sub%d\n", + chip->chip_idx, stream->pcm_number, subs->number); /* sample rate released */ if(--mgr->ref_count_rate == 0) { @@ -865,7 +898,9 @@ static int snd_mixart_close(struct snd_pcm_substream *subs) /* delete pipe */ if (snd_mixart_kill_ref_pipe(mgr, stream->pipe, 0 ) < 0) { - snd_printk(KERN_ERR "error snd_mixart_kill_ref_pipe C%dP%d\n", chip->chip_idx, stream->pcm_number); + dev_err(chip->card->dev, + "error snd_mixart_kill_ref_pipe C%dP%d\n", + chip->chip_idx, stream->pcm_number); } stream->pipe = NULL; @@ -940,7 +975,8 @@ static int snd_mixart_pcm_analog(struct snd_mixart *chip) if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_ANALOG, MIXART_PLAYBACK_STREAMS, MIXART_CAPTURE_STREAMS, &pcm)) < 0) { - snd_printk(KERN_ERR "cannot create the analog pcm %d\n", chip->chip_idx); + dev_err(chip->card->dev, + "cannot create the analog pcm %d\n", chip->chip_idx); return err; } @@ -971,7 +1007,8 @@ static int snd_mixart_pcm_digital(struct snd_mixart *chip) if ((err = snd_pcm_new(chip->card, name, MIXART_PCM_DIGITAL, MIXART_PLAYBACK_STREAMS, MIXART_CAPTURE_STREAMS, &pcm)) < 0) { - snd_printk(KERN_ERR "cannot create the digital pcm %d\n", chip->chip_idx); + dev_err(chip->card->dev, + "cannot create the digital pcm %d\n", chip->chip_idx); return err; } @@ -1004,7 +1041,7 @@ static int snd_mixart_chip_dev_free(struct snd_device *device) /* */ -static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx) +static int snd_mixart_create(struct mixart_mgr *mgr, struct snd_card *card, int idx) { int err; struct snd_mixart *chip; @@ -1014,7 +1051,7 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { - snd_printk(KERN_ERR "cannot allocate chip\n"); + dev_err(card->dev, "cannot allocate chip\n"); return -ENOMEM; } @@ -1028,8 +1065,6 @@ static int __devinit snd_mixart_create(struct mixart_mgr *mgr, struct snd_card * } mgr->chip[idx] = chip; - snd_card_set_dev(card, &mgr->pci->dev); - return 0; } @@ -1073,7 +1108,7 @@ static int snd_mixart_free(struct mixart_mgr *mgr) /* reset board if some firmware was loaded */ if(mgr->dsp_loaded) { snd_mixart_reset_board(mgr); - snd_printdd("reset miXart !\n"); + dev_dbg(&mgr->pci->dev, "reset miXart !\n"); } /* release the i/o ports */ @@ -1175,12 +1210,12 @@ static void snd_mixart_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\tstreaming : %d\n", streaming); snd_iprintf(buffer, "\tmailbox : %d\n", mailbox); - snd_iprintf(buffer, "\tinterrups handling : %d\n\n", interr); + snd_iprintf(buffer, "\tinterrupts handling : %d\n\n", interr); } } /* endif elf loaded */ } -static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) +static void snd_mixart_proc_init(struct snd_mixart *chip) { struct snd_info_entry *entry; @@ -1209,8 +1244,8 @@ static void __devinit snd_mixart_proc_init(struct snd_mixart *chip) /* * probe function - creates the card manager */ -static int __devinit snd_mixart_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_mixart_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct mixart_mgr *mgr; @@ -1234,7 +1269,8 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - snd_printk(KERN_ERR "architecture does not support 32bit PCI busmaster DMA\n"); + dev_err(&pci->dev, + "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1260,7 +1296,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, mgr->mem[i].phys = pci_resource_start(pci, i); mgr->mem[i].virt = pci_ioremap_bar(pci, i); if (!mgr->mem[i].virt) { - printk(KERN_ERR "unable to remap resource 0x%lx\n", + dev_err(&pci->dev, "unable to remap resource 0x%lx\n", mgr->mem[i].phys); snd_mixart_free(mgr); return -EBUSY; @@ -1269,7 +1305,7 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, if (request_irq(pci->irq, snd_mixart_interrupt, IRQF_SHARED, KBUILD_MODNAME, mgr)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq); snd_mixart_free(mgr); return -EBUSY; } @@ -1308,10 +1344,11 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, else idx = index[dev] + i; snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : "MIXART", i); - err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE, + 0, &card); if (err < 0) { - snd_printk(KERN_ERR "cannot allocate the card %d\n", i); + dev_err(&pci->dev, "cannot allocate the card %d\n", i); snd_mixart_free(mgr); return err; } @@ -1374,17 +1411,16 @@ static int __devinit snd_mixart_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_mixart_remove(struct pci_dev *pci) +static void snd_mixart_remove(struct pci_dev *pci) { snd_mixart_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver mixart_driver = { .name = KBUILD_MODNAME, .id_table = snd_mixart_ids, .probe = snd_mixart_probe, - .remove = __devexit_p(snd_mixart_remove), + .remove = snd_mixart_remove, }; module_pci_driver(mixart_driver); diff --git a/sound/pci/mixart/mixart_core.c b/sound/pci/mixart/mixart_core.c index 3df0f530f67..71f4bdcc405 100644 --- a/sound/pci/mixart/mixart_core.c +++ b/sound/pci/mixart/mixart_core.c @@ -22,6 +22,7 @@ #include <linux/interrupt.h> #include <linux/mutex.h> +#include <linux/pci.h> #include <asm/io.h> #include <sound/core.h> @@ -94,7 +95,8 @@ static int get_msg(struct mixart_mgr *mgr, struct mixart_msg *resp, if( (size < MSG_DESCRIPTOR_SIZE) || (resp->size < (size - MSG_DESCRIPTOR_SIZE))) { err = -EINVAL; - snd_printk(KERN_ERR "problem with response size = %d\n", size); + dev_err(&mgr->pci->dev, + "problem with response size = %d\n", size); goto _clean_exit; } size -= MSG_DESCRIPTOR_SIZE; @@ -161,7 +163,7 @@ static int send_msg( struct mixart_mgr *mgr, headptr = readl_be(MIXART_MEM(mgr, MSG_INBOUND_FREE_HEAD)); if (tailptr == headptr) { - snd_printk(KERN_ERR "error: no message frame available\n"); + dev_err(&mgr->pci->dev, "error: no message frame available\n"); return -EBUSY; } @@ -265,7 +267,8 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int if (! timeout) { /* error - no ack */ mutex_unlock(&mgr->msg_mutex); - snd_printk(KERN_ERR "error: no response on msg %x\n", msg_frame); + dev_err(&mgr->pci->dev, + "error: no response on msg %x\n", msg_frame); return -EIO; } @@ -278,7 +281,7 @@ int snd_mixart_send_msg(struct mixart_mgr *mgr, struct mixart_msg *request, int err = get_msg(mgr, &resp, msg_frame); if( request->message_id != resp.message_id ) - snd_printk(KERN_ERR "RESPONSE ERROR!\n"); + dev_err(&mgr->pci->dev, "RESPONSE ERROR!\n"); mutex_unlock(&mgr->msg_mutex); return err; @@ -321,7 +324,8 @@ int snd_mixart_send_msg_wait_notif(struct mixart_mgr *mgr, if (! timeout) { /* error - no ack */ mutex_unlock(&mgr->msg_mutex); - snd_printk(KERN_ERR "error: notification %x not received\n", notif_event); + dev_err(&mgr->pci->dev, + "error: notification %x not received\n", notif_event); return -EIO; } @@ -378,7 +382,9 @@ void snd_mixart_msg_tasklet(unsigned long arg) resp.size = sizeof(mixart_msg_data); err = get_msg(mgr, &resp, addr); if( err < 0 ) { - snd_printk(KERN_ERR "tasklet: error(%d) reading mf %x\n", err, msg); + dev_err(&mgr->pci->dev, + "tasklet: error(%d) reading mf %x\n", + err, msg); break; } @@ -388,10 +394,13 @@ void snd_mixart_msg_tasklet(unsigned long arg) case MSG_STREAM_STOP_INPUT_STAGE_PACKET: case MSG_STREAM_STOP_OUTPUT_STAGE_PACKET: if(mixart_msg_data[0]) - snd_printk(KERN_ERR "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", mixart_msg_data[0]); + dev_err(&mgr->pci->dev, + "tasklet : error MSG_STREAM_ST***_***PUT_STAGE_PACKET status=%x\n", + mixart_msg_data[0]); break; default: - snd_printdd("tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", + dev_dbg(&mgr->pci->dev, + "tasklet received mf(%x) : msg_id(%x) uid(%x, %x) size(%zd)\n", msg, resp.message_id, resp.uid.object_id, resp.uid.desc, resp.size); break; } @@ -401,7 +410,9 @@ void snd_mixart_msg_tasklet(unsigned long arg) case MSG_TYPE_COMMAND: /* get_msg() necessary */ default: - snd_printk(KERN_ERR "tasklet doesn't know what to do with message %x\n", msg); + dev_err(&mgr->pci->dev, + "tasklet doesn't know what to do with message %x\n", + msg); } /* switch type */ /* decrement counter */ @@ -451,7 +462,9 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) resp.size = sizeof(mixart_msg_data); err = get_msg(mgr, &resp, msg & ~MSG_TYPE_MASK); if( err < 0 ) { - snd_printk(KERN_ERR "interrupt: error(%d) reading mf %x\n", err, msg); + dev_err(&mgr->pci->dev, + "interrupt: error(%d) reading mf %x\n", + err, msg); break; } @@ -472,7 +485,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) struct mixart_stream *stream; if ((chip_number >= mgr->num_cards) || (pcm_number >= MIXART_PCM_TOTAL) || (sub_number >= MIXART_PLAYBACK_STREAMS)) { - snd_printk(KERN_ERR "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", + dev_err(&mgr->pci->dev, + "error MSG_SERVICES_TIMER_NOTIFY buffer_id (%x) pos(%d)\n", buffer_id, notify->streams[i].sample_pos_low_part); break; } @@ -524,18 +538,22 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) } #endif ((char*)mixart_msg_data)[resp.size - 1] = 0; - snd_printdd("MIXART TRACE : %s\n", (char*)mixart_msg_data); + dev_dbg(&mgr->pci->dev, + "MIXART TRACE : %s\n", + (char *)mixart_msg_data); } break; } - snd_printdd("command %x not handled\n", resp.message_id); + dev_dbg(&mgr->pci->dev, "command %x not handled\n", + resp.message_id); break; case MSG_TYPE_NOTIFY: if(msg & MSG_CANCEL_NOTIFY_MASK) { msg &= ~MSG_CANCEL_NOTIFY_MASK; - snd_printk(KERN_ERR "canceled notification %x !\n", msg); + dev_err(&mgr->pci->dev, + "canceled notification %x !\n", msg); } /* no break, continue ! */ case MSG_TYPE_ANSWER: @@ -556,7 +574,8 @@ irqreturn_t snd_mixart_interrupt(int irq, void *dev_id) break; case MSG_TYPE_REQUEST: default: - snd_printdd("interrupt received request %x\n", msg); + dev_dbg(&mgr->pci->dev, + "interrupt received request %x\n", msg); /* TODO : are there things to do here ? */ break; } /* switch on msg type */ diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c index e0f4d87555a..581e1e74863 100644 --- a/sound/pci/mixart/mixart_hwdep.c +++ b/sound/pci/mixart/mixart_hwdep.c @@ -165,7 +165,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector); if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) { - snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n"); + dev_err(&mgr->pci->dev, + "error MSG_SYSTEM_ENUM_PLAY_CONNECTOR\n"); err = -EINVAL; goto __error; } @@ -184,7 +185,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) pipe->uid_left_connector = connector->uid[k]; /* even */ } - /* snd_printk(KERN_DEBUG "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */ + /* dev_dbg(&mgr->pci->dev, "playback connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */ /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */ request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO; @@ -194,10 +195,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info); if( err < 0 ) { - snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); + dev_err(&mgr->pci->dev, + "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); goto __error; } - /*snd_printk(KERN_DEBUG "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/ + /*dev_dbg(&mgr->pci->dev, "play analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/ } request.message_id = MSG_SYSTEM_ENUM_RECORD_CONNECTOR; @@ -207,7 +209,8 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(*connector), connector); if((err < 0) || (connector->error_code) || (connector->uid_count > MIXART_MAX_PHYS_CONNECTORS)) { - snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n"); + dev_err(&mgr->pci->dev, + "error MSG_SYSTEM_ENUM_RECORD_CONNECTOR\n"); err = -EINVAL; goto __error; } @@ -226,7 +229,7 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) pipe->uid_left_connector = connector->uid[k]; /* even */ } - /* snd_printk(KERN_DEBUG "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */ + /* dev_dbg(&mgr->pci->dev, "capture connector[%d].object_id = %x\n", k, connector->uid[k].object_id); */ /* TODO: really need send_msg MSG_CONNECTOR_GET_AUDIO_INFO for each connector ? perhaps for analog level caps ? */ request.message_id = MSG_CONNECTOR_GET_AUDIO_INFO; @@ -236,10 +239,11 @@ static int mixart_enum_connectors(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(*audio_info), audio_info); if( err < 0 ) { - snd_printk(KERN_ERR "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); + dev_err(&mgr->pci->dev, + "error MSG_CONNECTOR_GET_AUDIO_INFO\n"); goto __error; } - /*snd_printk(KERN_DEBUG "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/ + /*dev_dbg(&mgr->pci->dev, "rec analog_info.analog_level_present = %x\n", audio_info->info.analog_info.analog_level_present);*/ } err = 0; @@ -272,7 +276,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(console_mgr), &console_mgr); if( (err < 0) || (console_mgr.error_code != 0) ) { - snd_printk(KERN_DEBUG "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", console_mgr.error_code); + dev_dbg(&mgr->pci->dev, + "error MSG_CONSOLE_GET_CLOCK_UID : err=%x\n", + console_mgr.error_code); return -EINVAL; } @@ -286,7 +292,9 @@ static int mixart_enum_physio(struct mixart_mgr *mgr) err = snd_mixart_send_msg(mgr, &request, sizeof(phys_io), &phys_io); if( (err < 0) || ( phys_io.error_code != 0 ) ) { - snd_printk(KERN_ERR "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", err, phys_io.error_code ); + dev_err(&mgr->pci->dev, + "error MSG_SYSTEM_ENUM_PHYSICAL_IO err(%x) error_code(%x)\n", + err, phys_io.error_code); return -EINVAL; } @@ -322,7 +330,7 @@ static int mixart_first_init(struct mixart_mgr *mgr) /* this command has no data. response is a 32 bit status */ err = snd_mixart_send_msg(mgr, &request, sizeof(k), &k); if( (err < 0) || (k != 0) ) { - snd_printk(KERN_ERR "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n"); + dev_err(&mgr->pci->dev, "error MSG_SYSTEM_SEND_SYNCHRO_CMD\n"); return err == 0 ? -EINVAL : err; } @@ -348,7 +356,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* motherboard xilinx status 5 will say that the board is performing a reset */ if (status_xilinx == 5) { - snd_printk(KERN_ERR "miXart is resetting !\n"); + dev_err(&mgr->pci->dev, "miXart is resetting !\n"); return -EAGAIN; /* try again later */ } @@ -357,12 +365,13 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* xilinx already loaded ? */ if (status_xilinx == 4) { - snd_printk(KERN_DEBUG "xilinx is already loaded !\n"); + dev_dbg(&mgr->pci->dev, "xilinx is already loaded !\n"); return 0; } /* the status should be 0 == "idle" */ if (status_xilinx != 0) { - snd_printk(KERN_ERR "xilinx load error ! status = %d\n", + dev_err(&mgr->pci->dev, + "xilinx load error ! status = %d\n", status_xilinx); return -EIO; /* modprob -r may help ? */ } @@ -393,13 +402,14 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw case MIXART_MOTHERBOARD_ELF_INDEX: if (status_elf == 4) { - snd_printk(KERN_DEBUG "elf file already loaded !\n"); + dev_dbg(&mgr->pci->dev, "elf file already loaded !\n"); return 0; } /* the status should be 0 == "idle" */ if (status_elf != 0) { - snd_printk(KERN_ERR "elf load error ! status = %d\n", + dev_err(&mgr->pci->dev, + "elf load error ! status = %d\n", status_elf); return -EIO; /* modprob -r may help ? */ } @@ -407,7 +417,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* wait for xilinx status == 4 */ err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_MXLX_STATUS_OFFSET, 1, 4, 500); /* 5sec */ if (err < 0) { - snd_printk(KERN_ERR "xilinx was not loaded or " + dev_err(&mgr->pci->dev, "xilinx was not loaded or " "could not be started\n"); return err; } @@ -429,7 +439,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* wait for elf status == 4 */ err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_ELF_STATUS_OFFSET, 1, 4, 300); /* 3sec */ if (err < 0) { - snd_printk(KERN_ERR "elf could not be started\n"); + dev_err(&mgr->pci->dev, "elf could not be started\n"); return err; } @@ -443,7 +453,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* elf and xilinx should be loaded */ if (status_elf != 4 || status_xilinx != 4) { - printk(KERN_ERR "xilinx or elf not " + dev_err(&mgr->pci->dev, "xilinx or elf not " "successfully loaded\n"); return -EIO; /* modprob -r may help ? */ } @@ -451,7 +461,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* wait for daughter detection != 0 */ err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DBRD_PRESENCE_OFFSET, 0, 0, 30); /* 300msec */ if (err < 0) { - snd_printk(KERN_ERR "error starting elf file\n"); + dev_err(&mgr->pci->dev, "error starting elf file\n"); return err; } @@ -467,7 +477,8 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* daughter should be idle */ if (status_daught != 0) { - printk(KERN_ERR "daughter load error ! status = %d\n", + dev_err(&mgr->pci->dev, + "daughter load error ! status = %d\n", status_daught); return -EIO; /* modprob -r may help ? */ } @@ -487,7 +498,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* wait for status == 2 */ err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 2, 30); /* 300msec */ if (err < 0) { - snd_printk(KERN_ERR "daughter board load error\n"); + dev_err(&mgr->pci->dev, "daughter board load error\n"); return err; } @@ -509,7 +520,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* wait for daughter status == 3 */ err = mixart_wait_nice_for_register_value( mgr, MIXART_PSEUDOREG_DXLX_STATUS_OFFSET, 1, 3, 300); /* 3sec */ if (err < 0) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "daughter board could not be initialised\n"); return err; } @@ -520,7 +531,7 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw /* first communication with embedded */ err = mixart_first_init(mgr); if (err < 0) { - snd_printk(KERN_ERR "miXart could not be set up\n"); + dev_err(&mgr->pci->dev, "miXart could not be set up\n"); return err; } @@ -540,20 +551,13 @@ static int mixart_dsp_load(struct mixart_mgr* mgr, int index, const struct firmw return err; } - snd_printdd("miXart firmware downloaded and successfully set up\n"); + dev_dbg(&mgr->pci->dev, + "miXart firmware downloaded and successfully set up\n"); return 0; } -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_MIXARTLOADER) && !defined(CONFIG_SND_MIXART) /* built-in kernel */ -#define SND_MIXART_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - -#ifdef SND_MIXART_FW_LOADER - int snd_mixart_setup_firmware(struct mixart_mgr *mgr) { static char *fw_files[3] = { @@ -567,7 +571,8 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) for (i = 0; i < 3; i++) { sprintf(path, "mixart/%s", fw_files[i]); if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - snd_printk(KERN_ERR "miXart: can't load firmware %s\n", path); + dev_err(&mgr->pci->dev, + "miXart: can't load firmware %s\n", path); return -ENOENT; } /* fake hwdep dsp record */ @@ -583,71 +588,3 @@ int snd_mixart_setup_firmware(struct mixart_mgr *mgr) MODULE_FIRMWARE("mixart/miXart8.xlx"); MODULE_FIRMWARE("mixart/miXart8.elf"); MODULE_FIRMWARE("mixart/miXart8AES.xlx"); - -#else /* old style firmware loading */ - -/* miXart hwdep interface id string */ -#define SND_MIXART_HWDEP_ID "miXart Loader" - -static int mixart_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct mixart_mgr *mgr = hw->private_data; - - strcpy(info->id, "miXart"); - info->num_dsps = MIXART_HARDW_FILES_MAX_INDEX; - - if (mgr->dsp_loaded & (1 << MIXART_MOTHERBOARD_ELF_INDEX)) - info->chip_ready = 1; - - info->version = MIXART_DRIVER_VERSION; - return 0; -} - -static int mixart_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct mixart_mgr* mgr = hw->private_data; - struct firmware fw; - int err; - - fw.size = dsp->length; - fw.data = vmalloc(dsp->length); - if (! fw.data) { - snd_printk(KERN_ERR "miXart: cannot allocate image size %d\n", - (int)dsp->length); - return -ENOMEM; - } - if (copy_from_user((void *) fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = mixart_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return err; -} - -int snd_mixart_setup_firmware(struct mixart_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX (see "index" module parameter)*/ - if ((err = snd_hwdep_new(mgr->chip[0]->card, SND_MIXART_HWDEP_ID, 0, &hw)) < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_MIXART; - hw->private_data = mgr; - hw->ops.dsp_status = mixart_hwdep_dsp_status; - hw->ops.dsp_load = mixart_hwdep_dsp_load; - hw->exclusive = 1; - sprintf(hw->name, SND_MIXART_HWDEP_ID); - mgr->dsp_loaded = 0; - - return snd_card_register(mgr->chip[0]->card); -} - -#endif /* SND_MIXART_FW_LOADER */ diff --git a/sound/pci/mixart/mixart_mixer.c b/sound/pci/mixart/mixart_mixer.c index 3ba6174c3df..24a1955b8c2 100644 --- a/sound/pci/mixart/mixart_mixer.c +++ b/sound/pci/mixart/mixart_mixer.c @@ -329,7 +329,9 @@ static int mixart_update_analog_audio_level(struct snd_mixart* chip, int is_capt err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err<0) || (resp.error_code)) { - snd_printk(KERN_DEBUG "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", chip->chip_idx, is_capture, resp.error_code); + dev_dbg(chip->card->dev, + "error MSG_PHYSICALIO_SET_LEVEL card(%d) is_capture(%d) error_code(%x)\n", + chip->chip_idx, is_capture, resp.error_code); return -EINVAL; } return 0; @@ -762,7 +764,9 @@ int mixart_update_playback_stream_level(struct snd_mixart* chip, int is_aes, int err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status); if((err<0) || status) { - snd_printk(KERN_DEBUG "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", chip->chip_idx, status); + dev_dbg(chip->card->dev, + "error MSG_STREAM_SET_OUT_STREAM_LEVEL card(%d) status(%x)\n", + chip->chip_idx, status); return -EINVAL; } return 0; @@ -805,7 +809,9 @@ int mixart_update_capture_stream_level(struct snd_mixart* chip, int is_aes) err = snd_mixart_send_msg(chip->mgr, &request, sizeof(status), &status); if((err<0) || status) { - snd_printk(KERN_DEBUG "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", chip->chip_idx, status); + dev_dbg(chip->card->dev, + "error MSG_STREAM_SET_IN_AUDIO_LEVEL card(%d) status(%x)\n", + chip->chip_idx, status); return -EINVAL; } return 0; @@ -977,7 +983,9 @@ static int mixart_update_monitoring(struct snd_mixart* chip, int channel) err = snd_mixart_send_msg(chip->mgr, &request, sizeof(resp), &resp); if((err<0) || resp) { - snd_printk(KERN_DEBUG "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", chip->chip_idx, resp); + dev_dbg(chip->card->dev, + "error MSG_CONNECTOR_SET_OUT_AUDIO_LEVEL card(%d) resp(%x)\n", + chip->chip_idx, resp); return -EINVAL; } return 0; diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index e80e9a1e84a..ddc60215cc1 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c @@ -318,7 +318,8 @@ snd_nm256_write_buffer(struct nm256 *chip, void *src, int offset, int size) offset -= chip->buffer_start; #ifdef CONFIG_SND_DEBUG if (offset < 0 || offset >= chip->buffer_size) { - snd_printk(KERN_ERR "write_buffer invalid offset = %d size = %d\n", + dev_err(chip->card->dev, + "write_buffer invalid offset = %d size = %d\n", offset, size); return; } @@ -366,7 +367,8 @@ snd_nm256_load_coefficient(struct nm256 *chip, int stream, int number) NM_RECORD_REG_OFFSET : NM_PLAYBACK_REG_OFFSET); if (snd_nm256_readb(chip, poffset) & 1) { - snd_printd("NM256: Engine was enabled while loading coefficients!\n"); + dev_dbg(chip->card->dev, + "NM256: Engine was enabled while loading coefficients!\n"); return; } @@ -466,7 +468,8 @@ static int snd_nm256_acquire_irq(struct nm256 *chip) if (chip->irq < 0) { if (request_irq(chip->pci->irq, chip->interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->pci->irq); + dev_err(chip->card->dev, + "unable to grab IRQ %d\n", chip->pci->irq); mutex_unlock(&chip->irq_mutex); return -EBUSY; } @@ -928,7 +931,7 @@ static struct snd_pcm_ops snd_nm256_capture_ops = { .mmap = snd_pcm_lib_mmap_iomem, }; -static int __devinit +static int snd_nm256_pcm(struct nm256 *chip, int device) { struct snd_pcm *pcm; @@ -1039,7 +1042,7 @@ snd_nm256_interrupt(int irq, void *dev_id) if (status & NM_MISC_INT_1) { status &= ~NM_MISC_INT_1; NM_ACK_INT(chip, NM_MISC_INT_1); - snd_printd("NM256: Got misc interrupt #1\n"); + dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n"); snd_nm256_writew(chip, NM_INT_REG, 0x8000); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte | 2); @@ -1048,14 +1051,15 @@ snd_nm256_interrupt(int irq, void *dev_id) if (status & NM_MISC_INT_2) { status &= ~NM_MISC_INT_2; NM_ACK_INT(chip, NM_MISC_INT_2); - snd_printd("NM256: Got misc interrupt #2\n"); + dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte & ~2); } /* Unknown interrupt. */ if (status) { - snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n", + dev_dbg(chip->card->dev, + "NM256: Fire in the hole! Unknown status 0x%x\n", status); /* Pray. */ NM_ACK_INT(chip, status); @@ -1104,7 +1108,7 @@ snd_nm256_interrupt_zx(int irq, void *dev_id) if (status & NM2_MISC_INT_1) { status &= ~NM2_MISC_INT_1; NM2_ACK_INT(chip, NM2_MISC_INT_1); - snd_printd("NM256: Got misc interrupt #1\n"); + dev_dbg(chip->card->dev, "NM256: Got misc interrupt #1\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte | 2); } @@ -1112,14 +1116,15 @@ snd_nm256_interrupt_zx(int irq, void *dev_id) if (status & NM2_MISC_INT_2) { status &= ~NM2_MISC_INT_2; NM2_ACK_INT(chip, NM2_MISC_INT_2); - snd_printd("NM256: Got misc interrupt #2\n"); + dev_dbg(chip->card->dev, "NM256: Got misc interrupt #2\n"); cbyte = snd_nm256_readb(chip, 0x400); snd_nm256_writeb(chip, 0x400, cbyte & ~2); } /* Unknown interrupt. */ if (status) { - snd_printd("NM256: Fire in the hole! Unknown status 0x%x\n", + dev_dbg(chip->card->dev, + "NM256: Fire in the hole! Unknown status 0x%x\n", status); /* Pray. */ NM2_ACK_INT(chip, status); @@ -1245,7 +1250,7 @@ snd_nm256_ac97_write(struct snd_ac97 *ac97, return; } } - snd_printd("nm256: ac97 codec not ready..\n"); + dev_dbg(chip->card->dev, "nm256: ac97 codec not ready..\n"); } /* static resolution table */ @@ -1295,7 +1300,7 @@ snd_nm256_ac97_reset(struct snd_ac97 *ac97) } /* create an ac97 mixer interface */ -static int __devinit +static int snd_nm256_mixer(struct nm256 *chip) { struct snd_ac97_bus *pbus; @@ -1336,7 +1341,7 @@ snd_nm256_mixer(struct nm256 *chip) * RAM. */ -static int __devinit +static int snd_nm256_peek_for_sig(struct nm256 *chip) { /* The signature is located 1K below the end of video RAM. */ @@ -1347,7 +1352,8 @@ snd_nm256_peek_for_sig(struct nm256 *chip) temp = ioremap_nocache(chip->buffer_addr + chip->buffer_end - 0x400, 16); if (temp == NULL) { - snd_printk(KERN_ERR "Unable to scan for card signature in video RAM\n"); + dev_err(chip->card->dev, + "Unable to scan for card signature in video RAM\n"); return -EBUSY; } @@ -1361,12 +1367,14 @@ snd_nm256_peek_for_sig(struct nm256 *chip) if (pointer == 0xffffffff || pointer < chip->buffer_size || pointer > chip->buffer_end) { - snd_printk(KERN_ERR "invalid signature found: 0x%x\n", pointer); + dev_err(chip->card->dev, + "invalid signature found: 0x%x\n", pointer); iounmap(temp); return -ENODEV; } else { pointer_found = pointer; - printk(KERN_INFO "nm256: found card signature in video RAM: 0x%x\n", + dev_info(chip->card->dev, + "found card signature in video RAM: 0x%x\n", pointer); } } @@ -1411,8 +1419,7 @@ static int nm256_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "nm256: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1472,7 +1479,7 @@ static int snd_nm256_dev_free(struct snd_device *device) return snd_nm256_free(chip); } -static int __devinit +static int snd_nm256_create(struct snd_card *card, struct pci_dev *pci, struct nm256 **chip_ret) { @@ -1520,14 +1527,15 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, chip->res_cport = request_mem_region(chip->cport_addr, NM_PORT2_SIZE, card->driver); if (chip->res_cport == NULL) { - snd_printk(KERN_ERR "memory region 0x%lx (size 0x%x) busy\n", + dev_err(card->dev, "memory region 0x%lx (size 0x%x) busy\n", chip->cport_addr, NM_PORT2_SIZE); err = -EBUSY; goto __error; } chip->cport = ioremap_nocache(chip->cport_addr, NM_PORT2_SIZE); if (chip->cport == NULL) { - snd_printk(KERN_ERR "unable to map control port %lx\n", chip->cport_addr); + dev_err(card->dev, "unable to map control port %lx\n", + chip->cport_addr); err = -ENOMEM; goto __error; } @@ -1537,12 +1545,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, pval = snd_nm256_readw(chip, NM_MIXER_PRESENCE); if ((pval & NM_PRESENCE_MASK) != NM_PRESENCE_VALUE) { if (! force_ac97) { - printk(KERN_ERR "nm256: no ac97 is found!\n"); - printk(KERN_ERR " force the driver to load by " - "passing in the module parameter\n"); - printk(KERN_ERR " force_ac97=1\n"); - printk(KERN_ERR " or try sb16, opl3sa2, or " - "cs423x drivers instead.\n"); + dev_err(card->dev, + "no ac97 is found!\n"); + dev_err(card->dev, + "force the driver to load by passing in the module parameter\n"); + dev_err(card->dev, + " force_ac97=1\n"); + dev_err(card->dev, + "or try sb16, opl3sa2, or cs423x drivers instead.\n"); err = -ENXIO; goto __error; } @@ -1581,14 +1591,14 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, chip->buffer_start = chip->buffer_end - chip->buffer_size; chip->buffer_addr += chip->buffer_start; - printk(KERN_INFO "nm256: Mapping port 1 from 0x%x - 0x%x\n", + dev_info(card->dev, "Mapping port 1 from 0x%x - 0x%x\n", chip->buffer_start, chip->buffer_end); chip->res_buffer = request_mem_region(chip->buffer_addr, chip->buffer_size, card->driver); if (chip->res_buffer == NULL) { - snd_printk(KERN_ERR "nm256: buffer 0x%lx (size 0x%x) busy\n", + dev_err(card->dev, "buffer 0x%lx (size 0x%x) busy\n", chip->buffer_addr, chip->buffer_size); err = -EBUSY; goto __error; @@ -1596,7 +1606,8 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, chip->buffer = ioremap_nocache(chip->buffer_addr, chip->buffer_size); if (chip->buffer == NULL) { err = -ENOMEM; - snd_printk(KERN_ERR "unable to map ring buffer at %lx\n", chip->buffer_addr); + dev_err(card->dev, "unable to map ring buffer at %lx\n", + chip->buffer_addr); goto __error; } @@ -1626,8 +1637,6 @@ snd_nm256_create(struct snd_card *card, struct pci_dev *pci, if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) goto __error; - snd_card_set_dev(card, &pci->dev); - *chip_ret = chip; return 0; @@ -1639,7 +1648,7 @@ __error: enum { NM_BLACKLISTED, NM_RESET_WORKAROUND, NM_RESET_WORKAROUND_2 }; -static struct snd_pci_quirk nm256_quirks[] __devinitdata = { +static struct snd_pci_quirk nm256_quirks[] = { /* HP omnibook 4150 has cs4232 codec internally */ SND_PCI_QUIRK(0x103c, 0x0007, "HP omnibook 4150", NM_BLACKLISTED), /* Reset workarounds to avoid lock-ups */ @@ -1650,8 +1659,8 @@ static struct snd_pci_quirk nm256_quirks[] __devinitdata = { }; -static int __devinit snd_nm256_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_nm256_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct nm256 *chip; @@ -1660,11 +1669,12 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, q = snd_pci_quirk_lookup(pci, nm256_quirks); if (q) { - snd_printdd(KERN_INFO "nm256: Enabled quirk for %s.\n", q->name); + dev_dbg(&pci->dev, "Enabled quirk for %s.\n", + snd_pci_quirk_name(q)); switch (q->value) { case NM_BLACKLISTED: - printk(KERN_INFO "nm256: The device is blacklisted. " - "Loading stopped\n"); + dev_info(&pci->dev, + "The device is blacklisted. Loading stopped\n"); return -ENODEV; case NM_RESET_WORKAROUND_2: reset_workaround_2 = 1; @@ -1675,7 +1685,7 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, } } - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -1690,7 +1700,7 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, strcpy(card->driver, "NM256XL+"); break; default: - snd_printk(KERN_ERR "invalid device id 0x%x\n", pci->device); + dev_err(&pci->dev, "invalid device id 0x%x\n", pci->device); snd_card_free(card); return -EINVAL; } @@ -1713,12 +1723,12 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, card->private_data = chip; if (reset_workaround) { - snd_printdd(KERN_INFO "nm256: reset_workaround activated\n"); + dev_dbg(&pci->dev, "reset_workaround activated\n"); chip->reset_workaround = 1; } if (reset_workaround_2) { - snd_printdd(KERN_INFO "nm256: reset_workaround_2 activated\n"); + dev_dbg(&pci->dev, "reset_workaround_2 activated\n"); chip->reset_workaround_2 = 1; } @@ -1742,10 +1752,9 @@ static int __devinit snd_nm256_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_nm256_remove(struct pci_dev *pci) +static void snd_nm256_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } @@ -1753,7 +1762,7 @@ static struct pci_driver nm256_driver = { .name = KBUILD_MODNAME, .id_table = snd_nm256_ids, .probe = snd_nm256_probe, - .remove = __devexit_p(snd_nm256_remove), + .remove = snd_nm256_remove, .driver = { .pm = NM256_PM_OPS, }, diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 0f8726551fd..8f4c409f7e4 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,5 +1,5 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o -snd-oxygen-objs := oxygen.o xonar_dg.o +snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o snd-virtuoso-objs := virtuoso.o xonar_lib.o \ xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o diff --git a/sound/pci/oxygen/cs4245.h b/sound/pci/oxygen/cs4245.h index 5e0197e07dd..99098657695 100644 --- a/sound/pci/oxygen/cs4245.h +++ b/sound/pci/oxygen/cs4245.h @@ -102,6 +102,9 @@ #define CS4245_ADC_OVFL 0x02 #define CS4245_ADC_UNDRFL 0x01 +#define CS4245_SPI_ADDRESS_S (0x9e << 16) +#define CS4245_SPI_WRITE_S (0 << 16) -#define CS4245_SPI_ADDRESS (0x9e << 16) -#define CS4245_SPI_WRITE (0 << 16) +#define CS4245_SPI_ADDRESS 0x9e +#define CS4245_SPI_WRITE 0 +#define CS4245_SPI_READ 1 diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 2becae155a4..ada6c256378 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -756,8 +756,8 @@ static const struct oxygen_model model_generic = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -static int __devinit get_oxygen_model(struct oxygen *chip, - const struct pci_device_id *id) +static int get_oxygen_model(struct oxygen *chip, + const struct pci_device_id *id) { static const char *const names[] = { [MODEL_MERIDIAN] = "AuzenTech X-Meridian", @@ -848,8 +848,8 @@ static int __devinit get_oxygen_model(struct oxygen *chip, return 0; } -static int __devinit generic_oxygen_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int generic_oxygen_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; int err; @@ -871,7 +871,7 @@ static struct pci_driver oxygen_driver = { .name = KBUILD_MODNAME, .id_table = oxygen_ids, .probe = generic_oxygen_probe, - .remove = __devexit_p(oxygen_pci_remove), + .remove = oxygen_pci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &oxygen_pci_pm, diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 09a24b24958..c10ab077afd 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -198,7 +198,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, unsigned int index, u16 data, u16 mask); -void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); +int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data); void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data); void oxygen_reset_uart(struct oxygen *chip); diff --git a/sound/pci/oxygen/oxygen_io.c b/sound/pci/oxygen/oxygen_io.c index 521eae45834..4b8a32c37e3 100644 --- a/sound/pci/oxygen/oxygen_io.c +++ b/sound/pci/oxygen/oxygen_io.c @@ -147,7 +147,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec, return; } } - snd_printk(KERN_ERR "AC'97 write timeout\n"); + dev_err(chip->card->dev, "AC'97 write timeout\n"); } EXPORT_SYMBOL(oxygen_write_ac97); @@ -179,7 +179,7 @@ u16 oxygen_read_ac97(struct oxygen *chip, unsigned int codec, reg ^= 0xffff; } } - snd_printk(KERN_ERR "AC'97 read timeout on codec %u\n", codec); + dev_err(chip->card->dev, "AC'97 read timeout on codec %u\n", codec); return 0; } EXPORT_SYMBOL(oxygen_read_ac97); @@ -194,23 +194,36 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec, } EXPORT_SYMBOL(oxygen_write_ac97_masked); -void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) +static int oxygen_wait_spi(struct oxygen *chip) { unsigned int count; - /* should not need more than 30.72 us (24 * 1.28 us) */ - count = 10; - while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY) - && count > 0) { + /* + * Higher timeout to be sure: 200 us; + * actual transaction should not need more than 40 us. + */ + for (count = 50; count > 0; count--) { udelay(4); - --count; + if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & + OXYGEN_SPI_BUSY) == 0) + return 0; } + dev_err(chip->card->dev, "oxygen: SPI wait timeout\n"); + return -EIO; +} +int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data) +{ + /* + * We need to wait AFTER initiating the SPI transaction, + * otherwise read operations will not work. + */ oxygen_write8(chip, OXYGEN_SPI_DATA1, data); oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8); if (control & OXYGEN_SPI_DATA_LENGTH_3) oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16); oxygen_write8(chip, OXYGEN_SPI_CONTROL, control); + return oxygen_wait_spi(chip); } EXPORT_SYMBOL(oxygen_write_spi); @@ -275,5 +288,5 @@ void oxygen_write_eeprom(struct oxygen *chip, unsigned int index, u16 value) & OXYGEN_EEPROM_BUSY)) return; } - snd_printk(KERN_ERR "EEPROM write timeout\n"); + dev_err(chip->card->dev, "EEPROM write timeout\n"); } diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9562dc63ba6..b67e3060247 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -313,7 +313,7 @@ static void oxygen_restore_eeprom(struct oxygen *chip, oxygen_clear_bits8(chip, OXYGEN_MISC, OXYGEN_MISC_WRITE_PCI_SUBID); - snd_printk(KERN_INFO "EEPROM ID restored\n"); + dev_info(chip->card->dev, "EEPROM ID restored\n"); } } @@ -595,7 +595,8 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, const struct pci_device_id *pci_id; int err; - err = snd_card_create(index, id, owner, sizeof(*chip), &card); + err = snd_card_new(&pci->dev, index, id, owner, + sizeof(*chip), &card); if (err < 0) return err; @@ -616,13 +617,13 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, err = pci_request_regions(pci, DRIVER); if (err < 0) { - snd_printk(KERN_ERR "cannot reserve PCI resources\n"); + dev_err(card->dev, "cannot reserve PCI resources\n"); goto err_pci_enable; } if (!(pci_resource_flags(pci, 0) & IORESOURCE_IO) || pci_resource_len(pci, 0) < OXYGEN_IO_SIZE) { - snd_printk(KERN_ERR "invalid PCI I/O range\n"); + dev_err(card->dev, "invalid PCI I/O range\n"); err = -ENXIO; goto err_pci_regions; } @@ -648,7 +649,6 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, } pci_set_master(pci); - snd_card_set_dev(card, &pci->dev); card->private_free = oxygen_card_free; configure_pcie_bridge(pci); @@ -658,7 +658,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, err = request_irq(pci->irq, oxygen_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip); if (err < 0) { - snd_printk(KERN_ERR "cannot grab interrupt %d\n", pci->irq); + dev_err(card->dev, "cannot grab interrupt %d\n", pci->irq); goto err_card; } chip->irq = pci->irq; @@ -722,7 +722,6 @@ EXPORT_SYMBOL(oxygen_pci_probe); void oxygen_pci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } EXPORT_SYMBOL(oxygen_pci_remove); @@ -797,7 +796,7 @@ static int oxygen_pci_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - snd_printk(KERN_ERR "cannot reenable device"); + dev_err(dev, "cannot reenable device"); snd_card_disconnect(card); return -EIO; } diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index c0dbb52d45b..5988e044c51 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct oxygen *chip) if (chip->model.update_center_lfe_mix) chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); } +EXPORT_SYMBOL(oxygen_update_dac_routing); static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { diff --git a/sound/pci/oxygen/oxygen_regs.h b/sound/pci/oxygen/oxygen_regs.h index 63dc7a0ab55..8c191badaae 100644 --- a/sound/pci/oxygen/oxygen_regs.h +++ b/sound/pci/oxygen/oxygen_regs.h @@ -318,6 +318,7 @@ #define OXYGEN_PLAY_MUTE23 0x0002 #define OXYGEN_PLAY_MUTE45 0x0004 #define OXYGEN_PLAY_MUTE67 0x0008 +#define OXYGEN_PLAY_MUTE_MASK 0x000f #define OXYGEN_PLAY_MULTICH_MASK 0x0010 #define OXYGEN_PLAY_MULTICH_I2S_DAC 0x0000 #define OXYGEN_PLAY_MULTICH_AC97 0x0010 diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 3d71423b23b..64b9fda5f04 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -52,13 +52,14 @@ static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, { OXYGEN_PCI_SUBID(0x1043, 0x835e) }, { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8522) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; MODULE_DEVICE_TABLE(pci, xonar_ids); -static int __devinit get_xonar_model(struct oxygen *chip, - const struct pci_device_id *id) +static int get_xonar_model(struct oxygen *chip, + const struct pci_device_id *id) { if (get_xonar_pcm179x_model(chip, id) >= 0) return 0; @@ -69,8 +70,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, return -EINVAL; } -static int __devinit xonar_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int xonar_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; int err; @@ -92,7 +93,7 @@ static struct pci_driver xonar_driver = { .name = KBUILD_MODNAME, .id_table = xonar_ids, .probe = xonar_probe, - .remove = __devexit_p(oxygen_pci_remove), + .remove = oxygen_pci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &oxygen_pci_pm, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index c8febf4b9bd..d231b93d6ab 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -431,8 +431,8 @@ static const struct oxygen_model model_xonar_d1 = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_cs43xx_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_cs43xx_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x834f: diff --git a/sound/pci/oxygen/xonar_dg.c b/sound/pci/oxygen/xonar_dg.c index 77acd790ea4..4cf3200e988 100644 --- a/sound/pci/oxygen/xonar_dg.c +++ b/sound/pci/oxygen/xonar_dg.c @@ -2,7 +2,7 @@ * card driver for the Xonar DG/DGX * * Copyright (c) Clemens Ladisch <clemens@ladisch.de> - * + * Copyright (c) Roman Volkov <v1ron@mail.ru> * * This driver is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2. @@ -20,27 +20,35 @@ * Xonar DG/DGX * ------------ * + * CS4245 and CS4361 both will mute all outputs if any clock ratio + * is invalid. + * * CMI8788: * * SPI 0 -> CS4245 * + * Playback: * I²S 1 -> CS4245 * I²S 2 -> CS4361 (center/LFE) * I²S 3 -> CS4361 (surround) * I²S 4 -> CS4361 (front) + * Capture: + * I²S ADC 1 <- CS4245 * * GPIO 3 <- ? * GPIO 4 <- headphone detect - * GPIO 5 -> route input jack to line-in (0) or mic-in (1) - * GPIO 6 -> route input jack to line-in (0) or mic-in (1) - * GPIO 7 -> enable rear headphone amp + * GPIO 5 -> enable ADC analog circuit for the left channel + * GPIO 6 -> enable ADC analog circuit for the right channel + * GPIO 7 -> switch green rear output jack between CS4245 and and the first + * channel of CS4361 (mechanical relay) * GPIO 8 -> enable output to speakers * * CS4245: * + * input 0 <- mic * input 1 <- aux * input 2 <- front mic - * input 4 <- line/mic + * input 4 <- line * DAC out -> headphones * aux out -> front panel headphones */ @@ -56,161 +64,178 @@ #include "xonar_dg.h" #include "cs4245.h" -#define GPIO_MAGIC 0x0008 -#define GPIO_HP_DETECT 0x0010 -#define GPIO_INPUT_ROUTE 0x0060 -#define GPIO_HP_REAR 0x0080 -#define GPIO_OUTPUT_ENABLE 0x0100 - -struct dg { - unsigned int output_sel; - s8 input_vol[4][2]; - unsigned int input_sel; - u8 hp_vol_att; - u8 cs4245_regs[0x11]; -}; - -static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value) +int cs4245_write_spi(struct oxygen *chip, u8 reg) { struct dg *data = chip->model_data; + unsigned int packet; + + packet = reg << 8; + packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16; + packet |= data->cs4245_shadow[reg]; - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | - OXYGEN_SPI_DATA_LENGTH_3 | - OXYGEN_SPI_CLOCK_1280 | - (0 << OXYGEN_SPI_CODEC_SHIFT) | - OXYGEN_SPI_CEN_LATCH_CLOCK_HI, - CS4245_SPI_ADDRESS | - CS4245_SPI_WRITE | - (reg << 8) | value); - data->cs4245_regs[reg] = value; + return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_3 | + OXYGEN_SPI_CLOCK_1280 | + (0 << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI, + packet); } -static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value) +int cs4245_read_spi(struct oxygen *chip, u8 addr) { struct dg *data = chip->model_data; + int ret; + + ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI | + OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), + ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr); + if (ret < 0) + return ret; + + ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI | + OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT), + (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8); + if (ret < 0) + return ret; + + data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1); - if (value != data->cs4245_regs[reg]) - cs4245_write(chip, reg, value); + return 0; } -static void cs4245_registers_init(struct oxygen *chip) +int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op) { struct dg *data = chip->model_data; - - cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN); - cs4245_write(chip, CS4245_DAC_CTRL_1, - data->cs4245_regs[CS4245_DAC_CTRL_1]); - cs4245_write(chip, CS4245_ADC_CTRL, - data->cs4245_regs[CS4245_ADC_CTRL]); - cs4245_write(chip, CS4245_SIGNAL_SEL, - data->cs4245_regs[CS4245_SIGNAL_SEL]); - cs4245_write(chip, CS4245_PGA_B_CTRL, - data->cs4245_regs[CS4245_PGA_B_CTRL]); - cs4245_write(chip, CS4245_PGA_A_CTRL, - data->cs4245_regs[CS4245_PGA_A_CTRL]); - cs4245_write(chip, CS4245_ANALOG_IN, - data->cs4245_regs[CS4245_ANALOG_IN]); - cs4245_write(chip, CS4245_DAC_A_CTRL, - data->cs4245_regs[CS4245_DAC_A_CTRL]); - cs4245_write(chip, CS4245_DAC_B_CTRL, - data->cs4245_regs[CS4245_DAC_B_CTRL]); - cs4245_write(chip, CS4245_DAC_CTRL_2, - CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC); - cs4245_write(chip, CS4245_INT_MASK, 0); - cs4245_write(chip, CS4245_POWER_CTRL, 0); + unsigned char addr; + int ret; + + for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) { + ret = (op == CS4245_SAVE_TO_SHADOW ? + cs4245_read_spi(chip, addr) : + cs4245_write_spi(chip, addr)); + if (ret < 0) + return ret; + } + return 0; } static void cs4245_init(struct oxygen *chip) { struct dg *data = chip->model_data; - data->cs4245_regs[CS4245_DAC_CTRL_1] = + /* save the initial state: codec version, registers */ + cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW); + + /* + * Power up the CODEC internals, enable soft ramp & zero cross, work in + * async. mode, enable aux output from DAC. Invert DAC output as in the + * Windows driver. + */ + data->cs4245_shadow[CS4245_POWER_CTRL] = 0; + data->cs4245_shadow[CS4245_SIGNAL_SEL] = + CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH; + data->cs4245_shadow[CS4245_DAC_CTRL_1] = CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST; - data->cs4245_regs[CS4245_ADC_CTRL] = + data->cs4245_shadow[CS4245_DAC_CTRL_2] = + CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC; + data->cs4245_shadow[CS4245_ADC_CTRL] = CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST; - data->cs4245_regs[CS4245_SIGNAL_SEL] = - CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH; - data->cs4245_regs[CS4245_PGA_B_CTRL] = 0; - data->cs4245_regs[CS4245_PGA_A_CTRL] = 0; - data->cs4245_regs[CS4245_ANALOG_IN] = - CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4; - data->cs4245_regs[CS4245_DAC_A_CTRL] = 0; - data->cs4245_regs[CS4245_DAC_B_CTRL] = 0; - cs4245_registers_init(chip); + data->cs4245_shadow[CS4245_ANALOG_IN] = + CS4245_PGA_SOFT | CS4245_PGA_ZERO; + data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0; + data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0; + data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8; + data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8; + + cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); snd_component_add(chip->card, "CS4245"); } -static void dg_output_enable(struct oxygen *chip) -{ - msleep(2500); - oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); -} - -static void dg_init(struct oxygen *chip) +void dg_init(struct oxygen *chip) { struct dg *data = chip->model_data; - data->output_sel = 0; - data->input_sel = 3; - data->hp_vol_att = 2 * 16; + data->output_sel = PLAYBACK_DST_HP_FP; + data->input_sel = CAPTURE_SRC_MIC; cs4245_init(chip); - - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_MAGIC | GPIO_HP_DETECT); - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE); - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, - GPIO_INPUT_ROUTE | GPIO_HP_REAR); - dg_output_enable(chip); + oxygen_write16(chip, OXYGEN_GPIO_CONTROL, + GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE); + /* anti-pop delay, wait some time before enabling the output */ + msleep(2500); + oxygen_write16(chip, OXYGEN_GPIO_DATA, + GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE); } -static void dg_cleanup(struct oxygen *chip) +void dg_cleanup(struct oxygen *chip) { oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); } -static void dg_suspend(struct oxygen *chip) +void dg_suspend(struct oxygen *chip) { dg_cleanup(chip); } -static void dg_resume(struct oxygen *chip) +void dg_resume(struct oxygen *chip) { - cs4245_registers_init(chip); - dg_output_enable(chip); + cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW); + msleep(2500); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE); } -static void set_cs4245_dac_params(struct oxygen *chip, +void set_cs4245_dac_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { struct dg *data = chip->model_data; - u8 value; - - value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; - if (params_rate(params) <= 50000) - value |= CS4245_DAC_FM_SINGLE; - else if (params_rate(params) <= 100000) - value |= CS4245_DAC_FM_DOUBLE; - else - value |= CS4245_DAC_FM_QUAD; - cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value); + unsigned char dac_ctrl; + unsigned char mclk_freq; + + dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK; + mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK; + if (params_rate(params) <= 50000) { + dac_ctrl |= CS4245_DAC_FM_SINGLE; + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; + } else if (params_rate(params) <= 100000) { + dac_ctrl |= CS4245_DAC_FM_DOUBLE; + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT; + } else { + dac_ctrl |= CS4245_DAC_FM_QUAD; + mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT; + } + data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl; + data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; + cs4245_write_spi(chip, CS4245_DAC_CTRL_1); + cs4245_write_spi(chip, CS4245_MCLK_FREQ); } -static void set_cs4245_adc_params(struct oxygen *chip, +void set_cs4245_adc_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { struct dg *data = chip->model_data; - u8 value; - - value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; - if (params_rate(params) <= 50000) - value |= CS4245_ADC_FM_SINGLE; - else if (params_rate(params) <= 100000) - value |= CS4245_ADC_FM_DOUBLE; - else - value |= CS4245_ADC_FM_QUAD; - cs4245_write_cached(chip, CS4245_ADC_CTRL, value); + unsigned char adc_ctrl; + unsigned char mclk_freq; + + adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK; + mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK; + if (params_rate(params) <= 50000) { + adc_ctrl |= CS4245_ADC_FM_SINGLE; + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; + } else if (params_rate(params) <= 100000) { + adc_ctrl |= CS4245_ADC_FM_DOUBLE; + mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT; + } else { + adc_ctrl |= CS4245_ADC_FM_QUAD; + mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT; + } + data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl; + data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq; + cs4245_write_spi(chip, CS4245_ADC_CTRL); + cs4245_write_spi(chip, CS4245_MCLK_FREQ); } static inline unsigned int shift_bits(unsigned int value, @@ -224,9 +249,23 @@ static inline unsigned int shift_bits(unsigned int value, return (value >> (shift_from - shift_to)) & mask; } -static unsigned int adjust_dg_dac_routing(struct oxygen *chip, +unsigned int adjust_dg_dac_routing(struct oxygen *chip, unsigned int play_routing) { + struct dg *data = chip->model_data; + + switch (data->output_sel) { + case PLAYBACK_DST_HP: + case PLAYBACK_DST_HP_FP: + oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, + OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 | + OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK); + break; + case PLAYBACK_DST_MULTICH: + oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING, + OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK); + break; + } return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) | shift_bits(play_routing, OXYGEN_PLAY_DAC2_SOURCE_SHIFT, @@ -242,367 +281,15 @@ static unsigned int adjust_dg_dac_routing(struct oxygen *chip, OXYGEN_PLAY_DAC3_SOURCE_MASK); } -static int output_switch_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "Speakers", "Headphones", "FP Headphones" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int output_switch_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - - mutex_lock(&chip->mutex); - value->value.enumerated.item[0] = data->output_sel; - mutex_unlock(&chip->mutex); - return 0; -} - -static int output_switch_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - u8 reg; - int changed; - - if (value->value.enumerated.item[0] > 2) - return -EINVAL; - - mutex_lock(&chip->mutex); - changed = value->value.enumerated.item[0] != data->output_sel; - if (changed) { - data->output_sel = value->value.enumerated.item[0]; - - reg = data->cs4245_regs[CS4245_SIGNAL_SEL] & - ~CS4245_A_OUT_SEL_MASK; - reg |= data->output_sel == 2 ? - CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ; - cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg); - - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, - data->output_sel ? data->hp_vol_att : 0); - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, - data->output_sel ? data->hp_vol_att : 0); - - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - data->output_sel == 1 ? GPIO_HP_REAR : 0, - GPIO_HP_REAR); - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int hp_volume_offset_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "< 64 ohms", "64-150 ohms", "150-300 ohms" - }; - - return snd_ctl_enum_info(info, 1, 3, names); -} - -static int hp_volume_offset_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - - mutex_lock(&chip->mutex); - if (data->hp_vol_att > 2 * 7) - value->value.enumerated.item[0] = 0; - else if (data->hp_vol_att > 0) - value->value.enumerated.item[0] = 1; - else - value->value.enumerated.item[0] = 2; - mutex_unlock(&chip->mutex); - return 0; -} - -static int hp_volume_offset_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - static const s8 atts[3] = { 2 * 16, 2 * 7, 0 }; - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - s8 att; - int changed; - - if (value->value.enumerated.item[0] > 2) - return -EINVAL; - att = atts[value->value.enumerated.item[0]]; - mutex_lock(&chip->mutex); - changed = att != data->hp_vol_att; - if (changed) { - data->hp_vol_att = att; - if (data->output_sel) { - cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att); - cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att); - } - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int input_vol_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - info->count = 2; - info->value.integer.min = 2 * -12; - info->value.integer.max = 2 * 12; - return 0; -} - -static int input_vol_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - unsigned int idx = ctl->private_value; - - mutex_lock(&chip->mutex); - value->value.integer.value[0] = data->input_vol[idx][0]; - value->value.integer.value[1] = data->input_vol[idx][1]; - mutex_unlock(&chip->mutex); - return 0; -} - -static int input_vol_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - unsigned int idx = ctl->private_value; - int changed = 0; - - if (value->value.integer.value[0] < 2 * -12 || - value->value.integer.value[0] > 2 * 12 || - value->value.integer.value[1] < 2 * -12 || - value->value.integer.value[1] > 2 * 12) - return -EINVAL; - mutex_lock(&chip->mutex); - changed = data->input_vol[idx][0] != value->value.integer.value[0] || - data->input_vol[idx][1] != value->value.integer.value[1]; - if (changed) { - data->input_vol[idx][0] = value->value.integer.value[0]; - data->input_vol[idx][1] = value->value.integer.value[1]; - if (idx == data->input_sel) { - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, - data->input_vol[idx][0]); - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, - data->input_vol[idx][1]); - } - } - mutex_unlock(&chip->mutex); - return changed; -} - -static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0); - -static int input_sel_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const names[4] = { - "Mic", "Aux", "Front Mic", "Line" - }; - - return snd_ctl_enum_info(info, 1, 4, names); -} - -static int input_sel_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - - mutex_lock(&chip->mutex); - value->value.enumerated.item[0] = data->input_sel; - mutex_unlock(&chip->mutex); - return 0; -} - -static int input_sel_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - static const u8 sel_values[4] = { - CS4245_SEL_MIC, - CS4245_SEL_INPUT_1, - CS4245_SEL_INPUT_2, - CS4245_SEL_INPUT_4 - }; - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - int changed; - - if (value->value.enumerated.item[0] > 3) - return -EINVAL; - - mutex_lock(&chip->mutex); - changed = value->value.enumerated.item[0] != data->input_sel; - if (changed) { - data->input_sel = value->value.enumerated.item[0]; - - cs4245_write(chip, CS4245_ANALOG_IN, - (data->cs4245_regs[CS4245_ANALOG_IN] & - ~CS4245_SEL_MASK) | - sel_values[data->input_sel]); - - cs4245_write_cached(chip, CS4245_PGA_A_CTRL, - data->input_vol[data->input_sel][0]); - cs4245_write_cached(chip, CS4245_PGA_B_CTRL, - data->input_vol[data->input_sel][1]); - - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - data->input_sel ? 0 : GPIO_INPUT_ROUTE, - GPIO_INPUT_ROUTE); - } - mutex_unlock(&chip->mutex); - return changed; -} - -static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) -{ - static const char *const names[2] = { "Active", "Frozen" }; - - return snd_ctl_enum_info(info, 1, 2, names); -} - -static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - - value->value.enumerated.item[0] = - !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); - return 0; -} - -static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - struct dg *data = chip->model_data; - u8 reg; - int changed; - - mutex_lock(&chip->mutex); - reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; - if (value->value.enumerated.item[0]) - reg |= CS4245_HPF_FREEZE; - changed = reg != data->cs4245_regs[CS4245_ADC_CTRL]; - if (changed) - cs4245_write(chip, CS4245_ADC_CTRL, reg); - mutex_unlock(&chip->mutex); - return changed; -} - -#define INPUT_VOLUME(xname, index) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .info = input_vol_info, \ - .get = input_vol_get, \ - .put = input_vol_put, \ - .tlv = { .p = cs4245_pga_db_scale }, \ - .private_value = index, \ -} -static const struct snd_kcontrol_new dg_controls[] = { - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Output Playback Enum", - .info = output_switch_info, - .get = output_switch_get, - .put = output_switch_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Headphones Impedance Playback Enum", - .info = hp_volume_offset_info, - .get = hp_volume_offset_get, - .put = hp_volume_offset_put, - }, - INPUT_VOLUME("Mic Capture Volume", 0), - INPUT_VOLUME("Aux Capture Volume", 1), - INPUT_VOLUME("Front Mic Capture Volume", 2), - INPUT_VOLUME("Line Capture Volume", 3), - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .info = input_sel_info, - .get = input_sel_get, - .put = input_sel_put, - }, - { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "ADC High-pass Filter Capture Enum", - .info = hpf_info, - .get = hpf_get, - .put = hpf_put, - }, -}; - -static int dg_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "Master Playback ", 16)) - return 1; - return 0; -} - -static int dg_mixer_init(struct oxygen *chip) -{ - unsigned int i; - int err; - - for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { - err = snd_ctl_add(chip->card, - snd_ctl_new1(&dg_controls[i], chip)); - if (err < 0) - return err; - } - return 0; -} - -static void dump_cs4245_registers(struct oxygen *chip, +void dump_cs4245_registers(struct oxygen *chip, struct snd_info_buffer *buffer) { struct dg *data = chip->model_data; - unsigned int i; + unsigned int addr; snd_iprintf(buffer, "\nCS4245:"); - for (i = 1; i <= 0x10; ++i) - snd_iprintf(buffer, " %02x", data->cs4245_regs[i]); + cs4245_read_spi(chip, CS4245_INT_STATUS); + for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) + snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]); snd_iprintf(buffer, "\n"); } - -struct oxygen_model model_xonar_dg = { - .longname = "C-Media Oxygen HD Audio", - .chip = "CMI8786", - .init = dg_init, - .control_filter = dg_control_filter, - .mixer_init = dg_mixer_init, - .cleanup = dg_cleanup, - .suspend = dg_suspend, - .resume = dg_resume, - .set_dac_params = set_cs4245_dac_params, - .set_adc_params = set_cs4245_adc_params, - .adjust_dac_routing = adjust_dg_dac_routing, - .dump_registers = dump_cs4245_registers, - .model_data_size = sizeof(struct dg), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF, - .dac_channels_pcm = 6, - .dac_channels_mixer = 0, - .function_flags = OXYGEN_FUNCTION_SPI, - .dac_mclks = OXYGEN_MCLKS(256, 128, 128), - .adc_mclks = OXYGEN_MCLKS(256, 128, 128), - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; diff --git a/sound/pci/oxygen/xonar_dg.h b/sound/pci/oxygen/xonar_dg.h index 5688d78609a..d461df357aa 100644 --- a/sound/pci/oxygen/xonar_dg.h +++ b/sound/pci/oxygen/xonar_dg.h @@ -3,6 +3,54 @@ #include "oxygen.h" +#define GPIO_MAGIC 0x0008 +#define GPIO_HP_DETECT 0x0010 +#define GPIO_INPUT_ROUTE 0x0060 +#define GPIO_HP_REAR 0x0080 +#define GPIO_OUTPUT_ENABLE 0x0100 + +#define CAPTURE_SRC_MIC 0 +#define CAPTURE_SRC_FP_MIC 1 +#define CAPTURE_SRC_LINE 2 +#define CAPTURE_SRC_AUX 3 + +#define PLAYBACK_DST_HP 0 +#define PLAYBACK_DST_HP_FP 1 +#define PLAYBACK_DST_MULTICH 2 + +enum cs4245_shadow_operation { + CS4245_SAVE_TO_SHADOW, + CS4245_LOAD_FROM_SHADOW +}; + +struct dg { + /* shadow copy of the CS4245 register space */ + unsigned char cs4245_shadow[17]; + /* output select: headphone/speakers */ + unsigned char output_sel; + /* volumes for all capture sources */ + char input_vol[4][2]; + /* input select: mic/fp mic/line/aux */ + unsigned char input_sel; +}; + +/* Xonar DG control routines */ +int cs4245_write_spi(struct oxygen *chip, u8 reg); +int cs4245_read_spi(struct oxygen *chip, u8 reg); +int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op); +void dg_init(struct oxygen *chip); +void set_cs4245_dac_params(struct oxygen *chip, + struct snd_pcm_hw_params *params); +void set_cs4245_adc_params(struct oxygen *chip, + struct snd_pcm_hw_params *params); +unsigned int adjust_dg_dac_routing(struct oxygen *chip, + unsigned int play_routing); +void dump_cs4245_registers(struct oxygen *chip, + struct snd_info_buffer *buffer); +void dg_suspend(struct oxygen *chip); +void dg_resume(struct oxygen *chip); +void dg_cleanup(struct oxygen *chip); + extern struct oxygen_model model_xonar_dg; #endif diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c new file mode 100644 index 00000000000..b885dac28a0 --- /dev/null +++ b/sound/pci/oxygen/xonar_dg_mixer.c @@ -0,0 +1,477 @@ +/* + * Mixer controls for the Xonar DG/DGX + * + * Copyright (c) Clemens Ladisch <clemens@ladisch.de> + * Copyright (c) Roman Volkov <v1ron@mail.ru> + * + * This driver is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2. + * + * This driver is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this driver; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <linux/pci.h> +#include <linux/delay.h> +#include <sound/control.h> +#include <sound/core.h> +#include <sound/info.h> +#include <sound/pcm.h> +#include <sound/tlv.h> +#include "oxygen.h" +#include "xonar_dg.h" +#include "cs4245.h" + +/* analog output select */ + +static int output_select_apply(struct oxygen *chip) +{ + struct dg *data = chip->model_data; + + data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK; + if (data->output_sel == PLAYBACK_DST_HP) { + /* mute FP (aux output) amplifier, switch rear jack to CS4245 */ + oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); + } else if (data->output_sel == PLAYBACK_DST_HP_FP) { + /* + * Unmute FP amplifier, switch rear jack to CS4361; + * I2S channels 2,3,4 should be inactive. + */ + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); + data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC; + } else { + /* + * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp., + * and change playback routing. + */ + oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR); + } + return cs4245_write_spi(chip, CS4245_SIGNAL_SEL); +} + +static int output_select_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "Stereo Headphones", + "Stereo Headphones FP", + "Multichannel", + }; + + return snd_ctl_enum_info(info, 1, 3, names); +} + +static int output_select_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = data->output_sel; + mutex_unlock(&chip->mutex); + return 0; +} + +static int output_select_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int new = value->value.enumerated.item[0]; + int changed = 0; + int ret; + + mutex_lock(&chip->mutex); + if (data->output_sel != new) { + data->output_sel = new; + ret = output_select_apply(chip); + changed = ret >= 0 ? 1 : ret; + oxygen_update_dac_routing(chip); + } + mutex_unlock(&chip->mutex); + + return changed; +} + +/* CS4245 Headphone Channels A&B Volume Control */ + +static int hp_stereo_volume_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 0; + info->value.integer.max = 255; + return 0; +} + +static int hp_stereo_volume_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *val) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int tmp; + + mutex_lock(&chip->mutex); + tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255; + val->value.integer.value[0] = tmp; + tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255; + val->value.integer.value[1] = tmp; + mutex_unlock(&chip->mutex); + return 0; +} + +static int hp_stereo_volume_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *val) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + int ret; + int changed = 0; + long new1 = val->value.integer.value[0]; + long new2 = val->value.integer.value[1]; + + if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0)) + return -EINVAL; + + mutex_lock(&chip->mutex); + if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) || + (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) { + data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1; + data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2; + ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL); + if (ret >= 0) + ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL); + changed = ret >= 0 ? 1 : ret; + } + mutex_unlock(&chip->mutex); + + return changed; +} + +/* Headphone Mute */ + +static int hp_mute_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *val) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + val->value.integer.value[0] = + !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC); + mutex_unlock(&chip->mutex); + return 0; +} + +static int hp_mute_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *val) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + int ret; + int changed; + + if (val->value.integer.value[0] > 1) + return -EINVAL; + mutex_lock(&chip->mutex); + data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC; + data->cs4245_shadow[CS4245_DAC_CTRL_1] |= + (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC; + ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1); + changed = ret >= 0 ? 1 : ret; + mutex_unlock(&chip->mutex); + return changed; +} + +/* capture volume for all sources */ + +static int input_volume_apply(struct oxygen *chip, char left, char right) +{ + struct dg *data = chip->model_data; + int ret; + + data->cs4245_shadow[CS4245_PGA_A_CTRL] = left; + data->cs4245_shadow[CS4245_PGA_B_CTRL] = right; + ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL); + if (ret < 0) + return ret; + return cs4245_write_spi(chip, CS4245_PGA_B_CTRL); +} + +static int input_vol_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + info->count = 2; + info->value.integer.min = 2 * -12; + info->value.integer.max = 2 * 12; + return 0; +} + +static int input_vol_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int idx = ctl->private_value; + + mutex_lock(&chip->mutex); + value->value.integer.value[0] = data->input_vol[idx][0]; + value->value.integer.value[1] = data->input_vol[idx][1]; + mutex_unlock(&chip->mutex); + return 0; +} + +static int input_vol_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + unsigned int idx = ctl->private_value; + int changed = 0; + int ret = 0; + + if (value->value.integer.value[0] < 2 * -12 || + value->value.integer.value[0] > 2 * 12 || + value->value.integer.value[1] < 2 * -12 || + value->value.integer.value[1] > 2 * 12) + return -EINVAL; + mutex_lock(&chip->mutex); + changed = data->input_vol[idx][0] != value->value.integer.value[0] || + data->input_vol[idx][1] != value->value.integer.value[1]; + if (changed) { + data->input_vol[idx][0] = value->value.integer.value[0]; + data->input_vol[idx][1] = value->value.integer.value[1]; + if (idx == data->input_sel) { + ret = input_volume_apply(chip, + data->input_vol[idx][0], + data->input_vol[idx][1]); + } + changed = ret >= 0 ? 1 : ret; + } + mutex_unlock(&chip->mutex); + return changed; +} + +/* Capture Source */ + +static int input_source_apply(struct oxygen *chip) +{ + struct dg *data = chip->model_data; + + data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK; + if (data->input_sel == CAPTURE_SRC_FP_MIC) + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2; + else if (data->input_sel == CAPTURE_SRC_LINE) + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4; + else if (data->input_sel != CAPTURE_SRC_MIC) + data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1; + return cs4245_write_spi(chip, CS4245_ANALOG_IN); +} + +static int input_sel_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[4] = { + "Mic", "Front Mic", "Line", "Aux" + }; + + return snd_ctl_enum_info(info, 1, 4, names); +} + +static int input_sel_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + mutex_lock(&chip->mutex); + value->value.enumerated.item[0] = data->input_sel; + mutex_unlock(&chip->mutex); + return 0; +} + +static int input_sel_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + int changed; + int ret; + + if (value->value.enumerated.item[0] > 3) + return -EINVAL; + + mutex_lock(&chip->mutex); + changed = value->value.enumerated.item[0] != data->input_sel; + if (changed) { + data->input_sel = value->value.enumerated.item[0]; + + ret = input_source_apply(chip); + if (ret >= 0) + ret = input_volume_apply(chip, + data->input_vol[data->input_sel][0], + data->input_vol[data->input_sel][1]); + changed = ret >= 0 ? 1 : ret; + } + mutex_unlock(&chip->mutex); + return changed; +} + +/* ADC high-pass filter */ + +static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { "Active", "Frozen" }; + + return snd_ctl_enum_info(info, 1, 2, names); +} + +static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + + value->value.enumerated.item[0] = + !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE); + return 0; +} + +static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct dg *data = chip->model_data; + u8 reg; + int changed; + + mutex_lock(&chip->mutex); + reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE; + if (value->value.enumerated.item[0]) + reg |= CS4245_HPF_FREEZE; + changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL]; + if (changed) { + data->cs4245_shadow[CS4245_ADC_CTRL] = reg; + cs4245_write_spi(chip, CS4245_ADC_CTRL); + } + mutex_unlock(&chip->mutex); + return changed; +} + +#define INPUT_VOLUME(xname, index) { \ + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = input_vol_info, \ + .get = input_vol_get, \ + .put = input_vol_put, \ + .tlv = { .p = pga_db_scale }, \ + .private_value = index, \ +} +static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0); +static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200); +static const struct snd_kcontrol_new dg_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Output Playback Enum", + .info = output_select_info, + .get = output_select_get, + .put = output_select_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Volume", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | + SNDRV_CTL_ELEM_ACCESS_TLV_READ, + .info = hp_stereo_volume_info, + .get = hp_stereo_volume_get, + .put = hp_stereo_volume_put, + .tlv = { .p = hp_db_scale, }, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphone Playback Switch", + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, + .info = snd_ctl_boolean_mono_info, + .get = hp_mute_get, + .put = hp_mute_put, + }, + INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC), + INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC), + INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE), + INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Capture Source", + .info = input_sel_info, + .get = input_sel_get, + .put = input_sel_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC High-pass Filter Capture Enum", + .info = hpf_info, + .get = hpf_get, + .put = hpf_put, + }, +}; + +static int dg_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "Master Playback ", 16)) + return 1; + return 0; +} + +static int dg_mixer_init(struct oxygen *chip) +{ + unsigned int i; + int err; + + output_select_apply(chip); + input_source_apply(chip); + oxygen_update_dac_routing(chip); + + for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&dg_controls[i], chip)); + if (err < 0) + return err; + } + + return 0; +} + +struct oxygen_model model_xonar_dg = { + .longname = "C-Media Oxygen HD Audio", + .chip = "CMI8786", + .init = dg_init, + .control_filter = dg_control_filter, + .mixer_init = dg_mixer_init, + .cleanup = dg_cleanup, + .suspend = dg_suspend, + .resume = dg_resume, + .set_dac_params = set_cs4245_dac_params, + .set_adc_params = set_cs4245_adc_params, + .adjust_dac_routing = adjust_dg_dac_routing, + .dump_registers = dump_cs4245_registers, + .model_data_size = sizeof(struct dg), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_1 | + CAPTURE_1_FROM_SPDIF, + .dac_channels_pcm = 6, + .dac_channels_mixer = 0, + .function_flags = OXYGEN_FUNCTION_SPI, + .dac_mclks = OXYGEN_MCLKS(256, 128, 128), + .adc_mclks = OXYGEN_MCLKS(256, 128, 128), + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c index 136dac6a396..91d92bc32b7 100644 --- a/sound/pci/oxygen/xonar_hdmi.c +++ b/sound/pci/oxygen/xonar_hdmi.c @@ -120,7 +120,7 @@ void xonar_hdmi_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 HDMI chip received:\n"); + dev_dbg(chip->card->dev, "message from HDMI chip received:\n"); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, chip->uart_input, chip->uart_input_count); chip->uart_input_count = 0; diff --git a/sound/pci/oxygen/xonar_lib.c b/sound/pci/oxygen/xonar_lib.c index 0ebe7f5916f..706b1a42163 100644 --- a/sound/pci/oxygen/xonar_lib.c +++ b/sound/pci/oxygen/xonar_lib.c @@ -56,9 +56,9 @@ static void xonar_ext_power_gpio_changed(struct oxygen *chip) if (has_power != data->has_power) { data->has_power = has_power; if (has_power) { - snd_printk(KERN_NOTICE "power restored\n"); + dev_notice(chip->card->dev, "power restored\n"); } else { - snd_printk(KERN_CRIT + dev_crit(chip->card->dev, "Hey! Don't unplug the power cable!\n"); /* TODO: stop PCMs */ } diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 8433aa7c3d7..c8c7f2c9b35 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -1087,8 +1087,8 @@ static const struct oxygen_model model_xonar_st = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_pcm179x_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_pcm179x_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x8269: diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 63cff90706b..6ce68604c25 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -1255,7 +1255,6 @@ static void dump_wm87x6_registers(struct oxygen *chip, } static const struct oxygen_model model_xonar_ds = { - .shortname = "Xonar DS", .longname = "Asus Virtuoso 66", .chip = "AV200", .init = xonar_ds_init, @@ -1321,12 +1320,17 @@ static const struct oxygen_model model_xonar_hdav_slim = { .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, }; -int __devinit get_xonar_wm87x6_model(struct oxygen *chip, - const struct pci_device_id *id) +int get_xonar_wm87x6_model(struct oxygen *chip, + const struct pci_device_id *id) { switch (id->subdevice) { case 0x838e: chip->model = model_xonar_ds; + chip->model.shortname = "Xonar DS"; + break; + case 0x8522: + chip->model = model_xonar_ds; + chip->model.shortname = "Xonar DSX"; break; case 0x835e: chip->model = model_xonar_hdav_slim; diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index be4f1456009..8d09444ff88 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c @@ -284,7 +284,7 @@ static int pcxhr_get_clock_reg(struct pcxhr_mgr *mgr, unsigned int rate, rmh.cmd_len = 3; err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "error CMD_ACCESS_IO_WRITE " "for PLL register : %x!\n", err); return err; @@ -357,7 +357,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, return err; } /* set the new frequency */ - snd_printdd("clock register : set %x\n", val); + dev_dbg(&mgr->pci->dev, "clock register : set %x\n", val); err = pcxhr_write_io_num_reg_cont(mgr, PCXHR_FREQ_REG_MASK, val, changed); if (err) @@ -380,7 +380,7 @@ static int pcxhr_sub_set_clock(struct pcxhr_mgr *mgr, mgr->codec_speed = speed; /* save new codec speed */ } - snd_printdd("pcxhr_sub_set_clock to %dHz (realfreq=%d)\n", + dev_dbg(&mgr->pci->dev, "pcxhr_sub_set_clock to %dHz (realfreq=%d)\n", rate, realfreq); return 0; } @@ -480,7 +480,7 @@ static int pcxhr_sub_get_external_clock(struct pcxhr_mgr *mgr, case REG_STATUS_SYNC_192000 : rate = 192000; break; default: rate = 0; } - snd_printdd("External clock is at %d Hz\n", rate); + dev_dbg(&mgr->pci->dev, "External clock is at %d Hz\n", rate); *sample_rate = rate; return 0; } @@ -537,8 +537,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream) err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state err=%x;\n", - err); + dev_err(chip->card->dev, + "ERROR pcxhr_set_stream_state err=%x;\n", err); stream->status = start ? PCXHR_STREAM_STATUS_STARTED : PCXHR_STREAM_STATUS_STOPPED; return err; @@ -628,7 +628,8 @@ static int pcxhr_set_format(struct pcxhr_stream *stream) rmh.cmd[rmh.cmd_len++] = (header & 0xff) << 16; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_set_format err=%x;\n", err); + dev_err(chip->card->dev, + "ERROR pcxhr_set_format err=%x;\n", err); return err; } @@ -665,7 +666,7 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream) rmh.cmd_len = 4; err = pcxhr_send_msg(chip->mgr, &rmh); if (err) - snd_printk(KERN_ERR + dev_err(chip->card->dev, "ERROR CMD_UPDATE_R_BUFFERS err=%x;\n", err); return err; } @@ -735,11 +736,11 @@ static void pcxhr_trigger_tasklet(unsigned long arg) } if (capture_mask == 0 && playback_mask == 0) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : no pipes\n"); + dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : no pipes\n"); return; } - snd_printdd("pcxhr_trigger_tasklet : " + dev_dbg(&mgr->pci->dev, "pcxhr_trigger_tasklet : " "playback_mask=%x capture_mask=%x\n", playback_mask, capture_mask); @@ -747,7 +748,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : " "error stop pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -792,7 +793,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 1); if (err) { mutex_unlock(&mgr->setup_mutex); - snd_printk(KERN_ERR "pcxhr_trigger_tasklet : " + dev_err(&mgr->pci->dev, "pcxhr_trigger_tasklet : " "error start pipes (P%x C%x)\n", playback_mask, capture_mask); return; @@ -825,7 +826,7 @@ static void pcxhr_trigger_tasklet(unsigned long arg) #ifdef CONFIG_SND_DEBUG_VERBOSE do_gettimeofday(&my_tv2); - snd_printdd("***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", + dev_dbg(&mgr->pci->dev, "***TRIGGER TASKLET*** TIME = %ld (err = %x)\n", (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); #endif } @@ -902,7 +903,7 @@ static int pcxhr_hardware_timer(struct pcxhr_mgr *mgr, int start) } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pcxhr_hardware_timer err(%x)\n", + dev_err(&mgr->pci->dev, "error pcxhr_hardware_timer err(%x)\n", err); return err; } @@ -916,7 +917,8 @@ static int pcxhr_prepare(struct snd_pcm_substream *subs) struct pcxhr_mgr *mgr = chip->mgr; int err = 0; - snd_printdd("pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n", + dev_dbg(chip->card->dev, + "pcxhr_prepare : period_size(%lx) periods(%x) buffer_size(%lx)\n", subs->runtime->period_size, subs->runtime->periods, subs->runtime->buffer_size); @@ -1025,11 +1027,11 @@ static int pcxhr_open(struct snd_pcm_substream *subs) runtime->hw = pcxhr_caps; if( subs->stream == SNDRV_PCM_STREAM_PLAYBACK ) { - snd_printdd("pcxhr_open playback chip%d subs%d\n", + dev_dbg(chip->card->dev, "pcxhr_open playback chip%d subs%d\n", chip->chip_idx, subs->number); stream = &chip->playback_stream[subs->number]; } else { - snd_printdd("pcxhr_open capture chip%d subs%d\n", + dev_dbg(chip->card->dev, "pcxhr_open capture chip%d subs%d\n", chip->chip_idx, subs->number); if (mgr->mono_capture) runtime->hw.channels_max = 1; @@ -1039,7 +1041,7 @@ static int pcxhr_open(struct snd_pcm_substream *subs) } if (stream->status != PCXHR_STREAM_STATUS_FREE){ /* streams in use */ - snd_printk(KERN_ERR "pcxhr_open chip%d subs%d in use\n", + dev_err(chip->card->dev, "pcxhr_open chip%d subs%d in use\n", chip->chip_idx, subs->number); mutex_unlock(&mgr->setup_mutex); return -EBUSY; @@ -1105,7 +1107,7 @@ static int pcxhr_close(struct snd_pcm_substream *subs) mutex_lock(&mgr->setup_mutex); - snd_printdd("pcxhr_close chip%d subs%d\n", + dev_dbg(chip->card->dev, "pcxhr_close chip%d subs%d\n", chip->chip_idx, subs->number); /* sample rate released */ @@ -1168,7 +1170,7 @@ int pcxhr_create_pcm(struct snd_pcxhr *chip) if ((err = snd_pcm_new(chip->card, name, 0, chip->nb_streams_play, chip->nb_streams_capt, &pcm)) < 0) { - snd_printk(KERN_ERR "cannot create pcm %s\n", name); + dev_err(chip->card->dev, "cannot create pcm %s\n", name); return err; } pcm->private_data = chip; @@ -1203,8 +1205,8 @@ static int pcxhr_chip_dev_free(struct snd_device *device) /* */ -static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, - struct snd_card *card, int idx) +static int pcxhr_create(struct pcxhr_mgr *mgr, + struct snd_card *card, int idx) { int err; struct snd_pcxhr *chip; @@ -1214,7 +1216,7 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (! chip) { - snd_printk(KERN_ERR "cannot allocate chip\n"); + dev_err(card->dev, "cannot allocate chip\n"); return -ENOMEM; } @@ -1239,7 +1241,6 @@ static int __devinit pcxhr_create(struct pcxhr_mgr *mgr, } mgr->chip[idx] = chip; - snd_card_set_dev(card, &mgr->pci->dev); return 0; } @@ -1453,7 +1454,7 @@ static void pcxhr_proc_ltc(struct snd_info_entry *entry, } } -static void __devinit pcxhr_proc_init(struct snd_pcxhr *chip) +static void pcxhr_proc_init(struct snd_pcxhr *chip) { struct snd_info_entry *entry; @@ -1488,7 +1489,7 @@ static int pcxhr_free(struct pcxhr_mgr *mgr) /* reset board if some firmware was loaded */ if(mgr->dsp_loaded) { pcxhr_reset_board(mgr); - snd_printdd("reset pcxhr !\n"); + dev_dbg(&mgr->pci->dev, "reset pcxhr !\n"); } /* release irq */ @@ -1513,8 +1514,8 @@ static int pcxhr_free(struct pcxhr_mgr *mgr) /* * probe function - creates the card manager */ -static int __devinit pcxhr_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int pcxhr_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct pcxhr_mgr *mgr; @@ -1537,8 +1538,8 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, /* check if we can restrict PCI DMA transfers to 32 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0) { - snd_printk(KERN_ERR "architecture does not support " - "32bit PCI busmaster DMA\n"); + dev_err(&pci->dev, + "architecture does not support 32bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1589,7 +1590,7 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, if (request_irq(pci->irq, pcxhr_interrupt, IRQF_SHARED, KBUILD_MODNAME, mgr)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(&pci->dev, "unable to grab IRQ %d\n", pci->irq); pcxhr_free(mgr); return -EBUSY; } @@ -1638,10 +1639,11 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, snprintf(tmpid, sizeof(tmpid), "%s-%d", id[dev] ? id[dev] : card_name, i); - err = snd_card_create(idx, tmpid, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, idx, tmpid, THIS_MODULE, + 0, &card); if (err < 0) { - snd_printk(KERN_ERR "cannot allocate the card %d\n", i); + dev_err(card->dev, "cannot allocate the card %d\n", i); pcxhr_free(mgr); return err; } @@ -1688,17 +1690,16 @@ static int __devinit pcxhr_probe(struct pci_dev *pci, return 0; } -static void __devexit pcxhr_remove(struct pci_dev *pci) +static void pcxhr_remove(struct pci_dev *pci) { pcxhr_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver pcxhr_driver = { .name = KBUILD_MODNAME, .id_table = pcxhr_ids, .probe = pcxhr_probe, - .remove = __devexit_p(pcxhr_remove), + .remove = pcxhr_remove, }; module_pci_driver(pcxhr_driver); diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c index b33db1e006e..df937191860 100644 --- a/sound/pci/pcxhr/pcxhr_core.c +++ b/sound/pci/pcxhr/pcxhr_core.c @@ -23,6 +23,7 @@ #include <linux/delay.h> #include <linux/firmware.h> #include <linux/interrupt.h> +#include <linux/pci.h> #include <asm/io.h> #include <sound/core.h> #include "pcxhr.h" @@ -132,14 +133,14 @@ static int pcxhr_check_reg_bit(struct pcxhr_mgr *mgr, unsigned int reg, *read = PCXHR_INPB(mgr, reg); if ((*read & mask) == bit) { if (i > 100) - snd_printdd("ATTENTION! check_reg(%x) " - "loopcount=%d\n", + dev_dbg(&mgr->pci->dev, + "ATTENTION! check_reg(%x) loopcount=%d\n", reg, i); return 0; } i++; } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "pcxhr_check_reg_bit: timeout, reg=%x, mask=0x%x, val=%x\n", reg, mask, *read); return -EIO; @@ -216,7 +217,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_CVR, PCXHR_CVR_HI08_HC, 0, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "pcxhr_send_it_dsp : TIMEOUT CVR\n"); + dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT CVR\n"); return err; } if (itdsp & PCXHR_MASK_IT_MANAGE_HF5) { @@ -227,7 +228,7 @@ static int pcxhr_send_it_dsp(struct pcxhr_mgr *mgr, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "pcxhr_send_it_dsp : TIMEOUT HF5\n"); return err; } @@ -294,7 +295,7 @@ int pcxhr_load_xilinx_binary(struct pcxhr_mgr *mgr, */ if(second) { if ((chipsc & PCXHR_CHIPSC_GPI_USERI) == 0) { - snd_printk(KERN_ERR "error loading first xilinx\n"); + dev_err(&mgr->pci->dev, "error loading first xilinx\n"); return -EINVAL; } /* activate second xilinx */ @@ -360,7 +361,7 @@ static int pcxhr_download_dsp(struct pcxhr_mgr *mgr, const struct firmware *dsp) PCXHR_ISR_HI08_TRDY, PCXHR_TIMEOUT_DSP, &dummy); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "dsp loading error at position %d\n", i); return err; } @@ -396,7 +397,7 @@ int pcxhr_load_eeprom_binary(struct pcxhr_mgr *mgr, msleep(PCXHR_WAIT_DEFAULT); PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); msleep(PCXHR_WAIT_DEFAULT); - snd_printdd("no need to load eeprom boot\n"); + dev_dbg(&mgr->pci->dev, "no need to load eeprom boot\n"); return 0; } PCXHR_OUTPB(mgr, PCXHR_DSP_ICR, reg); @@ -561,9 +562,9 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "ERROR RMH stat: " - "ISR:RXDF=1 (ISR = %x; i=%d )\n", - reg, i); + dev_err(&mgr->pci->dev, + "ERROR RMH stat: ISR:RXDF=1 (ISR = %x; i=%d )\n", + reg, i); return err; } /* read data */ @@ -591,13 +592,13 @@ static int pcxhr_read_rmh_status(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) } #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd(" stat[%d]=%x\n", i, data); + dev_dbg(&mgr->pci->dev, " stat[%d]=%x\n", i, data); #endif if (i < max_stat_len) rmh->stat[i] = data; } if (rmh->stat_len > max_stat_len) { - snd_printdd("PCXHR : rmh->stat_len=%x too big\n", + dev_dbg(&mgr->pci->dev, "PCXHR : rmh->stat_len=%x too big\n", rmh->stat_len); rmh->stat_len = max_stat_len; } @@ -615,7 +616,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) return -EINVAL; err = pcxhr_send_it_dsp(mgr, PCXHR_IT_MESSAGE, 1); if (err) { - snd_printk(KERN_ERR "pcxhr_send_message : ED_DSP_CRASHED\n"); + dev_err(&mgr->pci->dev, + "pcxhr_send_message : ED_DSP_CRASHED\n"); return err; } /* wait for chk bit */ @@ -641,7 +643,7 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data &= 0xff7fff; /* MASK_1_WORD_COMMAND */ #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd("MSG cmd[0]=%x (%s)\n", + dev_dbg(&mgr->pci->dev, "MSG cmd[0]=%x (%s)\n", data, cmd_names[rmh->cmd_idx]); #endif @@ -671,7 +673,8 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) data = rmh->cmd[i]; #ifdef CONFIG_SND_DEBUG_VERBOSE if (rmh->cmd_idx < CMD_LAST_INDEX) - snd_printdd(" cmd[%d]=%x\n", i, data); + dev_dbg(&mgr->pci->dev, + " cmd[%d]=%x\n", i, data); #endif err = pcxhr_check_reg_bit(mgr, PCXHR_DSP_ISR, PCXHR_ISR_HI08_TRDY, @@ -697,14 +700,15 @@ static int pcxhr_send_msg_nolock(struct pcxhr_mgr *mgr, struct pcxhr_rmh *rmh) PCXHR_ISR_HI08_RXDF, PCXHR_TIMEOUT_DSP, ®); if (err) { - snd_printk(KERN_ERR "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); + dev_err(&mgr->pci->dev, + "ERROR RMH: ISR:RXDF=1 (ISR = %x)\n", reg); return err; } /* read error code */ data = PCXHR_INPB(mgr, PCXHR_DSP_TXH) << 16; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXM) << 8; data |= PCXHR_INPB(mgr, PCXHR_DSP_TXL); - snd_printk(KERN_ERR "ERROR RMH(%d): 0x%x\n", + dev_err(&mgr->pci->dev, "ERROR RMH(%d): 0x%x\n", rmh->cmd_idx, data); err = -EINVAL; } else { @@ -780,7 +784,7 @@ static inline int pcxhr_pipes_running(struct pcxhr_mgr *mgr) * (PCXHR_PIPE_STATE_CAPTURE_OFFSET) */ start_mask &= 0xffffff; - snd_printdd("CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask); + dev_dbg(&mgr->pci->dev, "CMD_PIPE_STATE MBOX2=0x%06x\n", start_mask); return start_mask; } @@ -809,7 +813,7 @@ static int pcxhr_prepair_pipe_start(struct pcxhr_mgr *mgr, } err = pcxhr_send_msg(mgr, &rmh); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "error pipe start " "(CMD_CAN_START_PIPE) err=%x!\n", err); @@ -847,7 +851,7 @@ static int pcxhr_stop_pipes(struct pcxhr_mgr *mgr, int audio_mask) } err = pcxhr_send_msg(mgr, &rmh); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "error pipe stop " "(CMD_STOP_PIPE) err=%x!\n", err); return err; @@ -876,7 +880,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask) 1 << (audio - PCXHR_PIPE_STATE_CAPTURE_OFFSET)); err = pcxhr_send_msg(mgr, &rmh); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "error pipe start " "(CMD_CONF_PIPE) err=%x!\n", err); return err; @@ -889,7 +893,7 @@ static int pcxhr_toggle_pipes(struct pcxhr_mgr *mgr, int audio_mask) pcxhr_init_rmh(&rmh, CMD_SEND_IRQA); err = pcxhr_send_msg(mgr, &rmh); if (err) { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "error pipe start (CMD_SEND_IRQA) err=%x!\n", err); return err; @@ -913,7 +917,8 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, (capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET)); /* current pipe state (playback + record) */ state = pcxhr_pipes_running(mgr); - snd_printdd("pcxhr_set_pipe_state %s (mask %x current %x)\n", + dev_dbg(&mgr->pci->dev, + "pcxhr_set_pipe_state %s (mask %x current %x)\n", start ? "START" : "STOP", audio_mask, state); if (start) { /* start only pipes that are not yet started */ @@ -944,7 +949,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, if ((state & audio_mask) == (start ? audio_mask : 0)) break; if (++i >= MAX_WAIT_FOR_DSP * 100) { - snd_printk(KERN_ERR "error pipe start/stop\n"); + dev_err(&mgr->pci->dev, "error pipe start/stop\n"); return -EBUSY; } udelay(10); /* wait 10 microseconds */ @@ -956,7 +961,7 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask, } #ifdef CONFIG_SND_DEBUG_VERBOSE do_gettimeofday(&my_tv2); - snd_printdd("***SET PIPE STATE*** TIME = %ld (err = %x)\n", + dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n", (long)(my_tv2.tv_usec - my_tv1.tv_usec), err); #endif return 0; @@ -971,7 +976,8 @@ int pcxhr_write_io_num_reg_cont(struct pcxhr_mgr *mgr, unsigned int mask, spin_lock_irqsave(&mgr->msg_lock, flags); if ((mgr->io_num_reg_cont & mask) == value) { - snd_printdd("IO_NUM_REG_CONT mask %x already is set to %x\n", + dev_dbg(&mgr->pci->dev, + "IO_NUM_REG_CONT mask %x already is set to %x\n", mask, value); if (changed) *changed = 0; @@ -1012,20 +1018,19 @@ static int pcxhr_handle_async_err(struct pcxhr_mgr *mgr, u32 err, enum pcxhr_async_err_src err_src, int pipe, int is_capture) { -#ifdef CONFIG_SND_DEBUG_VERBOSE static char* err_src_name[] = { [PCXHR_ERR_PIPE] = "Pipe", [PCXHR_ERR_STREAM] = "Stream", [PCXHR_ERR_AUDIO] = "Audio" }; -#endif + if (err & 0xfff) err &= 0xfff; else err = ((err >> 12) & 0xfff); if (!err) return 0; - snd_printdd("CMD_ASYNC : Error %s %s Pipe %d err=%x\n", + dev_dbg(&mgr->pci->dev, "CMD_ASYNC : Error %s %s Pipe %d err=%x\n", err_src_name[err_src], is_capture ? "Record" : "Play", pipe, err); if (err == 0xe01) @@ -1046,20 +1051,24 @@ void pcxhr_msg_tasklet(unsigned long arg) int i, j; if (mgr->src_it_dsp & PCXHR_IRQ_FREQ_CHANGE) - snd_printdd("TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n"); + dev_dbg(&mgr->pci->dev, + "TASKLET : PCXHR_IRQ_FREQ_CHANGE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_TIME_CODE) - snd_printdd("TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n"); + dev_dbg(&mgr->pci->dev, + "TASKLET : PCXHR_IRQ_TIME_CODE event occurred\n"); if (mgr->src_it_dsp & PCXHR_IRQ_NOTIFY) - snd_printdd("TASKLET : PCXHR_IRQ_NOTIFY event occurred\n"); + dev_dbg(&mgr->pci->dev, + "TASKLET : PCXHR_IRQ_NOTIFY event occurred\n"); if (mgr->src_it_dsp & (PCXHR_IRQ_FREQ_CHANGE | PCXHR_IRQ_TIME_CODE)) { /* clear events FREQ_CHANGE and TIME_CODE */ pcxhr_init_rmh(prmh, CMD_TEST_IT); err = pcxhr_send_msg(mgr, prmh); - snd_printdd("CMD_TEST_IT : err=%x, stat=%x\n", + dev_dbg(&mgr->pci->dev, "CMD_TEST_IT : err=%x, stat=%x\n", err, prmh->stat[0]); } if (mgr->src_it_dsp & PCXHR_IRQ_ASYNC) { - snd_printdd("TASKLET : PCXHR_IRQ_ASYNC event occurred\n"); + dev_dbg(&mgr->pci->dev, + "TASKLET : PCXHR_IRQ_ASYNC event occurred\n"); pcxhr_init_rmh(prmh, CMD_ASYNC); prmh->cmd[0] |= 1; /* add SEL_ASYNC_EVENTS */ @@ -1067,7 +1076,7 @@ void pcxhr_msg_tasklet(unsigned long arg) prmh->stat_len = PCXHR_SIZE_MAX_LONG_STATUS; err = pcxhr_send_msg(mgr, prmh); if (err) - snd_printk(KERN_ERR "ERROR pcxhr_msg_tasklet=%x;\n", + dev_err(&mgr->pci->dev, "ERROR pcxhr_msg_tasklet=%x;\n", err); i = 1; while (i < prmh->stat_len) { @@ -1080,7 +1089,8 @@ void pcxhr_msg_tasklet(unsigned long arg) u32 err2; if (prmh->stat[i] & 0x800000) { /* if BIT_END */ - snd_printdd("TASKLET : End%sPipe %d\n", + dev_dbg(&mgr->pci->dev, + "TASKLET : End%sPipe %d\n", is_capture ? "Record" : "Play", pipe); } @@ -1137,7 +1147,8 @@ static u_int64_t pcxhr_stream_read_position(struct pcxhr_mgr *mgr, hw_sample_count = ((u_int64_t)rmh.stat[0]) << 24; hw_sample_count += (u_int64_t)rmh.stat[1]; - snd_printdd("stream %c%d : abs samples real(%llu) timer(%llu)\n", + dev_dbg(&mgr->pci->dev, + "stream %c%d : abs samples real(%llu) timer(%llu)\n", stream->pipe->is_capture ? 'C' : 'P', stream->substream->number, hw_sample_count, @@ -1203,7 +1214,7 @@ static void pcxhr_update_timer_pos(struct pcxhr_mgr *mgr, (u_int32_t)(new_sample_count - stream->timer_abs_periods); } else { - snd_printk(KERN_ERR + dev_err(&mgr->pci->dev, "ERROR new_sample_count too small ??? %ld\n", (long unsigned int)new_sample_count); } @@ -1248,33 +1259,39 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) (mgr->dsp_time_last != PCXHR_DSP_TIME_INVALID)) { /* handle dsp counter wraparound without resync */ int tmp_diff = dsp_time_diff + PCXHR_DSP_TIME_MASK + 1; - snd_printdd("WARNING DSP timestamp old(%d) new(%d)", + dev_dbg(&mgr->pci->dev, + "WARNING DSP timestamp old(%d) new(%d)", mgr->dsp_time_last, dsp_time_new); if (tmp_diff > 0 && tmp_diff <= (2*mgr->granularity)) { - snd_printdd("-> timestamp wraparound OK: " + dev_dbg(&mgr->pci->dev, + "-> timestamp wraparound OK: " "diff=%d\n", tmp_diff); dsp_time_diff = tmp_diff; } else { - snd_printdd("-> resynchronize all streams\n"); + dev_dbg(&mgr->pci->dev, + "-> resynchronize all streams\n"); mgr->dsp_time_err++; } } #ifdef CONFIG_SND_DEBUG_VERBOSE if (dsp_time_diff == 0) - snd_printdd("ERROR DSP TIME NO DIFF time(%d)\n", + dev_dbg(&mgr->pci->dev, + "ERROR DSP TIME NO DIFF time(%d)\n", dsp_time_new); else if (dsp_time_diff >= (2*mgr->granularity)) - snd_printdd("ERROR DSP TIME TOO BIG old(%d) add(%d)\n", + dev_dbg(&mgr->pci->dev, + "ERROR DSP TIME TOO BIG old(%d) add(%d)\n", mgr->dsp_time_last, dsp_time_new - mgr->dsp_time_last); else if (dsp_time_diff % mgr->granularity) - snd_printdd("ERROR DSP TIME increased by %d\n", + dev_dbg(&mgr->pci->dev, + "ERROR DSP TIME increased by %d\n", dsp_time_diff); #endif mgr->dsp_time_last = dsp_time_new; if (timer_toggle == mgr->timer_toggle) { - snd_printdd("ERROR TIMER TOGGLE\n"); + dev_dbg(&mgr->pci->dev, "ERROR TIMER TOGGLE\n"); mgr->dsp_time_err++; } mgr->timer_toggle = timer_toggle; @@ -1309,7 +1326,7 @@ irqreturn_t pcxhr_interrupt(int irq, void *dev_id) } #ifdef CONFIG_SND_DEBUG_VERBOSE if (reg & PCXHR_FATAL_DSP_ERR) - snd_printdd("FATAL DSP ERROR : %x\n", reg); + dev_dbg(&mgr->pci->dev, "FATAL DSP ERROR : %x\n", reg); #endif spin_unlock(&mgr->lock); return IRQ_HANDLED; /* this device caused the interrupt */ diff --git a/sound/pci/pcxhr/pcxhr_hwdep.c b/sound/pci/pcxhr/pcxhr_hwdep.c index bf207e317f7..15a8ce5f1f4 100644 --- a/sound/pci/pcxhr/pcxhr_hwdep.c +++ b/sound/pci/pcxhr/pcxhr_hwdep.c @@ -35,13 +35,6 @@ #include "pcxhr_mix22.h" -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(CONFIG_USE_PCXHRLOADER) && !defined(CONFIG_SND_PCXHR) /* built-in kernel */ -#define SND_PCXHR_FW_LOADER /* use the standard firmware loader */ -#endif -#endif - - static int pcxhr_sub_init(struct pcxhr_mgr *mgr); /* * get basic information and init pcxhr card @@ -79,7 +72,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) /* test max nb substream per pipe */ if (((rmh.stat[1] >> 7) & 0x5F) < PCXHR_PLAYBACK_STREAMS) return -EINVAL; - snd_printdd("supported formats : playback=%x capture=%x\n", + dev_dbg(&mgr->pci->dev, + "supported formats : playback=%x capture=%x\n", rmh.stat[2], rmh.stat[3]); pcxhr_init_rmh(&rmh, CMD_VERSION); @@ -91,7 +85,8 @@ static int pcxhr_init_board(struct pcxhr_mgr *mgr) err = pcxhr_send_msg(mgr, &rmh); if (err) return err; - snd_printdd("PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, + dev_dbg(&mgr->pci->dev, + "PCXHR DSP version is %d.%d.%d\n", (rmh.stat[0]>>16)&0xff, (rmh.stat[0]>>8)&0xff, rmh.stat[0]&0xff); mgr->dsp_version = rmh.stat[0]; @@ -186,7 +181,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, stream_count = PCXHR_PLAYBACK_STREAMS; audio_count = 2; /* always stereo */ } - snd_printdd("snd_add_ref_pipe pin(%d) pcm%c0\n", + dev_dbg(&mgr->pci->dev, "snd_add_ref_pipe pin(%d) pcm%c0\n", pin, is_capture ? 'c' : 'p'); pipe->is_capture = is_capture; pipe->first_audio = pin; @@ -201,7 +196,7 @@ static int pcxhr_dsp_allocate_pipe(struct pcxhr_mgr *mgr, } err = pcxhr_send_msg(mgr, &rmh); if (err < 0) { - snd_printk(KERN_ERR "error pipe allocation " + dev_err(&mgr->pci->dev, "error pipe allocation " "(CMD_RES_PIPE) err=%x!\n", err); return err; } @@ -229,14 +224,14 @@ static int pcxhr_dsp_free_pipe( struct pcxhr_mgr *mgr, struct pcxhr_pipe *pipe) /* stop one pipe */ err = pcxhr_set_pipe_state(mgr, playback_mask, capture_mask, 0); if (err < 0) - snd_printk(KERN_ERR "error stopping pipe!\n"); + dev_err(&mgr->pci->dev, "error stopping pipe!\n"); /* release the pipe */ pcxhr_init_rmh(&rmh, CMD_FREE_PIPE); pcxhr_set_pipe_cmd_params(&rmh, pipe->is_capture, pipe->first_audio, 0, 0); err = pcxhr_send_msg(mgr, &rmh); if (err < 0) - snd_printk(KERN_ERR "error pipe release " + dev_err(&mgr->pci->dev, "error pipe release " "(CMD_FREE_PIPE) err(%x)\n", err); pipe->status = PCXHR_PIPE_UNDEFINED; return err; @@ -296,7 +291,8 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, { int err, card_index; - snd_printdd("loading dsp [%d] size = %Zd\n", index, dsp->size); + dev_dbg(&mgr->pci->dev, + "loading dsp [%d] size = %Zd\n", index, dsp->size); switch (index) { case PCXHR_FIRMWARE_XLX_INT_INDEX: @@ -320,19 +316,19 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, return err; break; /* continue with first init */ default: - snd_printk(KERN_ERR "wrong file index\n"); + dev_err(&mgr->pci->dev, "wrong file index\n"); return -EFAULT; } /* end of switch file index*/ /* first communication with embedded */ err = pcxhr_init_board(mgr); if (err < 0) { - snd_printk(KERN_ERR "pcxhr could not be set up\n"); + dev_err(&mgr->pci->dev, "pcxhr could not be set up\n"); return err; } err = pcxhr_config_pipes(mgr); if (err < 0) { - snd_printk(KERN_ERR "pcxhr pipes could not be set up\n"); + dev_err(&mgr->pci->dev, "pcxhr pipes could not be set up\n"); return err; } /* create devices and mixer in accordance with HW options*/ @@ -351,10 +347,11 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, } err = pcxhr_start_pipes(mgr); if (err < 0) { - snd_printk(KERN_ERR "pcxhr pipes could not be started\n"); + dev_err(&mgr->pci->dev, "pcxhr pipes could not be started\n"); return err; } - snd_printdd("pcxhr firmware downloaded and successfully set up\n"); + dev_dbg(&mgr->pci->dev, + "pcxhr firmware downloaded and successfully set up\n"); return 0; } @@ -362,8 +359,6 @@ static int pcxhr_dsp_load(struct pcxhr_mgr *mgr, int index, /* * fw loader entry */ -#ifdef SND_PCXHR_FW_LOADER - int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) { static char *fw_files[][5] = { @@ -391,7 +386,8 @@ int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) continue; sprintf(path, "pcxhr/%s", fw_files[fw_set][i]); if (request_firmware(&fw_entry, path, &mgr->pci->dev)) { - snd_printk(KERN_ERR "pcxhr: can't load firmware %s\n", + dev_err(&mgr->pci->dev, + "pcxhr: can't load firmware %s\n", path); return -ENOENT; } @@ -424,80 +420,3 @@ MODULE_FIRMWARE("pcxhr/xlxc924.dat"); MODULE_FIRMWARE("pcxhr/dspe924.e56"); MODULE_FIRMWARE("pcxhr/dspb924.b56"); MODULE_FIRMWARE("pcxhr/dspd222.d56"); - - -#else /* old style firmware loading */ - -/* pcxhr hwdep interface id string */ -#define PCXHR_HWDEP_ID "pcxhr loader" - - -static int pcxhr_hwdep_dsp_status(struct snd_hwdep *hw, - struct snd_hwdep_dsp_status *info) -{ - struct pcxhr_mgr *mgr = hw->private_data; - sprintf(info->id, "pcxhr%d", mgr->fw_file_set); - info->num_dsps = PCXHR_FIRMWARE_FILES_MAX_INDEX; - - if (hw->dsp_loaded & (1 << PCXHR_FIRMWARE_DSP_MAIN_INDEX)) - info->chip_ready = 1; - - info->version = PCXHR_DRIVER_VERSION; - return 0; -} - -static int pcxhr_hwdep_dsp_load(struct snd_hwdep *hw, - struct snd_hwdep_dsp_image *dsp) -{ - struct pcxhr_mgr *mgr = hw->private_data; - int err; - struct firmware fw; - - fw.size = dsp->length; - fw.data = vmalloc(fw.size); - if (! fw.data) { - snd_printk(KERN_ERR "pcxhr: cannot allocate dsp image " - "(%lu bytes)\n", (unsigned long)fw.size); - return -ENOMEM; - } - if (copy_from_user((void *)fw.data, dsp->image, dsp->length)) { - vfree(fw.data); - return -EFAULT; - } - err = pcxhr_dsp_load(mgr, dsp->index, &fw); - vfree(fw.data); - if (err < 0) - return err; - mgr->dsp_loaded |= 1 << dsp->index; - return 0; -} - -int pcxhr_setup_firmware(struct pcxhr_mgr *mgr) -{ - int err; - struct snd_hwdep *hw; - - /* only create hwdep interface for first cardX - * (see "index" module parameter) - */ - err = snd_hwdep_new(mgr->chip[0]->card, PCXHR_HWDEP_ID, 0, &hw); - if (err < 0) - return err; - - hw->iface = SNDRV_HWDEP_IFACE_PCXHR; - hw->private_data = mgr; - hw->ops.dsp_status = pcxhr_hwdep_dsp_status; - hw->ops.dsp_load = pcxhr_hwdep_dsp_load; - hw->exclusive = 1; - /* stereo cards don't need fw_file_0 -> dsp_loaded = 1 */ - hw->dsp_loaded = mgr->is_hr_stereo ? 1 : 0; - mgr->dsp_loaded = 0; - sprintf(hw->name, PCXHR_HWDEP_ID); - - err = snd_card_register(mgr->chip[0]->card); - if (err < 0) - return err; - return 0; -} - -#endif /* SND_PCXHR_FW_LOADER */ diff --git a/sound/pci/pcxhr/pcxhr_mix22.c b/sound/pci/pcxhr/pcxhr_mix22.c index 84fe57626eb..6a56e5306a6 100644 --- a/sound/pci/pcxhr/pcxhr_mix22.c +++ b/sound/pci/pcxhr/pcxhr_mix22.c @@ -22,6 +22,7 @@ #include <linux/delay.h> #include <linux/io.h> +#include <linux/pci.h> #include <sound/core.h> #include <sound/control.h> #include <sound/tlv.h> @@ -290,7 +291,8 @@ int hr222_sub_init(struct pcxhr_mgr *mgr) reg = PCXHR_INPB(mgr, PCXHR_XLX_STATUS); if (reg & PCXHR_STAT_MIC_CAPS) mgr->board_has_mic = 1; /* microphone available */ - snd_printdd("MIC input available = %d\n", mgr->board_has_mic); + dev_dbg(&mgr->pci->dev, + "MIC input available = %d\n", mgr->board_has_mic); /* reset codec */ PCXHR_OUTPB(mgr, PCXHR_DSP_RESET, @@ -405,7 +407,7 @@ int hr222_sub_set_clock(struct pcxhr_mgr *mgr, hr222_config_akm(mgr, AKM_UNMUTE_CMD); - snd_printdd("set_clock to %dHz (realfreq=%d pllreg=%x)\n", + dev_dbg(&mgr->pci->dev, "set_clock to %dHz (realfreq=%d pllreg=%x)\n", rate, realfreq, pllreg); return 0; } @@ -431,13 +433,15 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr, reg = PCXHR_STAT_FREQ_UER1_MASK; } else { - snd_printdd("get_external_clock : type %d not supported\n", + dev_dbg(&mgr->pci->dev, + "get_external_clock : type %d not supported\n", clock_type); return -EINVAL; /* other clocks not supported */ } if ((PCXHR_INPB(mgr, PCXHR_XLX_CSUER) & mask) != mask) { - snd_printdd("get_external_clock(%d) = 0 Hz\n", clock_type); + dev_dbg(&mgr->pci->dev, + "get_external_clock(%d) = 0 Hz\n", clock_type); *sample_rate = 0; return 0; /* no external clock locked */ } @@ -495,7 +499,7 @@ int hr222_get_external_clock(struct pcxhr_mgr *mgr, else rate = 0; - snd_printdd("External clock is at %d Hz (measured %d Hz)\n", + dev_dbg(&mgr->pci->dev, "External clock is at %d Hz (measured %d Hz)\n", rate, calc_rate); *sample_rate = rate; return 0; @@ -542,7 +546,8 @@ int hr222_manage_timecode(struct pcxhr_mgr *mgr, int enable) int hr222_update_analog_audio_level(struct snd_pcxhr *chip, int is_capture, int channel) { - snd_printdd("hr222_update_analog_audio_level(%s chan=%d)\n", + dev_dbg(chip->card->dev, + "hr222_update_analog_audio_level(%s chan=%d)\n", is_capture ? "capture" : "playback", channel); if (is_capture) { int level_l, level_r, level_mic; @@ -642,7 +647,7 @@ int hr222_iec958_capture_byte(struct snd_pcxhr *chip, if (PCXHR_INPB(chip->mgr, PCXHR_XLX_CSUER) & mask) temp |= 1; } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; @@ -684,7 +689,7 @@ static void hr222_micro_boost(struct pcxhr_mgr *mgr, int level) PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); - snd_printdd("hr222_micro_boost : set %x\n", boost_mask); + dev_dbg(&mgr->pci->dev, "hr222_micro_boost : set %x\n", boost_mask); } static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) @@ -696,7 +701,7 @@ static void hr222_phantom_power(struct pcxhr_mgr *mgr, int power) PCXHR_OUTPB(mgr, PCXHR_XLX_SELMIC, mgr->xlx_selmic); - snd_printdd("hr222_phantom_power : set %d\n", power); + dev_dbg(&mgr->pci->dev, "hr222_phantom_power : set %d\n", power); } diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c index fec04934462..95c9571780d 100644 --- a/sound/pci/pcxhr/pcxhr_mixer.c +++ b/sound/pci/pcxhr/pcxhr_mixer.c @@ -72,7 +72,8 @@ static int pcxhr_update_analog_audio_level(struct snd_pcxhr *chip, rmh.cmd_len = 3; err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_analog_audio_level card(%d)" + dev_dbg(chip->card->dev, + "error update_analog_audio_level card(%d)" " is_capture(%d) err(%x)\n", chip->chip_idx, is_capture, err); return -EINVAL; @@ -284,7 +285,7 @@ static int pcxhr_update_playback_stream_level(struct snd_pcxhr* chip, int idx) err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_playback_stream_level " + dev_dbg(chip->card->dev, "error update_playback_stream_level " "card(%d) err(%x)\n", chip->chip_idx, err); return -EINVAL; } @@ -335,7 +336,8 @@ static int pcxhr_update_audio_pipe_level(struct snd_pcxhr *chip, err = pcxhr_send_msg(chip->mgr, &rmh); if (err < 0) { - snd_printk(KERN_DEBUG "error update_audio_level(%d) err=%x\n", + dev_dbg(chip->card->dev, + "error update_audio_level(%d) err=%x\n", chip->chip_idx, err); return -EINVAL; } @@ -930,7 +932,7 @@ static int pcxhr_iec958_capture_byte(struct snd_pcxhr *chip, temp |= 1; } } - snd_printdd("read iec958 AES %d byte %d = 0x%x\n", + dev_dbg(chip->card->dev, "read iec958 AES %d byte %d = 0x%x\n", chip->chip_idx, aes_idx, temp); *aes_bits = temp; return 0; @@ -992,7 +994,8 @@ static int pcxhr_iec958_update_byte(struct snd_pcxhr *chip, rmh.cmd[0] |= IO_NUM_REG_CUER; rmh.cmd[1] = cmd; rmh.cmd_len = 2; - snd_printdd("write iec958 AES %d byte %d bit %d (cmd %x)\n", + dev_dbg(chip->card->dev, + "write iec958 AES %d byte %d bit %d (cmd %x)\n", chip->chip_idx, aes_idx, i, cmd); err = pcxhr_send_msg(chip->mgr, &rmh); if (err) diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 7d291542c5b..b4a8278241b 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1706,7 +1706,7 @@ static struct snd_pcm_ops snd_riptide_capture_ops = { .pointer = snd_riptide_pointer, }; -static int __devinit +static int snd_riptide_pcm(struct snd_riptide *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; @@ -1857,7 +1857,7 @@ static int snd_riptide_dev_free(struct snd_device *device) return snd_riptide_free(chip); } -static int __devinit +static int snd_riptide_create(struct snd_card *card, struct pci_dev *pci, struct snd_riptide **rchip) { @@ -1916,8 +1916,6 @@ snd_riptide_create(struct snd_card *card, struct pci_dev *pci, return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } @@ -1993,7 +1991,7 @@ snd_riptide_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "\n"); } -static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) +static void snd_riptide_proc_init(struct snd_riptide *chip) { struct snd_info_entry *entry; @@ -2001,7 +1999,7 @@ static void __devinit snd_riptide_proc_init(struct snd_riptide *chip) snd_info_set_text_ops(entry, chip, snd_riptide_proc_read); } -static int __devinit snd_riptide_mixer(struct snd_riptide *chip) +static int snd_riptide_mixer(struct snd_riptide *chip) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; @@ -2027,7 +2025,7 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip) #ifdef SUPPORT_JOYSTICK -static int __devinit +static int snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) { static int dev; @@ -2060,18 +2058,17 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) return 0; } -static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) +static void snd_riptide_joystick_remove(struct pci_dev *pci) { struct gameport *gameport = pci_get_drvdata(pci); if (gameport) { release_region(gameport->io, 8); gameport_unregister_port(gameport); - pci_set_drvdata(pci, NULL); } } #endif -static int __devinit +static int snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -2087,7 +2084,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; err = snd_riptide_create(card, pci, &chip); @@ -2176,17 +2174,16 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return err; } -static void __devexit snd_card_riptide_remove(struct pci_dev *pci) +static void snd_card_riptide_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_riptide_ids, .probe = snd_card_riptide_probe, - .remove = __devexit_p(snd_card_riptide_remove), + .remove = snd_card_riptide_remove, .driver = { .pm = RIPTIDE_PM_OPS, }, @@ -2197,7 +2194,7 @@ static struct pci_driver joystick_driver = { .name = KBUILD_MODNAME "-joystick", .id_table = snd_riptide_joystick_ids, .probe = snd_riptide_joystick_probe, - .remove = __devexit_p(snd_riptide_joystick_remove), + .remove = snd_riptide_joystick_remove, }; #endif diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index 46b3629dda2..cc2f0c1b648 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c @@ -1017,7 +1017,7 @@ static int snd_rme32_capture_close(struct snd_pcm_substream *substream) spin_lock_irq(&rme32->lock); rme32->capture_substream = NULL; rme32->capture_periodsize = 0; - spin_unlock(&rme32->lock); + spin_unlock_irq(&rme32->lock); return 0; } @@ -1332,7 +1332,7 @@ snd_rme32_free_adat_pcm(struct snd_pcm *pcm) rme32->adat_pcm = NULL; } -static int __devinit snd_rme32_create(struct rme32 * rme32) +static int snd_rme32_create(struct rme32 *rme32) { struct pci_dev *pci = rme32->pci; int err; @@ -1349,14 +1349,15 @@ static int __devinit snd_rme32_create(struct rme32 * rme32) rme32->iobase = ioremap_nocache(rme32->port, RME32_IO_SIZE); if (!rme32->iobase) { - snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", + dev_err(rme32->card->dev, + "unable to remap memory region 0x%lx-0x%lx\n", rme32->port, rme32->port + RME32_IO_SIZE - 1); return -ENOMEM; } if (request_irq(pci->irq, snd_rme32_interrupt, IRQF_SHARED, KBUILD_MODNAME, rme32)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(rme32->card->dev, "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } rme32->irq = pci->irq; @@ -1554,7 +1555,7 @@ snd_rme32_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffe } } -static void __devinit snd_rme32_proc_init(struct rme32 * rme32) +static void snd_rme32_proc_init(struct rme32 *rme32) { struct snd_info_entry *entry; @@ -1922,7 +1923,7 @@ static void snd_rme32_card_free(struct snd_card *card) snd_rme32_free(card->private_data); } -static int __devinit +static int snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { static int dev; @@ -1938,15 +1939,14 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct rme32), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(struct rme32), &card); if (err < 0) return err; card->private_free = snd_rme32_card_free; rme32 = (struct rme32 *) card->private_data; rme32->card = card; rme32->pci = pci; - snd_card_set_dev(card, &pci->dev); if (fullduplex[dev]) rme32->fullduplex_mode = 1; if ((err = snd_rme32_create(rme32)) < 0) { @@ -1978,17 +1978,16 @@ snd_rme32_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) return 0; } -static void __devexit snd_rme32_remove(struct pci_dev *pci) +static void snd_rme32_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme32_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme32_ids, .probe = snd_rme32_probe, - .remove = __devexit_p(snd_rme32_remove), + .remove = snd_rme32_remove, }; module_pci_driver(rme32_driver); diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 9b98dc40698..76169929770 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c @@ -28,6 +28,7 @@ #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/module.h> +#include <linux/vmalloc.h> #include <sound/core.h> #include <sound/info.h> @@ -198,6 +199,31 @@ MODULE_PARM_DESC(enable, "Enable RME Digi96 soundcard."); #define RME96_AD1852_VOL_BITS 14 #define RME96_AD1855_VOL_BITS 10 +/* Defines for snd_rme96_trigger */ +#define RME96_TB_START_PLAYBACK 1 +#define RME96_TB_START_CAPTURE 2 +#define RME96_TB_STOP_PLAYBACK 4 +#define RME96_TB_STOP_CAPTURE 8 +#define RME96_TB_RESET_PLAYPOS 16 +#define RME96_TB_RESET_CAPTUREPOS 32 +#define RME96_TB_CLEAR_PLAYBACK_IRQ 64 +#define RME96_TB_CLEAR_CAPTURE_IRQ 128 +#define RME96_RESUME_PLAYBACK (RME96_TB_START_PLAYBACK) +#define RME96_RESUME_CAPTURE (RME96_TB_START_CAPTURE) +#define RME96_RESUME_BOTH (RME96_RESUME_PLAYBACK \ + | RME96_RESUME_CAPTURE) +#define RME96_START_PLAYBACK (RME96_TB_START_PLAYBACK \ + | RME96_TB_RESET_PLAYPOS) +#define RME96_START_CAPTURE (RME96_TB_START_CAPTURE \ + | RME96_TB_RESET_CAPTUREPOS) +#define RME96_START_BOTH (RME96_START_PLAYBACK \ + | RME96_START_CAPTURE) +#define RME96_STOP_PLAYBACK (RME96_TB_STOP_PLAYBACK \ + | RME96_TB_CLEAR_PLAYBACK_IRQ) +#define RME96_STOP_CAPTURE (RME96_TB_STOP_CAPTURE \ + | RME96_TB_CLEAR_CAPTURE_IRQ) +#define RME96_STOP_BOTH (RME96_STOP_PLAYBACK \ + | RME96_STOP_CAPTURE) struct rme96 { spinlock_t lock; @@ -214,6 +240,13 @@ struct rme96 { u8 rev; /* card revision number */ +#ifdef CONFIG_PM_SLEEP + u32 playback_pointer; + u32 capture_pointer; + void *playback_suspend_buffer; + void *capture_suspend_buffer; +#endif + struct snd_pcm_substream *playback_substream; struct snd_pcm_substream *capture_substream; @@ -270,8 +303,7 @@ snd_rme96_playback_pointer(struct snd_pcm_substream *substream); static snd_pcm_uframes_t snd_rme96_capture_pointer(struct snd_pcm_substream *substream); -static void __devinit -snd_rme96_proc_init(struct rme96 *rme96); +static void snd_rme96_proc_init(struct rme96 *rme96); static int snd_rme96_create_switches(struct snd_card *card, @@ -318,9 +350,8 @@ snd_rme96_playback_copy(struct snd_pcm_substream *substream, struct rme96 *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->playback_frlog; pos <<= rme96->playback_frlog; - copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, - count); - return 0; + return copy_from_user_toio(rme96->iobase + RME96_IO_PLAY_BUFFER + pos, src, + count); } static int @@ -333,9 +364,8 @@ snd_rme96_capture_copy(struct snd_pcm_substream *substream, struct rme96 *rme96 = snd_pcm_substream_chip(substream); count <<= rme96->capture_frlog; pos <<= rme96->capture_frlog; - copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, - count); - return 0; + return copy_to_user_fromio(dst, rme96->iobase + RME96_IO_REC_BUFFER + pos, + count); } /* @@ -345,6 +375,8 @@ static struct snd_pcm_hardware snd_rme96_playback_spdif_info = { .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -374,6 +406,8 @@ static struct snd_pcm_hardware snd_rme96_capture_spdif_info = { .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -403,6 +437,8 @@ static struct snd_pcm_hardware snd_rme96_playback_adat_info = { .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -428,6 +464,8 @@ static struct snd_pcm_hardware snd_rme96_capture_adat_info = { .info = (SNDRV_PCM_INFO_MMAP_IOMEM | SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_SYNC_START | + SNDRV_PCM_INFO_RESUME | SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_PAUSE), .formats = (SNDRV_PCM_FMTBIT_S16_LE | @@ -1046,54 +1084,35 @@ snd_rme96_capture_hw_params(struct snd_pcm_substream *substream, } static void -snd_rme96_playback_start(struct rme96 *rme96, - int from_pause) +snd_rme96_trigger(struct rme96 *rme96, + int op) { - if (!from_pause) { + if (op & RME96_TB_RESET_PLAYPOS) writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); - } - - rme96->wcreg |= RME96_WCR_START; - writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); -} - -static void -snd_rme96_capture_start(struct rme96 *rme96, - int from_pause) -{ - if (!from_pause) { + if (op & RME96_TB_RESET_CAPTUREPOS) writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); - } - - rme96->wcreg |= RME96_WCR_START_2; + if (op & RME96_TB_CLEAR_PLAYBACK_IRQ) { + rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); + if (rme96->rcreg & RME96_RCR_IRQ) + writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); + } + if (op & RME96_TB_CLEAR_CAPTURE_IRQ) { + rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); + if (rme96->rcreg & RME96_RCR_IRQ_2) + writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); + } + if (op & RME96_TB_START_PLAYBACK) + rme96->wcreg |= RME96_WCR_START; + if (op & RME96_TB_STOP_PLAYBACK) + rme96->wcreg &= ~RME96_WCR_START; + if (op & RME96_TB_START_CAPTURE) + rme96->wcreg |= RME96_WCR_START_2; + if (op & RME96_TB_STOP_CAPTURE) + rme96->wcreg &= ~RME96_WCR_START_2; writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); } -static void -snd_rme96_playback_stop(struct rme96 *rme96) -{ - /* - * Check if there is an unconfirmed IRQ, if so confirm it, or else - * the hardware will not stop generating interrupts - */ - rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); - if (rme96->rcreg & RME96_RCR_IRQ) { - writel(0, rme96->iobase + RME96_IO_CONFIRM_PLAY_IRQ); - } - rme96->wcreg &= ~RME96_WCR_START; - writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); -} -static void -snd_rme96_capture_stop(struct rme96 *rme96) -{ - rme96->rcreg = readl(rme96->iobase + RME96_IO_CONTROL_REGISTER); - if (rme96->rcreg & RME96_RCR_IRQ_2) { - writel(0, rme96->iobase + RME96_IO_CONFIRM_REC_IRQ); - } - rme96->wcreg &= ~RME96_WCR_START_2; - writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER); -} static irqreturn_t snd_rme96_interrupt(int irq, @@ -1156,6 +1175,7 @@ snd_rme96_playback_spdif_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_set_sync(substream); spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1192,6 +1212,7 @@ snd_rme96_capture_spdif_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_set_sync(substream); runtime->hw = snd_rme96_capture_spdif_info; if (snd_rme96_getinputtype(rme96) != RME96_INPUT_ANALOG && (rate = snd_rme96_capture_getrate(rme96, &isadat)) > 0) @@ -1223,6 +1244,7 @@ snd_rme96_playback_adat_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_set_sync(substream); spin_lock_irq(&rme96->lock); if (rme96->playback_substream != NULL) { spin_unlock_irq(&rme96->lock); @@ -1254,6 +1276,7 @@ snd_rme96_capture_adat_open(struct snd_pcm_substream *substream) struct rme96 *rme96 = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; + snd_pcm_set_sync(substream); runtime->hw = snd_rme96_capture_adat_info; if (snd_rme96_getinputtype(rme96) == RME96_INPUT_ANALOG) { /* makes no sense to use analog input. Note that analog @@ -1289,7 +1312,7 @@ snd_rme96_playback_close(struct snd_pcm_substream *substream) spin_lock_irq(&rme96->lock); if (RME96_ISPLAYING(rme96)) { - snd_rme96_playback_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); } rme96->playback_substream = NULL; rme96->playback_periodsize = 0; @@ -1310,7 +1333,7 @@ snd_rme96_capture_close(struct snd_pcm_substream *substream) spin_lock_irq(&rme96->lock); if (RME96_ISRECORDING(rme96)) { - snd_rme96_capture_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); } rme96->capture_substream = NULL; rme96->capture_periodsize = 0; @@ -1325,7 +1348,7 @@ snd_rme96_playback_prepare(struct snd_pcm_substream *substream) spin_lock_irq(&rme96->lock); if (RME96_ISPLAYING(rme96)) { - snd_rme96_playback_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_PLAYBACK); } writel(0, rme96->iobase + RME96_IO_RESET_PLAY_POS); spin_unlock_irq(&rme96->lock); @@ -1339,7 +1362,7 @@ snd_rme96_capture_prepare(struct snd_pcm_substream *substream) spin_lock_irq(&rme96->lock); if (RME96_ISRECORDING(rme96)) { - snd_rme96_capture_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_CAPTURE); } writel(0, rme96->iobase + RME96_IO_RESET_REC_POS); spin_unlock_irq(&rme96->lock); @@ -1351,41 +1374,55 @@ snd_rme96_playback_trigger(struct snd_pcm_substream *substream, int cmd) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *s; + bool sync; + + snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) == rme96) + snd_pcm_trigger_done(s, substream); + } + + sync = (rme96->playback_substream && rme96->capture_substream) && + (rme96->playback_substream->group == + rme96->capture_substream->group); switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (!RME96_ISPLAYING(rme96)) { - if (substream != rme96->playback_substream) { + if (substream != rme96->playback_substream) return -EBUSY; - } - snd_rme96_playback_start(rme96, 0); + snd_rme96_trigger(rme96, sync ? RME96_START_BOTH + : RME96_START_PLAYBACK); } break; + case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: if (RME96_ISPLAYING(rme96)) { - if (substream != rme96->playback_substream) { + if (substream != rme96->playback_substream) return -EBUSY; - } - snd_rme96_playback_stop(rme96); + snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH + : RME96_STOP_PLAYBACK); } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (RME96_ISPLAYING(rme96)) { - snd_rme96_playback_stop(rme96); - } + if (RME96_ISPLAYING(rme96)) + snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH + : RME96_STOP_PLAYBACK); break; + case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!RME96_ISPLAYING(rme96)) { - snd_rme96_playback_start(rme96, 1); - } + if (!RME96_ISPLAYING(rme96)) + snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH + : RME96_RESUME_PLAYBACK); break; - + default: return -EINVAL; } + return 0; } @@ -1394,38 +1431,51 @@ snd_rme96_capture_trigger(struct snd_pcm_substream *substream, int cmd) { struct rme96 *rme96 = snd_pcm_substream_chip(substream); + struct snd_pcm_substream *s; + bool sync; + + snd_pcm_group_for_each_entry(s, substream) { + if (snd_pcm_substream_chip(s) == rme96) + snd_pcm_trigger_done(s, substream); + } + + sync = (rme96->playback_substream && rme96->capture_substream) && + (rme96->playback_substream->group == + rme96->capture_substream->group); switch (cmd) { case SNDRV_PCM_TRIGGER_START: if (!RME96_ISRECORDING(rme96)) { - if (substream != rme96->capture_substream) { + if (substream != rme96->capture_substream) return -EBUSY; - } - snd_rme96_capture_start(rme96, 0); + snd_rme96_trigger(rme96, sync ? RME96_START_BOTH + : RME96_START_CAPTURE); } break; + case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_STOP: if (RME96_ISRECORDING(rme96)) { - if (substream != rme96->capture_substream) { + if (substream != rme96->capture_substream) return -EBUSY; - } - snd_rme96_capture_stop(rme96); + snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH + : RME96_STOP_CAPTURE); } break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - if (RME96_ISRECORDING(rme96)) { - snd_rme96_capture_stop(rme96); - } + if (RME96_ISRECORDING(rme96)) + snd_rme96_trigger(rme96, sync ? RME96_STOP_BOTH + : RME96_STOP_CAPTURE); break; + case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - if (!RME96_ISRECORDING(rme96)) { - snd_rme96_capture_start(rme96, 1); - } + if (!RME96_ISRECORDING(rme96)) + snd_rme96_trigger(rme96, sync ? RME96_RESUME_BOTH + : RME96_RESUME_CAPTURE); break; - + default: return -EINVAL; } @@ -1506,8 +1556,7 @@ snd_rme96_free(void *private_data) return; } if (rme96->irq >= 0) { - snd_rme96_playback_stop(rme96); - snd_rme96_capture_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_BOTH); rme96->areg &= ~RME96_AR_DAC_EN; writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); free_irq(rme96->irq, (void *)rme96); @@ -1521,6 +1570,10 @@ snd_rme96_free(void *private_data) pci_release_regions(rme96->pci); rme96->port = 0; } +#ifdef CONFIG_PM_SLEEP + vfree(rme96->playback_suspend_buffer); + vfree(rme96->capture_suspend_buffer); +#endif pci_disable_device(rme96->pci); } @@ -1538,7 +1591,7 @@ snd_rme96_free_adat_pcm(struct snd_pcm *pcm) rme96->adat_pcm = NULL; } -static int __devinit +static int snd_rme96_create(struct rme96 *rme96) { struct pci_dev *pci = rme96->pci; @@ -1556,13 +1609,15 @@ snd_rme96_create(struct rme96 *rme96) rme96->iobase = ioremap_nocache(rme96->port, RME96_IO_SIZE); if (!rme96->iobase) { - snd_printk(KERN_ERR "unable to remap memory region 0x%lx-0x%lx\n", rme96->port, rme96->port + RME96_IO_SIZE - 1); + dev_err(rme96->card->dev, + "unable to remap memory region 0x%lx-0x%lx\n", + rme96->port, rme96->port + RME96_IO_SIZE - 1); return -ENOMEM; } if (request_irq(pci->irq, snd_rme96_interrupt, IRQF_SHARED, KBUILD_MODNAME, rme96)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(rme96->card->dev, "unable to grab IRQ %d\n", pci->irq); return -EBUSY; } rme96->irq = pci->irq; @@ -1607,8 +1662,7 @@ snd_rme96_create(struct rme96 *rme96) rme96->capture_periodsize = 0; /* make sure playback/capture is stopped, if by some reason active */ - snd_rme96_playback_stop(rme96); - snd_rme96_capture_stop(rme96); + snd_rme96_trigger(rme96, RME96_STOP_BOTH); /* set default values in registers */ rme96->wcreg = @@ -1786,8 +1840,7 @@ snd_rme96_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer } } -static void __devinit -snd_rme96_proc_init(struct rme96 *rme96) +static void snd_rme96_proc_init(struct rme96 *rme96) { struct snd_info_entry *entry; @@ -2321,12 +2374,96 @@ snd_rme96_create_switches(struct snd_card *card, * Card initialisation */ +#ifdef CONFIG_PM_SLEEP + +static int rme96_suspend(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); + struct rme96 *rme96 = card->private_data; + + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); + snd_pcm_suspend(rme96->playback_substream); + snd_pcm_suspend(rme96->capture_substream); + + /* save capture & playback pointers */ + rme96->playback_pointer = readl(rme96->iobase + RME96_IO_GET_PLAY_POS) + & RME96_RCR_AUDIO_ADDR_MASK; + rme96->capture_pointer = readl(rme96->iobase + RME96_IO_GET_REC_POS) + & RME96_RCR_AUDIO_ADDR_MASK; + + /* save playback and capture buffers */ + memcpy_fromio(rme96->playback_suspend_buffer, + rme96->iobase + RME96_IO_PLAY_BUFFER, RME96_BUFFER_SIZE); + memcpy_fromio(rme96->capture_suspend_buffer, + rme96->iobase + RME96_IO_REC_BUFFER, RME96_BUFFER_SIZE); + + /* disable the DAC */ + rme96->areg &= ~RME96_AR_DAC_EN; + writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); + + pci_disable_device(pci); + pci_save_state(pci); + + return 0; +} + +static int rme96_resume(struct device *dev) +{ + struct pci_dev *pci = to_pci_dev(dev); + struct snd_card *card = dev_get_drvdata(dev); + struct rme96 *rme96 = card->private_data; + + pci_restore_state(pci); + if (pci_enable_device(pci) < 0) { + dev_err(dev, "pci_enable_device failed, disabling device\n"); + snd_card_disconnect(card); + return -EIO; + } + + /* reset playback and record buffer pointers */ + writel(0, rme96->iobase + RME96_IO_SET_PLAY_POS + + rme96->playback_pointer); + writel(0, rme96->iobase + RME96_IO_SET_REC_POS + + rme96->capture_pointer); + + /* restore playback and capture buffers */ + memcpy_toio(rme96->iobase + RME96_IO_PLAY_BUFFER, + rme96->playback_suspend_buffer, RME96_BUFFER_SIZE); + memcpy_toio(rme96->iobase + RME96_IO_REC_BUFFER, + rme96->capture_suspend_buffer, RME96_BUFFER_SIZE); + + /* reset the ADC */ + writel(rme96->areg | RME96_AR_PD2, + rme96->iobase + RME96_IO_ADDITIONAL_REG); + writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); + + /* reset and enable DAC, restore analog volume */ + snd_rme96_reset_dac(rme96); + rme96->areg |= RME96_AR_DAC_EN; + writel(rme96->areg, rme96->iobase + RME96_IO_ADDITIONAL_REG); + if (RME96_HAS_ANALOG_OUT(rme96)) { + usleep_range(3000, 10000); + snd_rme96_apply_dac_volume(rme96); + } + + snd_power_change_state(card, SNDRV_CTL_POWER_D0); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(rme96_pm, rme96_suspend, rme96_resume); +#define RME96_PM_OPS &rme96_pm +#else +#define RME96_PM_OPS NULL +#endif /* CONFIG_PM_SLEEP */ + static void snd_rme96_card_free(struct snd_card *card) { snd_rme96_free(card->private_data); } -static int __devinit +static int snd_rme96_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { @@ -2343,20 +2480,36 @@ snd_rme96_probe(struct pci_dev *pci, dev++; return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct rme96), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(struct rme96), &card); if (err < 0) return err; card->private_free = snd_rme96_card_free; rme96 = card->private_data; rme96->card = card; rme96->pci = pci; - snd_card_set_dev(card, &pci->dev); if ((err = snd_rme96_create(rme96)) < 0) { snd_card_free(card); return err; } +#ifdef CONFIG_PM_SLEEP + rme96->playback_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); + if (!rme96->playback_suspend_buffer) { + dev_err(card->dev, + "Failed to allocate playback suspend buffer!\n"); + snd_card_free(card); + return -ENOMEM; + } + rme96->capture_suspend_buffer = vmalloc(RME96_BUFFER_SIZE); + if (!rme96->capture_suspend_buffer) { + dev_err(card->dev, + "Failed to allocate capture suspend buffer!\n"); + snd_card_free(card); + return -ENOMEM; + } +#endif + strcpy(card->driver, "Digi96"); switch (rme96->pci->device) { case PCI_DEVICE_ID_RME_DIGI96: @@ -2389,17 +2542,19 @@ snd_rme96_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_rme96_remove(struct pci_dev *pci) +static void snd_rme96_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme96_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme96_ids, .probe = snd_rme96_probe, - .remove = __devexit_p(snd_rme96_remove), + .remove = snd_rme96_remove, + .driver = { + .pm = RME96_PM_OPS, + }, }; module_pci_driver(rme96_driver); diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 0d6930c4f4b..4c6f5d1c988 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c @@ -28,6 +28,7 @@ #include <linux/firmware.h> #include <linux/module.h> #include <linux/math64.h> +#include <linux/vmalloc.h> #include <sound/core.h> #include <sound/control.h> @@ -59,13 +60,11 @@ MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{RME Hammerfall-DSP}," "{RME HDSP-9652}," "{RME HDSP-9632}}"); -#ifdef HDSP_FW_LOADER MODULE_FIRMWARE("rpm_firmware.bin"); MODULE_FIRMWARE("multiface_firmware.bin"); MODULE_FIRMWARE("multiface_firmware_rev11.bin"); MODULE_FIRMWARE("digiface_firmware.bin"); MODULE_FIRMWARE("digiface_firmware_rev11.bin"); -#endif #define HDSP_MAX_CHANNELS 26 #define HDSP_MAX_DS_CHANNELS 14 @@ -155,10 +154,13 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_BIGENDIAN_MODE 0x200 #define HDSP_RD_MULTIPLE 0x400 #define HDSP_9652_ENABLE_MIXER 0x800 +#define HDSP_S200 0x800 +#define HDSP_S300 (0x100 | HDSP_S200) /* dummy, purpose of 0x100 unknown */ +#define HDSP_CYCLIC_MODE 0x1000 #define HDSP_TDO 0x10000000 -#define HDSP_S_PROGRAM (HDSP_PROGRAM|HDSP_CONFIG_MODE_0) -#define HDSP_S_LOAD (HDSP_PROGRAM|HDSP_CONFIG_MODE_1) +#define HDSP_S_PROGRAM (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_0) +#define HDSP_S_LOAD (HDSP_CYCLIC_MODE|HDSP_PROGRAM|HDSP_CONFIG_MODE_1) /* Control Register bits */ @@ -423,12 +425,7 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) -/* use hotplug firmware loader? */ -#if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) -#if !defined(HDSP_USE_HWDEP_LOADER) -#define HDSP_FW_LOADER -#endif -#endif +#define HDSP_FIRMWARE_SIZE (24413 * 4) struct hdsp_9632_meters { u32 input_peak[16]; @@ -475,7 +472,8 @@ struct hdsp { enum HDSP_IO_Type io_type; /* ditto, but for code use */ unsigned short firmware_rev; unsigned short state; /* stores state bits */ - u32 firmware_cache[24413]; /* this helps recover from accidental iobox power failure */ + const struct firmware *firmware; + u32 *fw_uploaded; size_t period_bytes; /* guess what this is */ unsigned char max_channels; unsigned char qs_in_channels; /* quad speed mode for H9632 */ @@ -586,10 +584,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (dmab->bytes >= size) - return 0; - } if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, dmab) < 0) return -ENOMEM; @@ -598,10 +592,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) { - dmab->dev.dev = NULL; /* make it anonymous */ - snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); - } + if (dmab->area) + snd_dma_free_pages(dmab); } @@ -676,13 +668,24 @@ static unsigned int hdsp_read(struct hdsp *hdsp, int reg) static int hdsp_check_for_iobox (struct hdsp *hdsp) { + int i; + if (hdsp->io_type == H9652 || hdsp->io_type == H9632) return 0; - if (hdsp_read (hdsp, HDSP_statusRegister) & HDSP_ConfigError) { - snd_printk("Hammerfall-DSP: no IO box connected!\n"); - hdsp->state &= ~HDSP_FirmwareLoaded; - return -EIO; + for (i = 0; i < 500; i++) { + if (0 == (hdsp_read(hdsp, HDSP_statusRegister) & + HDSP_ConfigError)) { + if (i) { + dev_dbg(hdsp->card->dev, + "IO box found after %d ms\n", + (20 * i)); + } + return 0; + } + msleep(20); } - return 0; + dev_err(hdsp->card->dev, "no IO box connected!\n"); + hdsp->state &= ~HDSP_FirmwareLoaded; + return -EIO; } static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops, @@ -697,13 +700,13 @@ static int hdsp_wait_for_iobox(struct hdsp *hdsp, unsigned int loops, if (hdsp_read(hdsp, HDSP_statusRegister) & HDSP_ConfigError) msleep(delay); else { - snd_printd("Hammerfall-DSP: iobox found after %ums!\n", + dev_dbg(hdsp->card->dev, "iobox found after %ums!\n", i * delay); return 0; } } - snd_printk("Hammerfall-DSP: no IO box connected!\n"); + dev_info(hdsp->card->dev, "no IO box connected!\n"); hdsp->state &= ~HDSP_FirmwareLoaded; return -EIO; } @@ -712,47 +715,60 @@ static int snd_hdsp_load_firmware_from_cache(struct hdsp *hdsp) { int i; unsigned long flags; + const u32 *cache; + + if (hdsp->fw_uploaded) + cache = hdsp->fw_uploaded; + else { + if (!hdsp->firmware) + return -ENODEV; + cache = (u32 *)hdsp->firmware->data; + if (!cache) + return -ENODEV; + } if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { - snd_printk ("Hammerfall-DSP: loading firmware\n"); + dev_info(hdsp->card->dev, "loading firmware\n"); hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_PROGRAM); hdsp_write (hdsp, HDSP_fifoData, 0); if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { - snd_printk ("Hammerfall-DSP: timeout waiting for download preparation\n"); + dev_info(hdsp->card->dev, + "timeout waiting for download preparation\n"); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); return -EIO; } hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); - for (i = 0; i < 24413; ++i) { - hdsp_write(hdsp, HDSP_fifoData, hdsp->firmware_cache[i]); + for (i = 0; i < HDSP_FIRMWARE_SIZE / 4; ++i) { + hdsp_write(hdsp, HDSP_fifoData, cache[i]); if (hdsp_fifo_wait (hdsp, 127, HDSP_LONG_WAIT)) { - snd_printk ("Hammerfall-DSP: timeout during firmware loading\n"); + dev_info(hdsp->card->dev, + "timeout during firmware loading\n"); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); return -EIO; } } - ssleep(3); - - if (hdsp_fifo_wait (hdsp, 0, HDSP_LONG_WAIT)) { - snd_printk ("Hammerfall-DSP: timeout at end of firmware loading\n"); - return -EIO; - } + hdsp_fifo_wait(hdsp, 3, HDSP_LONG_WAIT); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200); + ssleep(3); #ifdef SNDRV_BIG_ENDIAN hdsp->control2_register = HDSP_BIGENDIAN_MODE; #else hdsp->control2_register = 0; #endif hdsp_write (hdsp, HDSP_control2Reg, hdsp->control2_register); - snd_printk ("Hammerfall-DSP: finished firmware loading\n"); + dev_info(hdsp->card->dev, "finished firmware loading\n"); } if (hdsp->state & HDSP_InitializationComplete) { - snd_printk(KERN_INFO "Hammerfall-DSP: firmware loaded from cache, restoring defaults\n"); + dev_info(hdsp->card->dev, + "firmware loaded from cache, restoring defaults\n"); spin_lock_irqsave(&hdsp->lock, flags); snd_hdsp_set_defaults(hdsp); spin_unlock_irqrestore(&hdsp->lock, flags); @@ -767,24 +783,51 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) { if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { - hdsp_write (hdsp, HDSP_control2Reg, HDSP_PROGRAM); - hdsp_write (hdsp, HDSP_fifoData, 0); - if (hdsp_fifo_wait (hdsp, 0, HDSP_SHORT_WAIT) < 0) - return -EIO; + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); - hdsp_write (hdsp, HDSP_control2Reg, HDSP_S_LOAD); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S200 | HDSP_PROGRAM); hdsp_write (hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp->io_type = Multiface; + dev_info(hdsp->card->dev, "Multiface found\n"); + return 0; + } - if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) { - hdsp_write(hdsp, HDSP_control2Reg, HDSP_VERSION_BIT); - hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); - if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT)) - hdsp->io_type = RPM; - else - hdsp->io_type = Multiface; - } else { + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) { hdsp->io_type = Digiface; + dev_info(hdsp->card->dev, "Digiface found\n"); + return 0; + } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) == 0) { + hdsp->io_type = Multiface; + dev_info(hdsp->card->dev, "Multiface found\n"); + return 0; + } + + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S300); + hdsp_write(hdsp, HDSP_control2Reg, HDSP_S_LOAD); + hdsp_write(hdsp, HDSP_fifoData, 0); + if (hdsp_fifo_wait(hdsp, 0, HDSP_SHORT_WAIT) < 0) { + hdsp->io_type = Multiface; + dev_info(hdsp->card->dev, "Multiface found\n"); + return 0; } + + hdsp->io_type = RPM; + dev_info(hdsp->card->dev, "RPM found\n"); + return 0; } else { /* firmware was already loaded, get iobox type */ if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2) @@ -798,9 +841,7 @@ static int hdsp_get_iobox_version (struct hdsp *hdsp) } -#ifdef HDSP_FW_LOADER static int hdsp_request_fw_loader(struct hdsp *hdsp); -#endif static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) { @@ -810,22 +851,18 @@ static int hdsp_check_for_firmware (struct hdsp *hdsp, int load_on_demand) hdsp->state &= ~HDSP_FirmwareLoaded; if (! load_on_demand) return -EIO; - snd_printk(KERN_ERR "Hammerfall-DSP: firmware not present.\n"); + dev_err(hdsp->card->dev, "firmware not present.\n"); /* try to load firmware */ if (! (hdsp->state & HDSP_FirmwareCached)) { -#ifdef HDSP_FW_LOADER if (! hdsp_request_fw_loader(hdsp)) return 0; -#endif - snd_printk(KERN_ERR - "Hammerfall-DSP: No firmware loaded nor " - "cached, please upload firmware.\n"); + dev_err(hdsp->card->dev, + "No firmware loaded nor cached, please upload firmware.\n"); return -EIO; } if (snd_hdsp_load_firmware_from_cache(hdsp) != 0) { - snd_printk(KERN_ERR - "Hammerfall-DSP: Firmware loading from " - "cache failed, please upload manually.\n"); + dev_err(hdsp->card->dev, + "Firmware loading from cache failed, please upload manually.\n"); return -EIO; } } @@ -853,7 +890,8 @@ static int hdsp_fifo_wait(struct hdsp *hdsp, int count, int timeout) udelay (100); } - snd_printk ("Hammerfall-DSP: wait for FIFO status <= %d failed after %d iterations\n", + dev_warn(hdsp->card->dev, + "wait for FIFO status <= %d failed after %d iterations\n", count, timeout); return -1; } @@ -970,7 +1008,9 @@ static int hdsp_spdif_sample_rate(struct hdsp *hdsp) default: break; } - snd_printk ("Hammerfall-DSP: unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", rate_bits, status); + dev_warn(hdsp->card->dev, + "unknown spdif frequency status; bits = 0x%x, status = 0x%x\n", + rate_bits, status); return 0; } @@ -1104,7 +1144,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) if (!(hdsp->control_register & HDSP_ClockModeMaster)) { if (called_internally) { /* request from ctl or card initialization */ - snd_printk(KERN_ERR "Hammerfall-DSP: device is not running as a clock master: cannot set sample rate.\n"); + dev_err(hdsp->card->dev, + "device is not running as a clock master: cannot set sample rate.\n"); return -1; } else { /* hw_param request while in AutoSync mode */ @@ -1112,11 +1153,14 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) int spdif_freq = hdsp_spdif_sample_rate(hdsp); if ((spdif_freq == external_freq*2) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) - snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in double speed mode\n"); + dev_info(hdsp->card->dev, + "Detected ADAT in double speed mode\n"); else if (hdsp->io_type == H9632 && (spdif_freq == external_freq*4) && (hdsp_autosync_ref(hdsp) >= HDSP_AUTOSYNC_FROM_ADAT1)) - snd_printk(KERN_INFO "Hammerfall-DSP: Detected ADAT in quad speed mode\n"); + dev_info(hdsp->card->dev, + "Detected ADAT in quad speed mode\n"); else if (rate != external_freq) { - snd_printk(KERN_INFO "Hammerfall-DSP: No AutoSync source for requested rate\n"); + dev_info(hdsp->card->dev, + "No AutoSync source for requested rate\n"); return -1; } } @@ -1188,7 +1232,8 @@ static int hdsp_set_rate(struct hdsp *hdsp, int rate, int called_internally) } if (reject_if_open && (hdsp->capture_pid >= 0 || hdsp->playback_pid >= 0)) { - snd_printk ("Hammerfall-DSP: cannot change speed mode (capture PID = %d, playback PID = %d)\n", + dev_warn(hdsp->card->dev, + "cannot change speed mode (capture PID = %d, playback PID = %d)\n", hdsp->capture_pid, hdsp->playback_pid); return -EBUSY; @@ -1672,127 +1717,50 @@ static int snd_hdsp_put_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define HDSP_SPDIF_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_out, .put = snd_hdsp_put_spdif_out } +#define HDSP_TOGGLE_SETTING(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdsp_info_toggle_setting, \ + .get = snd_hdsp_get_toggle_setting, \ + .put = snd_hdsp_put_toggle_setting \ +} -static int hdsp_spdif_out(struct hdsp *hdsp) +static int hdsp_toggle_setting(struct hdsp *hdsp, u32 regmask) { - return (hdsp->control_register & HDSP_SPDIFOpticalOut) ? 1 : 0; + return (hdsp->control_register & regmask) ? 1 : 0; } -static int hdsp_set_spdif_output(struct hdsp *hdsp, int out) +static int hdsp_set_toggle_setting(struct hdsp *hdsp, u32 regmask, int out) { if (out) - hdsp->control_register |= HDSP_SPDIFOpticalOut; + hdsp->control_register |= regmask; else - hdsp->control_register &= ~HDSP_SPDIFOpticalOut; + hdsp->control_register &= ~regmask; hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_spdif_bits snd_ctl_boolean_mono_info - -static int snd_hdsp_get_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_out(hdsp); - return 0; -} - -static int snd_hdsp_put_spdif_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_out(hdsp); - hdsp_set_spdif_output(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - -#define HDSP_SPDIF_PROFESSIONAL(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_professional, .put = snd_hdsp_put_spdif_professional } - -static int hdsp_spdif_professional(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFProfessional) ? 1 : 0; -} -static int hdsp_set_spdif_professional(struct hdsp *hdsp, int val) -{ - if (val) - hdsp->control_register |= HDSP_SPDIFProfessional; - else - hdsp->control_register &= ~HDSP_SPDIFProfessional; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); return 0; } -static int snd_hdsp_get_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_professional(hdsp); - return 0; -} +#define snd_hdsp_info_toggle_setting snd_ctl_boolean_mono_info -static int snd_hdsp_put_spdif_professional(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_get_toggle_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; + u32 regmask = kcontrol->private_value; - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_professional(hdsp); - hdsp_set_spdif_professional(hdsp, val); + ucontrol->value.integer.value[0] = hdsp_toggle_setting(hdsp, regmask); spin_unlock_irq(&hdsp->lock); - return change; -} - -#define HDSP_SPDIF_EMPHASIS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_emphasis, .put = snd_hdsp_put_spdif_emphasis } - -static int hdsp_spdif_emphasis(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFEmphasis) ? 1 : 0; -} - -static int hdsp_set_spdif_emphasis(struct hdsp *hdsp, int val) -{ - if (val) - hdsp->control_register |= HDSP_SPDIFEmphasis; - else - hdsp->control_register &= ~HDSP_SPDIFEmphasis; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -static int snd_hdsp_get_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_emphasis(hdsp); return 0; } -static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) +static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; int change; unsigned int val; @@ -1800,52 +1768,9 @@ static int snd_hdsp_put_spdif_emphasis(struct snd_kcontrol *kcontrol, struct snd return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_emphasis(hdsp); - hdsp_set_spdif_emphasis(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - -#define HDSP_SPDIF_NON_AUDIO(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ - .info = snd_hdsp_info_spdif_bits, \ - .get = snd_hdsp_get_spdif_nonaudio, .put = snd_hdsp_put_spdif_nonaudio } - -static int hdsp_spdif_nonaudio(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_SPDIFNonAudio) ? 1 : 0; -} - -static int hdsp_set_spdif_nonaudio(struct hdsp *hdsp, int val) -{ - if (val) - hdsp->control_register |= HDSP_SPDIFNonAudio; - else - hdsp->control_register &= ~HDSP_SPDIFNonAudio; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -static int snd_hdsp_get_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = hdsp_spdif_nonaudio(hdsp); - return 0; -} - -static int snd_hdsp_put_spdif_nonaudio(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_spdif_nonaudio(hdsp); - hdsp_set_spdif_nonaudio(hdsp, val); + change = (int) val != hdsp_toggle_setting(hdsp, regmask); + if (change) + hdsp_set_toggle_setting(hdsp, regmask, val); spin_unlock_irq(&hdsp->lock); return change; } @@ -2449,114 +2374,6 @@ static int snd_hdsp_put_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl return change; } -#define HDSP_XLR_BREAKOUT_CABLE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_xlr_breakout_cable, \ - .get = snd_hdsp_get_xlr_breakout_cable, \ - .put = snd_hdsp_put_xlr_breakout_cable \ -} - -static int hdsp_xlr_breakout_cable(struct hdsp *hdsp) -{ - if (hdsp->control_register & HDSP_XLRBreakoutCable) - return 1; - return 0; -} - -static int hdsp_set_xlr_breakout_cable(struct hdsp *hdsp, int mode) -{ - if (mode) - hdsp->control_register |= HDSP_XLRBreakoutCable; - else - hdsp->control_register &= ~HDSP_XLRBreakoutCable; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_xlr_breakout_cable snd_ctl_boolean_mono_info - -static int snd_hdsp_get_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.enumerated.item[0] = hdsp_xlr_breakout_cable(hdsp); - return 0; -} - -static int snd_hdsp_put_xlr_breakout_cable(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_xlr_breakout_cable(hdsp); - hdsp_set_xlr_breakout_cable(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - -/* (De)activates old RME Analog Extension Board - These are connected to the internal ADAT connector - Switching this on desactivates external ADAT -*/ -#define HDSP_AEB(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_aeb, \ - .get = snd_hdsp_get_aeb, \ - .put = snd_hdsp_put_aeb \ -} - -static int hdsp_aeb(struct hdsp *hdsp) -{ - if (hdsp->control_register & HDSP_AnalogExtensionBoard) - return 1; - return 0; -} - -static int hdsp_set_aeb(struct hdsp *hdsp, int mode) -{ - if (mode) - hdsp->control_register |= HDSP_AnalogExtensionBoard; - else - hdsp->control_register &= ~HDSP_AnalogExtensionBoard; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_aeb snd_ctl_boolean_mono_info - -static int snd_hdsp_get_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - ucontrol->value.enumerated.item[0] = hdsp_aeb(hdsp); - return 0; -} - -static int snd_hdsp_put_aeb(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_aeb(hdsp); - hdsp_set_aeb(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - #define HDSP_PREF_SYNC_REF(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -2745,58 +2562,6 @@ static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_c return 0; } -#define HDSP_LINE_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdsp_info_line_out, \ - .get = snd_hdsp_get_line_out, \ - .put = snd_hdsp_put_line_out \ -} - -static int hdsp_line_out(struct hdsp *hdsp) -{ - return (hdsp->control_register & HDSP_LineOut) ? 1 : 0; -} - -static int hdsp_set_line_output(struct hdsp *hdsp, int out) -{ - if (out) - hdsp->control_register |= HDSP_LineOut; - else - hdsp->control_register &= ~HDSP_LineOut; - hdsp_write(hdsp, HDSP_controlRegister, hdsp->control_register); - return 0; -} - -#define snd_hdsp_info_line_out snd_ctl_boolean_mono_info - -static int snd_hdsp_get_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdsp->lock); - ucontrol->value.integer.value[0] = hdsp_line_out(hdsp); - spin_unlock_irq(&hdsp->lock); - return 0; -} - -static int snd_hdsp_put_line_out(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) -{ - struct hdsp *hdsp = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdsp_use_is_exclusive(hdsp)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdsp->lock); - change = (int)val != hdsp_line_out(hdsp); - hdsp_set_line_output(hdsp, val); - spin_unlock_irq(&hdsp->lock); - return change; -} - #define HDSP_PRECISE_POINTER(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_CARD, \ .name = xname, \ @@ -3188,7 +2953,7 @@ static struct snd_kcontrol_new snd_hdsp_9632_controls[] = { HDSP_DA_GAIN("DA Gain", 0), HDSP_AD_GAIN("AD Gain", 0), HDSP_PHONE_GAIN("Phones Gain", 0), -HDSP_XLR_BREAKOUT_CABLE("XLR Breakout Cable", 0), +HDSP_TOGGLE_SETTING("XLR Breakout Cable", HDSP_XLRBreakoutCable), HDSP_DDS_OFFSET("DDS Sample Rate Offset", 0) }; @@ -3230,10 +2995,10 @@ static struct snd_kcontrol_new snd_hdsp_controls[] = { }, HDSP_MIXER("Mixer", 0), HDSP_SPDIF_IN("IEC958 Input Connector", 0), -HDSP_SPDIF_OUT("IEC958 Output also on ADAT1", 0), -HDSP_SPDIF_PROFESSIONAL("IEC958 Professional Bit", 0), -HDSP_SPDIF_EMPHASIS("IEC958 Emphasis Bit", 0), -HDSP_SPDIF_NON_AUDIO("IEC958 Non-audio Bit", 0), +HDSP_TOGGLE_SETTING("IEC958 Output also on ADAT1", HDSP_SPDIFOpticalOut), +HDSP_TOGGLE_SETTING("IEC958 Professional Bit", HDSP_SPDIFProfessional), +HDSP_TOGGLE_SETTING("IEC958 Emphasis Bit", HDSP_SPDIFEmphasis), +HDSP_TOGGLE_SETTING("IEC958 Non-audio Bit", HDSP_SPDIFNonAudio), /* 'Sample Clock Source' complies with the alsa control naming scheme */ HDSP_CLOCK_SOURCE("Sample Clock Source", 0), { @@ -3253,7 +3018,7 @@ HDSP_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSP_WC_SYNC_CHECK("Word Clock Lock Status", 0), HDSP_SPDIF_SYNC_CHECK("SPDIF Lock Status", 0), HDSP_ADATSYNC_SYNC_CHECK("ADAT Sync Lock Status", 0), -HDSP_LINE_OUT("Line Out", 0), +HDSP_TOGGLE_SETTING("Line Out", HDSP_LineOut), HDSP_PRECISE_POINTER("Precise Pointer", 0), HDSP_USE_MIDI_TASKLET("Use Midi Tasklet", 0), }; @@ -3570,7 +3335,9 @@ static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = { HDSP_MIXER("Mixer", 0) }; -static struct snd_kcontrol_new snd_hdsp_96xx_aeb = HDSP_AEB("Analog Extension Board", 0); +static struct snd_kcontrol_new snd_hdsp_96xx_aeb = + HDSP_TOGGLE_SETTING("Analog Extension Board", + HDSP_AnalogExtensionBoard); static struct snd_kcontrol_new snd_hdsp_adat_sync_check = HDSP_ADAT_SYNC_CHECK; static int snd_hdsp_create_controls(struct snd_card *card, struct hdsp *hdsp) @@ -3673,9 +3440,7 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } } else { int err = -EINVAL; -#ifdef HDSP_FW_LOADER err = hdsp_request_fw_loader(hdsp); -#endif if (err < 0) { snd_iprintf(buffer, "No firmware loaded nor cached, " @@ -3995,7 +3760,9 @@ snd_hdsp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) } snd_iprintf(buffer, "Phones Gain : %s\n", tmp); - snd_iprintf(buffer, "XLR Breakout Cable : %s\n", hdsp_xlr_breakout_cable(hdsp) ? "yes" : "no"); + snd_iprintf(buffer, "XLR Breakout Cable : %s\n", + hdsp_toggle_setting(hdsp, HDSP_XLRBreakoutCable) ? + "yes" : "no"); if (hdsp->control_register & HDSP_AnalogExtensionBoard) snd_iprintf(buffer, "AEB : on (ADAT1 internal)\n"); @@ -4020,7 +3787,7 @@ static void snd_hdsp_free_buffers(struct hdsp *hdsp) snd_hammerfall_free_buffer(&hdsp->playback_dma_buf, hdsp->pci); } -static int __devinit snd_hdsp_initialize_memory(struct hdsp *hdsp) +static int snd_hdsp_initialize_memory(struct hdsp *hdsp) { unsigned long pb_bus, cb_bus; @@ -4028,7 +3795,8 @@ static int __devinit snd_hdsp_initialize_memory(struct hdsp *hdsp) snd_hammerfall_get_buffer(hdsp->pci, &hdsp->playback_dma_buf, HDSP_DMA_AREA_BYTES) < 0) { if (hdsp->capture_dma_buf.area) snd_dma_free_pages(&hdsp->capture_dma_buf); - printk(KERN_ERR "%s: no buffers available\n", hdsp->card_name); + dev_err(hdsp->card->dev, + "%s: no buffers available\n", hdsp->card_name); return -ENOMEM; } @@ -4990,7 +4758,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne return err; if (!(hdsp->state & HDSP_FirmwareLoaded)) { - snd_printk(KERN_ERR "Hammerfall-DSP: firmware needs to be uploaded to the card.\n"); + dev_err(hdsp->card->dev, + "firmware needs to be uploaded to the card.\n"); return -EINVAL; } @@ -5026,29 +4795,38 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne for (i = 0; i < ((hdsp->io_type != Multiface && hdsp->io_type != RPM && hdsp->io_type != H9632) ? 3 : 1); ++i) info.adat_sync_check[i] = (unsigned char)hdsp_adat_sync_check(hdsp, i); info.spdif_in = (unsigned char)hdsp_spdif_in(hdsp); - info.spdif_out = (unsigned char)hdsp_spdif_out(hdsp); - info.spdif_professional = (unsigned char)hdsp_spdif_professional(hdsp); - info.spdif_emphasis = (unsigned char)hdsp_spdif_emphasis(hdsp); - info.spdif_nonaudio = (unsigned char)hdsp_spdif_nonaudio(hdsp); + info.spdif_out = (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_SPDIFOpticalOut); + info.spdif_professional = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFProfessional); + info.spdif_emphasis = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFEmphasis); + info.spdif_nonaudio = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_SPDIFNonAudio); info.spdif_sample_rate = hdsp_spdif_sample_rate(hdsp); info.system_sample_rate = hdsp->system_sample_rate; info.autosync_sample_rate = hdsp_external_sample_rate(hdsp); info.system_clock_mode = (unsigned char)hdsp_system_clock_mode(hdsp); info.clock_source = (unsigned char)hdsp_clock_source(hdsp); info.autosync_ref = (unsigned char)hdsp_autosync_ref(hdsp); - info.line_out = (unsigned char)hdsp_line_out(hdsp); + info.line_out = (unsigned char) + hdsp_toggle_setting(hdsp, HDSP_LineOut); if (hdsp->io_type == H9632) { info.da_gain = (unsigned char)hdsp_da_gain(hdsp); info.ad_gain = (unsigned char)hdsp_ad_gain(hdsp); info.phone_gain = (unsigned char)hdsp_phone_gain(hdsp); - info.xlr_breakout_cable = (unsigned char)hdsp_xlr_breakout_cable(hdsp); + info.xlr_breakout_cable = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_XLRBreakoutCable); } else if (hdsp->io_type == RPM) { info.da_gain = (unsigned char) hdsp_rpm_input12(hdsp); info.ad_gain = (unsigned char) hdsp_rpm_input34(hdsp); } if (hdsp->io_type == H9632 || hdsp->io_type == H9652) - info.analog_extension_board = (unsigned char)hdsp_aeb(hdsp); + info.analog_extension_board = + (unsigned char)hdsp_toggle_setting(hdsp, + HDSP_AnalogExtensionBoard); spin_unlock_irqrestore(&hdsp->lock, flags); if (copy_to_user(argp, &info, sizeof(info))) return -EFAULT; @@ -5073,6 +4851,7 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if ((err = hdsp_get_iobox_version(hdsp)) < 0) return err; } + memset(&hdsp_version, 0, sizeof(hdsp_version)); hdsp_version.io_type = hdsp->io_type; hdsp_version.firmware_rev = hdsp->firmware_rev; if ((err = copy_to_user(argp, &hdsp_version, sizeof(hdsp_version)))) @@ -5091,7 +4870,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if (hdsp->state & (HDSP_FirmwareCached | HDSP_FirmwareLoaded)) return -EBUSY; - snd_printk(KERN_INFO "Hammerfall-DSP: initializing firmware upload\n"); + dev_info(hdsp->card->dev, + "initializing firmware upload\n"); firmware = (struct hdsp_firmware __user *)argp; if (get_user(firmware_data, &firmware->firmware_data)) @@ -5100,8 +4880,18 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne if (hdsp_check_for_iobox (hdsp)) return -EIO; - if (copy_from_user(hdsp->firmware_cache, firmware_data, sizeof(hdsp->firmware_cache)) != 0) + if (!hdsp->fw_uploaded) { + hdsp->fw_uploaded = vmalloc(HDSP_FIRMWARE_SIZE); + if (!hdsp->fw_uploaded) + return -ENOMEM; + } + + if (copy_from_user(hdsp->fw_uploaded, firmware_data, + HDSP_FIRMWARE_SIZE)) { + vfree(hdsp->fw_uploaded); + hdsp->fw_uploaded = NULL; return -EFAULT; + } hdsp->state |= HDSP_FirmwareCached; @@ -5116,7 +4906,8 @@ static int snd_hdsp_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, unsigne snd_hdsp_initialize_midi_flush(hdsp); if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n"); + dev_err(hdsp->card->dev, + "error creating alsa devices\n"); return err; } } @@ -5206,7 +4997,8 @@ static int snd_hdsp_enable_io (struct hdsp *hdsp) int i; if (hdsp_fifo_wait (hdsp, 0, 100)) { - snd_printk(KERN_ERR "Hammerfall-DSP: enable_io fifo_wait failed\n"); + dev_err(hdsp->card->dev, + "enable_io fifo_wait failed\n"); return -EIO; } @@ -5280,25 +5072,29 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp int err; if ((err = snd_hdsp_create_pcm(card, hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: Error creating pcm interface\n"); + dev_err(card->dev, + "Error creating pcm interface\n"); return err; } if ((err = snd_hdsp_create_midi(card, hdsp, 0)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: Error creating first midi interface\n"); + dev_err(card->dev, + "Error creating first midi interface\n"); return err; } if (hdsp->io_type == Digiface || hdsp->io_type == H9652) { if ((err = snd_hdsp_create_midi(card, hdsp, 1)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: Error creating second midi interface\n"); + dev_err(card->dev, + "Error creating second midi interface\n"); return err; } } if ((err = snd_hdsp_create_controls(card, hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: Error creating ctl interface\n"); + dev_err(card->dev, + "Error creating ctl interface\n"); return err; } @@ -5311,7 +5107,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp hdsp->playback_substream = NULL; if ((err = snd_hdsp_set_defaults(hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: Error setting default values\n"); + dev_err(card->dev, + "Error setting default values\n"); return err; } @@ -5321,7 +5118,8 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp hdsp->port, hdsp->irq); if ((err = snd_card_register(card)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: error registering card\n"); + dev_err(card->dev, + "error registering card\n"); return err; } hdsp->state |= HDSP_InitializationComplete; @@ -5330,7 +5128,6 @@ static int snd_hdsp_create_alsa_devices(struct snd_card *card, struct hdsp *hdsp return 0; } -#ifdef HDSP_FW_LOADER /* load firmware via hotplug fw loader */ static int hdsp_request_fw_loader(struct hdsp *hdsp) { @@ -5365,24 +5162,24 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) fwfile = "digiface_firmware_rev11.bin"; break; default: - snd_printk(KERN_ERR "Hammerfall-DSP: invalid io_type %d\n", hdsp->io_type); + dev_err(hdsp->card->dev, + "invalid io_type %d\n", hdsp->io_type); return -EINVAL; } if (request_firmware(&fw, fwfile, &hdsp->pci->dev)) { - snd_printk(KERN_ERR "Hammerfall-DSP: cannot load firmware %s\n", fwfile); + dev_err(hdsp->card->dev, + "cannot load firmware %s\n", fwfile); return -ENOENT; } - if (fw->size < sizeof(hdsp->firmware_cache)) { - snd_printk(KERN_ERR "Hammerfall-DSP: too short firmware size %d (expected %d)\n", - (int)fw->size, (int)sizeof(hdsp->firmware_cache)); - release_firmware(fw); + if (fw->size < HDSP_FIRMWARE_SIZE) { + dev_err(hdsp->card->dev, + "too short firmware size %d (expected %d)\n", + (int)fw->size, HDSP_FIRMWARE_SIZE); return -EINVAL; } - memcpy(hdsp->firmware_cache, fw->data, sizeof(hdsp->firmware_cache)); - - release_firmware(fw); + hdsp->firmware = fw; hdsp->state |= HDSP_FirmwareCached; @@ -5394,22 +5191,23 @@ static int hdsp_request_fw_loader(struct hdsp *hdsp) return err; if ((err = snd_hdsp_create_hwdep(hdsp->card, hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: error creating hwdep device\n"); + dev_err(hdsp->card->dev, + "error creating hwdep device\n"); return err; } snd_hdsp_initialize_channels(hdsp); snd_hdsp_initialize_midi_flush(hdsp); if ((err = snd_hdsp_create_alsa_devices(hdsp->card, hdsp)) < 0) { - snd_printk(KERN_ERR "Hammerfall-DSP: error creating alsa devices\n"); + dev_err(hdsp->card->dev, + "error creating alsa devices\n"); return err; } } return 0; } -#endif -static int __devinit snd_hdsp_create(struct snd_card *card, - struct hdsp *hdsp) +static int snd_hdsp_create(struct snd_card *card, + struct hdsp *hdsp) { struct pci_dev *pci = hdsp->pci; int err; @@ -5477,13 +5275,14 @@ static int __devinit snd_hdsp_create(struct snd_card *card, return err; hdsp->port = pci_resource_start(pci, 0); if ((hdsp->iobase = ioremap_nocache(hdsp->port, HDSP_IO_EXTENT)) == NULL) { - snd_printk(KERN_ERR "Hammerfall-DSP: unable to remap region 0x%lx-0x%lx\n", hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1); + dev_err(hdsp->card->dev, "unable to remap region 0x%lx-0x%lx\n", + hdsp->port, hdsp->port + HDSP_IO_EXTENT - 1); return -EBUSY; } if (request_irq(pci->irq, snd_hdsp_interrupt, IRQF_SHARED, KBUILD_MODNAME, hdsp)) { - snd_printk(KERN_ERR "Hammerfall-DSP: unable to use IRQ %d\n", pci->irq); + dev_err(hdsp->card->dev, "unable to use IRQ %d\n", pci->irq); return -EBUSY; } @@ -5504,24 +5303,25 @@ static int __devinit snd_hdsp_create(struct snd_card *card, return err; if ((hdsp_read (hdsp, HDSP_statusRegister) & HDSP_DllError) != 0) { -#ifdef HDSP_FW_LOADER if ((err = hdsp_request_fw_loader(hdsp)) < 0) /* we don't fail as this can happen if userspace is not ready for firmware upload */ - snd_printk(KERN_ERR "Hammerfall-DSP: couldn't get firmware from userspace. try using hdsploader\n"); + dev_err(hdsp->card->dev, + "couldn't get firmware from userspace. try using hdsploader\n"); else /* init is complete, we return */ return 0; -#endif /* we defer initialization */ - snd_printk(KERN_INFO "Hammerfall-DSP: card initialization pending : waiting for firmware\n"); + dev_info(hdsp->card->dev, + "card initialization pending : waiting for firmware\n"); if ((err = snd_hdsp_create_hwdep(card, hdsp)) < 0) return err; return 0; } else { - snd_printk(KERN_INFO "Hammerfall-DSP: Firmware already present, initializing card.\n"); + dev_info(hdsp->card->dev, + "Firmware already present, initializing card.\n"); if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version2) hdsp->io_type = RPM; else if (hdsp_read(hdsp, HDSP_status2Register) & HDSP_version1) @@ -5568,6 +5368,10 @@ static int snd_hdsp_free(struct hdsp *hdsp) snd_hdsp_free_buffers(hdsp); + if (hdsp->firmware) + release_firmware(hdsp->firmware); + vfree(hdsp->fw_uploaded); + if (hdsp->iobase) iounmap(hdsp->iobase); @@ -5586,8 +5390,8 @@ static void snd_hdsp_card_free(struct snd_card *card) snd_hdsp_free(hdsp); } -static int __devinit snd_hdsp_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_hdsp_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct hdsp *hdsp; @@ -5601,8 +5405,8 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct hdsp), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(struct hdsp), &card); if (err < 0) return err; @@ -5610,7 +5414,6 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, card->private_free = snd_hdsp_card_free; hdsp->dev = dev; hdsp->pci = pci; - snd_card_set_dev(card, &pci->dev); if ((err = snd_hdsp_create(card, hdsp)) < 0) { snd_card_free(card); @@ -5630,17 +5433,16 @@ static int __devinit snd_hdsp_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_hdsp_remove(struct pci_dev *pci) +static void snd_hdsp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver hdsp_driver = { .name = KBUILD_MODNAME, .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, - .remove = __devexit_p(snd_hdsp_remove), + .remove = snd_hdsp_remove, }; module_pci_driver(hdsp_driver); diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index b12308b5ba2..cb82b593473 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -38,6 +38,97 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ + +/* ************* Register Documentation ******************************************************* + * + * Work in progress! Documentation is based on the code in this file. + * + * --------- HDSPM_controlRegister --------- + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : x . : HDSPM_AudioInterruptEnable \_ setting both bits + * : . : . : . : . x: HDSPM_Start / enables audio IO + * : . : . : . : x. : HDSPM_ClockModeMaster - 1: Master, 0: Slave + * : . : . : . : .210 : HDSPM_LatencyMask - 3 Bit value for latency + * : . : . : . : . : 0:64, 1:128, 2:256, 3:512, + * : . : . : . : . : 4:1024, 5:2048, 6:4096, 7:8192 + * :x . : . : . x:xx . : HDSPM_FrequencyMask + * : . : . : . :10 . : HDSPM_Frequency1|HDSPM_Frequency0: 1=32K,2=44.1K,3=48K,0=?? + * : . : . : . x: . : <MADI> HDSPM_DoubleSpeed + * :x . : . : . : . : <MADI> HDSPM_QuadSpeed + * : . 3 : . 10: 2 . : . : HDSPM_SyncRefMask : + * : . : . x: . : . : HDSPM_SyncRef0 + * : . : . x : . : . : HDSPM_SyncRef1 + * : . : . : x . : . : <AES32> HDSPM_SyncRef2 + * : . x : . : . : . : <AES32> HDSPM_SyncRef3 + * : . : . 10: . : . : <MADI> sync ref: 0:WC, 1:Madi, 2:TCO, 3:SyncIn + * : . 3 : . 10: 2 . : . : <AES32> 0:WC, 1:AES1 ... 8:AES8, 9: TCO, 10:SyncIn? + * : . x : . : . : . : <MADIe> HDSPe_FLOAT_FORMAT + * : . : . : x . : . : <MADI> HDSPM_InputSelect0 : 0=optical,1=coax + * : . : . :x . : . : <MADI> HDSPM_InputSelect1 + * : . : .x : . : . : <MADI> HDSPM_clr_tms + * : . : . : . x : . : <MADI> HDSPM_TX_64ch + * : . : . : . x : . : <AES32> HDSPM_Emphasis + * : . : . : .x : . : <MADI> HDSPM_AutoInp + * : . : . x : . : . : <MADI> HDSPM_SMUX + * : . : .x : . : . : <MADI> HDSPM_clr_tms + * : . : x. : . : . : <MADI> HDSPM_taxi_reset + * : . x: . : . : . : <MADI> HDSPM_LineOut + * : . x: . : . : . : <AES32> ?????????????????? + * : . : x. : . : . : <AES32> HDSPM_WCK48 + * : . : . : .x : . : <AES32> HDSPM_Dolby + * : . : x . : . : . : HDSPM_Midi0InterruptEnable + * : . :x . : . : . : HDSPM_Midi1InterruptEnable + * : . : x . : . : . : HDSPM_Midi2InterruptEnable + * : . x : . : . : . : <MADI> HDSPM_Midi3InterruptEnable + * : . x : . : . : . : <AES32> HDSPM_DS_DoubleWire + * : .x : . : . : . : <AES32> HDSPM_QS_DoubleWire + * : x. : . : . : . : <AES32> HDSPM_QS_QuadWire + * : . : . : . x : . : <AES32> HDSPM_Professional + * : x . : . : . : . : HDSPM_wclk_sel + * : . : . : . : . : + * :7654.3210:7654.3210:7654.3210:7654.3210: bit number per byte + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number + * :1098.7654:3210.9876:5432.1098:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421:hex digit + * + * + * + * AIO / RayDAT only + * + * ------------ HDSPM_WR_SETTINGS ---------- + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * : . : . : . : . x: HDSPM_c0Master 1: Master, 0: Slave + * : . : . : . : . x : HDSPM_c0_SyncRef0 + * : . : . : . : . x : HDSPM_c0_SyncRef1 + * : . : . : . : .x : HDSPM_c0_SyncRef2 + * : . : . : . : x. : HDSPM_c0_SyncRef3 + * : . : . : . : 3.210 : HDSPM_c0_SyncRefMask: + * : . : . : . : . : RayDat: 0:WC, 1:AES, 2:SPDIF, 3..6: ADAT1..4, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : AIO: 0:WC, 1:AES, 2: SPDIF, 3: ATAT, + * : . : . : . : . : 9:TCO, 10:SyncIn + * : . : . : . : . : + * : . : . : . : . : + * :3322.2222:2222.1111:1111.1100:0000.0000: bit number per byte + * :1098.7654:3210.9876:5432.1098:7654.3210: + * :||||.||||:||||.||||:||||.||||:||||.||||: bit number + * :7654.3210:7654.3210:7654.3210:7654.3210: 0..31 + * :||||.||||:||||.||||:||||.||||:||||.||||: + * :8421.8421:8421.8421:8421.8421:8421.8421: hex digit + * + */ #include <linux/init.h> #include <linux/delay.h> #include <linux/interrupt.h> @@ -95,7 +186,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_controlRegister 64 #define HDSPM_interruptConfirmation 96 #define HDSPM_control2Reg 256 /* not in specs ???????? */ -#define HDSPM_freqReg 256 /* for AES32 */ +#define HDSPM_freqReg 256 /* for setting arbitrary clock values (DDS feature) */ #define HDSPM_midiDataOut0 352 /* just believe in old code */ #define HDSPM_midiDataOut1 356 #define HDSPM_eeprom_wr 384 /* for AES32 */ @@ -258,6 +349,25 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wclk_sel (1<<30) +/* additional control register bits for AIO*/ +#define HDSPM_c0_Wck48 0x20 /* also RayDAT */ +#define HDSPM_c0_Input0 0x1000 +#define HDSPM_c0_Input1 0x2000 +#define HDSPM_c0_Spdif_Opt 0x4000 +#define HDSPM_c0_Pro 0x8000 +#define HDSPM_c0_clr_tms 0x10000 +#define HDSPM_c0_AEB1 0x20000 +#define HDSPM_c0_AEB2 0x40000 +#define HDSPM_c0_LineOut 0x80000 +#define HDSPM_c0_AD_GAIN0 0x100000 +#define HDSPM_c0_AD_GAIN1 0x200000 +#define HDSPM_c0_DA_GAIN0 0x400000 +#define HDSPM_c0_DA_GAIN1 0x800000 +#define HDSPM_c0_PH_GAIN0 0x1000000 +#define HDSPM_c0_PH_GAIN1 0x2000000 +#define HDSPM_c0_Sym6db 0x4000000 + + /* --- bit helper defines */ #define HDSPM_LatencyMask (HDSPM_Latency0|HDSPM_Latency1|HDSPM_Latency2) #define HDSPM_FrequencyMask (HDSPM_Frequency0|HDSPM_Frequency1|\ @@ -341,11 +451,11 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_madiLock (1<<3) /* MADI Locked =1, no=0 */ #define HDSPM_madiSync (1<<18) /* MADI is in sync */ -#define HDSPM_tcoLock 0x00000020 /* Optional TCO locked status FOR HDSPe MADI! */ -#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status */ +#define HDSPM_tcoLockMadi 0x00000020 /* Optional TCO locked status for HDSPe MADI*/ +#define HDSPM_tcoSync 0x10000000 /* Optional TCO sync status for HDSPe MADI and AES32!*/ -#define HDSPM_syncInLock 0x00010000 /* Sync In lock status FOR HDSPe MADI! */ -#define HDSPM_syncInSync 0x00020000 /* Sync In sync status FOR HDSPe MADI! */ +#define HDSPM_syncInLock 0x00010000 /* Sync In lock status for HDSPe MADI! */ +#define HDSPM_syncInSync 0x00020000 /* Sync In sync status for HDSPe MADI! */ #define HDSPM_BufferPositionMask 0x000FFC0 /* Bit 6..15 : h/w buffer pointer */ /* since 64byte accurate, last 6 bits are not used */ @@ -363,7 +473,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); * Interrupt */ #define HDSPM_tco_detect 0x08000000 -#define HDSPM_tco_lock 0x20000000 +#define HDSPM_tcoLockAes 0x20000000 /* Optional TCO locked status for HDSPe AES */ #define HDSPM_s2_tco_detect 0x00000040 #define HDSPM_s2_AEBO_D 0x00000080 @@ -400,8 +510,8 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wc_freq0 (1<<5) /* input freq detected via autosync */ #define HDSPM_wc_freq1 (1<<6) /* 001=32, 010==44.1, 011=48, */ -#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, */ -/* missing Bit for 111=128, 1000=176.4, 1001=192 */ +#define HDSPM_wc_freq2 (1<<7) /* 100=64, 101=88.2, 110=96, 111=128 */ +#define HDSPM_wc_freq3 0x800 /* 1000=176.4, 1001=192 */ #define HDSPM_SyncRef0 0x10000 /* Sync Reference */ #define HDSPM_SyncRef1 0x20000 @@ -412,13 +522,17 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_wc_valid (HDSPM_wcLock|HDSPM_wcSync) -#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreqMask (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2|\ + HDSPM_wc_freq3) #define HDSPM_wcFreq32 (HDSPM_wc_freq0) #define HDSPM_wcFreq44_1 (HDSPM_wc_freq1) #define HDSPM_wcFreq48 (HDSPM_wc_freq0|HDSPM_wc_freq1) #define HDSPM_wcFreq64 (HDSPM_wc_freq2) #define HDSPM_wcFreq88_2 (HDSPM_wc_freq0|HDSPM_wc_freq2) #define HDSPM_wcFreq96 (HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq128 (HDSPM_wc_freq0|HDSPM_wc_freq1|HDSPM_wc_freq2) +#define HDSPM_wcFreq176_4 (HDSPM_wc_freq3) +#define HDSPM_wcFreq192 (HDSPM_wc_freq0|HDSPM_wc_freq3) #define HDSPM_status1_F_0 0x0400000 #define HDSPM_status1_F_1 0x0800000 @@ -441,6 +555,7 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); */ /* status */ #define HDSPM_AES32_wcLock 0x0200000 +#define HDSPM_AES32_wcSync 0x0100000 #define HDSPM_AES32_wcFreq_bit 22 /* (status >> HDSPM_AES32_wcFreq_bit) & 0xF gives WC frequency (cf function HDSPM_bit2freq */ @@ -456,7 +571,9 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); #define HDSPM_AES32_AUTOSYNC_FROM_AES6 6 #define HDSPM_AES32_AUTOSYNC_FROM_AES7 7 #define HDSPM_AES32_AUTOSYNC_FROM_AES8 8 -#define HDSPM_AES32_AUTOSYNC_FROM_NONE 9 +#define HDSPM_AES32_AUTOSYNC_FROM_TCO 9 +#define HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN 10 +#define HDSPM_AES32_AUTOSYNC_FROM_NONE 11 /* status2 */ /* HDSPM_LockAES_bit is given by HDSPM_LockAES >> (AES# - 1) */ @@ -532,36 +649,39 @@ MODULE_SUPPORTED_DEVICE("{{RME HDSPM-MADI}}"); /* names for speed modes */ static char *hdspm_speed_names[] = { "single", "double", "quad" }; -static char *texts_autosync_aes_tco[] = { "Word Clock", +static const char *const texts_autosync_aes_tco[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", "AES5", "AES6", "AES7", "AES8", - "TCO" }; -static char *texts_autosync_aes[] = { "Word Clock", + "TCO", "Sync In" +}; +static const char *const texts_autosync_aes[] = { "Word Clock", "AES1", "AES2", "AES3", "AES4", - "AES5", "AES6", "AES7", "AES8" }; -static char *texts_autosync_madi_tco[] = { "Word Clock", + "AES5", "AES6", "AES7", "AES8", + "Sync In" +}; +static const char *const texts_autosync_madi_tco[] = { "Word Clock", "MADI", "TCO", "Sync In" }; -static char *texts_autosync_madi[] = { "Word Clock", +static const char *const texts_autosync_madi[] = { "Word Clock", "MADI", "Sync In" }; -static char *texts_autosync_raydat_tco[] = { +static const char *const texts_autosync_raydat_tco[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_raydat[] = { +static const char *const texts_autosync_raydat[] = { "Word Clock", "ADAT 1", "ADAT 2", "ADAT 3", "ADAT 4", "AES", "SPDIF", "Sync In" }; -static char *texts_autosync_aio_tco[] = { +static const char *const texts_autosync_aio_tco[] = { "Word Clock", "ADAT", "AES", "SPDIF", "TCO", "Sync In" }; -static char *texts_autosync_aio[] = { "Word Clock", +static const char *const texts_autosync_aio[] = { "Word Clock", "ADAT", "AES", "SPDIF", "Sync In" }; -static char *texts_freq[] = { +static const char *const texts_freq[] = { "No Lock", "32 kHz", "44.1 kHz", @@ -624,7 +744,8 @@ static char *texts_ports_aio_in_ss[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", - "ADAT.7", "ADAT.8" + "ADAT.7", "ADAT.8", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ss[] = { @@ -633,14 +754,16 @@ static char *texts_ports_aio_out_ss[] = { "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", "ADAT.5", "ADAT.6", "ADAT.7", "ADAT.8", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_ds[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_ds[] = { @@ -648,14 +771,16 @@ static char *texts_ports_aio_out_ds[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_in_qs[] = { "Analogue.L", "Analogue.R", "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", - "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4" + "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aio_out_qs[] = { @@ -663,7 +788,8 @@ static char *texts_ports_aio_out_qs[] = { "AES.L", "AES.R", "SPDIF.L", "SPDIF.R", "ADAT.1", "ADAT.2", "ADAT.3", "ADAT.4", - "Phone.L", "Phone.R" + "Phone.L", "Phone.R", + "AEB.1", "AEB.2", "AEB.3", "AEB.4" }; static char *texts_ports_aes32[] = { @@ -740,8 +866,8 @@ static char channel_map_aio_in_ss[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in, */ 10, 11, /* spdif in */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT in */ - -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -755,7 +881,8 @@ static char channel_map_aio_out_ss[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 13, 14, 15, 16, 17, 18, 19, /* ADAT out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -768,7 +895,8 @@ static char channel_map_aio_in_ds[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 14, 16, 18, /* adat in */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -783,7 +911,7 @@ static char channel_map_aio_out_ds[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 14, 16, 18, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -797,7 +925,8 @@ static char channel_map_aio_in_qs[HDSPM_MAX_CHANNELS] = { 8, 9, /* aes in */ 10, 11, /* spdif in */ 12, 16, /* adat in */ - -1, -1, -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -812,7 +941,8 @@ static char channel_map_aio_out_qs[HDSPM_MAX_CHANNELS] = { 10, 11, /* spdif out */ 12, 16, /* adat out */ 6, 7, /* phone out */ - -1, -1, -1, -1, -1, -1, + 2, 3, 4, 5, /* AEB */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -851,11 +981,11 @@ struct hdspm_midi { }; struct hdspm_tco { - int input; - int framerate; - int wordclock; - int samplerate; - int pull; + int input; /* 0: LTC, 1:Video, 2: WC*/ + int framerate; /* 0=24, 1=25, 2=29.97, 3=29.97d, 4=30, 5=30d */ + int wordclock; /* 0=1:1, 1=44.1->48, 2=48->44.1 */ + int samplerate; /* 0=44.1, 1=48, 2= freq from app */ + int pull; /* 0=0, 1=+0.1%, 2=-0.1%, 3=+4%, 4=-4%*/ int term; /* 0 = off, 1 = on */ }; @@ -874,7 +1004,7 @@ struct hdspm { u32 control_register; /* cached value */ u32 control2_register; /* cached value */ - u32 settings_register; + u32 settings_register; /* cached value for AIO / RayDat (sync reference, master/slave) */ struct hdspm_midi midi[4]; struct tasklet_struct midi_tasklet; @@ -936,7 +1066,7 @@ struct hdspm { struct hdspm_tco *tco; /* NULL if no TCO detected */ - char **texts_autosync; + const char *const *texts_autosync; int texts_autosync_items; cycles_t last_interrupt; @@ -962,19 +1092,33 @@ static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { MODULE_DEVICE_TABLE(pci, snd_hdspm_ids); /* prototypes */ -static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, - struct hdspm * hdspm); -static int __devinit snd_hdspm_create_pcm(struct snd_card *card, - struct hdspm * hdspm); +static int snd_hdspm_create_alsa_devices(struct snd_card *card, + struct hdspm *hdspm); +static int snd_hdspm_create_pcm(struct snd_card *card, + struct hdspm *hdspm); static inline void snd_hdspm_initialize_midi_flush(struct hdspm *hdspm); +static inline int hdspm_get_pll_freq(struct hdspm *hdspm); static int hdspm_update_simple_mixer_controls(struct hdspm *hdspm); static int hdspm_autosync_ref(struct hdspm *hdspm); +static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out); static int snd_hdspm_set_defaults(struct hdspm *hdspm); +static int hdspm_system_clock_mode(struct hdspm *hdspm); static void hdspm_set_sgbuf(struct hdspm *hdspm, struct snd_pcm_substream *substream, unsigned int reg, int channels); +static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx); +static int hdspm_wc_sync_check(struct hdspm *hdspm); +static int hdspm_tco_sync_check(struct hdspm *hdspm); +static int hdspm_sync_in_sync_check(struct hdspm *hdspm); + +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index); +static int hdspm_get_tco_sample_rate(struct hdspm *hdspm); +static int hdspm_get_wc_sample_rate(struct hdspm *hdspm); + + + static inline int HDSPM_bit2freq(int n) { static const int bit2freq_tab[] = { @@ -985,6 +1129,12 @@ static inline int HDSPM_bit2freq(int n) return bit2freq_tab[n]; } +static bool hdspm_is_raydat_or_aio(struct hdspm *hdspm) +{ + return ((AIO == hdspm->io_type) || (RayDAT == hdspm->io_type)); +} + + /* Write/read to/from HDSPM with Adresses in Bytes not words but only 32Bit writes are allowed */ @@ -1073,7 +1223,38 @@ static int snd_hdspm_use_is_exclusive(struct hdspm *hdspm) return ret; } -/* check for external sample rate */ +/* round arbitary sample rates to commonly known rates */ +static int hdspm_round_frequency(int rate) +{ + if (rate < 38050) + return 32000; + if (rate < 46008) + return 44100; + else + return 48000; +} + +/* QS and DS rates normally can not be detected + * automatically by the card. Only exception is MADI + * in 96k frame mode. + * + * So if we read SS values (32 .. 48k), check for + * user-provided DS/QS bits in the control register + * and multiply the base frequency accordingly. + */ +static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate) +{ + if (rate <= 48000) { + if (hdspm->control_register & HDSPM_QuadSpeed) + return rate * 4; + else if (hdspm->control_register & + HDSPM_DoubleSpeed) + return rate * 2; + } + return rate; +} + +/* check for external sample rate, returns the sample rate in Hz*/ static int hdspm_external_sample_rate(struct hdspm *hdspm) { unsigned int status, status2, timecode; @@ -1086,17 +1267,36 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); syncref = hdspm_autosync_ref(hdspm); + switch (syncref) { + case HDSPM_AES32_AUTOSYNC_FROM_WORD: + /* Check WC sync and get sample rate */ + if (hdspm_wc_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_wc_sample_rate(hdspm)); + break; + + case HDSPM_AES32_AUTOSYNC_FROM_AES1: + case HDSPM_AES32_AUTOSYNC_FROM_AES2: + case HDSPM_AES32_AUTOSYNC_FROM_AES3: + case HDSPM_AES32_AUTOSYNC_FROM_AES4: + case HDSPM_AES32_AUTOSYNC_FROM_AES5: + case HDSPM_AES32_AUTOSYNC_FROM_AES6: + case HDSPM_AES32_AUTOSYNC_FROM_AES7: + case HDSPM_AES32_AUTOSYNC_FROM_AES8: + /* Check AES sync and get sample rate */ + if (hdspm_aes_sync_check(hdspm, syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)) + return HDSPM_bit2freq(hdspm_get_aes_sample_rate(hdspm, + syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1)); + break; - if (syncref == HDSPM_AES32_AUTOSYNC_FROM_WORD && - status & HDSPM_AES32_wcLock) - return HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF); - if (syncref >= HDSPM_AES32_AUTOSYNC_FROM_AES1 && - syncref <= HDSPM_AES32_AUTOSYNC_FROM_AES8 && - status2 & (HDSPM_LockAES >> - (syncref - HDSPM_AES32_AUTOSYNC_FROM_AES1))) - return HDSPM_bit2freq((timecode >> (4*(syncref-HDSPM_AES32_AUTOSYNC_FROM_AES1))) & 0xF); - return 0; + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + /* Check TCO sync and get sample rate */ + if (hdspm_tco_sync_check(hdspm)) + return HDSPM_bit2freq(hdspm_get_tco_sample_rate(hdspm)); + break; + default: + return 0; + } /* end switch(syncref) */ break; case MADIface: @@ -1164,6 +1364,15 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) case HDSPM_wcFreq96: rate = 96000; break; + case HDSPM_wcFreq128: + rate = 128000; + break; + case HDSPM_wcFreq176_4: + rate = 176400; + break; + case HDSPM_wcFreq192: + rate = 192000; + break; default: rate = 0; break; @@ -1175,7 +1384,7 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) */ if (rate != 0 && (status2 & HDSPM_SelSyncRefMask) == HDSPM_SelSyncRef_WORD) - return rate; + return hdspm_rate_multiplier(hdspm, rate); /* maybe a madi input (which is taken if sel sync is madi) */ if (status & HDSPM_madiLock) { @@ -1214,22 +1423,32 @@ static int hdspm_external_sample_rate(struct hdspm *hdspm) break; } - /* QS and DS rates normally can not be detected - * automatically by the card. Only exception is MADI - * in 96k frame mode. - * - * So if we read SS values (32 .. 48k), check for - * user-provided DS/QS bits in the control register - * and multiply the base frequency accordingly. - */ - if (rate <= 48000) { - if (hdspm->control_register & HDSPM_QuadSpeed) - rate *= 4; - else if (hdspm->control_register & - HDSPM_DoubleSpeed) - rate *= 2; + } /* endif HDSPM_madiLock */ + + /* check sample rate from TCO or SYNC_IN */ + { + bool is_valid_input = 0; + bool has_sync = 0; + + syncref = hdspm_autosync_ref(hdspm); + if (HDSPM_AUTOSYNC_FROM_TCO == syncref) { + is_valid_input = 1; + has_sync = (HDSPM_SYNC_CHECK_SYNC == + hdspm_tco_sync_check(hdspm)); + } else if (HDSPM_AUTOSYNC_FROM_SYNC_IN == syncref) { + is_valid_input = 1; + has_sync = (HDSPM_SYNC_CHECK_SYNC == + hdspm_sync_in_sync_check(hdspm)); + } + + if (is_valid_input && has_sync) { + rate = hdspm_round_frequency( + hdspm_get_pll_freq(hdspm)); } } + + rate = hdspm_rate_multiplier(hdspm, rate); + break; } @@ -1432,9 +1651,8 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) just make a warning an remember setting for future master mode switching */ - snd_printk(KERN_WARNING "HDSPM: " - "Warning: device is not running " - "as a clock master.\n"); + dev_warn(hdspm->card->dev, + "Warning: device is not running as a clock master.\n"); not_set = 1; } else { @@ -1445,15 +1663,14 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) if (hdspm_autosync_ref(hdspm) == HDSPM_AUTOSYNC_FROM_NONE) { - snd_printk(KERN_WARNING "HDSPM: " - "Detected no Externel Sync \n"); + dev_warn(hdspm->card->dev, + "Detected no Externel Sync\n"); not_set = 1; } else if (rate != external_freq) { - snd_printk(KERN_WARNING "HDSPM: " - "Warning: No AutoSync source for " - "requested rate\n"); + dev_warn(hdspm->card->dev, + "Warning: No AutoSync source for requested rate\n"); not_set = 1; } } @@ -1519,13 +1736,11 @@ static int hdspm_set_rate(struct hdspm * hdspm, int rate, int called_internally) if (current_speed != target_speed && (hdspm->capture_pid >= 0 || hdspm->playback_pid >= 0)) { - snd_printk - (KERN_ERR "HDSPM: " - "cannot change from %s speed to %s speed mode " - "(capture PID = %d, playback PID = %d)\n", - hdspm_speed_names[current_speed], - hdspm_speed_names[target_speed], - hdspm->capture_pid, hdspm->playback_pid); + dev_err(hdspm->card->dev, + "cannot change from %s speed to %s speed mode (capture PID = %d, playback PID = %d)\n", + hdspm_speed_names[current_speed], + hdspm_speed_names[target_speed], + hdspm->capture_pid, hdspm->playback_pid); return -EBUSY; } @@ -1844,8 +2059,8 @@ static struct snd_rawmidi_ops snd_hdspm_midi_input = .trigger = snd_hdspm_midi_input_trigger, }; -static int __devinit snd_hdspm_create_midi (struct snd_card *card, - struct hdspm *hdspm, int id) +static int snd_hdspm_create_midi(struct snd_card *card, + struct hdspm *hdspm, int id) { int err; char buf[32]; @@ -1977,22 +2192,35 @@ static void hdspm_midi_tasklet(unsigned long arg) /* get the system sample rate which is set */ +static inline int hdspm_get_pll_freq(struct hdspm *hdspm) +{ + unsigned int period, rate; + + period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); + rate = hdspm_calc_dds_value(hdspm, period); + + return rate; +} + /** * Calculate the real sample rate from the * current DDS value. **/ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) { - unsigned int period, rate; + unsigned int rate; - period = hdspm_read(hdspm, HDSPM_RD_PLL_FREQ); - rate = hdspm_calc_dds_value(hdspm, period); + rate = hdspm_get_pll_freq(hdspm); if (rate > 207000) { - /* Unreasonable high sample rate as seen on PCI MADI cards. - * Use the cached value instead. - */ - rate = hdspm->system_sample_rate; + /* Unreasonable high sample rate as seen on PCI MADI cards. */ + if (0 == hdspm_system_clock_mode(hdspm)) { + /* master mode, return internal sample rate */ + rate = hdspm->system_sample_rate; + } else { + /* slave mode, return external sample rate */ + rate = hdspm_external_sample_rate(hdspm); + } } return rate; @@ -2000,12 +2228,14 @@ static int hdspm_get_system_sample_rate(struct hdspm *hdspm) #define HDSPM_SYSTEM_SAMPLE_RATE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ - .info = snd_hdspm_info_system_sample_rate, \ - .get = snd_hdspm_get_system_sample_rate \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_system_sample_rate, \ + .put = snd_hdspm_put_system_sample_rate, \ + .get = snd_hdspm_get_system_sample_rate \ } static int snd_hdspm_info_system_sample_rate(struct snd_kcontrol *kcontrol, @@ -2030,6 +2260,16 @@ static int snd_hdspm_get_system_sample_rate(struct snd_kcontrol *kcontrol, return 0; } +static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value * + ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + + hdspm_set_dds_value(hdspm, ucontrol->value.enumerated.item[0]); + return 0; +} + /** * Returns the WordClock sample rate class for the given card. @@ -2044,6 +2284,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm) status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 16) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> HDSPM_AES32_wcFreq_bit) & 0xF; default: break; } @@ -2067,6 +2310,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm) status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); return (status >> 20) & 0xF; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister); + return (status >> 1) & 0xF; default: break; } @@ -2098,6 +2344,23 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm) return 0; } +/** + * Returns the AES sample rate class for the given card. + **/ +static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index) +{ + int timecode; + + switch (hdspm->io_type) { + case AES32: + timecode = hdspm_read(hdspm, HDSPM_timecodeRegister); + return (timecode >> (4*index)) & 0xF; + break; + default: + break; + } + return 0; +} /** * Returns the sample rate class for input source <idx> for @@ -2110,6 +2373,24 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) return (status >> (idx*4)) & 0xF; } +#define ENUMERATED_CTL_INFO(info, texts) \ + snd_ctl_enum_info(info, 1, ARRAY_SIZE(texts), texts) + + +/* Helper function to query the external sample rate and return the + * corresponding enum to be returned to userspace. + */ +static int hdspm_external_rate_to_enum(struct hdspm *hdspm) +{ + int rate = hdspm_external_sample_rate(hdspm); + int i, selected_rate = 0; + for (i = 1; i < 10; i++) + if (HDSPM_bit2freq(i) == rate) { + selected_rate = i; + break; + } + return selected_rate; +} #define HDSPM_AUTOSYNC_SAMPLE_RATE(xname, xindex) \ @@ -2125,14 +2406,7 @@ static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx) static int snd_hdspm_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 10; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts_freq[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts_freq); return 0; } @@ -2163,6 +2437,7 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, hdspm_get_s1_sample_rate(hdspm, kcontrol->private_value-1); } + break; case AIO: switch (kcontrol->private_value) { @@ -2181,8 +2456,9 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, default: ucontrol->value.enumerated.item[0] = hdspm_get_s1_sample_rate(hdspm, - ucontrol->id.index-1); + kcontrol->private_value-1); } + break; case AES32: @@ -2199,13 +2475,24 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, ucontrol->value.enumerated.item[0] = hdspm_get_sync_in_sample_rate(hdspm); break; + case 11: /* External Rate */ + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); + break; default: /* AES1 to AES8 */ ucontrol->value.enumerated.item[0] = - hdspm_get_s1_sample_rate(hdspm, - kcontrol->private_value-1); + hdspm_get_aes_sample_rate(hdspm, + kcontrol->private_value - + HDSPM_AES32_AUTOSYNC_FROM_AES1); break; - } + break; + + case MADI: + case MADIface: + ucontrol->value.enumerated.item[0] = + hdspm_external_rate_to_enum(hdspm); + break; default: break; } @@ -2254,42 +2541,18 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm) **/ static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode) { - switch (hdspm->io_type) { - case AIO: - case RayDAT: - if (0 == mode) - hdspm->settings_register |= HDSPM_c0Master; - else - hdspm->settings_register &= ~HDSPM_c0Master; - - hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - break; - - default: - if (0 == mode) - hdspm->control_register |= HDSPM_ClockModeMaster; - else - hdspm->control_register &= ~HDSPM_ClockModeMaster; - - hdspm_write(hdspm, HDSPM_controlRegister, - hdspm->control_register); - } + hdspm_set_toggle_setting(hdspm, + (hdspm_is_raydat_or_aio(hdspm)) ? + HDSPM_c0Master : HDSPM_ClockModeMaster, + (0 == mode)); } static int snd_hdspm_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Master", "AutoSync" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + static const char *const texts[] = { "Master", "AutoSync" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -2430,7 +2693,7 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol, #define HDSPM_PREF_SYNC_REF(xname, xindex) \ -{.iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ .index = xindex, \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |\ @@ -2712,16 +2975,7 @@ static int snd_hdspm_info_pref_sync_ref(struct snd_kcontrol *kcontrol, { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = hdspm->texts_autosync_items; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - hdspm->texts_autosync[uinfo->value.enumerated.item]); + snd_ctl_enum_info(uinfo, 1, hdspm->texts_autosync_items, hdspm->texts_autosync); return 0; } @@ -2766,29 +3020,30 @@ static int snd_hdspm_put_pref_sync_ref(struct snd_kcontrol *kcontrol, #define HDSPM_AUTOSYNC_REF(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ, \ - .info = snd_hdspm_info_autosync_ref, \ - .get = snd_hdspm_get_autosync_ref, \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ, \ + .info = snd_hdspm_info_autosync_ref, \ + .get = snd_hdspm_get_autosync_ref, \ } static int hdspm_autosync_ref(struct hdspm *hdspm) { + /* This looks at the autosync selected sync reference */ if (AES32 == hdspm->io_type) { + unsigned int status = hdspm_read(hdspm, HDSPM_statusRegister); - unsigned int syncref = - (status >> HDSPM_AES32_syncref_bit) & 0xF; - if (syncref == 0) - return HDSPM_AES32_AUTOSYNC_FROM_WORD; - if (syncref <= 8) + unsigned int syncref = (status >> HDSPM_AES32_syncref_bit) & 0xF; + if ((syncref >= HDSPM_AES32_AUTOSYNC_FROM_WORD) && + (syncref <= HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN)) { return syncref; + } return HDSPM_AES32_AUTOSYNC_FROM_NONE; + } else if (MADI == hdspm->io_type) { - /* This looks at the autosync selected sync reference */ - unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + unsigned int status2 = hdspm_read(hdspm, HDSPM_statusRegister2); switch (status2 & HDSPM_SelSyncRefMask) { case HDSPM_SelSyncRef_WORD: return HDSPM_AUTOSYNC_FROM_WORD; @@ -2801,7 +3056,7 @@ static int hdspm_autosync_ref(struct hdspm *hdspm) case HDSPM_SelSyncRef_NVALID: return HDSPM_AUTOSYNC_FROM_NONE; default: - return 0; + return HDSPM_AUTOSYNC_FROM_NONE; } } @@ -2815,31 +3070,15 @@ static int snd_hdspm_info_autosync_ref(struct snd_kcontrol *kcontrol, struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); if (AES32 == hdspm->io_type) { - static char *texts[] = { "WordClock", "AES1", "AES2", "AES3", - "AES4", "AES5", "AES6", "AES7", "AES8", "None"}; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 10; - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + static const char *const texts[] = { "WordClock", "AES1", "AES2", "AES3", + "AES4", "AES5", "AES6", "AES7", "AES8", "TCO", "Sync In", "None"}; + + ENUMERATED_CTL_INFO(uinfo, texts); } else if (MADI == hdspm->io_type) { - static char *texts[] = {"Word Clock", "MADI", "TCO", + static const char *const texts[] = {"Word Clock", "MADI", "TCO", "Sync In", "None" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - if (uinfo->value.enumerated.item >= - uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + ENUMERATED_CTL_INFO(uinfo, texts); } return 0; } @@ -2854,329 +3093,174 @@ static int snd_hdspm_get_autosync_ref(struct snd_kcontrol *kcontrol, } -#define HDSPM_LINE_OUT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_line_out, \ - .get = snd_hdspm_get_line_out, \ - .put = snd_hdspm_put_line_out \ -} - -static int hdspm_line_out(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_LineOut) ? 1 : 0; -} - - -static int hdspm_set_line_output(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_LineOut; - else - hdspm->control_register &= ~HDSPM_LineOut; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - return 0; +#define HDSPM_TCO_VIDEO_INPUT_FORMAT(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_tco_video_input_format, \ + .get = snd_hdspm_get_tco_video_input_format, \ } -#define snd_hdspm_info_line_out snd_ctl_boolean_mono_info - -static int snd_hdspm_get_line_out(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_hdspm_info_tco_video_input_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_line_out(hdspm); - spin_unlock_irq(&hdspm->lock); + static const char *const texts[] = {"No video", "NTSC", "PAL"}; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } -static int snd_hdspm_put_line_out(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_line_out(hdspm); - hdspm_set_line_output(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_TX_64(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_tx_64, \ - .get = snd_hdspm_get_tx_64, \ - .put = snd_hdspm_put_tx_64 \ -} - -static int hdspm_tx_64(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_TX_64ch) ? 1 : 0; -} - -static int hdspm_set_tx_64(struct hdspm * hdspm, int out) +static int snd_hdspm_get_tco_video_input_format(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { - if (out) - hdspm->control_register |= HDSPM_TX_64ch; - else - hdspm->control_register &= ~HDSPM_TX_64ch; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + u32 status; + int ret = 0; - return 0; -} - -#define snd_hdspm_info_tx_64 snd_ctl_boolean_mono_info - -static int snd_hdspm_get_tx_64(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_tx_64(hdspm); - spin_unlock_irq(&hdspm->lock); + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + switch (status & (HDSPM_TCO1_Video_Input_Format_NTSC | + HDSPM_TCO1_Video_Input_Format_PAL)) { + case HDSPM_TCO1_Video_Input_Format_NTSC: + /* ntsc */ + ret = 1; + break; + case HDSPM_TCO1_Video_Input_Format_PAL: + /* pal */ + ret = 2; + break; + default: + /* no video */ + ret = 0; + break; + } + ucontrol->value.enumerated.item[0] = ret; return 0; } -static int snd_hdspm_put_tx_64(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_tx_64(hdspm); - hdspm_set_tx_64(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - -#define HDSPM_C_TMS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_c_tms, \ - .get = snd_hdspm_get_c_tms, \ - .put = snd_hdspm_put_c_tms \ -} - -static int hdspm_c_tms(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_clr_tms) ? 1 : 0; -} -static int hdspm_set_c_tms(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_clr_tms; - else - hdspm->control_register &= ~HDSPM_clr_tms; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; +#define HDSPM_TCO_LTC_FRAMES(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ |\ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_tco_ltc_frames, \ + .get = snd_hdspm_get_tco_ltc_frames, \ } -#define snd_hdspm_info_c_tms snd_ctl_boolean_mono_info - -static int snd_hdspm_get_c_tms(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_hdspm_info_tco_ltc_frames(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) { - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_c_tms(hdspm); - spin_unlock_irq(&hdspm->lock); + static const char *const texts[] = {"No lock", "24 fps", "25 fps", "29.97 fps", + "30 fps"}; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } -static int snd_hdspm_put_c_tms(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_c_tms(hdspm); - hdspm_set_c_tms(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_SAFE_MODE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_safe_mode, \ - .get = snd_hdspm_get_safe_mode, \ - .put = snd_hdspm_put_safe_mode \ -} - -static int hdspm_safe_mode(struct hdspm * hdspm) +static int hdspm_tco_ltc_frames(struct hdspm *hdspm) { - return (hdspm->control_register & HDSPM_AutoInp) ? 1 : 0; -} + u32 status; + int ret = 0; -static int hdspm_set_safe_mode(struct hdspm * hdspm, int out) -{ - if (out) - hdspm->control_register |= HDSPM_AutoInp; - else - hdspm->control_register &= ~HDSPM_AutoInp; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + if (status & HDSPM_TCO1_LTC_Input_valid) { + switch (status & (HDSPM_TCO1_LTC_Format_LSB | + HDSPM_TCO1_LTC_Format_MSB)) { + case 0: + /* 24 fps */ + ret = fps_24; + break; + case HDSPM_TCO1_LTC_Format_LSB: + /* 25 fps */ + ret = fps_25; + break; + case HDSPM_TCO1_LTC_Format_MSB: + /* 29.97 fps */ + ret = fps_2997; + break; + default: + /* 30 fps */ + ret = fps_30; + break; + } + } - return 0; + return ret; } -#define snd_hdspm_info_safe_mode snd_ctl_boolean_mono_info - -static int snd_hdspm_get_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int snd_hdspm_get_tco_ltc_frames(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - spin_lock_irq(&hdspm->lock); - ucontrol->value.integer.value[0] = hdspm_safe_mode(hdspm); - spin_unlock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_tco_ltc_frames(hdspm); return 0; } -static int snd_hdspm_put_safe_mode(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_safe_mode(hdspm); - hdspm_set_safe_mode(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_EMPHASIS(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_emphasis, \ - .get = snd_hdspm_get_emphasis, \ - .put = snd_hdspm_put_emphasis \ +#define HDSPM_TOGGLE_SETTING(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdspm_info_toggle_setting, \ + .get = snd_hdspm_get_toggle_setting, \ + .put = snd_hdspm_put_toggle_setting \ } -static int hdspm_emphasis(struct hdspm * hdspm) +static int hdspm_toggle_setting(struct hdspm *hdspm, u32 regmask) { - return (hdspm->control_register & HDSPM_Emphasis) ? 1 : 0; -} + u32 reg; -static int hdspm_set_emphasis(struct hdspm * hdspm, int emp) -{ - if (emp) - hdspm->control_register |= HDSPM_Emphasis; + if (hdspm_is_raydat_or_aio(hdspm)) + reg = hdspm->settings_register; else - hdspm->control_register &= ~HDSPM_Emphasis; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + reg = hdspm->control_register; - return 0; -} - -#define snd_hdspm_info_emphasis snd_ctl_boolean_mono_info - -static int snd_hdspm_get_emphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_emphasis(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; + return (reg & regmask) ? 1 : 0; } -static int snd_hdspm_put_emphasis(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) +static int hdspm_set_toggle_setting(struct hdspm *hdspm, u32 regmask, int out) { - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_emphasis(hdspm); - hdspm_set_emphasis(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - + u32 *reg; + u32 target_reg; -#define HDSPM_DOLBY(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_dolby, \ - .get = snd_hdspm_get_dolby, \ - .put = snd_hdspm_put_dolby \ -} - -static int hdspm_dolby(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_Dolby) ? 1 : 0; -} + if (hdspm_is_raydat_or_aio(hdspm)) { + reg = &(hdspm->settings_register); + target_reg = HDSPM_WR_SETTINGS; + } else { + reg = &(hdspm->control_register); + target_reg = HDSPM_controlRegister; + } -static int hdspm_set_dolby(struct hdspm * hdspm, int dol) -{ - if (dol) - hdspm->control_register |= HDSPM_Dolby; + if (out) + *reg |= regmask; else - hdspm->control_register &= ~HDSPM_Dolby; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); + *reg &= ~regmask; + + hdspm_write(hdspm, target_reg, *reg); return 0; } -#define snd_hdspm_info_dolby snd_ctl_boolean_mono_info +#define snd_hdspm_info_toggle_setting snd_ctl_boolean_mono_info -static int snd_hdspm_get_dolby(struct snd_kcontrol *kcontrol, +static int snd_hdspm_get_toggle_setting(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_dolby(hdspm); + ucontrol->value.integer.value[0] = hdspm_toggle_setting(hdspm, regmask); spin_unlock_irq(&hdspm->lock); return 0; } -static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, +static int snd_hdspm_put_toggle_setting(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; int change; unsigned int val; @@ -3184,75 +3268,19 @@ static int snd_hdspm_put_dolby(struct snd_kcontrol *kcontrol, return -EBUSY; val = ucontrol->value.integer.value[0] & 1; spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_dolby(hdspm); - hdspm_set_dolby(hdspm, val); - spin_unlock_irq(&hdspm->lock); - return change; -} - - -#define HDSPM_PROFESSIONAL(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_professional, \ - .get = snd_hdspm_get_professional, \ - .put = snd_hdspm_put_professional \ -} - -static int hdspm_professional(struct hdspm * hdspm) -{ - return (hdspm->control_register & HDSPM_Professional) ? 1 : 0; -} - -static int hdspm_set_professional(struct hdspm * hdspm, int dol) -{ - if (dol) - hdspm->control_register |= HDSPM_Professional; - else - hdspm->control_register &= ~HDSPM_Professional; - hdspm_write(hdspm, HDSPM_controlRegister, hdspm->control_register); - - return 0; -} - -#define snd_hdspm_info_professional snd_ctl_boolean_mono_info - -static int snd_hdspm_get_professional(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - - spin_lock_irq(&hdspm->lock); - ucontrol->value.enumerated.item[0] = hdspm_professional(hdspm); - spin_unlock_irq(&hdspm->lock); - return 0; -} - -static int snd_hdspm_put_professional(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); - int change; - unsigned int val; - - if (!snd_hdspm_use_is_exclusive(hdspm)) - return -EBUSY; - val = ucontrol->value.integer.value[0] & 1; - spin_lock_irq(&hdspm->lock); - change = (int) val != hdspm_professional(hdspm); - hdspm_set_professional(hdspm, val); + change = (int) val != hdspm_toggle_setting(hdspm, regmask); + hdspm_set_toggle_setting(hdspm, regmask, val); spin_unlock_irq(&hdspm->lock); return change; } #define HDSPM_INPUT_SELECT(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_input_select, \ - .get = snd_hdspm_get_input_select, \ - .put = snd_hdspm_put_input_select \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_input_select, \ + .get = snd_hdspm_get_input_select, \ + .put = snd_hdspm_put_input_select \ } static int hdspm_input_select(struct hdspm * hdspm) @@ -3274,18 +3302,8 @@ static int hdspm_set_input_select(struct hdspm * hdspm, int out) static int snd_hdspm_info_input_select(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "optical", "coaxial" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "optical", "coaxial" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3319,12 +3337,12 @@ static int snd_hdspm_put_input_select(struct snd_kcontrol *kcontrol, #define HDSPM_DS_WIRE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_ds_wire, \ - .get = snd_hdspm_get_ds_wire, \ - .put = snd_hdspm_put_ds_wire \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_ds_wire, \ + .get = snd_hdspm_get_ds_wire, \ + .put = snd_hdspm_put_ds_wire \ } static int hdspm_ds_wire(struct hdspm * hdspm) @@ -3346,18 +3364,8 @@ static int hdspm_set_ds_wire(struct hdspm * hdspm, int ds) static int snd_hdspm_info_ds_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "Single", "Double" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3391,12 +3399,12 @@ static int snd_hdspm_put_ds_wire(struct snd_kcontrol *kcontrol, #define HDSPM_QS_WIRE(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = xindex, \ - .info = snd_hdspm_info_qs_wire, \ - .get = snd_hdspm_get_qs_wire, \ - .put = snd_hdspm_put_qs_wire \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .index = xindex, \ + .info = snd_hdspm_info_qs_wire, \ + .get = snd_hdspm_get_qs_wire, \ + .put = snd_hdspm_put_qs_wire \ } static int hdspm_qs_wire(struct hdspm * hdspm) @@ -3429,18 +3437,8 @@ static int hdspm_set_qs_wire(struct hdspm * hdspm, int mode) static int snd_hdspm_info_qs_wire(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "Single", "Double", "Quad" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3476,6 +3474,84 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, return change; } +#define HDSPM_CONTROL_TRISTATE(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .info = snd_hdspm_info_tristate, \ + .get = snd_hdspm_get_tristate, \ + .put = snd_hdspm_put_tristate \ +} + +static int hdspm_tristate(struct hdspm *hdspm, u32 regmask) +{ + u32 reg = hdspm->settings_register & (regmask * 3); + return reg / regmask; +} + +static int hdspm_set_tristate(struct hdspm *hdspm, int mode, u32 regmask) +{ + hdspm->settings_register &= ~(regmask * 3); + hdspm->settings_register |= (regmask * mode); + hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); + + return 0; +} + +static int snd_hdspm_info_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + u32 regmask = kcontrol->private_value; + + static const char *const texts_spdif[] = { "Optical", "Coaxial", "Internal" }; + static const char *const texts_levels[] = { "Hi Gain", "+4 dBu", "-10 dBV" }; + + switch (regmask) { + case HDSPM_c0_Input0: + ENUMERATED_CTL_INFO(uinfo, texts_spdif); + break; + default: + ENUMERATED_CTL_INFO(uinfo, texts_levels); + break; + } + return 0; +} + +static int snd_hdspm_get_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + + spin_lock_irq(&hdspm->lock); + ucontrol->value.enumerated.item[0] = hdspm_tristate(hdspm, regmask); + spin_unlock_irq(&hdspm->lock); + return 0; +} + +static int snd_hdspm_put_tristate(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hdspm *hdspm = snd_kcontrol_chip(kcontrol); + u32 regmask = kcontrol->private_value; + int change; + int val; + + if (!snd_hdspm_use_is_exclusive(hdspm)) + return -EBUSY; + val = ucontrol->value.integer.value[0]; + if (val < 0) + val = 0; + if (val > 2) + val = 2; + + spin_lock_irq(&hdspm->lock); + change = val != hdspm_tristate(hdspm, regmask); + hdspm_set_tristate(hdspm, val, regmask); + spin_unlock_irq(&hdspm->lock); + return change; +} + #define HDSPM_MADI_SPEEDMODE(xname, xindex) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ .name = xname, \ @@ -3515,18 +3591,8 @@ static int hdspm_set_madi_speedmode(struct hdspm *hdspm, int mode) static int snd_hdspm_info_madi_speedmode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "Single", "Double", "Quad" }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "Single", "Double", "Quad" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3563,15 +3629,15 @@ static int snd_hdspm_put_madi_speedmode(struct snd_kcontrol *kcontrol, } #define HDSPM_MIXER(xname, xindex) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ - .name = xname, \ - .index = xindex, \ - .device = 0, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdspm_info_mixer, \ - .get = snd_hdspm_get_mixer, \ - .put = snd_hdspm_put_mixer \ +{ .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, \ + .name = xname, \ + .index = xindex, \ + .device = 0, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_mixer, \ + .get = snd_hdspm_get_mixer, \ + .put = snd_hdspm_put_mixer \ } static int snd_hdspm_info_mixer(struct snd_kcontrol *kcontrol, @@ -3670,12 +3736,12 @@ static int snd_hdspm_put_mixer(struct snd_kcontrol *kcontrol, */ #define HDSPM_PLAYBACK_MIXER \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ - SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ - .info = snd_hdspm_info_playback_mixer, \ - .get = snd_hdspm_get_playback_mixer, \ - .put = snd_hdspm_put_playback_mixer \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_WRITE | \ + SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_info_playback_mixer, \ + .get = snd_hdspm_get_playback_mixer, \ + .put = snd_hdspm_put_playback_mixer \ } static int snd_hdspm_info_playback_mixer(struct snd_kcontrol *kcontrol, @@ -3746,19 +3812,30 @@ static int snd_hdspm_put_playback_mixer(struct snd_kcontrol *kcontrol, .get = snd_hdspm_get_sync_check \ } +#define HDSPM_TCO_LOCK_CHECK(xname, xindex) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ + .name = xname, \ + .private_value = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, \ + .info = snd_hdspm_tco_info_lock_check, \ + .get = snd_hdspm_get_sync_check \ +} + + static int snd_hdspm_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "No Lock", "Lock", "Sync", "N/A" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 4; - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); + static const char *const texts[] = { "No Lock", "Lock", "Sync", "N/A" }; + ENUMERATED_CTL_INFO(uinfo, texts); + return 0; +} + +static int snd_hdspm_tco_info_lock_check(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + static const char *const texts[] = { "No Lock", "Lock" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -3769,10 +3846,12 @@ static int hdspm_wc_sync_check(struct hdspm *hdspm) switch (hdspm->io_type) { case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); - if (status & HDSPM_wcSync) - return 2; - else if (status & HDSPM_wcLock) - return 1; + if (status & HDSPM_AES32_wcLock) { + if (status & HDSPM_AES32_wcSync) + return 2; + else + return 1; + } return 0; break; @@ -3851,12 +3930,17 @@ static int hdspm_sync_in_sync_check(struct hdspm *hdspm) break; case MADI: - case AES32: - status = hdspm_read(hdspm, HDSPM_statusRegister2); + status = hdspm_read(hdspm, HDSPM_statusRegister); lock = (status & HDSPM_syncInLock) ? 1 : 0; sync = (status & HDSPM_syncInSync) ? 1 : 0; break; + case AES32: + status = hdspm_read(hdspm, HDSPM_statusRegister2); + lock = (status & 0x100000) ? 1 : 0; + sync = (status & 0x200000) ? 1 : 0; + break; + case MADIface: break; } @@ -3884,6 +3968,14 @@ static int hdspm_aes_sync_check(struct hdspm *hdspm, int idx) return 0; } +static int hdspm_tco_input_check(struct hdspm *hdspm, u32 mask) +{ + u32 status; + status = hdspm_read(hdspm, HDSPM_RD_TCO + 4); + + return (status & mask) ? 1 : 0; +} + static int hdspm_tco_sync_check(struct hdspm *hdspm) { @@ -3892,18 +3984,23 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm) if (hdspm->tco) { switch (hdspm->io_type) { case MADI: + status = hdspm_read(hdspm, HDSPM_statusRegister); + if (status & HDSPM_tcoLockMadi) { + if (status & HDSPM_tcoSync) + return 2; + else + return 1; + } + return 0; case AES32: status = hdspm_read(hdspm, HDSPM_statusRegister); - if (status & HDSPM_tcoLock) { + if (status & HDSPM_tcoLockAes) { if (status & HDSPM_tcoSync) return 2; else return 1; } return 0; - - break; - case RayDAT: case AIO: status = hdspm_read(hdspm, HDSPM_RD_STATUS_1); @@ -3913,7 +4010,6 @@ static int hdspm_tco_sync_check(struct hdspm *hdspm) if (status & 0x4000000) return 1; /* Lock */ return 0; /* No signal */ - break; default: break; @@ -3940,8 +4036,10 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, case 8: /* SYNC IN */ val = hdspm_sync_in_sync_check(hdspm); break; default: - val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); + val = hdspm_s1_sync_check(hdspm, + kcontrol->private_value-1); } + break; case AIO: switch (kcontrol->private_value) { @@ -3952,8 +4050,10 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, case 5: /* SYNC IN */ val = hdspm_sync_in_sync_check(hdspm); break; default: - val = hdspm_s1_sync_check(hdspm, ucontrol->id.index-1); + val = hdspm_s1_sync_check(hdspm, + kcontrol->private_value-1); } + break; case MADI: switch (kcontrol->private_value) { @@ -3966,6 +4066,7 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, case 3: /* SYNC_IN */ val = hdspm_sync_in_sync_check(hdspm); break; } + break; case MADIface: val = hdspm_madi_sync_check(hdspm); /* MADI */ @@ -3983,9 +4084,26 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol, val = hdspm_aes_sync_check(hdspm, kcontrol->private_value-1); } + break; } + if (hdspm->tco) { + switch (kcontrol->private_value) { + case 11: + /* Check TCO for lock state of its current input */ + val = hdspm_tco_input_check(hdspm, HDSPM_TCO1_TCO_lock); + break; + case 12: + /* Check TCO for valid time code on LTC input. */ + val = hdspm_tco_input_check(hdspm, + HDSPM_TCO1_LTC_Input_valid); + break; + default: + break; + } + } + if (-1 == val) val = 3; @@ -4101,18 +4219,9 @@ static void hdspm_tco_write(struct hdspm *hdspm) static int snd_hdspm_info_tco_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "44.1 kHz", "48 kHz" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 2; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + /* TODO freq from app could be supported here, see tco->samplerate */ + static const char *const texts[] = { "44.1 kHz", "48 kHz" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4157,18 +4266,9 @@ static int snd_hdspm_put_tco_sample_rate(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_pull(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "0", "+ 0.1 %", "- 0.1 %", "+ 4 %", "- 4 %" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 5; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "0", "+ 0.1 %", "- 0.1 %", + "+ 4 %", "- 4 %" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4212,18 +4312,8 @@ static int snd_hdspm_put_tco_pull(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_wck_conversion(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "1:1", "44.1 -> 48", "48 -> 44.1" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4268,19 +4358,9 @@ static int snd_hdspm_put_tco_wck_conversion(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_frame_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "24 fps", "25 fps", "29.97fps", + static const char *const texts[] = { "24 fps", "25 fps", "29.97fps", "29.97 dfps", "30 fps", "30 dfps" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 6; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4325,18 +4405,8 @@ static int snd_hdspm_put_tco_frame_rate(struct snd_kcontrol *kcontrol, static int snd_hdspm_info_tco_sync_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts[] = { "LTC", "Video", "WCK" }; - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 3; - - if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) - uinfo->value.enumerated.item = - uinfo->value.enumerated.items - 1; - - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - + static const char *const texts[] = { "LTC", "Video", "WCK" }; + ENUMERATED_CTL_INFO(uinfo, texts); return 0; } @@ -4427,14 +4497,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_madi[] = { HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), HDSPM_SYNC_CHECK("MADI SyncCheck", 1), - HDSPM_SYNC_CHECK("TCO SyncCHeck", 2), + HDSPM_SYNC_CHECK("TCO SyncCheck", 2), HDSPM_SYNC_CHECK("SYNC IN SyncCheck", 3), - HDSPM_LINE_OUT("Line Out", 0), - HDSPM_TX_64("TX 64 channels mode", 0), - HDSPM_C_TMS("Clear Track Marker", 0), - HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), + HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), + HDSPM_TOGGLE_SETTING("Disable 96K frames", HDSPM_SMUX), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), + HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), HDSPM_INPUT_SELECT("Input Select", 0), HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) }; @@ -4447,9 +4519,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_madiface[] = { HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("MADI SyncCheck", 0), - HDSPM_TX_64("TX 64 channels mode", 0), - HDSPM_C_TMS("Clear Track Marker", 0), - HDSPM_SAFE_MODE("Safe Mode", 0), + HDSPM_TOGGLE_SETTING("TX 64 channels mode", HDSPM_TX_64ch), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), + HDSPM_TOGGLE_SETTING("Safe Mode", HDSPM_AutoInp), HDSPM_MADI_SPEEDMODE("MADI Speed Mode", 0) }; @@ -4458,7 +4530,6 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { HDSPM_INTERNAL_CLOCK("Internal Clock", 0), HDSPM_SYSTEM_CLOCK_MODE("System Clock Mode", 0), HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), - HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), HDSPM_SYNC_CHECK("WC SyncCheck", 0), @@ -4472,7 +4543,16 @@ static struct snd_kcontrol_new snd_hdspm_controls_aio[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("SPDIF Frequency", 2), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT Frequency", 3), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 4), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 5), + HDSPM_CONTROL_TRISTATE("S/PDIF Input", HDSPM_c0_Input0), + HDSPM_TOGGLE_SETTING("S/PDIF Out Optical", HDSPM_c0_Spdif_Opt), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("ADAT internal (AEB/TEB)", HDSPM_c0_AEB1), + HDSPM_TOGGLE_SETTING("XLR Breakout Cable", HDSPM_c0_Sym6db), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48), + HDSPM_CONTROL_TRISTATE("Input Level", HDSPM_c0_AD_GAIN0), + HDSPM_CONTROL_TRISTATE("Output Level", HDSPM_c0_DA_GAIN0), + HDSPM_CONTROL_TRISTATE("Phones Level", HDSPM_c0_PH_GAIN0) /* HDSPM_INPUT_SELECT("Input Select", 0), @@ -4509,7 +4589,9 @@ static struct snd_kcontrol_new snd_hdspm_controls_raydat[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT3 Frequency", 5), HDSPM_AUTOSYNC_SAMPLE_RATE("ADAT4 Frequency", 6), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 7), - HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8) + HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 8), + HDSPM_TOGGLE_SETTING("S/PDIF Out Professional", HDSPM_c0_Pro), + HDSPM_TOGGLE_SETTING("Single Speed WordClock Out", HDSPM_c0_Wck48) }; static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { @@ -4519,7 +4601,7 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { HDSPM_PREF_SYNC_REF("Preferred Sync Reference", 0), HDSPM_AUTOSYNC_REF("AutoSync Reference", 0), HDSPM_SYSTEM_SAMPLE_RATE("System Sample Rate", 0), - HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 0), + HDSPM_AUTOSYNC_SAMPLE_RATE("External Rate", 11), HDSPM_SYNC_CHECK("WC Sync Check", 0), HDSPM_SYNC_CHECK("AES1 Sync Check", 1), HDSPM_SYNC_CHECK("AES2 Sync Check", 2), @@ -4542,11 +4624,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_aes32[] = { HDSPM_AUTOSYNC_SAMPLE_RATE("AES8 Frequency", 8), HDSPM_AUTOSYNC_SAMPLE_RATE("TCO Frequency", 9), HDSPM_AUTOSYNC_SAMPLE_RATE("SYNC IN Frequency", 10), - HDSPM_LINE_OUT("Line Out", 0), - HDSPM_EMPHASIS("Emphasis", 0), - HDSPM_DOLBY("Non Audio", 0), - HDSPM_PROFESSIONAL("Professional", 0), - HDSPM_C_TMS("Clear Track Marker", 0), + HDSPM_TOGGLE_SETTING("Line Out", HDSPM_LineOut), + HDSPM_TOGGLE_SETTING("Emphasis", HDSPM_Emphasis), + HDSPM_TOGGLE_SETTING("Non Audio", HDSPM_Dolby), + HDSPM_TOGGLE_SETTING("Professional", HDSPM_Professional), + HDSPM_TOGGLE_SETTING("Clear Track Marker", HDSPM_clr_tms), HDSPM_DS_WIRE("Double Speed Wire Mode", 0), HDSPM_QS_WIRE("Quad Speed Wire Mode", 0), }; @@ -4560,7 +4642,11 @@ static struct snd_kcontrol_new snd_hdspm_controls_tco[] = { HDSPM_TCO_WCK_CONVERSION("TCO WCK Conversion", 0), HDSPM_TCO_FRAME_RATE("TCO Frame Rate", 0), HDSPM_TCO_SYNC_SOURCE("TCO Sync Source", 0), - HDSPM_TCO_WORD_TERM("TCO Word Term", 0) + HDSPM_TCO_WORD_TERM("TCO Word Term", 0), + HDSPM_TCO_LOCK_CHECK("TCO Input Check", 11), + HDSPM_TCO_LOCK_CHECK("TCO LTC Valid", 12), + HDSPM_TCO_LTC_FRAMES("TCO Detected Frame Rate", 0), + HDSPM_TCO_VIDEO_INPUT_FORMAT("Video Input Format", 0) }; @@ -4671,77 +4757,22 @@ static int snd_hdspm_create_controls(struct snd_card *card, ------------------------------------------------------------*/ static void -snd_hdspm_proc_read_madi(struct snd_info_entry * entry, - struct snd_info_buffer *buffer) +snd_hdspm_proc_read_tco(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) { struct hdspm *hdspm = entry->private_data; - unsigned int status, status2, control, freq; - - char *pref_sync_ref; - char *autosync_ref; - char *system_clock_mode; - char *insel; - int x, x2; - - /* TCO stuff */ + unsigned int status, control; int a, ltc, frames, seconds, minutes, hours; unsigned int period; u64 freq_const = 0; u32 rate; + snd_iprintf(buffer, "--- TCO ---\n"); + status = hdspm_read(hdspm, HDSPM_statusRegister); - status2 = hdspm_read(hdspm, HDSPM_statusRegister2); control = hdspm->control_register; - freq = hdspm_read(hdspm, HDSPM_timecodeRegister); - - snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", - hdspm->card_name, hdspm->card->number + 1, - hdspm->firmware_rev, - (status2 & HDSPM_version0) | - (status2 & HDSPM_version1) | (status2 & - HDSPM_version2)); - snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", - (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, - hdspm->serial); - - snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", - hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); - snd_iprintf(buffer, "--- System ---\n"); - - snd_iprintf(buffer, - "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", - status & HDSPM_audioIRQPending, - (status & HDSPM_midi0IRQPending) ? 1 : 0, - (status & HDSPM_midi1IRQPending) ? 1 : 0, - hdspm->irq_count); - snd_iprintf(buffer, - "HW pointer: id = %d, rawptr = %d (%d->%d) " - "estimated= %ld (bytes)\n", - ((status & HDSPM_BufferID) ? 1 : 0), - (status & HDSPM_BufferPositionMask), - (status & HDSPM_BufferPositionMask) % - (2 * (int)hdspm->period_bytes), - ((status & HDSPM_BufferPositionMask) - 64) % - (2 * (int)hdspm->period_bytes), - (long) hdspm_hw_pointer(hdspm) * 4); - - snd_iprintf(buffer, - "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); - snd_iprintf(buffer, - "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", - hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, - hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); - snd_iprintf(buffer, - "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " - "status2=0x%x\n", - hdspm->control_register, hdspm->control2_register, - status, status2); if (status & HDSPM_tco_detect) { snd_iprintf(buffer, "TCO module detected.\n"); a = hdspm_read(hdspm, HDSPM_RD_TCO+4); @@ -4835,6 +4866,75 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, } else { snd_iprintf(buffer, "No TCO module detected.\n"); } +} + +static void +snd_hdspm_proc_read_madi(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdspm *hdspm = entry->private_data; + unsigned int status, status2, control, freq; + + char *pref_sync_ref; + char *autosync_ref; + char *system_clock_mode; + char *insel; + int x, x2; + + status = hdspm_read(hdspm, HDSPM_statusRegister); + status2 = hdspm_read(hdspm, HDSPM_statusRegister2); + control = hdspm->control_register; + freq = hdspm_read(hdspm, HDSPM_timecodeRegister); + + snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n", + hdspm->card_name, hdspm->card->number + 1, + hdspm->firmware_rev, + (status2 & HDSPM_version0) | + (status2 & HDSPM_version1) | (status2 & + HDSPM_version2)); + + snd_iprintf(buffer, "HW Serial: 0x%06x%06x\n", + (hdspm_read(hdspm, HDSPM_midiStatusIn1)>>8) & 0xFFFFFF, + hdspm->serial); + + snd_iprintf(buffer, "IRQ: %d Registers bus: 0x%lx VM: 0x%lx\n", + hdspm->irq, hdspm->port, (unsigned long)hdspm->iobase); + + snd_iprintf(buffer, "--- System ---\n"); + + snd_iprintf(buffer, + "IRQ Pending: Audio=%d, MIDI0=%d, MIDI1=%d, IRQcount=%d\n", + status & HDSPM_audioIRQPending, + (status & HDSPM_midi0IRQPending) ? 1 : 0, + (status & HDSPM_midi1IRQPending) ? 1 : 0, + hdspm->irq_count); + snd_iprintf(buffer, + "HW pointer: id = %d, rawptr = %d (%d->%d) " + "estimated= %ld (bytes)\n", + ((status & HDSPM_BufferID) ? 1 : 0), + (status & HDSPM_BufferPositionMask), + (status & HDSPM_BufferPositionMask) % + (2 * (int)hdspm->period_bytes), + ((status & HDSPM_BufferPositionMask) - 64) % + (2 * (int)hdspm->period_bytes), + (long) hdspm_hw_pointer(hdspm) * 4); + + snd_iprintf(buffer, + "MIDI FIFO: Out1=0x%x, Out2=0x%x, In1=0x%x, In2=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusOut0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut1) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn0) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusIn1) & 0xFF); + snd_iprintf(buffer, + "MIDIoverMADI FIFO: In=0x%x, Out=0x%x \n", + hdspm_read(hdspm, HDSPM_midiStatusIn2) & 0xFF, + hdspm_read(hdspm, HDSPM_midiStatusOut2) & 0xFF); + snd_iprintf(buffer, + "Register: ctrl1=0x%x, ctrl2=0x%x, status1=0x%x, " + "status2=0x%x\n", + hdspm->control_register, hdspm->control2_register, + status, status2); + snd_iprintf(buffer, "--- Settings ---\n"); @@ -4855,7 +4955,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, insel = "Coaxial"; break; default: - insel = "Unkown"; + insel = "Unknown"; } snd_iprintf(buffer, @@ -4938,6 +5038,9 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, (status & HDSPM_RX_64ch) ? "64 channels" : "56 channels"); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } @@ -4949,6 +5052,7 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, unsigned int status; unsigned int status2; unsigned int timecode; + unsigned int wcLock, wcSync; int pref_syncref; char *autosync_ref; int x; @@ -5042,8 +5146,11 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, snd_iprintf(buffer, "--- Status:\n"); + wcLock = status & HDSPM_AES32_wcLock; + wcSync = wcLock && (status & HDSPM_AES32_wcSync); + snd_iprintf(buffer, "Word: %s Frequency: %d\n", - (status & HDSPM_AES32_wcLock) ? "Sync " : "No Lock", + (wcLock) ? (wcSync ? "Sync " : "Lock ") : "No Lock", HDSPM_bit2freq((status >> HDSPM_AES32_wcFreq_bit) & 0xF)); for (x = 0; x < 8; x++) { @@ -5075,11 +5182,18 @@ snd_hdspm_proc_read_aes32(struct snd_info_entry * entry, autosync_ref = "AES7"; break; case HDSPM_AES32_AUTOSYNC_FROM_AES8: autosync_ref = "AES8"; break; + case HDSPM_AES32_AUTOSYNC_FROM_TCO: + autosync_ref = "TCO"; break; + case HDSPM_AES32_AUTOSYNC_FROM_SYNC_IN: + autosync_ref = "Sync In"; break; default: autosync_ref = "---"; break; } snd_iprintf(buffer, "AutoSync ref = %s\n", autosync_ref); + /* call readout function for TCO specific status */ + snd_hdspm_proc_read_tco(entry, buffer); + snd_iprintf(buffer, "\n"); } @@ -5188,7 +5302,7 @@ static void snd_hdspm_proc_ports_out(struct snd_info_entry *entry, } -static void __devinit snd_hdspm_proc_init(struct hdspm *hdspm) +static void snd_hdspm_proc_init(struct hdspm *hdspm) { struct snd_info_entry *entry; @@ -5263,7 +5377,7 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) case AES32: hdspm->control_register = - HDSPM_ClockModeMaster | /* Master Cloack Mode on */ + HDSPM_ClockModeMaster | /* Master Clock Mode on */ hdspm_encode_latency(7) | /* latency max=8192samples */ HDSPM_SyncRef0 | /* AES1 is syncclock */ HDSPM_LineOut | /* Analog output in */ @@ -5289,9 +5403,8 @@ static int snd_hdspm_set_defaults(struct hdspm * hdspm) all_in_all_mixer(hdspm, 0 * UNITY_GAIN); - if (hdspm->io_type == AIO || hdspm->io_type == RayDAT) { + if (hdspm_is_raydat_or_aio(hdspm)) hdspm_write(hdspm, HDSPM_WR_SETTINGS, hdspm->settings_register); - } /* set a default rate so that the channel map is set up. */ hdspm_set_rate(hdspm, 48000, 1); @@ -5329,7 +5442,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id) * 0 64 ~3998231 ~8191558 **/ /* - snd_printk(KERN_INFO "snd_hdspm_interrupt %llu @ %llx\n", + dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n", now-hdspm->last_interrupt, status & 0xFFC0); hdspm->last_interrupt = now; */ @@ -5466,7 +5579,7 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, spin_lock_irq(&hdspm->lock); err = hdspm_set_rate(hdspm, params_rate(params), 0); if (err < 0) { - snd_printk(KERN_INFO "err on hdspm_set_rate: %d\n", err); + dev_info(hdspm->card->dev, "err on hdspm_set_rate: %d\n", err); spin_unlock_irq(&hdspm->lock); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_RATE); @@ -5477,7 +5590,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, err = hdspm_set_interrupt_interval(hdspm, params_period_size(params)); if (err < 0) { - snd_printk(KERN_INFO "err on hdspm_set_interrupt_interval: %d\n", err); + dev_info(hdspm->card->dev, + "err on hdspm_set_interrupt_interval: %d\n", err); _snd_pcm_hw_param_setempty(params, SNDRV_PCM_HW_PARAM_PERIOD_SIZE); return err; @@ -5493,7 +5607,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, HDSPM_DMA_AREA_BYTES); if (err < 0) { - snd_printk(KERN_INFO "err on snd_pcm_lib_malloc_pages: %d\n", err); + dev_info(hdspm->card->dev, + "err on snd_pcm_lib_malloc_pages: %d\n", err); return err; } @@ -5507,7 +5622,8 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->playback_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for playback at %p\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for playback at %p\n", hdspm->playback_buffer); } else { hdspm_set_sgbuf(hdspm, substream, HDSPM_pageAddressBufferIn, @@ -5518,18 +5634,21 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, hdspm->capture_buffer = (unsigned char *) substream->runtime->dma_area; - snd_printdd("Allocated sample buffer for capture at %p\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for capture at %p\n", hdspm->capture_buffer); } /* - snd_printdd("Allocated sample buffer for %s at 0x%08X\n", + dev_dbg(hdspm->card->dev, + "Allocated sample buffer for %s at 0x%08X\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture", snd_pcm_sgbuf_get_addr(substream, 0)); */ /* - snd_printdd("set_hwparams: %s %d Hz, %d channels, bs = %d\n", + dev_dbg(hdspm->card->dev, + "set_hwparams: %s %d Hz, %d channels, bs = %d\n", substream->stream == SNDRV_PCM_STREAM_PLAYBACK ? "playback" : "capture", params_rate(params), params_channels(params), @@ -5537,15 +5656,27 @@ static int snd_hdspm_hw_params(struct snd_pcm_substream *substream, */ + /* For AES cards, the float format bit is the same as the + * preferred sync reference. Since we don't want to break + * sync settings, we have to skip the remaining part of this + * function. + */ + if (hdspm->io_type == AES32) { + return 0; + } + + /* Switch to native float format if requested */ if (SNDRV_PCM_FORMAT_FLOAT_LE == params_format(params)) { if (!(hdspm->control_register & HDSPe_FLOAT_FORMAT)) - snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE float format.\n"); + dev_info(hdspm->card->dev, + "Switching to native 32bit LE float format.\n"); hdspm->control_register |= HDSPe_FLOAT_FORMAT; } else if (SNDRV_PCM_FORMAT_S32_LE == params_format(params)) { if (hdspm->control_register & HDSPe_FLOAT_FORMAT) - snd_printk(KERN_INFO "hdspm: Switching to native 32bit LE integer format.\n"); + dev_info(hdspm->card->dev, + "Switching to native 32bit LE integer format.\n"); hdspm->control_register &= ~HDSPe_FLOAT_FORMAT; } @@ -5588,12 +5719,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (snd_BUG_ON(info->channel >= hdspm->max_channels_out)) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel out of range (%d)\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: output channel out of range (%d)\n", + info->channel); return -EINVAL; } if (hdspm->channel_map_out[info->channel] < 0) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: output channel %d mapped out\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: output channel %d mapped out\n", + info->channel); return -EINVAL; } @@ -5601,12 +5736,16 @@ static int snd_hdspm_channel_info(struct snd_pcm_substream *substream, HDSPM_CHANNEL_BUFFER_BYTES; } else { if (snd_BUG_ON(info->channel >= hdspm->max_channels_in)) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel out of range (%d)\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: input channel out of range (%d)\n", + info->channel); return -EINVAL; } if (hdspm->channel_map_in[info->channel] < 0) { - snd_printk(KERN_INFO "snd_hdspm_channel_info: input channel %d mapped out\n", info->channel); + dev_info(hdspm->card->dev, + "snd_hdspm_channel_info: input channel %d mapped out\n", + info->channel); return -EINVAL; } @@ -6156,7 +6295,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, s = copy_to_user(argp, levels, sizeof(struct hdspm_peak_rms)); if (0 != s) { - /* snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu + /* dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [Levels]\n", sizeof(struct hdspm_peak_rms), s); */ return -EFAULT; @@ -6179,7 +6318,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, ltc.format = fps_2997; break; default: - ltc.format = 30; + ltc.format = fps_30; break; } if (i & HDSPM_TCO1_set_drop_frame_flag) { @@ -6202,7 +6341,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, s = copy_to_user(argp, <c, sizeof(struct hdspm_ltc)); if (0 != s) { /* - snd_printk(KERN_ERR "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ + dev_err(hdspm->card->dev, "copy_to_user(.., .., %lu): %lu [LTC]\n", sizeof(struct hdspm_ltc), s); */ return -EFAULT; } @@ -6221,7 +6360,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, info.system_clock_mode = hdspm_system_clock_mode(hdspm); info.clock_source = hdspm_clock_source(hdspm); info.autosync_ref = hdspm_autosync_ref(hdspm); - info.line_out = hdspm_line_out(hdspm); + info.line_out = hdspm_toggle_setting(hdspm, HDSPM_LineOut); info.passthru = 0; spin_unlock_irq(&hdspm->lock); if (copy_to_user(argp, &info, sizeof(info))) @@ -6273,7 +6412,7 @@ static int snd_hdspm_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, memset(&hdspm_version, 0, sizeof(hdspm_version)); hdspm_version.card_type = hdspm->io_type; - strncpy(hdspm_version.cardname, hdspm->card_name, + strlcpy(hdspm_version.cardname, hdspm->card_name, sizeof(hdspm_version.cardname)); hdspm_version.serial = hdspm->serial; hdspm_version.firmware_rev = hdspm->firmware_rev; @@ -6324,8 +6463,8 @@ static struct snd_pcm_ops snd_hdspm_capture_ops = { .page = snd_pcm_sgbuf_ops_page, }; -static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, - struct hdspm * hdspm) +static int snd_hdspm_create_hwdep(struct snd_card *card, + struct hdspm *hdspm) { struct snd_hwdep *hw; int err; @@ -6350,7 +6489,7 @@ static int __devinit snd_hdspm_create_hwdep(struct snd_card *card, /*------------------------------------------------------------ memory interface ------------------------------------------------------------*/ -static int __devinit snd_hdspm_preallocate_memory(struct hdspm *hdspm) +static int snd_hdspm_preallocate_memory(struct hdspm *hdspm) { int err; struct snd_pcm *pcm; @@ -6367,11 +6506,13 @@ static int __devinit snd_hdspm_preallocate_memory(struct hdspm *hdspm) wanted, wanted); if (err < 0) { - snd_printdd("Could not preallocate %zd Bytes\n", wanted); + dev_dbg(hdspm->card->dev, + "Could not preallocate %zd Bytes\n", wanted); return err; } else - snd_printdd(" Preallocated %zd Bytes\n", wanted); + dev_dbg(hdspm->card->dev, + " Preallocated %zd Bytes\n", wanted); return 0; } @@ -6391,8 +6532,8 @@ static void hdspm_set_sgbuf(struct hdspm *hdspm, /* ------------- ALSA Devices ---------------------------- */ -static int __devinit snd_hdspm_create_pcm(struct snd_card *card, - struct hdspm *hdspm) +static int snd_hdspm_create_pcm(struct snd_card *card, + struct hdspm *hdspm) { struct snd_pcm *pcm; int err; @@ -6427,12 +6568,12 @@ static inline void snd_hdspm_initialize_midi_flush(struct hdspm * hdspm) snd_hdspm_flush_midi_input(hdspm, i); } -static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, - struct hdspm * hdspm) +static int snd_hdspm_create_alsa_devices(struct snd_card *card, + struct hdspm *hdspm) { int err, i; - snd_printdd("Create card...\n"); + dev_dbg(card->dev, "Create card...\n"); err = snd_hdspm_create_pcm(card, hdspm); if (err < 0) return err; @@ -6454,7 +6595,7 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, if (err < 0) return err; - snd_printdd("proc init...\n"); + dev_dbg(card->dev, "proc init...\n"); snd_hdspm_proc_init(hdspm); hdspm->system_sample_rate = -1; @@ -6465,29 +6606,30 @@ static int __devinit snd_hdspm_create_alsa_devices(struct snd_card *card, hdspm->capture_substream = NULL; hdspm->playback_substream = NULL; - snd_printdd("Set defaults...\n"); + dev_dbg(card->dev, "Set defaults...\n"); err = snd_hdspm_set_defaults(hdspm); if (err < 0) return err; - snd_printdd("Update mixer controls...\n"); + dev_dbg(card->dev, "Update mixer controls...\n"); hdspm_update_simple_mixer_controls(hdspm); - snd_printdd("Initializeing complete ???\n"); + dev_dbg(card->dev, "Initializeing complete ???\n"); err = snd_card_register(card); if (err < 0) { - snd_printk(KERN_ERR "HDSPM: error registering card\n"); + dev_err(card->dev, "error registering card\n"); return err; } - snd_printdd("... yes now\n"); + dev_dbg(card->dev, "... yes now\n"); return 0; } -static int __devinit snd_hdspm_create(struct snd_card *card, - struct hdspm *hdspm) { +static int snd_hdspm_create(struct snd_card *card, + struct hdspm *hdspm) +{ struct pci_dev *pci = hdspm->pci; int err; @@ -6534,8 +6676,8 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->card_name = "RME MADI"; hdspm->midiPorts = 3; } else { - snd_printk(KERN_ERR - "HDSPM: unknown firmware revision %x\n", + dev_err(card->dev, + "unknown firmware revision %x\n", hdspm->firmware_rev); return -ENODEV; } @@ -6554,36 +6696,35 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->port = pci_resource_start(pci, 0); io_extent = pci_resource_len(pci, 0); - snd_printdd("grabbed memory region 0x%lx-0x%lx\n", + dev_dbg(card->dev, "grabbed memory region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); hdspm->iobase = ioremap_nocache(hdspm->port, io_extent); if (!hdspm->iobase) { - snd_printk(KERN_ERR "HDSPM: " - "unable to remap region 0x%lx-0x%lx\n", + dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n", hdspm->port, hdspm->port + io_extent - 1); return -EBUSY; } - snd_printdd("remapped region (0x%lx) 0x%lx-0x%lx\n", + dev_dbg(card->dev, "remapped region (0x%lx) 0x%lx-0x%lx\n", (unsigned long)hdspm->iobase, hdspm->port, hdspm->port + io_extent - 1); if (request_irq(pci->irq, snd_hdspm_interrupt, IRQF_SHARED, KBUILD_MODNAME, hdspm)) { - snd_printk(KERN_ERR "HDSPM: unable to use IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to use IRQ %d\n", pci->irq); return -EBUSY; } - snd_printdd("use IRQ %d\n", pci->irq); + dev_dbg(card->dev, "use IRQ %d\n", pci->irq); hdspm->irq = pci->irq; - snd_printdd("kmalloc Mixer memory of %zd Bytes\n", + dev_dbg(card->dev, "kmalloc Mixer memory of %zd Bytes\n", sizeof(struct hdspm_mixer)); hdspm->mixer = kzalloc(sizeof(struct hdspm_mixer), GFP_KERNEL); if (!hdspm->mixer) { - snd_printk(KERN_ERR "HDSPM: " - "unable to kmalloc Mixer memory of %d Bytes\n", + dev_err(card->dev, + "unable to kmalloc Mixer memory of %d Bytes\n", (int)sizeof(struct hdspm_mixer)); return -ENOMEM; } @@ -6644,10 +6785,6 @@ static int __devinit snd_hdspm_create(struct snd_card *card, break; case AIO: - if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { - snd_printk(KERN_INFO "HDSPM: AEB input board found, but not supported\n"); - } - hdspm->ss_in_channels = AIO_IN_SS_CHANNELS; hdspm->ds_in_channels = AIO_IN_DS_CHANNELS; hdspm->qs_in_channels = AIO_IN_QS_CHANNELS; @@ -6655,6 +6792,20 @@ static int __devinit snd_hdspm_create(struct snd_card *card, hdspm->ds_out_channels = AIO_OUT_DS_CHANNELS; hdspm->qs_out_channels = AIO_OUT_QS_CHANNELS; + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBI_D)) { + dev_info(card->dev, "AEB input board found\n"); + hdspm->ss_in_channels += 4; + hdspm->ds_in_channels += 4; + hdspm->qs_in_channels += 4; + } + + if (0 == (hdspm_read(hdspm, HDSPM_statusRegister2) & HDSPM_s2_AEBO_D)) { + dev_info(card->dev, "AEB output board found\n"); + hdspm->ss_out_channels += 4; + hdspm->ds_out_channels += 4; + hdspm->qs_out_channels += 4; + } + hdspm->channel_map_out_ss = channel_map_aio_out_ss; hdspm->channel_map_out_ds = channel_map_aio_out_ds; hdspm->channel_map_out_qs = channel_map_aio_out_qs; @@ -6716,13 +6867,14 @@ static int __devinit snd_hdspm_create(struct snd_card *card, if (NULL != hdspm->tco) { hdspm_tco_write(hdspm); } - snd_printk(KERN_INFO "HDSPM: AIO/RayDAT TCO module found\n"); + dev_info(card->dev, "AIO/RayDAT TCO module found\n"); } else { hdspm->tco = NULL; } break; case MADI: + case AES32: if (hdspm_read(hdspm, HDSPM_statusRegister) & HDSPM_tco_detect) { hdspm->midiPorts++; hdspm->tco = kzalloc(sizeof(struct hdspm_tco), @@ -6730,7 +6882,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card, if (NULL != hdspm->tco) { hdspm_tco_write(hdspm); } - snd_printk(KERN_INFO "HDSPM: MADI TCO module found\n"); + dev_info(card->dev, "MADI/AES TCO module found\n"); } else { hdspm->tco = NULL; } @@ -6745,10 +6897,12 @@ static int __devinit snd_hdspm_create(struct snd_card *card, case AES32: if (hdspm->tco) { hdspm->texts_autosync = texts_autosync_aes_tco; - hdspm->texts_autosync_items = 10; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes_tco); } else { hdspm->texts_autosync = texts_autosync_aes; - hdspm->texts_autosync_items = 9; + hdspm->texts_autosync_items = + ARRAY_SIZE(texts_autosync_aes); } break; @@ -6810,7 +6964,7 @@ static int __devinit snd_hdspm_create(struct snd_card *card, } } - snd_printdd("create alsa devices.\n"); + dev_dbg(card->dev, "create alsa devices.\n"); err = snd_hdspm_create_alsa_devices(card, hdspm); if (err < 0) return err; @@ -6860,8 +7014,8 @@ static void snd_hdspm_card_free(struct snd_card *card) } -static int __devinit snd_hdspm_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_hdspm_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct hdspm *hdspm; @@ -6875,8 +7029,8 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], - THIS_MODULE, sizeof(struct hdspm), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], + THIS_MODULE, sizeof(struct hdspm), &card); if (err < 0) return err; @@ -6885,8 +7039,6 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, hdspm->dev = dev; hdspm->pci = pci; - snd_card_set_dev(card, &pci->dev); - err = snd_hdspm_create(card, hdspm); if (err < 0) { snd_card_free(card); @@ -6919,17 +7071,16 @@ static int __devinit snd_hdspm_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_hdspm_remove(struct pci_dev *pci) +static void snd_hdspm_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver hdspm_driver = { .name = KBUILD_MODNAME, .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, - .remove = __devexit_p(snd_hdspm_remove), + .remove = snd_hdspm_remove, }; module_pci_driver(hdspm_driver); diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index a15fc100ab0..1d9be90f774 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c @@ -285,7 +285,7 @@ static char channel_map_9636_ds[26] = { /* ADAT channels are remapped */ 1, 3, 5, 7, 9, 11, 13, 15, /* channels 8 and 9 are S/PDIF */ - 24, 25 + 24, 25, /* others don't exist */ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; @@ -294,10 +294,6 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer { dmab->dev.type = SNDRV_DMA_TYPE_DEV; dmab->dev.dev = snd_dma_pci_data(pci); - if (snd_dma_get_reserved_buf(dmab, snd_dma_pci_buf_id(pci))) { - if (dmab->bytes >= size) - return 0; - } if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(pci), size, dmab) < 0) return -ENOMEM; @@ -306,10 +302,8 @@ static int snd_hammerfall_get_buffer(struct pci_dev *pci, struct snd_dma_buffer static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_dev *pci) { - if (dmab->area) { - dmab->dev.dev = NULL; /* make it anonymous */ - snd_dma_reserve_buf(dmab, snd_dma_pci_buf_id(pci)); - } + if (dmab->area) + snd_dma_free_pages(dmab); } @@ -400,7 +394,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652) if (offset < period_size) { if (offset > rme9652->max_jitter) { if (frag) - printk(KERN_ERR "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", status, offset); + dev_err(rme9652->card->dev, + "Unexpected hw_pointer position (bufid == 0): status: %x offset: %d\n", + status, offset); } else if (!frag) return 0; offset -= rme9652->max_jitter; @@ -409,7 +405,9 @@ static snd_pcm_uframes_t rme9652_hw_pointer(struct snd_rme9652 *rme9652) } else { if (offset > period_size + rme9652->max_jitter) { if (!frag) - printk(KERN_ERR "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", status, offset); + dev_err(rme9652->card->dev, + "Unexpected hw_pointer position (bufid == 1): status: %x offset: %d\n", + status, offset); } else if (frag) return period_size; offset -= rme9652->max_jitter; @@ -775,7 +773,8 @@ static inline int rme9652_spdif_sample_rate(struct snd_rme9652 *s) break; default: - snd_printk(KERN_ERR "%s: unknown S/PDIF input rate (bits = 0x%x)\n", + dev_err(s->card->dev, + "%s: unknown S/PDIF input rate (bits = 0x%x)\n", s->card_name, rate_bits); return 0; break; @@ -1757,7 +1756,7 @@ snd_rme9652_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buff snd_iprintf(buffer, "\n"); } -static void __devinit snd_rme9652_proc_init(struct snd_rme9652 *rme9652) +static void snd_rme9652_proc_init(struct snd_rme9652 *rme9652) { struct snd_info_entry *entry; @@ -1788,7 +1787,7 @@ static int snd_rme9652_free(struct snd_rme9652 *rme9652) return 0; } -static int __devinit snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) +static int snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) { unsigned long pb_bus, cb_bus; @@ -1796,7 +1795,8 @@ static int __devinit snd_rme9652_initialize_memory(struct snd_rme9652 *rme9652) snd_hammerfall_get_buffer(rme9652->pci, &rme9652->playback_dma_buf, RME9652_DMA_AREA_BYTES) < 0) { if (rme9652->capture_dma_buf.area) snd_dma_free_pages(&rme9652->capture_dma_buf); - printk(KERN_ERR "%s: no buffers available\n", rme9652->card_name); + dev_err(rme9652->card->dev, + "%s: no buffers available\n", rme9652->card_name); return -ENOMEM; } @@ -2414,8 +2414,8 @@ static struct snd_pcm_ops snd_rme9652_capture_ops = { .copy = snd_rme9652_capture_copy, }; -static int __devinit snd_rme9652_create_pcm(struct snd_card *card, - struct snd_rme9652 *rme9652) +static int snd_rme9652_create_pcm(struct snd_card *card, + struct snd_rme9652 *rme9652) { struct snd_pcm *pcm; int err; @@ -2438,9 +2438,9 @@ static int __devinit snd_rme9652_create_pcm(struct snd_card *card, return 0; } -static int __devinit snd_rme9652_create(struct snd_card *card, - struct snd_rme9652 *rme9652, - int precise_ptr) +static int snd_rme9652_create(struct snd_card *card, + struct snd_rme9652 *rme9652, + int precise_ptr) { struct pci_dev *pci = rme9652->pci; int err; @@ -2474,13 +2474,14 @@ static int __devinit snd_rme9652_create(struct snd_card *card, rme9652->port = pci_resource_start(pci, 0); rme9652->iobase = ioremap_nocache(rme9652->port, RME9652_IO_EXTENT); if (rme9652->iobase == NULL) { - snd_printk(KERN_ERR "unable to remap region 0x%lx-0x%lx\n", rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1); + dev_err(card->dev, "unable to remap region 0x%lx-0x%lx\n", + rme9652->port, rme9652->port + RME9652_IO_EXTENT - 1); return -EBUSY; } if (request_irq(pci->irq, snd_rme9652_interrupt, IRQF_SHARED, KBUILD_MODNAME, rme9652)) { - snd_printk(KERN_ERR "unable to request IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to request IRQ %d\n", pci->irq); return -EBUSY; } rme9652->irq = pci->irq; @@ -2578,8 +2579,8 @@ static void snd_rme9652_card_free(struct snd_card *card) snd_rme9652_free(rme9652); } -static int __devinit snd_rme9652_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_rme9652_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_rme9652 *rme9652; @@ -2593,8 +2594,8 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_rme9652), &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + sizeof(struct snd_rme9652), &card); if (err < 0) return err; @@ -2603,7 +2604,6 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci, card->private_free = snd_rme9652_card_free; rme9652->dev = dev; rme9652->pci = pci; - snd_card_set_dev(card, &pci->dev); if ((err = snd_rme9652_create(card, rme9652, precise_ptr[dev])) < 0) { snd_card_free(card); @@ -2625,17 +2625,16 @@ static int __devinit snd_rme9652_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_rme9652_remove(struct pci_dev *pci) +static void snd_rme9652_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver rme9652_driver = { .name = KBUILD_MODNAME, .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, - .remove = __devexit_p(snd_rme9652_remove), + .remove = snd_rme9652_remove, }; module_pci_driver(rme9652_driver); diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 51e43407ebc..6b26b93e001 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c @@ -894,7 +894,7 @@ static struct snd_pcm_ops sis_capture_ops = { .pointer = sis_pcm_pointer, }; -static int __devinit sis_pcm_create(struct sis7019 *sis) +static int sis_pcm_create(struct sis7019 *sis) { struct snd_pcm *pcm; int rc; @@ -1013,7 +1013,7 @@ static unsigned short sis_ac97_read(struct snd_ac97 *ac97, unsigned short reg) (reg << 8) | cmd[ac97->num]); } -static int __devinit sis_mixer_create(struct sis7019 *sis) +static int sis_mixer_create(struct sis7019 *sis) { struct snd_ac97_bus *bus; struct snd_ac97_template ac97; @@ -1171,7 +1171,7 @@ static int sis_chip_init(struct sis7019 *sis) outl(SIS_DMA_CSR_PCI_SETTINGS, io + SIS_DMA_CSR); /* Reset the synchronization groups for all of the channels - * to be asyncronous. If we start doing SPDIF or 5.1 sound, etc. + * to be asynchronous. If we start doing SPDIF or 5.1 sound, etc. * we'll need to change how we handle these. Until then, we just * assign sub-mixer 0 to all playback channels, and avoid any * attenuation on the audio. @@ -1326,8 +1326,8 @@ static int sis_alloc_suspend(struct sis7019 *sis) return 0; } -static int __devinit sis_chip_create(struct snd_card *card, - struct pci_dev *pci) +static int sis_chip_create(struct snd_card *card, + struct pci_dev *pci) { struct sis7019 *sis = card->private_data; struct voice *voice; @@ -1341,7 +1341,8 @@ static int __devinit sis_chip_create(struct snd_card *card, if (rc) goto error_out; - if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0) { + rc = pci_set_dma_mask(pci, DMA_BIT_MASK(30)); + if (rc < 0) { dev_err(&pci->dev, "architecture does not support 30-bit PCI busmaster DMA"); goto error_out_enabled; } @@ -1403,8 +1404,6 @@ static int __devinit sis_chip_create(struct snd_card *card, if (rc) goto error_out_cleanup; - snd_card_set_dev(card, &pci->dev); - return 0; error_out_cleanup: @@ -1417,8 +1416,8 @@ error_out: return rc; } -static int __devinit snd_sis7019_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_sis7019_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct sis7019 *sis; @@ -1439,7 +1438,8 @@ static int __devinit snd_sis7019_probe(struct pci_dev *pci, if (!codecs) codecs = SIS_PRIMARY_CODEC_PRESENT; - rc = snd_card_create(index, id, THIS_MODULE, sizeof(*sis), &card); + rc = snd_card_new(&pci->dev, index, id, THIS_MODULE, + sizeof(*sis), &card); if (rc < 0) goto error_out; @@ -1478,17 +1478,16 @@ error_out: return rc; } -static void __devexit snd_sis7019_remove(struct pci_dev *pci) +static void snd_sis7019_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver sis7019_driver = { .name = KBUILD_MODNAME, .id_table = snd_sis7019_ids, .probe = snd_sis7019_probe, - .remove = __devexit_p(snd_sis7019_remove), + .remove = snd_sis7019_remove, .driver = { .pm = SIS_PM_OPS, }, diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index baa9946bedf..2044dc74207 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c @@ -273,7 +273,7 @@ static inline void snd_sonicvibes_setdmaa(struct sonicvibes * sonic, outl(count, sonic->dmaa_port + SV_DMA_COUNT0); outb(0x18, sonic->dmaa_port + SV_DMA_MODE); #if 0 - printk(KERN_DEBUG "program dmaa: addr = 0x%x, paddr = 0x%x\n", + dev_dbg(sonic->card->dev, "program dmaa: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmaa_port + SV_DMA_ADDR0)); #endif } @@ -289,7 +289,7 @@ static inline void snd_sonicvibes_setdmac(struct sonicvibes * sonic, outl(count, sonic->dmac_port + SV_DMA_COUNT0); outb(0x14, sonic->dmac_port + SV_DMA_MODE); #if 0 - printk(KERN_DEBUG "program dmac: addr = 0x%x, paddr = 0x%x\n", + dev_dbg(sonic->card->dev, "program dmac: addr = 0x%x, paddr = 0x%x\n", addr, inl(sonic->dmac_port + SV_DMA_ADDR0)); #endif } @@ -357,105 +357,105 @@ static unsigned char snd_sonicvibes_in(struct sonicvibes * sonic, unsigned char #if 0 static void snd_sonicvibes_debug(struct sonicvibes * sonic) { - printk(KERN_DEBUG - "SV REGS: INDEX = 0x%02x ", inb(SV_REG(sonic, INDEX))); - printk(" STATUS = 0x%02x\n", inb(SV_REG(sonic, STATUS))); - printk(KERN_DEBUG - " 0x00: left input = 0x%02x ", snd_sonicvibes_in(sonic, 0x00)); - printk(" 0x20: synth rate low = 0x%02x\n", snd_sonicvibes_in(sonic, 0x20)); - printk(KERN_DEBUG - " 0x01: right input = 0x%02x ", snd_sonicvibes_in(sonic, 0x01)); - printk(" 0x21: synth rate high = 0x%02x\n", snd_sonicvibes_in(sonic, 0x21)); - printk(KERN_DEBUG - " 0x02: left AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x02)); - printk(" 0x22: ADC clock = 0x%02x\n", snd_sonicvibes_in(sonic, 0x22)); - printk(KERN_DEBUG - " 0x03: right AUX1 = 0x%02x ", snd_sonicvibes_in(sonic, 0x03)); - printk(" 0x23: ADC alt rate = 0x%02x\n", snd_sonicvibes_in(sonic, 0x23)); - printk(KERN_DEBUG - " 0x04: left CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x04)); - printk(" 0x24: ADC pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x24)); - printk(KERN_DEBUG - " 0x05: right CD = 0x%02x ", snd_sonicvibes_in(sonic, 0x05)); - printk(" 0x25: ADC pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x25)); - printk(KERN_DEBUG - " 0x06: left line = 0x%02x ", snd_sonicvibes_in(sonic, 0x06)); - printk(" 0x26: Synth pll M = 0x%02x\n", snd_sonicvibes_in(sonic, 0x26)); - printk(KERN_DEBUG - " 0x07: right line = 0x%02x ", snd_sonicvibes_in(sonic, 0x07)); - printk(" 0x27: Synth pll N = 0x%02x\n", snd_sonicvibes_in(sonic, 0x27)); - printk(KERN_DEBUG - " 0x08: MIC = 0x%02x ", snd_sonicvibes_in(sonic, 0x08)); - printk(" 0x28: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x28)); - printk(KERN_DEBUG - " 0x09: Game port = 0x%02x ", snd_sonicvibes_in(sonic, 0x09)); - printk(" 0x29: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x29)); - printk(KERN_DEBUG - " 0x0a: left synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0a)); - printk(" 0x2a: MPU401 = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2a)); - printk(KERN_DEBUG - " 0x0b: right synth = 0x%02x ", snd_sonicvibes_in(sonic, 0x0b)); - printk(" 0x2b: drive ctrl = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2b)); - printk(KERN_DEBUG - " 0x0c: left AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0c)); - printk(" 0x2c: SRS space = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2c)); - printk(KERN_DEBUG - " 0x0d: right AUX2 = 0x%02x ", snd_sonicvibes_in(sonic, 0x0d)); - printk(" 0x2d: SRS center = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2d)); - printk(KERN_DEBUG - " 0x0e: left analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0e)); - printk(" 0x2e: wave source = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2e)); - printk(KERN_DEBUG - " 0x0f: right analog = 0x%02x ", snd_sonicvibes_in(sonic, 0x0f)); - printk(" 0x2f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x2f)); - printk(KERN_DEBUG - " 0x10: left PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x10)); - printk(" 0x30: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x30)); - printk(KERN_DEBUG - " 0x11: right PCM = 0x%02x ", snd_sonicvibes_in(sonic, 0x11)); - printk(" 0x31: analog power = 0x%02x\n", snd_sonicvibes_in(sonic, 0x31)); - printk(KERN_DEBUG - " 0x12: DMA data format = 0x%02x ", snd_sonicvibes_in(sonic, 0x12)); - printk(" 0x32: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x32)); - printk(KERN_DEBUG - " 0x13: P/C enable = 0x%02x ", snd_sonicvibes_in(sonic, 0x13)); - printk(" 0x33: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x33)); - printk(KERN_DEBUG - " 0x14: U/D button = 0x%02x ", snd_sonicvibes_in(sonic, 0x14)); - printk(" 0x34: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x34)); - printk(KERN_DEBUG - " 0x15: revision = 0x%02x ", snd_sonicvibes_in(sonic, 0x15)); - printk(" 0x35: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x35)); - printk(KERN_DEBUG - " 0x16: ADC output ctrl = 0x%02x ", snd_sonicvibes_in(sonic, 0x16)); - printk(" 0x36: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x36)); - printk(KERN_DEBUG - " 0x17: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x17)); - printk(" 0x37: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x37)); - printk(KERN_DEBUG - " 0x18: DMA A upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x18)); - printk(" 0x38: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x38)); - printk(KERN_DEBUG - " 0x19: DMA A lower cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x19)); - printk(" 0x39: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x39)); - printk(KERN_DEBUG - " 0x1a: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1a)); - printk(" 0x3a: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3a)); - printk(KERN_DEBUG - " 0x1b: --- = 0x%02x ", snd_sonicvibes_in(sonic, 0x1b)); - printk(" 0x3b: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3b)); - printk(KERN_DEBUG - " 0x1c: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1c)); - printk(" 0x3c: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3c)); - printk(KERN_DEBUG - " 0x1d: DMA C upper cnt = 0x%02x ", snd_sonicvibes_in(sonic, 0x1d)); - printk(" 0x3d: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3d)); - printk(KERN_DEBUG - " 0x1e: PCM rate low = 0x%02x ", snd_sonicvibes_in(sonic, 0x1e)); - printk(" 0x3e: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3e)); - printk(KERN_DEBUG - " 0x1f: PCM rate high = 0x%02x ", snd_sonicvibes_in(sonic, 0x1f)); - printk(" 0x3f: --- = 0x%02x\n", snd_sonicvibes_in(sonic, 0x3f)); + dev_dbg(sonic->card->dev, + "SV REGS: INDEX = 0x%02x STATUS = 0x%02x\n", + inb(SV_REG(sonic, INDEX)), inb(SV_REG(sonic, STATUS))); + dev_dbg(sonic->card->dev, + " 0x00: left input = 0x%02x 0x20: synth rate low = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x00), snd_sonicvibes_in(sonic, 0x20)); + dev_dbg(sonic->card->dev, + " 0x01: right input = 0x%02x 0x21: synth rate high = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x01), snd_sonicvibes_in(sonic, 0x21)); + dev_dbg(sonic->card->dev, + " 0x02: left AUX1 = 0x%02x 0x22: ADC clock = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x02), snd_sonicvibes_in(sonic, 0x22)); + dev_dbg(sonic->card->dev, + " 0x03: right AUX1 = 0x%02x 0x23: ADC alt rate = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x03), snd_sonicvibes_in(sonic, 0x23)); + dev_dbg(sonic->card->dev, + " 0x04: left CD = 0x%02x 0x24: ADC pll M = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x04), snd_sonicvibes_in(sonic, 0x24)); + dev_dbg(sonic->card->dev, + " 0x05: right CD = 0x%02x 0x25: ADC pll N = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x05), snd_sonicvibes_in(sonic, 0x25)); + dev_dbg(sonic->card->dev, + " 0x06: left line = 0x%02x 0x26: Synth pll M = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x06), snd_sonicvibes_in(sonic, 0x26)); + dev_dbg(sonic->card->dev, + " 0x07: right line = 0x%02x 0x27: Synth pll N = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x07), snd_sonicvibes_in(sonic, 0x27)); + dev_dbg(sonic->card->dev, + " 0x08: MIC = 0x%02x 0x28: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x08), snd_sonicvibes_in(sonic, 0x28)); + dev_dbg(sonic->card->dev, + " 0x09: Game port = 0x%02x 0x29: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x09), snd_sonicvibes_in(sonic, 0x29)); + dev_dbg(sonic->card->dev, + " 0x0a: left synth = 0x%02x 0x2a: MPU401 = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0a), snd_sonicvibes_in(sonic, 0x2a)); + dev_dbg(sonic->card->dev, + " 0x0b: right synth = 0x%02x 0x2b: drive ctrl = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0b), snd_sonicvibes_in(sonic, 0x2b)); + dev_dbg(sonic->card->dev, + " 0x0c: left AUX2 = 0x%02x 0x2c: SRS space = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0c), snd_sonicvibes_in(sonic, 0x2c)); + dev_dbg(sonic->card->dev, + " 0x0d: right AUX2 = 0x%02x 0x2d: SRS center = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0d), snd_sonicvibes_in(sonic, 0x2d)); + dev_dbg(sonic->card->dev, + " 0x0e: left analog = 0x%02x 0x2e: wave source = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0e), snd_sonicvibes_in(sonic, 0x2e)); + dev_dbg(sonic->card->dev, + " 0x0f: right analog = 0x%02x 0x2f: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x0f), snd_sonicvibes_in(sonic, 0x2f)); + dev_dbg(sonic->card->dev, + " 0x10: left PCM = 0x%02x 0x30: analog power = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x10), snd_sonicvibes_in(sonic, 0x30)); + dev_dbg(sonic->card->dev, + " 0x11: right PCM = 0x%02x 0x31: analog power = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x11), snd_sonicvibes_in(sonic, 0x31)); + dev_dbg(sonic->card->dev, + " 0x12: DMA data format = 0x%02x 0x32: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x12), snd_sonicvibes_in(sonic, 0x32)); + dev_dbg(sonic->card->dev, + " 0x13: P/C enable = 0x%02x 0x33: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x13), snd_sonicvibes_in(sonic, 0x33)); + dev_dbg(sonic->card->dev, + " 0x14: U/D button = 0x%02x 0x34: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x14), snd_sonicvibes_in(sonic, 0x34)); + dev_dbg(sonic->card->dev, + " 0x15: revision = 0x%02x 0x35: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x15), snd_sonicvibes_in(sonic, 0x35)); + dev_dbg(sonic->card->dev, + " 0x16: ADC output ctrl = 0x%02x 0x36: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x16), snd_sonicvibes_in(sonic, 0x36)); + dev_dbg(sonic->card->dev, + " 0x17: --- = 0x%02x 0x37: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x17), snd_sonicvibes_in(sonic, 0x37)); + dev_dbg(sonic->card->dev, + " 0x18: DMA A upper cnt = 0x%02x 0x38: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x18), snd_sonicvibes_in(sonic, 0x38)); + dev_dbg(sonic->card->dev, + " 0x19: DMA A lower cnt = 0x%02x 0x39: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x19), snd_sonicvibes_in(sonic, 0x39)); + dev_dbg(sonic->card->dev, + " 0x1a: --- = 0x%02x 0x3a: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1a), snd_sonicvibes_in(sonic, 0x3a)); + dev_dbg(sonic->card->dev, + " 0x1b: --- = 0x%02x 0x3b: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1b), snd_sonicvibes_in(sonic, 0x3b)); + dev_dbg(sonic->card->dev, + " 0x1c: DMA C upper cnt = 0x%02x 0x3c: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1c), snd_sonicvibes_in(sonic, 0x3c)); + dev_dbg(sonic->card->dev, + " 0x1d: DMA C upper cnt = 0x%02x 0x3d: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1d), snd_sonicvibes_in(sonic, 0x3d)); + dev_dbg(sonic->card->dev, + " 0x1e: PCM rate low = 0x%02x 0x3e: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1e), snd_sonicvibes_in(sonic, 0x3e)); + dev_dbg(sonic->card->dev, + " 0x1f: PCM rate high = 0x%02x 0x3f: --- = 0x%02x\n", + snd_sonicvibes_in(sonic, 0x1f), snd_sonicvibes_in(sonic, 0x3f)); } #endif @@ -511,8 +511,10 @@ static void snd_sonicvibes_pll(unsigned int rate, *res_m = m; *res_n = n; #if 0 - printk(KERN_DEBUG "metric = %i, xm = %i, xn = %i\n", metric, xm, xn); - printk(KERN_DEBUG "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n); + dev_dbg(sonic->card->dev, + "metric = %i, xm = %i, xn = %i\n", metric, xm, xn); + dev_dbg(sonic->card->dev, + "pll: m = 0x%x, r = 0x%x, n = 0x%x\n", reg, m, r, n); #endif } @@ -624,7 +626,8 @@ static irqreturn_t snd_sonicvibes_interrupt(int irq, void *dev_id) return IRQ_NONE; if (status == 0xff) { /* failure */ outb(sonic->irqmask = ~0, SV_REG(sonic, IRQMASK)); - snd_printk(KERN_ERR "IRQ failure - interrupts disabled!!\n"); + dev_err(sonic->card->dev, + "IRQ failure - interrupts disabled!!\n"); return IRQ_HANDLED; } if (sonic->pcm) { @@ -877,7 +880,8 @@ static struct snd_pcm_ops snd_sonicvibes_capture_ops = { .pointer = snd_sonicvibes_capture_pointer, }; -static int __devinit snd_sonicvibes_pcm(struct sonicvibes * sonic, int device, struct snd_pcm ** rpcm) +static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1087,7 +1091,7 @@ static int snd_sonicvibes_put_double(struct snd_kcontrol *kcontrol, struct snd_c return change; } -static struct snd_kcontrol_new snd_sonicvibes_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_sonicvibes_controls[] = { SONICVIBES_DOUBLE("Capture Volume", 0, SV_IREG_LEFT_ADC, SV_IREG_RIGHT_ADC, 0, 0, 15, 0), SONICVIBES_DOUBLE("Aux Playback Switch", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 7, 7, 1, 1), SONICVIBES_DOUBLE("Aux Playback Volume", 0, SV_IREG_LEFT_AUX1, SV_IREG_RIGHT_AUX1, 0, 0, 31, 1), @@ -1118,7 +1122,7 @@ static void snd_sonicvibes_master_free(struct snd_kcontrol *kcontrol) sonic->master_volume = NULL; } -static int __devinit snd_sonicvibes_mixer(struct sonicvibes * sonic) +static int snd_sonicvibes_mixer(struct sonicvibes *sonic) { struct snd_card *card; struct snd_kcontrol *kctl; @@ -1175,7 +1179,7 @@ static void snd_sonicvibes_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "MIDI to ext. Tx : %s\n", tmp & 0x04 ? "on" : "off"); } -static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) +static void snd_sonicvibes_proc_init(struct sonicvibes *sonic) { struct snd_info_entry *entry; @@ -1188,16 +1192,17 @@ static void __devinit snd_sonicvibes_proc_init(struct sonicvibes * sonic) */ #ifdef SUPPORT_JOYSTICK -static struct snd_kcontrol_new snd_sonicvibes_game_control __devinitdata = +static struct snd_kcontrol_new snd_sonicvibes_game_control = SONICVIBES_SINGLE("Joystick Speed", 0, SV_IREG_GAME_PORT, 1, 15, 0); -static int __devinit snd_sonicvibes_create_gameport(struct sonicvibes *sonic) +static int snd_sonicvibes_create_gameport(struct sonicvibes *sonic) { struct gameport *gp; sonic->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "sonicvibes: cannot allocate memory for gameport\n"); + dev_err(sonic->card->dev, + "sonicvibes: cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -1246,11 +1251,11 @@ static int snd_sonicvibes_dev_free(struct snd_device *device) return snd_sonicvibes_free(sonic); } -static int __devinit snd_sonicvibes_create(struct snd_card *card, - struct pci_dev *pci, - int reverb, - int mge, - struct sonicvibes ** rsonic) +static int snd_sonicvibes_create(struct snd_card *card, + struct pci_dev *pci, + int reverb, + int mge, + struct sonicvibes **rsonic) { struct sonicvibes *sonic; unsigned int dmaa, dmac; @@ -1266,7 +1271,8 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 24 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(24)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(24)) < 0) { - snd_printk(KERN_ERR "architecture does not support 24bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 24bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -1295,7 +1301,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, if (request_irq(pci->irq, snd_sonicvibes_interrupt, IRQF_SHARED, KBUILD_MODNAME, sonic)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_sonicvibes_free(sonic); return -EBUSY; } @@ -1309,24 +1315,32 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, if (!dmaa) { dmaa = dmaio; dmaio += 0x10; - snd_printk(KERN_INFO "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", dmaa); + dev_info(card->dev, + "BIOS did not allocate DDMA channel A i/o, allocated at 0x%x\n", + dmaa); } if (!dmac) { dmac = dmaio; dmaio += 0x10; - snd_printk(KERN_INFO "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", dmac); + dev_info(card->dev, + "BIOS did not allocate DDMA channel C i/o, allocated at 0x%x\n", + dmac); } pci_write_config_dword(pci, 0x40, dmaa); pci_write_config_dword(pci, 0x48, dmac); if ((sonic->res_dmaa = request_region(dmaa, 0x10, "S3 SonicVibes DDMA-A")) == NULL) { snd_sonicvibes_free(sonic); - snd_printk(KERN_ERR "unable to grab DDMA-A port at 0x%x-0x%x\n", dmaa, dmaa + 0x10 - 1); + dev_err(card->dev, + "unable to grab DDMA-A port at 0x%x-0x%x\n", + dmaa, dmaa + 0x10 - 1); return -EBUSY; } if ((sonic->res_dmac = request_region(dmac, 0x10, "S3 SonicVibes DDMA-C")) == NULL) { snd_sonicvibes_free(sonic); - snd_printk(KERN_ERR "unable to grab DDMA-C port at 0x%x-0x%x\n", dmac, dmac + 0x10 - 1); + dev_err(card->dev, + "unable to grab DDMA-C port at 0x%x-0x%x\n", + dmac, dmac + 0x10 - 1); return -EBUSY; } @@ -1391,8 +1405,6 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, snd_sonicvibes_proc_init(sonic); - snd_card_set_dev(card, &pci->dev); - *rsonic = sonic; return 0; } @@ -1401,7 +1413,7 @@ static int __devinit snd_sonicvibes_create(struct snd_card *card, * MIDI section */ -static struct snd_kcontrol_new snd_sonicvibes_midi_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_sonicvibes_midi_controls[] = { SONICVIBES_SINGLE("SonicVibes Wave Source RAM", 0, SV_IREG_WAVE_SOURCE, 0, 1, 0), SONICVIBES_SINGLE("SonicVibes Wave Source RAM+ROM", 0, SV_IREG_WAVE_SOURCE, 1, 1, 0), SONICVIBES_SINGLE("SonicVibes Onboard Synth", 0, SV_IREG_MPU401, 0, 1, 0), @@ -1422,8 +1434,8 @@ static void snd_sonicvibes_midi_input_close(struct snd_mpu401 * mpu) outb(sonic->irqmask |= SV_MIDI_MASK, SV_REG(sonic, IRQMASK)); } -static int __devinit snd_sonicvibes_midi(struct sonicvibes * sonic, - struct snd_rawmidi *rmidi) +static int snd_sonicvibes_midi(struct sonicvibes *sonic, + struct snd_rawmidi *rmidi) { struct snd_mpu401 * mpu = rmidi->private_data; struct snd_card *card = sonic->card; @@ -1441,8 +1453,8 @@ static int __devinit snd_sonicvibes_midi(struct sonicvibes * sonic, return 0; } -static int __devinit snd_sonic_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_sonic_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -1458,7 +1470,8 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; for (idx = 0; idx < 5; idx++) { @@ -1524,17 +1537,16 @@ static int __devinit snd_sonic_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_sonic_remove(struct pci_dev *pci) +static void snd_sonic_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver sonicvibes_driver = { .name = KBUILD_MODNAME, .id_table = snd_sonic_ids, .probe = snd_sonic_probe, - .remove = __devexit_p(snd_sonic_remove), + .remove = snd_sonic_remove, }; module_pci_driver(sonicvibes_driver); diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 8a6f1f76e87..d852458caf3 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c @@ -73,8 +73,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { MODULE_DEVICE_TABLE(pci, snd_trident_ids); -static int __devinit snd_trident_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_trident_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -89,7 +89,8 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -166,17 +167,16 @@ static int __devinit snd_trident_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_trident_remove(struct pci_dev *pci) +static void snd_trident_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver trident_driver = { .name = KBUILD_MODNAME, .id_table = snd_trident_ids, .probe = snd_trident_probe, - .remove = __devexit_p(snd_trident_remove), + .remove = snd_trident_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_trident_pm, diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c index 06b10d1a76e..1272c18a254 100644 --- a/sound/pci/trident/trident_main.c +++ b/sound/pci/trident/trident_main.c @@ -69,40 +69,40 @@ static void snd_trident_print_voice_regs(struct snd_trident *trident, int voice) { unsigned int val, tmp; - printk(KERN_DEBUG "Trident voice %i:\n", voice); + dev_dbg(trident->card->dev, "Trident voice %i:\n", voice); outb(voice, TRID_REG(trident, T4D_LFO_GC_CIR)); val = inl(TRID_REG(trident, CH_LBA)); - printk(KERN_DEBUG "LBA: 0x%x\n", val); + dev_dbg(trident->card->dev, "LBA: 0x%x\n", val); val = inl(TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); - printk(KERN_DEBUG "GVSel: %i\n", val >> 31); - printk(KERN_DEBUG "Pan: 0x%x\n", (val >> 24) & 0x7f); - printk(KERN_DEBUG "Vol: 0x%x\n", (val >> 16) & 0xff); - printk(KERN_DEBUG "CTRL: 0x%x\n", (val >> 12) & 0x0f); - printk(KERN_DEBUG "EC: 0x%x\n", val & 0x0fff); + dev_dbg(trident->card->dev, "GVSel: %i\n", val >> 31); + dev_dbg(trident->card->dev, "Pan: 0x%x\n", (val >> 24) & 0x7f); + dev_dbg(trident->card->dev, "Vol: 0x%x\n", (val >> 16) & 0xff); + dev_dbg(trident->card->dev, "CTRL: 0x%x\n", (val >> 12) & 0x0f); + dev_dbg(trident->card->dev, "EC: 0x%x\n", val & 0x0fff); if (trident->device != TRIDENT_DEVICE_ID_NX) { val = inl(TRID_REG(trident, CH_DX_CSO_ALPHA_FMS)); - printk(KERN_DEBUG "CSO: 0x%x\n", val >> 16); - printk("Alpha: 0x%x\n", (val >> 4) & 0x0fff); - printk(KERN_DEBUG "FMS: 0x%x\n", val & 0x0f); + dev_dbg(trident->card->dev, "CSO: 0x%x\n", val >> 16); + dev_dbg(trident->card->dev, "Alpha: 0x%x\n", (val >> 4) & 0x0fff); + dev_dbg(trident->card->dev, "FMS: 0x%x\n", val & 0x0f); val = inl(TRID_REG(trident, CH_DX_ESO_DELTA)); - printk(KERN_DEBUG "ESO: 0x%x\n", val >> 16); - printk(KERN_DEBUG "Delta: 0x%x\n", val & 0xffff); + dev_dbg(trident->card->dev, "ESO: 0x%x\n", val >> 16); + dev_dbg(trident->card->dev, "Delta: 0x%x\n", val & 0xffff); val = inl(TRID_REG(trident, CH_DX_FMC_RVOL_CVOL)); } else { // TRIDENT_DEVICE_ID_NX val = inl(TRID_REG(trident, CH_NX_DELTA_CSO)); tmp = (val >> 24) & 0xff; - printk(KERN_DEBUG "CSO: 0x%x\n", val & 0x00ffffff); + dev_dbg(trident->card->dev, "CSO: 0x%x\n", val & 0x00ffffff); val = inl(TRID_REG(trident, CH_NX_DELTA_ESO)); tmp |= (val >> 16) & 0xff00; - printk(KERN_DEBUG "Delta: 0x%x\n", tmp); - printk(KERN_DEBUG "ESO: 0x%x\n", val & 0x00ffffff); + dev_dbg(trident->card->dev, "Delta: 0x%x\n", tmp); + dev_dbg(trident->card->dev, "ESO: 0x%x\n", val & 0x00ffffff); val = inl(TRID_REG(trident, CH_NX_ALPHA_FMS_FMC_RVOL_CVOL)); - printk(KERN_DEBUG "Alpha: 0x%x\n", val >> 20); - printk(KERN_DEBUG "FMS: 0x%x\n", (val >> 16) & 0x0f); + dev_dbg(trident->card->dev, "Alpha: 0x%x\n", val >> 20); + dev_dbg(trident->card->dev, "FMS: 0x%x\n", (val >> 16) & 0x0f); } - printk(KERN_DEBUG "FMC: 0x%x\n", (val >> 14) & 3); - printk(KERN_DEBUG "RVol: 0x%x\n", (val >> 7) & 0x7f); - printk(KERN_DEBUG "CVol: 0x%x\n", val & 0x7f); + dev_dbg(trident->card->dev, "FMC: 0x%x\n", (val >> 14) & 3); + dev_dbg(trident->card->dev, "RVol: 0x%x\n", (val >> 7) & 0x7f); + dev_dbg(trident->card->dev, "CVol: 0x%x\n", val & 0x7f); } #endif @@ -156,7 +156,8 @@ static unsigned short snd_trident_codec_read(struct snd_ac97 *ac97, unsigned sho } if (count == 0 && !trident->ac97_detect) { - snd_printk(KERN_ERR "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", + dev_err(trident->card->dev, + "ac97 codec read TIMEOUT [0x%x/0x%x]!!!\n", reg, data); data = 0; } @@ -497,16 +498,16 @@ void snd_trident_write_voice_regs(struct snd_trident * trident, outl(regs[4], TRID_REG(trident, CH_START + 16)); #if 0 - printk(KERN_DEBUG "written %i channel:\n", voice->number); - printk(KERN_DEBUG " regs[0] = 0x%x/0x%x\n", + dev_dbg(trident->card->dev, "written %i channel:\n", voice->number); + dev_dbg(trident->card->dev, " regs[0] = 0x%x/0x%x\n", regs[0], inl(TRID_REG(trident, CH_START + 0))); - printk(KERN_DEBUG " regs[1] = 0x%x/0x%x\n", + dev_dbg(trident->card->dev, " regs[1] = 0x%x/0x%x\n", regs[1], inl(TRID_REG(trident, CH_START + 4))); - printk(KERN_DEBUG " regs[2] = 0x%x/0x%x\n", + dev_dbg(trident->card->dev, " regs[2] = 0x%x/0x%x\n", regs[2], inl(TRID_REG(trident, CH_START + 8))); - printk(KERN_DEBUG " regs[3] = 0x%x/0x%x\n", + dev_dbg(trident->card->dev, " regs[3] = 0x%x/0x%x\n", regs[3], inl(TRID_REG(trident, CH_START + 12))); - printk(KERN_DEBUG " regs[4] = 0x%x/0x%x\n", + dev_dbg(trident->card->dev, " regs[4] = 0x%x/0x%x\n", regs[4], inl(TRID_REG(trident, CH_START + 16))); #endif } @@ -589,7 +590,7 @@ static void snd_trident_write_vol_reg(struct snd_trident * trident, outb(voice->Vol >> 2, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC + 2)); break; case TRIDENT_DEVICE_ID_SI7018: - /* printk(KERN_DEBUG "voice->Vol = 0x%x\n", voice->Vol); */ + /* dev_dbg(trident->card->dev, "voice->Vol = 0x%x\n", voice->Vol); */ outw((voice->CTRL << 12) | voice->Vol, TRID_REG(trident, CH_GVSEL_PAN_VOL_CTRL_EC)); break; @@ -2171,8 +2172,8 @@ static struct snd_pcm_ops snd_trident_spdif_7018_ops = { ---------------------------------------------------------------------------*/ -int __devinit snd_trident_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -2229,8 +2230,8 @@ int __devinit snd_trident_pcm(struct snd_trident * trident, ---------------------------------------------------------------------------*/ -int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_foldback_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *foldback; int err; @@ -2286,8 +2287,8 @@ int __devinit snd_trident_foldback_pcm(struct snd_trident * trident, ---------------------------------------------------------------------------*/ -int __devinit snd_trident_spdif_pcm(struct snd_trident * trident, - int device, struct snd_pcm ** rpcm) +int snd_trident_spdif_pcm(struct snd_trident *trident, + int device, struct snd_pcm **rpcm) { struct snd_pcm *spdif; int err; @@ -2371,7 +2372,7 @@ static int snd_trident_spdif_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_control __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), @@ -2434,7 +2435,7 @@ static int snd_trident_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -2467,7 +2468,7 @@ static int snd_trident_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_trident_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2529,7 +2530,7 @@ static int snd_trident_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_trident_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -2579,7 +2580,7 @@ static int snd_trident_ac97_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_ac97_rear_control __devinitdata = +static struct snd_kcontrol_new snd_trident_ac97_rear_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Rear Path", @@ -2637,7 +2638,7 @@ static int snd_trident_vol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = +static struct snd_kcontrol_new snd_trident_vol_music_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Music Playback Volume", @@ -2648,7 +2649,7 @@ static struct snd_kcontrol_new snd_trident_vol_music_control __devinitdata = .tlv = { .p = db_scale_gvol }, }; -static struct snd_kcontrol_new snd_trident_vol_wave_control __devinitdata = +static struct snd_kcontrol_new snd_trident_vol_wave_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Wave Playback Volume", @@ -2715,7 +2716,7 @@ static int snd_trident_pcm_vol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_vol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_vol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Front Playback Volume", @@ -2779,7 +2780,7 @@ static int snd_trident_pcm_pan_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_pan_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_pan_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Pan Playback Control", @@ -2836,7 +2837,7 @@ static int snd_trident_pcm_rvol_control_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_crvol, -3175, 25, 1); -static struct snd_kcontrol_new snd_trident_pcm_rvol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_rvol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Reverb Playback Volume", @@ -2892,7 +2893,7 @@ static int snd_trident_pcm_cvol_control_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_trident_pcm_cvol_control __devinitdata = +static struct snd_kcontrol_new snd_trident_pcm_cvol_control = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "PCM Chorus Playback Volume", @@ -2972,7 +2973,7 @@ static int snd_trident_pcm_mixer_free(struct snd_trident *trident, struct snd_tr ---------------------------------------------------------------------------*/ -static int __devinit snd_trident_mixer(struct snd_trident * trident, int pcm_spdif_device) +static int snd_trident_mixer(struct snd_trident *trident, int pcm_spdif_device) { struct snd_ac97_template _ac97; struct snd_card *card = trident->card; @@ -3013,13 +3014,15 @@ static int __devinit snd_trident_mixer(struct snd_trident * trident, int pcm_spd _ac97.num = 1; err = snd_ac97_mixer(trident->ac97_bus, &_ac97, &trident->ac97_sec); if (err < 0) - snd_printk(KERN_ERR "SI7018: the secondary codec - invalid access\n"); + dev_err(trident->card->dev, + "SI7018: the secondary codec - invalid access\n"); #if 0 // only for my testing purpose --jk { struct snd_ac97 *mc97; err = snd_ac97_modem(trident->card, &_ac97, &mc97); if (err < 0) - snd_printk(KERN_ERR "snd_ac97_modem returned error %i\n", err); + dev_err(trident->card->dev, + "snd_ac97_modem returned error %i\n", err); } #endif } @@ -3191,13 +3194,14 @@ static int snd_trident_gameport_open(struct gameport *gameport, int mode) } } -int __devinit snd_trident_create_gameport(struct snd_trident *chip) +int snd_trident_create_gameport(struct snd_trident *chip) { struct gameport *gp; chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "trident: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); return -ENOMEM; } @@ -3225,7 +3229,7 @@ static inline void snd_trident_free_gameport(struct snd_trident *chip) } } #else -int __devinit snd_trident_create_gameport(struct snd_trident *chip) { return -ENOSYS; } +int snd_trident_create_gameport(struct snd_trident *chip) { return -ENOSYS; } static inline void snd_trident_free_gameport(struct snd_trident *chip) { } #endif /* CONFIG_GAMEPORT */ @@ -3270,7 +3274,8 @@ static int snd_trident_sis_reset(struct snd_trident *trident) goto __si7018_ok; do_delay(trident); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL))); + dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n", + inl(TRID_REG(trident, SI_SERIAL_INTF_CTRL))); if (r-- > 0) { end_time = jiffies + HZ; do { @@ -3329,7 +3334,7 @@ static void snd_trident_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_trident_proc_init(struct snd_trident * trident) +static void snd_trident_proc_init(struct snd_trident *trident) { struct snd_info_entry *entry; const char *s = "trident"; @@ -3358,7 +3363,7 @@ static int snd_trident_dev_free(struct snd_device *device) ---------------------------------------------------------------------------*/ -static int __devinit snd_trident_tlb_alloc(struct snd_trident *trident) +static int snd_trident_tlb_alloc(struct snd_trident *trident) { int i; @@ -3367,7 +3372,7 @@ static int __devinit snd_trident_tlb_alloc(struct snd_trident *trident) if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), 2 * SNDRV_TRIDENT_MAX_PAGES * 4, &trident->tlb.buffer) < 0) { - snd_printk(KERN_ERR "trident: unable to allocate TLB buffer\n"); + dev_err(trident->card->dev, "unable to allocate TLB buffer\n"); return -ENOMEM; } trident->tlb.entries = (unsigned int*)ALIGN((unsigned long)trident->tlb.buffer.area, SNDRV_TRIDENT_MAX_PAGES * 4); @@ -3375,13 +3380,14 @@ static int __devinit snd_trident_tlb_alloc(struct snd_trident *trident) /* allocate shadow TLB page table (virtual addresses) */ trident->tlb.shadow_entries = vmalloc(SNDRV_TRIDENT_MAX_PAGES*sizeof(unsigned long)); if (trident->tlb.shadow_entries == NULL) { - snd_printk(KERN_ERR "trident: unable to allocate shadow TLB entries\n"); + dev_err(trident->card->dev, + "unable to allocate shadow TLB entries\n"); return -ENOMEM; } /* allocate and setup silent page and initialise TLB entries */ if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(trident->pci), SNDRV_TRIDENT_PAGE_SIZE, &trident->tlb.silent_page) < 0) { - snd_printk(KERN_ERR "trident: unable to allocate silent page\n"); + dev_err(trident->card->dev, "unable to allocate silent page\n"); return -ENOMEM; } memset(trident->tlb.silent_page.area, 0, SNDRV_TRIDENT_PAGE_SIZE); @@ -3439,7 +3445,7 @@ static int snd_trident_4d_dx_init(struct snd_trident *trident) goto __dx_ok; do_delay(trident); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 codec ready error\n"); + dev_err(trident->card->dev, "AC'97 codec ready error\n"); return -EIO; __dx_ok: @@ -3477,7 +3483,8 @@ static int snd_trident_4d_nx_init(struct snd_trident *trident) goto __nx_ok; do_delay(trident); } while (time_after_eq(end_time, jiffies)); - snd_printk(KERN_ERR "AC'97 codec ready error [0x%x]\n", inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT))); + dev_err(trident->card->dev, "AC'97 codec ready error [0x%x]\n", + inl(TRID_REG(trident, NX_ACR0_AC97_COM_STAT))); return -EIO; __nx_ok: @@ -3539,7 +3546,7 @@ static int snd_trident_sis_init(struct snd_trident *trident) ---------------------------------------------------------------------------*/ -int __devinit snd_trident_create(struct snd_card *card, +int snd_trident_create(struct snd_card *card, struct pci_dev *pci, int pcm_streams, int pcm_spdif_device, @@ -3562,7 +3569,8 @@ int __devinit snd_trident_create(struct snd_card *card, /* check, if we can restrict PCI DMA transfers to 30 bits */ if (pci_set_dma_mask(pci, DMA_BIT_MASK(30)) < 0 || pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(30)) < 0) { - snd_printk(KERN_ERR "architecture does not support 30bit PCI busmaster DMA\n"); + dev_err(card->dev, + "architecture does not support 30bit PCI busmaster DMA\n"); pci_disable_device(pci); return -ENXIO; } @@ -3600,7 +3608,7 @@ int __devinit snd_trident_create(struct snd_card *card, if (request_irq(pci->irq, snd_trident_interrupt, IRQF_SHARED, KBUILD_MODNAME, trident)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_trident_free(trident); return -EBUSY; } @@ -3664,7 +3672,6 @@ int __devinit snd_trident_create(struct snd_card *card, snd_trident_enable_eso(trident); snd_trident_proc_init(trident); - snd_card_set_dev(card, &pci->dev); *rtrident = trident; return 0; } @@ -3950,8 +3957,7 @@ static int snd_trident_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "trident: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index f0b4efdb483..95b98f537b6 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c @@ -459,7 +459,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre unsigned int addr; if (idx >= VIA_TABLE_SIZE) { - snd_printk(KERN_ERR "via82xx: too much table size!\n"); + dev_err(&pci->dev, "too much table size!\n"); return -EINVAL; } addr = snd_pcm_sgbuf_get_addr(substream, ofs); @@ -474,8 +474,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre } else flag = 0; /* period continues to the next */ /* - printk(KERN_DEBUG "via: tbl %d: at %d size %d " - "(rest %d)\n", idx, ofs, r, rest); + dev_dbg(&pci->dev, + "tbl %d: at %d size %d (rest %d)\n", + idx, ofs, r, rest); */ ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag); dev->idx_table[idx].offset = ofs; @@ -528,7 +529,7 @@ static int snd_via82xx_codec_ready(struct via82xx *chip, int secondary) if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)) return val & 0xffff; } - snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", + dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip)); return -EIO; } @@ -587,7 +588,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT; while (1) { if (again++ > 3) { - snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n", + dev_err(chip->card->dev, + "codec_read: codec %i is not valid [0x%x]\n", ac97->num, snd_via82xx_codec_xread(chip)); return 0xffff; } @@ -777,7 +779,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\ viadev->lastpos < viadev->bufsize2)) -static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx, +static inline unsigned int calc_linear_pos(struct via82xx *chip, + struct viadev *viadev, + unsigned int idx, unsigned int count) { unsigned int size, base, res; @@ -790,7 +794,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i /* check the validity of the calculated position */ if (size < count) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n", + dev_dbg(chip->card->dev, + "invalid via82xx_cur_ptr (size = %d, count = %d)\n", (int)size, (int)count); res = viadev->lastpos; } else { @@ -807,9 +812,9 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i } if (check_invalid_pos(viadev, res)) { #ifdef POINTER_DEBUG - printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, " - "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, " - "count = 0x%x\n", idx, viadev->tbl_entries, + dev_dbg(chip->card->dev, + "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", + idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count); @@ -817,8 +822,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i /* count register returns full size when end of buffer is reached */ res = base + size; if (check_invalid_pos(viadev, res)) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), " - "using last valid pointer\n"); + dev_dbg(chip->card->dev, + "invalid via82xx_cur_ptr (2), using last valid pointer\n"); res = viadev->lastpos; } } @@ -850,7 +855,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr idx = 0; else /* CURR_PTR holds the address + 8 */ idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; - res = calc_linear_pos(viadev, idx, count); + res = calc_linear_pos(chip, viadev, idx, count); viadev->lastpos = res; /* remember the last position */ spin_unlock(&chip->reg_lock); @@ -889,13 +894,14 @@ static snd_pcm_uframes_t snd_via8233_pcm_pointer(struct snd_pcm_substream *subst idx = count >> 24; if (idx >= viadev->tbl_entries) { #ifdef POINTER_DEBUG - printk(KERN_DEBUG "fail: invalid idx = %i/%i\n", idx, + dev_dbg(chip->card->dev, + "fail: invalid idx = %i/%i\n", idx, viadev->tbl_entries); #endif res = viadev->lastpos; } else { count &= 0xffffff; - res = calc_linear_pos(viadev, idx, count); + res = calc_linear_pos(chip, viadev, idx, count); } } else { res = viadev->hwptr_done; @@ -1437,7 +1443,7 @@ static void init_viadev(struct via82xx *chip, int idx, unsigned int reg_offset, /* * create pcm instances for VIA8233, 8233C and 8235 (not 8233A) */ -static int __devinit snd_via8233_pcm_new(struct via82xx *chip) +static int snd_via8233_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1505,7 +1511,7 @@ static int __devinit snd_via8233_pcm_new(struct via82xx *chip) /* * create pcm instances for VIA8233A */ -static int __devinit snd_via8233a_pcm_new(struct via82xx *chip) +static int snd_via8233a_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; struct snd_pcm_chmap *chmap; @@ -1566,7 +1572,7 @@ static int __devinit snd_via8233a_pcm_new(struct via82xx *chip) /* * create a pcm instance for via686a/b */ -static int __devinit snd_via686_pcm_new(struct via82xx *chip) +static int snd_via686_pcm_new(struct via82xx *chip) { struct snd_pcm *pcm; int err; @@ -1643,7 +1649,7 @@ static int snd_via8233_capture_source_put(struct snd_kcontrol *kcontrol, return val != oval; } -static struct snd_kcontrol_new snd_via8233_capture_source __devinitdata = { +static struct snd_kcontrol_new snd_via8233_capture_source = { .name = "Input Source Select", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_capture_source_info, @@ -1683,7 +1689,7 @@ static int snd_via8233_dxs3_spdif_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_dxs3_spdif_control = { .name = SNDRV_CTL_NAME_IEC958("Output ",NONE,SWITCH), .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_via8233_dxs3_spdif_info, @@ -1772,7 +1778,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1); -static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control = { .name = "PCM Playback Volume", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1783,7 +1789,7 @@ static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = .tlv = { .p = db_scale_dxs } }; -static struct snd_kcontrol_new snd_via8233_dxs_volume_control __devinitdata = { +static struct snd_kcontrol_new snd_via8233_dxs_volume_control = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .device = 0, /* .subdevice set later */ @@ -1895,7 +1901,7 @@ static struct ac97_quirk ac97_quirks[] = { { } /* terminator */ }; -static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override) +static int snd_via82xx_mixer_new(struct via82xx *chip, const char *quirk_override) { struct snd_ac97_template ac97; int err; @@ -1930,7 +1936,7 @@ static int __devinit snd_via82xx_mixer_new(struct via82xx *chip, const char *qui #ifdef SUPPORT_JOYSTICK #define JOYSTICK_ADDR 0x200 -static int __devinit snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy) +static int snd_via686_create_gameport(struct via82xx *chip, unsigned char *legacy) { struct gameport *gp; struct resource *r; @@ -1940,14 +1946,15 @@ static int __devinit snd_via686_create_gameport(struct via82xx *chip, unsigned c r = request_region(JOYSTICK_ADDR, 8, "VIA686 gameport"); if (!r) { - printk(KERN_WARNING "via82xx: cannot reserve joystick port 0x%#x\n", + dev_warn(chip->card->dev, "cannot reserve joystick port %#x\n", JOYSTICK_ADDR); return -EBUSY; } chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "via82xx: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } @@ -1990,7 +1997,7 @@ static inline void snd_via686_free_gameport(struct via82xx *chip) { } * */ -static int __devinit snd_via8233_init_misc(struct via82xx *chip) +static int snd_via8233_init_misc(struct via82xx *chip) { int i, err, caps; unsigned char val; @@ -2016,7 +2023,8 @@ static int __devinit snd_via8233_init_misc(struct via82xx *chip) strcpy(sid.name, "PCM Playback Volume"); sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; if (! snd_ctl_find_id(chip->card, &sid)) { - snd_printd(KERN_INFO "Using DXS as PCM Playback\n"); + dev_info(chip->card->dev, + "Using DXS as PCM Playback\n"); err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_via8233_pcmdxs_volume_control, chip)); if (err < 0) return err; @@ -2047,7 +2055,7 @@ static int __devinit snd_via8233_init_misc(struct via82xx *chip) return 0; } -static int __devinit snd_via686_init_misc(struct via82xx *chip) +static int snd_via686_init_misc(struct via82xx *chip) { unsigned char legacy, legacy_cfg; int rev_h = 0; @@ -2102,8 +2110,9 @@ static int __devinit snd_via686_init_misc(struct via82xx *chip) mpu_port, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rmidi) < 0) { - printk(KERN_WARNING "unable to initialize MPU-401" - " at 0x%lx, skipping\n", mpu_port); + dev_warn(chip->card->dev, + "unable to initialize MPU-401 at 0x%lx, skipping\n", + mpu_port); legacy &= ~VIA_FUNC_ENABLE_MIDI; } else { legacy &= ~VIA_FUNC_MIDI_IRQMASK; /* enable MIDI interrupt */ @@ -2137,7 +2146,7 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, } } -static void __devinit snd_via82xx_proc_init(struct via82xx *chip) +static void snd_via82xx_proc_init(struct via82xx *chip) { struct snd_info_entry *entry; @@ -2203,7 +2212,8 @@ static int snd_via82xx_chip_init(struct via82xx *chip) } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) - snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val); + dev_err(chip->card->dev, + "AC'97 codec is not ready [0x%x]\n", val); #if 0 /* FIXME: we don't support the second codec yet so skip the detection now.. */ snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | @@ -2303,8 +2313,7 @@ static int snd_via82xx_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "via82xx: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2370,12 +2379,12 @@ static int snd_via82xx_dev_free(struct snd_device *device) return snd_via82xx_free(chip); } -static int __devinit snd_via82xx_create(struct snd_card *card, - struct pci_dev *pci, - int chip_type, - int revision, - unsigned int ac97_clock, - struct via82xx ** r_via) +static int snd_via82xx_create(struct snd_card *card, + struct pci_dev *pci, + int chip_type, + int revision, + unsigned int ac97_clock, + struct via82xx **r_via) { struct via82xx *chip; int err; @@ -2417,7 +2426,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, snd_via8233_interrupt : snd_via686_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; } @@ -2441,8 +2450,6 @@ static int __devinit snd_via82xx_create(struct snd_card *card, * We call pci_set_master here because it does not hurt. */ pci_set_master(pci); - snd_card_set_dev(card, &pci->dev); - *r_via = chip; return 0; } @@ -2452,7 +2459,7 @@ struct via823x_info { char *name; int type; }; -static struct via823x_info via823x_cards[] __devinitdata = { +static struct via823x_info via823x_cards[] = { { VIA_REV_PRE_8233, "VIA 8233-Pre", TYPE_VIA8233 }, { VIA_REV_8233C, "VIA 8233C", TYPE_VIA8233 }, { VIA_REV_8233, "VIA 8233", TYPE_VIA8233 }, @@ -2466,7 +2473,7 @@ static struct via823x_info via823x_cards[] __devinitdata = { * auto detection of DXS channel supports. */ -static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { +static struct snd_pci_quirk dxs_whitelist[] = { SND_PCI_QUIRK(0x1005, 0x4710, "Avance Logic Mobo", VIA_DXS_ENABLE), SND_PCI_QUIRK(0x1019, 0x0996, "ESC Mobo", VIA_DXS_48K), SND_PCI_QUIRK(0x1019, 0x0a81, "ECS K7VTA3 v8.0", VIA_DXS_NO_VRA), @@ -2510,14 +2517,14 @@ static struct snd_pci_quirk dxs_whitelist[] __devinitdata = { { } /* terminator */ }; -static int __devinit check_dxs_list(struct pci_dev *pci, int revision) +static int check_dxs_list(struct pci_dev *pci, int revision) { const struct snd_pci_quirk *w; w = snd_pci_quirk_lookup(pci, dxs_whitelist); if (w) { - snd_printdd(KERN_INFO "via82xx: DXS white list for %s found\n", - w->name); + dev_dbg(&pci->dev, "DXS white list for %s found\n", + snd_pci_quirk_name(w)); return w->value; } @@ -2528,15 +2535,15 @@ static int __devinit check_dxs_list(struct pci_dev *pci, int revision) /* * not detected, try 48k rate only to be sure. */ - printk(KERN_INFO "via82xx: Assuming DXS channels with 48k fixed sample rate.\n"); - printk(KERN_INFO " Please try dxs_support=5 option\n"); - printk(KERN_INFO " and report if it works on your machine.\n"); - printk(KERN_INFO " For more details, read ALSA-Configuration.txt.\n"); + dev_info(&pci->dev, "Assuming DXS channels with 48k fixed sample rate.\n"); + dev_info(&pci->dev, " Please try dxs_support=5 option\n"); + dev_info(&pci->dev, " and report if it works on your machine.\n"); + dev_info(&pci->dev, " For more details, read ALSA-Configuration.txt.\n"); return VIA_DXS_48K; }; -static int __devinit snd_via82xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_via82xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct via82xx *chip; @@ -2544,7 +2551,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, unsigned int i; int err; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -2584,7 +2591,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, strcpy(card->driver, "VIA8233"); break; default: - snd_printk(KERN_ERR "invalid card type %d\n", card_type); + dev_err(card->dev, "invalid card type %d\n", card_type); err = -EINVAL; goto __error; } @@ -2643,17 +2650,16 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } -static void __devexit snd_via82xx_remove(struct pci_dev *pci) +static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver via82xx_driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, - .remove = __devexit_p(snd_via82xx_remove), + .remove = snd_via82xx_remove, .driver = { .pm = SND_VIA82XX_PM_OPS, }, diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 8e0efc416f2..46a0526b1d7 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c @@ -312,7 +312,7 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre unsigned int addr; if (idx >= VIA_TABLE_SIZE) { - snd_printk(KERN_ERR "via82xx: too much table size!\n"); + dev_err(&pci->dev, "too much table size!\n"); return -EINVAL; } addr = snd_pcm_sgbuf_get_addr(substream, ofs); @@ -329,8 +329,9 @@ static int build_via_table(struct viadev *dev, struct snd_pcm_substream *substre } else flag = 0; /* period continues to the next */ /* - printk(KERN_DEBUG "via: tbl %d: at %d size %d " - "(rest %d)\n", idx, ofs, r, rest); + dev_dbg(&pci->dev, + "tbl %d: at %d size %d (rest %d)\n", + idx, ofs, r, rest); */ ((u32 *)dev->table.area)[(idx<<1) + 1] = cpu_to_le32(r | flag); dev->idx_table[idx].offset = ofs; @@ -382,7 +383,7 @@ static int snd_via82xx_codec_ready(struct via82xx_modem *chip, int secondary) if (!((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY)) return val & 0xffff; } - snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", + dev_err(chip->card->dev, "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_via82xx_codec_xread(chip)); return -EIO; } @@ -443,7 +444,8 @@ static unsigned short snd_via82xx_codec_read(struct snd_ac97 *ac97, unsigned sho xval |= (reg & 0x7f) << VIA_REG_AC97_CMD_SHIFT; while (1) { if (again++ > 3) { - snd_printk(KERN_ERR "codec_read: codec %i is not valid [0x%x]\n", + dev_err(chip->card->dev, + "codec_read: codec %i is not valid [0x%x]\n", ac97->num, snd_via82xx_codec_xread(chip)); return 0xffff; } @@ -560,7 +562,9 @@ static int snd_via82xx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) ((pos) < viadev->lastpos && ((pos) >= viadev->bufsize2 ||\ viadev->lastpos < viadev->bufsize2)) -static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int idx, +static inline unsigned int calc_linear_pos(struct via82xx_modem *chip, + struct viadev *viadev, + unsigned int idx, unsigned int count) { unsigned int size, res; @@ -570,20 +574,21 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i /* check the validity of the calculated position */ if (size < count) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr (size = %d, count = %d)\n", + dev_err(chip->card->dev, + "invalid via82xx_cur_ptr (size = %d, count = %d)\n", (int)size, (int)count); res = viadev->lastpos; } else if (check_invalid_pos(viadev, res)) { #ifdef POINTER_DEBUG - printk(KERN_DEBUG "fail: idx = %i/%i, lastpos = 0x%x, " - "bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, " - "count = 0x%x\n", idx, viadev->tbl_entries, viadev->lastpos, + dev_dbg(chip->card->dev, + "fail: idx = %i/%i, lastpos = 0x%x, bufsize2 = 0x%x, offsize = 0x%x, size = 0x%x, count = 0x%x\n", + idx, viadev->tbl_entries, viadev->lastpos, viadev->bufsize2, viadev->idx_table[idx].offset, viadev->idx_table[idx].size, count); #endif if (count && size < count) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr, " - "using last valid pointer\n"); + dev_dbg(chip->card->dev, + "invalid via82xx_cur_ptr, using last valid pointer\n"); res = viadev->lastpos; } else { if (! count) @@ -595,8 +600,8 @@ static inline unsigned int calc_linear_pos(struct viadev *viadev, unsigned int i */ res = viadev->idx_table[idx].offset + size; if (check_invalid_pos(viadev, res)) { - snd_printd(KERN_ERR "invalid via82xx_cur_ptr (2), " - "using last valid pointer\n"); + dev_dbg(chip->card->dev, + "invalid via82xx_cur_ptr (2), using last valid pointer\n"); res = viadev->lastpos; } } @@ -632,7 +637,7 @@ static snd_pcm_uframes_t snd_via686_pcm_pointer(struct snd_pcm_substream *substr else /* CURR_PTR holds the address + 8 */ idx = ((ptr - (unsigned int)viadev->table.addr) / 8 - 1) % viadev->tbl_entries; - res = calc_linear_pos(viadev, idx, count); + res = calc_linear_pos(chip, viadev, idx, count); spin_unlock(&chip->reg_lock); return bytes_to_frames(substream->runtime, res); @@ -836,7 +841,7 @@ static void init_viadev(struct via82xx_modem *chip, int idx, unsigned int reg_of /* * create a pcm instance for via686a/b */ -static int __devinit snd_via686_pcm_new(struct via82xx_modem *chip) +static int snd_via686_pcm_new(struct via82xx_modem *chip) { struct snd_pcm *pcm; int err; @@ -885,7 +890,7 @@ static void snd_via82xx_mixer_free_ac97(struct snd_ac97 *ac97) } -static int __devinit snd_via82xx_mixer_new(struct via82xx_modem *chip) +static int snd_via82xx_mixer_new(struct via82xx_modem *chip) { struct snd_ac97_template ac97; int err; @@ -928,7 +933,7 @@ static void snd_via82xx_proc_read(struct snd_info_entry *entry, struct snd_info_ } } -static void __devinit snd_via82xx_proc_init(struct via82xx_modem *chip) +static void snd_via82xx_proc_init(struct via82xx_modem *chip) { struct snd_info_entry *entry; @@ -991,7 +996,8 @@ static int snd_via82xx_chip_init(struct via82xx_modem *chip) } while (time_before(jiffies, end_time)); if ((val = snd_via82xx_codec_xread(chip)) & VIA_REG_AC97_BUSY) - snd_printk(KERN_ERR "AC'97 codec is not ready [0x%x]\n", val); + dev_err(chip->card->dev, + "AC'97 codec is not ready [0x%x]\n", val); snd_via82xx_codec_xwrite(chip, VIA_REG_AC97_READ | VIA_REG_AC97_SECONDARY_VALID | @@ -1054,8 +1060,7 @@ static int snd_via82xx_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "via82xx-modem: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -1103,12 +1108,12 @@ static int snd_via82xx_dev_free(struct snd_device *device) return snd_via82xx_free(chip); } -static int __devinit snd_via82xx_create(struct snd_card *card, - struct pci_dev *pci, - int chip_type, - int revision, - unsigned int ac97_clock, - struct via82xx_modem ** r_via) +static int snd_via82xx_create(struct snd_card *card, + struct pci_dev *pci, + int chip_type, + int revision, + unsigned int ac97_clock, + struct via82xx_modem **r_via) { struct via82xx_modem *chip; int err; @@ -1137,7 +1142,7 @@ static int __devinit snd_via82xx_create(struct snd_card *card, chip->port = pci_resource_start(pci, 0); if (request_irq(pci->irq, snd_via82xx_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_via82xx_free(chip); return -EBUSY; } @@ -1161,15 +1166,13 @@ static int __devinit snd_via82xx_create(struct snd_card *card, * We call pci_set_master here because it does not hurt. */ pci_set_master(pci); - snd_card_set_dev(card, &pci->dev); - *r_via = chip; return 0; } -static int __devinit snd_via82xx_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_via82xx_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { struct snd_card *card; struct via82xx_modem *chip; @@ -1177,7 +1180,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, unsigned int i; int err; - err = snd_card_create(index, id, THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index, id, THIS_MODULE, 0, &card); if (err < 0) return err; @@ -1188,7 +1191,7 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, sprintf(card->shortname, "VIA 82XX modem"); break; default: - snd_printk(KERN_ERR "invalid card type %d\n", card_type); + dev_err(card->dev, "invalid card type %d\n", card_type); err = -EINVAL; goto __error; } @@ -1224,17 +1227,16 @@ static int __devinit snd_via82xx_probe(struct pci_dev *pci, return err; } -static void __devexit snd_via82xx_remove(struct pci_dev *pci) +static void snd_via82xx_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver via82xx_modem_driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, - .remove = __devexit_p(snd_via82xx_remove), + .remove = snd_via82xx_remove, .driver = { .pm = SND_VIA82XX_PM_OPS, }, diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fdfbaf85723..ff9074d2260 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c @@ -134,9 +134,9 @@ static int snd_vx222_dev_free(struct snd_device *device) } -static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci, - struct snd_vx_hardware *hw, - struct snd_vx222 **rchip) +static int snd_vx222_create(struct snd_card *card, struct pci_dev *pci, + struct snd_vx_hardware *hw, + struct snd_vx222 **rchip) { struct vx_core *chip; struct snd_vx222 *vx; @@ -170,7 +170,7 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci if (request_irq(pci->irq, snd_vx_irq_handler, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(card->dev, "unable to grab IRQ %d\n", pci->irq); snd_vx222_free(chip); return -EBUSY; } @@ -181,15 +181,13 @@ static int __devinit snd_vx222_create(struct snd_card *card, struct pci_dev *pci return err; } - snd_card_set_dev(card, &pci->dev); - *rchip = vx; return 0; } -static int __devinit snd_vx222_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_vx222_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -204,7 +202,8 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -229,7 +228,7 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx & 0x%lx, irq %i", card->shortname, vx->port[0], vx->port[1], vx->core.irq); - snd_printdd("%s at 0x%lx & 0x%lx, irq %i\n", + dev_dbg(card->dev, "%s at 0x%lx & 0x%lx, irq %i\n", card->shortname, vx->port[0], vx->port[1], vx->core.irq); #ifdef SND_VX_FW_LOADER @@ -251,10 +250,9 @@ static int __devinit snd_vx222_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_vx222_remove(struct pci_dev *pci) +static void snd_vx222_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } #ifdef CONFIG_PM_SLEEP @@ -281,8 +279,7 @@ static int snd_vx222_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "vx222: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -300,7 +297,7 @@ static struct pci_driver vx222_driver = { .name = KBUILD_MODNAME, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, - .remove = __devexit_p(snd_vx222_remove), + .remove = snd_vx222_remove, .driver = { .pm = SND_VX222_PM_OPS, }, diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c index a69e774d0b1..2d1570273e9 100644 --- a/sound/pci/vx222/vx222_ops.c +++ b/sound/pci/vx222/vx222_ops.c @@ -108,7 +108,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val) { outb(val, vx2_reg_addr(chip, offset)); /* - printk(KERN_DEBUG "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset)); + dev_dbg(chip->card->dev, "outb: %x -> %x\n", val, vx2_reg_addr(chip, offset)); */ } @@ -129,7 +129,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset) static void vx2_outl(struct vx_core *chip, int offset, unsigned int val) { /* - printk(KERN_DEBUG "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset)); + dev_dbg(chip->card->dev, "outl: %x -> %x\n", val, vx2_reg_addr(chip, offset)); */ outl(val, vx2_reg_addr(chip, offset)); } @@ -173,7 +173,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) struct snd_vx222 *chip = (struct snd_vx222 *)_chip; unsigned int data; - snd_printdd("testing xilinx...\n"); + dev_dbg(_chip->card->dev, "testing xilinx...\n"); /* This test uses several write/read sequences on TEST0 and TEST1 bits * to figure out whever or not the xilinx was correctly loaded */ @@ -183,7 +183,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if ((data & VX_STATUS_VAL_TEST0_MASK) == VX_STATUS_VAL_TEST0_MASK) { - snd_printdd("bad!\n"); + dev_dbg(_chip->card->dev, "bad!\n"); return -ENODEV; } @@ -192,7 +192,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if (! (data & VX_STATUS_VAL_TEST0_MASK)) { - snd_printdd("bad! #2\n"); + dev_dbg(_chip->card->dev, "bad! #2\n"); return -ENODEV; } @@ -203,7 +203,7 @@ static int vx2_test_xilinx(struct vx_core *_chip) vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if ((data & VX_STATUS_VAL_TEST1_MASK) == VX_STATUS_VAL_TEST1_MASK) { - snd_printdd("bad! #3\n"); + dev_dbg(_chip->card->dev, "bad! #3\n"); return -ENODEV; } @@ -212,11 +212,11 @@ static int vx2_test_xilinx(struct vx_core *_chip) vx_inl(chip, ISR); data = vx_inl(chip, STATUS); if (! (data & VX_STATUS_VAL_TEST1_MASK)) { - snd_printdd("bad! #4\n"); + dev_dbg(_chip->card->dev, "bad! #4\n"); return -ENODEV; } } - snd_printdd("ok, xilinx fine.\n"); + dev_dbg(_chip->card->dev, "ok, xilinx fine.\n"); return 0; } @@ -397,7 +397,8 @@ static int vx2_load_xilinx_binary(struct vx_core *chip, const struct firmware *x i = vx_inl(chip, GPIOC); if (i & 0x0100) return 0; - snd_printk(KERN_ERR "vx222: xilinx test failed after load, GPIOC=0x%x\n", i); + dev_err(chip->card->dev, + "xilinx test failed after load, GPIOC=0x%x\n", i); return -EINVAL; } diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e01fe34db9e..82eed164b27 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c @@ -79,8 +79,8 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { MODULE_DEVICE_TABLE(pci, snd_ymfpci_ids); #ifdef SUPPORT_JOYSTICK -static int __devinit snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, - int legacy_ctrl, int legacy_ctrl2) +static int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, + int legacy_ctrl, int legacy_ctrl2) { struct gameport *gp; struct resource *r = NULL; @@ -106,7 +106,8 @@ static int __devinit snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev break; } if (!r) { - printk(KERN_ERR "ymfpci: no gameport ports available\n"); + dev_err(chip->card->dev, + "no gameport ports available\n"); return -EBUSY; } } @@ -116,19 +117,22 @@ static int __devinit snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev case 0x204: legacy_ctrl2 |= 2 << 6; break; case 0x205: legacy_ctrl2 |= 3 << 6; break; default: - printk(KERN_ERR "ymfpci: invalid joystick port %#x", io_port); + dev_err(chip->card->dev, + "invalid joystick port %#x", io_port); return -EINVAL; } } if (!r && !(r = request_region(io_port, 1, "YMFPCI gameport"))) { - printk(KERN_ERR "ymfpci: joystick port %#x is in use.\n", io_port); + dev_err(chip->card->dev, + "joystick port %#x is in use.\n", io_port); return -EBUSY; } chip->gameport = gp = gameport_allocate_port(); if (!gp) { - printk(KERN_ERR "ymfpci: cannot allocate memory for gameport\n"); + dev_err(chip->card->dev, + "cannot allocate memory for gameport\n"); release_and_free_resource(r); return -ENOMEM; } @@ -167,8 +171,8 @@ static inline int snd_ymfpci_create_gameport(struct snd_ymfpci *chip, int dev, i void snd_ymfpci_free_gameport(struct snd_ymfpci *chip) { } #endif /* SUPPORT_JOYSTICK */ -static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, - const struct pci_device_id *pci_id) +static int snd_card_ymfpci_probe(struct pci_dev *pci, + const struct pci_device_id *pci_id) { static int dev; struct snd_card *card; @@ -187,7 +191,8 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, return -ENOENT; } - err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); + err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE, + 0, &card); if (err < 0) return err; @@ -313,7 +318,9 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, MPU401_INFO_INTEGRATED | MPU401_INFO_IRQ_HOOK, -1, &chip->rawmidi)) < 0) { - printk(KERN_WARNING "ymfpci: cannot initialize MPU401 at 0x%lx, skipping...\n", mpu_port[dev]); + dev_warn(card->dev, + "cannot initialize MPU401 at 0x%lx, skipping...\n", + mpu_port[dev]); legacy_ctrl &= ~YMFPCI_LEGACY_MIEN; /* disable MPU401 irq */ pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); } @@ -323,12 +330,14 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, fm_port[dev], fm_port[dev] + 2, OPL3_HW_OPL3, 1, &opl3)) < 0) { - printk(KERN_WARNING "ymfpci: cannot initialize FM OPL3 at 0x%lx, skipping...\n", fm_port[dev]); + dev_warn(card->dev, + "cannot initialize FM OPL3 at 0x%lx, skipping...\n", + fm_port[dev]); legacy_ctrl &= ~YMFPCI_LEGACY_FMEN; pci_write_config_word(pci, PCIR_DSXG_LEGACY, legacy_ctrl); } else if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { snd_card_free(card); - snd_printk(KERN_ERR "cannot create opl3 hwdep\n"); + dev_err(card->dev, "cannot create opl3 hwdep\n"); return err; } } @@ -344,17 +353,16 @@ static int __devinit snd_card_ymfpci_probe(struct pci_dev *pci, return 0; } -static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) +static void snd_card_ymfpci_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); - pci_set_drvdata(pci, NULL); } static struct pci_driver ymfpci_driver = { .name = KBUILD_MODNAME, .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, - .remove = __devexit_p(snd_card_ymfpci_remove), + .remove = snd_card_ymfpci_remove, #ifdef CONFIG_PM_SLEEP .driver = { .pm = &snd_ymfpci_pm, diff --git a/sound/pci/ymfpci/ymfpci_main.c b/sound/pci/ymfpci/ymfpci_main.c index 3a6f03f9b02..81c916a5eb9 100644 --- a/sound/pci/ymfpci/ymfpci_main.c +++ b/sound/pci/ymfpci/ymfpci_main.c @@ -25,7 +25,6 @@ #include <linux/pci.h> #include <linux/sched.h> #include <linux/slab.h> -#include <linux/vmalloc.h> #include <linux/mutex.h> #include <linux/module.h> @@ -87,7 +86,9 @@ static int snd_ymfpci_codec_ready(struct snd_ymfpci *chip, int secondary) return 0; schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); - snd_printk(KERN_ERR "codec_ready: codec %i is not ready [0x%x]\n", secondary, snd_ymfpci_readw(chip, reg)); + dev_err(chip->card->dev, + "codec_ready: codec %i is not ready [0x%x]\n", + secondary, snd_ymfpci_readw(chip, reg)); return -EBUSY; } @@ -320,7 +321,7 @@ static void snd_ymfpci_pcm_interrupt(struct snd_ymfpci *chip, struct snd_ymfpci_ ypcm->last_pos = pos; if (ypcm->period_pos >= ypcm->period_size) { /* - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start); @@ -373,7 +374,7 @@ static void snd_ymfpci_pcm_capture_interrupt(struct snd_pcm_substream *substream if (ypcm->period_pos >= ypcm->period_size) { ypcm->period_pos %= ypcm->period_size; /* - printk(KERN_DEBUG + dev_dbg(chip->card->dev, "done - active_bank = 0x%x, start = 0x%x\n", chip->active_bank, voice->bank[chip->active_bank].start); @@ -598,7 +599,7 @@ static void snd_ymfpci_pcm_init_voice(struct snd_ymfpci_pcm *ypcm, unsigned int } } -static int __devinit snd_ymfpci_ac3_init(struct snd_ymfpci *chip) +static int snd_ymfpci_ac3_init(struct snd_ymfpci *chip) { if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 4096, &chip->ac3_tmp_base) < 0) @@ -1144,7 +1145,7 @@ static struct snd_pcm_ops snd_ymfpci_capture_rec_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int __devinit snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1187,7 +1188,7 @@ static struct snd_pcm_ops snd_ymfpci_capture_ac97_ops = { .pointer = snd_ymfpci_capture_pointer, }; -int __devinit snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm2(struct snd_ymfpci *chip, int device, struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1225,7 +1226,8 @@ static struct snd_pcm_ops snd_ymfpci_playback_spdif_ops = { .pointer = snd_ymfpci_playback_pointer, }; -int __devinit snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm_spdif(struct snd_ymfpci *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1270,7 +1272,8 @@ static const struct snd_pcm_chmap_elem surround_map[] = { { } }; -int __devinit snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, struct snd_pcm ** rpcm) +int snd_ymfpci_pcm_4ch(struct snd_ymfpci *chip, int device, + struct snd_pcm **rpcm) { struct snd_pcm *pcm; int err; @@ -1339,7 +1342,7 @@ static int snd_ymfpci_spdif_default_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ymfpci_spdif_default __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_default = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), @@ -1367,7 +1370,7 @@ static int snd_ymfpci_spdif_mask_get(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ymfpci_spdif_mask __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_mask = { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1414,7 +1417,7 @@ static int snd_ymfpci_spdif_stream_put(struct snd_kcontrol *kcontrol, return change; } -static struct snd_kcontrol_new snd_ymfpci_spdif_stream __devinitdata = +static struct snd_kcontrol_new snd_ymfpci_spdif_stream = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_INACTIVE, .iface = SNDRV_CTL_ELEM_IFACE_PCM, @@ -1462,7 +1465,7 @@ static int snd_ymfpci_drec_source_put(struct snd_kcontrol *kcontrol, struct snd_ return reg != old_reg; } -static struct snd_kcontrol_new snd_ymfpci_drec_source __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_drec_source = { .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Direct Recording Source", @@ -1632,7 +1635,7 @@ static int snd_ymfpci_put_dup4ch(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static struct snd_kcontrol_new snd_ymfpci_dup4ch __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_dup4ch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "4ch Duplication", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, @@ -1641,7 +1644,7 @@ static struct snd_kcontrol_new snd_ymfpci_dup4ch __devinitdata = { .put = snd_ymfpci_put_dup4ch, }; -static struct snd_kcontrol_new snd_ymfpci_controls[] __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_controls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Wave Playback Volume", @@ -1735,7 +1738,7 @@ static int snd_ymfpci_gpio_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ return 0; } -static struct snd_kcontrol_new snd_ymfpci_rear_shared __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_rear_shared = { .name = "Shared Rear/Line-In Switch", .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .info = snd_ymfpci_gpio_sw_info, @@ -1799,7 +1802,7 @@ static int snd_ymfpci_pcm_vol_put(struct snd_kcontrol *kcontrol, return 0; } -static struct snd_kcontrol_new snd_ymfpci_pcm_volume __devinitdata = { +static struct snd_kcontrol_new snd_ymfpci_pcm_volume = { .iface = SNDRV_CTL_ELEM_IFACE_PCM, .name = "PCM Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | @@ -1826,7 +1829,7 @@ static void snd_ymfpci_mixer_free_ac97(struct snd_ac97 *ac97) chip->ac97 = NULL; } -int __devinit snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) +int snd_ymfpci_mixer(struct snd_ymfpci *chip, int rear_switch) { struct snd_ac97_template ac97; struct snd_kcontrol *kctl; @@ -1970,7 +1973,7 @@ static struct snd_timer_hardware snd_ymfpci_timer_hw = { .precise_resolution = snd_ymfpci_timer_precise_resolution, }; -int __devinit snd_ymfpci_timer(struct snd_ymfpci *chip, int device) +int snd_ymfpci_timer(struct snd_ymfpci *chip, int device) { struct snd_timer *timer = NULL; struct snd_timer_id tid; @@ -2006,7 +2009,7 @@ static void snd_ymfpci_proc_read(struct snd_info_entry *entry, snd_iprintf(buffer, "%04x: %04x\n", i, snd_ymfpci_readl(chip, i)); } -static int __devinit snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) +static int snd_ymfpci_proc_init(struct snd_card *card, struct snd_ymfpci *chip) { struct snd_info_entry *entry; @@ -2066,7 +2069,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) &chip->pci->dev); if (err >= 0) { if (chip->dsp_microcode->size != YDSXG_DSPLENGTH) { - snd_printk(KERN_ERR "DSP microcode has wrong size\n"); + dev_err(chip->card->dev, + "DSP microcode has wrong size\n"); err = -EINVAL; } } @@ -2081,8 +2085,8 @@ static int snd_ymfpci_request_firmware(struct snd_ymfpci *chip) &chip->pci->dev); if (err >= 0) { if (chip->controller_microcode->size != YDSXG_CTRLLENGTH) { - snd_printk(KERN_ERR "controller microcode" - " has wrong size\n"); + dev_err(chip->card->dev, + "controller microcode has wrong size\n"); err = -EINVAL; } } @@ -2128,7 +2132,7 @@ static void snd_ymfpci_download_image(struct snd_ymfpci *chip) snd_ymfpci_enable_dsp(chip); } -static int __devinit snd_ymfpci_memalloc(struct snd_ymfpci *chip) +static int snd_ymfpci_memalloc(struct snd_ymfpci *chip) { long size, playback_ctrl_size; int voice, bank, reg; @@ -2257,11 +2261,11 @@ static int snd_ymfpci_free(struct snd_ymfpci *chip) /* FIXME: temporarily disabled, otherwise we cannot fire up * the chip again unless reboot. ACPI bug? */ - pci_set_power_state(chip->pci, 3); + pci_set_power_state(chip->pci, PCI_D3hot); #endif #ifdef CONFIG_PM_SLEEP - vfree(chip->saved_regs); + kfree(chip->saved_regs); #endif if (chip->irq >= 0) free_irq(chip->irq, chip); @@ -2359,8 +2363,7 @@ static int snd_ymfpci_resume(struct device *dev) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "ymfpci: pci_enable_device failed, " - "disabling device\n"); + dev_err(dev, "pci_enable_device failed, disabling device\n"); snd_card_disconnect(card); return -EIO; } @@ -2394,10 +2397,10 @@ static int snd_ymfpci_resume(struct device *dev) SIMPLE_DEV_PM_OPS(snd_ymfpci_pm, snd_ymfpci_suspend, snd_ymfpci_resume); #endif /* CONFIG_PM_SLEEP */ -int __devinit snd_ymfpci_create(struct snd_card *card, - struct pci_dev * pci, - unsigned short old_legacy_ctrl, - struct snd_ymfpci ** rchip) +int snd_ymfpci_create(struct snd_card *card, + struct pci_dev *pci, + unsigned short old_legacy_ctrl, + struct snd_ymfpci **rchip) { struct snd_ymfpci *chip; int err; @@ -2432,13 +2435,15 @@ int __devinit snd_ymfpci_create(struct snd_card *card, chip->src441_used = -1; if ((chip->res_reg_area = request_mem_region(chip->reg_area_phys, 0x8000, "YMFPCI")) == NULL) { - snd_printk(KERN_ERR "unable to grab memory region 0x%lx-0x%lx\n", chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); + dev_err(chip->card->dev, + "unable to grab memory region 0x%lx-0x%lx\n", + chip->reg_area_phys, chip->reg_area_phys + 0x8000 - 1); snd_ymfpci_free(chip); return -EBUSY; } if (request_irq(pci->irq, snd_ymfpci_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { - snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); + dev_err(chip->card->dev, "unable to grab IRQ %d\n", pci->irq); snd_ymfpci_free(chip); return -EBUSY; } @@ -2452,7 +2457,7 @@ int __devinit snd_ymfpci_create(struct snd_card *card, err = snd_ymfpci_request_firmware(chip); if (err < 0) { - snd_printk(KERN_ERR "firmware request failed: %d\n", err); + dev_err(chip->card->dev, "firmware request failed: %d\n", err); snd_ymfpci_free(chip); return err; } @@ -2471,7 +2476,8 @@ int __devinit snd_ymfpci_create(struct snd_card *card, } #ifdef CONFIG_PM_SLEEP - chip->saved_regs = vmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32)); + chip->saved_regs = kmalloc(YDSXGR_NUM_SAVED_REGS * sizeof(u32), + GFP_KERNEL); if (chip->saved_regs == NULL) { snd_ymfpci_free(chip); return -ENOMEM; @@ -2485,8 +2491,6 @@ int __devinit snd_ymfpci_create(struct snd_card *card, snd_ymfpci_proc_init(card, chip); - snd_card_set_dev(card, &pci->dev); - *rchip = chip; return 0; } |
