From 8f34692f63d66805b51ff408f4067748d3c1c3fd Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:36 +0200 Subject: ALSA: ak4620 support, codec regs listed in proc * complete support for ak4620 * codec regs listed in proc for all codecs/chips * adding total regs for each codec * fixing nb. of steps in input attenuation controls Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/i2c/other/ak4xxx-adda.c | 136 ++++++++++++++++++++++++++++++++---------- sound/pci/ice1712/juli.c | 21 ------- 2 files changed, 104 insertions(+), 53 deletions(-) (limited to 'sound') diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c index ee47abab764e..1adb8a3c2b62 100644 --- a/sound/i2c/other/ak4xxx-adda.c +++ b/sound/i2c/other/ak4xxx-adda.c @@ -19,7 +19,7 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * - */ + */ #include #include @@ -29,6 +29,7 @@ #include #include #include +#include MODULE_AUTHOR("Jaroslav Kysela , Takashi Iwai "); MODULE_DESCRIPTION("Routines for control of AK452x / AK43xx AD/DA converters"); @@ -52,26 +53,21 @@ EXPORT_SYMBOL(snd_akm4xxx_write); static void ak4524_reset(struct snd_akm4xxx *ak, int state) { unsigned int chip; - unsigned char reg, maxreg; + unsigned char reg; - if (ak->type == SND_AK4528) - maxreg = 0x06; - else - maxreg = 0x08; for (chip = 0; chip < ak->num_dacs/2; chip++) { snd_akm4xxx_write(ak, chip, 0x01, state ? 0x00 : 0x03); if (state) continue; /* DAC volumes */ - for (reg = 0x04; reg < maxreg; reg++) + for (reg = 0x04; reg < ak->total_regs; reg++) snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); } } /* reset procedure for AK4355 and AK4358 */ -static void ak435X_reset(struct snd_akm4xxx *ak, int state, - unsigned char total_regs) +static void ak435X_reset(struct snd_akm4xxx *ak, int state) { unsigned char reg; @@ -79,7 +75,7 @@ static void ak435X_reset(struct snd_akm4xxx *ak, int state, snd_akm4xxx_write(ak, 0, 0x01, 0x02); /* reset and soft-mute */ return; } - for (reg = 0x00; reg < total_regs; reg++) + for (reg = 0x00; reg < ak->total_regs; reg++) if (reg != 0x01) snd_akm4xxx_write(ak, 0, reg, snd_akm4xxx_get(ak, 0, reg)); @@ -91,12 +87,11 @@ static void ak4381_reset(struct snd_akm4xxx *ak, int state) { unsigned int chip; unsigned char reg; - for (chip = 0; chip < ak->num_dacs/2; chip++) { snd_akm4xxx_write(ak, chip, 0x00, state ? 0x0c : 0x0f); if (state) continue; - for (reg = 0x01; reg < 0x05; reg++) + for (reg = 0x01; reg < ak->total_regs; reg++) snd_akm4xxx_write(ak, chip, reg, snd_akm4xxx_get(ak, chip, reg)); } @@ -113,16 +108,17 @@ void snd_akm4xxx_reset(struct snd_akm4xxx *ak, int state) switch (ak->type) { case SND_AK4524: case SND_AK4528: + case SND_AK4620: ak4524_reset(ak, state); break; case SND_AK4529: /* FIXME: needed for ak4529? */ break; case SND_AK4355: - ak435X_reset(ak, state, 0x0b); + ak435X_reset(ak, state); break; case SND_AK4358: - ak435X_reset(ak, state, 0x10); + ak435X_reset(ak, state); break; case SND_AK4381: ak4381_reset(ak, state); @@ -139,7 +135,7 @@ EXPORT_SYMBOL(snd_akm4xxx_reset); * Volume conversion table for non-linear volumes * from -63.5dB (mute) to 0dB step 0.5dB * - * Used for AK4524 input/ouput attenuation, AK4528, and + * Used for AK4524/AK4620 input/ouput attenuation, AK4528, and * AK5365 input attenuation */ static const unsigned char vol_cvt_datt[128] = { @@ -259,8 +255,22 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) 0x00, 0x0f, /* 0: power-up, un-reset */ 0xff, 0xff }; + static const unsigned char inits_ak4620[] = { + 0x00, 0x07, /* 0: normal */ + 0x01, 0x00, /* 0: reset */ + 0x01, 0x02, /* 1: RSTAD */ + 0x01, 0x03, /* 1: RSTDA */ + 0x01, 0x0f, /* 1: normal */ + 0x02, 0x60, /* 2: 24bit I2S */ + 0x03, 0x01, /* 3: deemphasis off */ + 0x04, 0x00, /* 4: LIN muted */ + 0x05, 0x00, /* 5: RIN muted */ + 0x06, 0x00, /* 6: LOUT muted */ + 0x07, 0x00, /* 7: ROUT muted */ + 0xff, 0xff + }; - int chip, num_chips; + int chip; const unsigned char *ptr, *inits; unsigned char reg, data; @@ -270,42 +280,64 @@ void snd_akm4xxx_init(struct snd_akm4xxx *ak) switch (ak->type) { case SND_AK4524: inits = inits_ak4524; - num_chips = ak->num_dacs / 2; + ak->num_chips = ak->num_dacs / 2; + ak->name = "ak4524"; + ak->total_regs = 0x08; break; case SND_AK4528: inits = inits_ak4528; - num_chips = ak->num_dacs / 2; + ak->num_chips = ak->num_dacs / 2; + ak->name = "ak4528"; + ak->total_regs = 0x06; break; case SND_AK4529: inits = inits_ak4529; - num_chips = 1; + ak->num_chips = 1; + ak->name = "ak4529"; + ak->total_regs = 0x0d; break; case SND_AK4355: inits = inits_ak4355; - num_chips = 1; + ak->num_chips = 1; + ak->name = "ak4355"; + ak->total_regs = 0x0b; break; case SND_AK4358: inits = inits_ak4358; - num_chips = 1; + ak->num_chips = 1; + ak->name = "ak4358"; + ak->total_regs = 0x10; break; case SND_AK4381: inits = inits_ak4381; - num_chips = ak->num_dacs / 2; + ak->num_chips = ak->num_dacs / 2; + ak->name = "ak4381"; + ak->total_regs = 0x05; break; case SND_AK5365: /* FIXME: any init sequence? */ + ak->num_chips = 1; + ak->name = "ak5365"; + ak->total_regs = 0x08; return; + case SND_AK4620: + inits = inits_ak4620; + ak->num_chips = ak->num_dacs / 2; + ak->name = "ak4620"; + ak->total_regs = 0x08; + break; default: snd_BUG(); return; } - for (chip = 0; chip < num_chips; chip++) { + for (chip = 0; chip < ak->num_chips; chip++) { ptr = inits; while (*ptr != 0xff) { reg = *ptr++; data = *ptr++; snd_akm4xxx_write(ak, chip, reg, data); + udelay(10); } } } @@ -688,6 +720,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak) AK_COMPOSE(idx/2, (idx%2) + 3, 0, 255); knew.tlv.p = db_scale_linear; break; + case SND_AK4620: + /* register 6 & 7 */ + knew.private_value = + AK_COMPOSE(idx/2, (idx%2) + 6, 0, 255); + knew.tlv.p = db_scale_linear; + break; default: return -EINVAL; } @@ -704,10 +742,12 @@ static int build_dac_controls(struct snd_akm4xxx *ak) static int build_adc_controls(struct snd_akm4xxx *ak) { - int idx, err, mixer_ch, num_stereo; + int idx, err, mixer_ch, num_stereo, max_steps; struct snd_kcontrol_new knew; mixer_ch = 0; + if (ak->type == SND_AK4528) + return 0; /* no controls */ for (idx = 0; idx < ak->num_adcs;) { memset(&knew, 0, sizeof(knew)); if (! ak->adc_info || ! ak->adc_info[mixer_ch].name) { @@ -733,13 +773,12 @@ static int build_adc_controls(struct snd_akm4xxx *ak) } /* register 4 & 5 */ if (ak->type == SND_AK5365) - knew.private_value = - AK_COMPOSE(idx/2, (idx%2) + 4, 0, 151) | - AK_VOL_CVT | AK_IPGA; + max_steps = 152; else - knew.private_value = - AK_COMPOSE(idx/2, (idx%2) + 4, 0, 163) | - AK_VOL_CVT | AK_IPGA; + max_steps = 164; + knew.private_value = + AK_COMPOSE(idx/2, (idx%2) + 4, 0, max_steps) | + AK_VOL_CVT | AK_IPGA; knew.tlv.p = db_scale_vol_datt; err = snd_ctl_add(ak->card, snd_ctl_new1(&knew, ak)); if (err < 0) @@ -808,6 +847,7 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) switch (ak->type) { case SND_AK4524: case SND_AK4528: + case SND_AK4620: /* register 3 */ knew.private_value = AK_COMPOSE(idx, 3, 0, 0); break; @@ -834,6 +874,35 @@ static int build_deemphasis(struct snd_akm4xxx *ak, int num_emphs) return 0; } +#ifdef CONFIG_PROC_FS +static void proc_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_akm4xxx *ak = (struct snd_akm4xxx *)entry->private_data; + int reg, val, chip; + for (chip = 0; chip < ak->num_chips; chip++) { + for (reg = 0; reg < ak->total_regs; reg++) { + val = snd_akm4xxx_get(ak, chip, reg); + snd_iprintf(buffer, "chip %d: 0x%02x = 0x%02x\n", chip, + reg, val); + } + } +} + +static int proc_init(struct snd_akm4xxx *ak) +{ + struct snd_info_entry *entry; + int err; + err = snd_card_proc_new(ak->card, ak->name, &entry); + if (err < 0) + return err; + snd_info_set_text_ops(entry, ak, proc_regs_read); + return 0; +} +#else /* !CONFIG_PROC_FS */ +static int proc_init(struct snd_akm4xxx *ak) {} +#endif + int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) { int err, num_emphs; @@ -845,18 +914,21 @@ int snd_akm4xxx_build_controls(struct snd_akm4xxx *ak) err = build_adc_controls(ak); if (err < 0) return err; - if (ak->type == SND_AK4355 || ak->type == SND_AK4358) num_emphs = 1; + else if (ak->type == SND_AK4620) + num_emphs = 0; else num_emphs = ak->num_dacs / 2; err = build_deemphasis(ak, num_emphs); + if (err < 0) + return err; + err = proc_init(ak); if (err < 0) return err; return 0; } - EXPORT_SYMBOL(snd_akm4xxx_build_controls); static int __init alsa_akm4xxx_module_init(void) diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9aef..4789e8bfdc17 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -412,25 +412,6 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { }, }; - -static void ak4358_proc_regs_read(struct snd_info_entry *entry, - struct snd_info_buffer *buffer) -{ - struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; - int reg, val; - for (reg = 0; reg <= 0xf; reg++) { - val = snd_akm4xxx_get(ice->akm, 0, reg); - snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); - } -} - -static void ak4358_proc_init(struct snd_ice1712 *ice) -{ - struct snd_info_entry *entry; - if (!snd_card_proc_new(ice->card, "ak4358_codec", &entry)) - snd_info_set_text_ops(entry, ice, ak4358_proc_regs_read); -} - static char *slave_vols[] __devinitdata = { PCM_VOLUME, MONITOR_AN_IN_VOLUME, @@ -496,8 +477,6 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) /* only capture SPDIF over AK4114 */ err = snd_ak4114_build(spec->ak4114, NULL, ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); - - ak4358_proc_init(ice); if (err < 0) return err; return 0; -- cgit v1.2.3 From 42cfa276aebd28e5cc4350ff6c7d75f1cb84dd98 Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:37 +0200 Subject: ALSA: ak4113 support * complete support for ak4113 * based on code for ak4114 and ak4117 Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/i2c/other/Makefile | 3 +- sound/i2c/other/ak4113.c | 639 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 641 insertions(+), 1 deletion(-) create mode 100644 sound/i2c/other/ak4113.c (limited to 'sound') diff --git a/sound/i2c/other/Makefile b/sound/i2c/other/Makefile index 703d954238f4..2dad40f3f622 100644 --- a/sound/i2c/other/Makefile +++ b/sound/i2c/other/Makefile @@ -5,6 +5,7 @@ snd-ak4114-objs := ak4114.o snd-ak4117-objs := ak4117.o +snd-ak4113-objs := ak4113.o snd-ak4xxx-adda-objs := ak4xxx-adda.o snd-pt2258-objs := pt2258.o snd-tea575x-tuner-objs := tea575x-tuner.o @@ -12,5 +13,5 @@ snd-tea575x-tuner-objs := tea575x-tuner.o # Module Dependency obj-$(CONFIG_SND_PDAUDIOCF) += snd-ak4117.o obj-$(CONFIG_SND_ICE1712) += snd-ak4xxx-adda.o -obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4xxx-adda.o snd-pt2258.o +obj-$(CONFIG_SND_ICE1724) += snd-ak4114.o snd-ak4113.o snd-ak4xxx-adda.o snd-pt2258.o obj-$(CONFIG_SND_FM801_TEA575X) += snd-tea575x-tuner.o diff --git a/sound/i2c/other/ak4113.c b/sound/i2c/other/ak4113.c new file mode 100644 index 000000000000..fff62cc8607c --- /dev/null +++ b/sound/i2c/other/ak4113.c @@ -0,0 +1,639 @@ +/* + * Routines for control of the AK4113 via I2C/4-wire serial interface + * IEC958 (S/PDIF) receiver by Asahi Kasei + * Copyright (c) by Jaroslav Kysela + * Copyright (c) by Pavel Hofman + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Pavel Hofman "); +MODULE_DESCRIPTION("AK4113 IEC958 (S/PDIF) receiver by Asahi Kasei"); +MODULE_LICENSE("GPL"); + +#define AK4113_ADDR 0x00 /* fixed address */ + +static void ak4113_stats(struct work_struct *work); +static void ak4113_init_regs(struct ak4113 *chip); + + +static void reg_write(struct ak4113 *ak4113, unsigned char reg, + unsigned char val) +{ + ak4113->write(ak4113->private_data, reg, val); + if (reg < sizeof(ak4113->regmap)) + ak4113->regmap[reg] = val; +} + +static inline unsigned char reg_read(struct ak4113 *ak4113, unsigned char reg) +{ + return ak4113->read(ak4113->private_data, reg); +} + +static void snd_ak4113_free(struct ak4113 *chip) +{ + chip->init = 1; /* don't schedule new work */ + mb(); + cancel_delayed_work(&chip->work); + flush_scheduled_work(); + kfree(chip); +} + +static int snd_ak4113_dev_free(struct snd_device *device) +{ + struct ak4113 *chip = device->device_data; + snd_ak4113_free(chip); + return 0; +} + +int snd_ak4113_create(struct snd_card *card, ak4113_read_t *read, + ak4113_write_t *write, const unsigned char pgm[5], + void *private_data, struct ak4113 **r_ak4113) +{ + struct ak4113 *chip; + int err = 0; + unsigned char reg; + static struct snd_device_ops ops = { + .dev_free = snd_ak4113_dev_free, + }; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + spin_lock_init(&chip->lock); + chip->card = card; + chip->read = read; + chip->write = write; + chip->private_data = private_data; + INIT_DELAYED_WORK(&chip->work, ak4113_stats); + + for (reg = 0; reg < AK4113_WRITABLE_REGS ; reg++) + chip->regmap[reg] = pgm[reg]; + ak4113_init_regs(chip); + + chip->rcs0 = reg_read(chip, AK4113_REG_RCS0) & ~(AK4113_QINT | + AK4113_CINT | AK4113_STC); + chip->rcs1 = reg_read(chip, AK4113_REG_RCS1); + chip->rcs2 = reg_read(chip, AK4113_REG_RCS2); + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) + goto __fail; + + if (r_ak4113) + *r_ak4113 = chip; + return 0; + +__fail: + snd_ak4113_free(chip); + return err < 0 ? err : -EIO; +} +EXPORT_SYMBOL_GPL(snd_ak4113_create); + +void snd_ak4113_reg_write(struct ak4113 *chip, unsigned char reg, + unsigned char mask, unsigned char val) +{ + if (reg >= AK4113_WRITABLE_REGS) + return; + reg_write(chip, reg, (chip->regmap[reg] & ~mask) | val); +} +EXPORT_SYMBOL_GPL(snd_ak4113_reg_write); + +static void ak4113_init_regs(struct ak4113 *chip) +{ + unsigned char old = chip->regmap[AK4113_REG_PWRDN], reg; + + /* bring the chip to reset state and powerdown state */ + reg_write(chip, AK4113_REG_PWRDN, old & ~(AK4113_RST|AK4113_PWN)); + udelay(200); + /* release reset, but leave powerdown */ + reg_write(chip, AK4113_REG_PWRDN, (old | AK4113_RST) & ~AK4113_PWN); + udelay(200); + for (reg = 1; reg < AK4113_WRITABLE_REGS; reg++) + reg_write(chip, reg, chip->regmap[reg]); + /* release powerdown, everything is initialized now */ + reg_write(chip, AK4113_REG_PWRDN, old | AK4113_RST | AK4113_PWN); +} + +void snd_ak4113_reinit(struct ak4113 *chip) +{ + chip->init = 1; + mb(); + flush_scheduled_work(); + ak4113_init_regs(chip); + /* bring up statistics / event queing */ + chip->init = 0; + if (chip->kctls[0]) + schedule_delayed_work(&chip->work, HZ / 10); +} +EXPORT_SYMBOL_GPL(snd_ak4113_reinit); + +static unsigned int external_rate(unsigned char rcs1) +{ + switch (rcs1 & (AK4113_FS0|AK4113_FS1|AK4113_FS2|AK4113_FS3)) { + case AK4113_FS_8000HZ: + return 8000; + case AK4113_FS_11025HZ: + return 11025; + case AK4113_FS_16000HZ: + return 16000; + case AK4113_FS_22050HZ: + return 22050; + case AK4113_FS_24000HZ: + return 24000; + case AK4113_FS_32000HZ: + return 32000; + case AK4113_FS_44100HZ: + return 44100; + case AK4113_FS_48000HZ: + return 48000; + case AK4113_FS_64000HZ: + return 64000; + case AK4113_FS_88200HZ: + return 88200; + case AK4113_FS_96000HZ: + return 96000; + case AK4113_FS_176400HZ: + return 176400; + case AK4113_FS_192000HZ: + return 192000; + default: + return 0; + } +} + +static int snd_ak4113_in_error_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = LONG_MAX; + return 0; +} + +static int snd_ak4113_in_error_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + long *ptr; + + spin_lock_irq(&chip->lock); + ptr = (long *)(((char *)chip) + kcontrol->private_value); + ucontrol->value.integer.value[0] = *ptr; + *ptr = 0; + spin_unlock_irq(&chip->lock); + return 0; +} + +#define snd_ak4113_in_bit_info snd_ctl_boolean_mono_info + +static int snd_ak4113_in_bit_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + unsigned char reg = kcontrol->private_value & 0xff; + unsigned char bit = (kcontrol->private_value >> 8) & 0xff; + unsigned char inv = (kcontrol->private_value >> 31) & 1; + + ucontrol->value.integer.value[0] = + ((reg_read(chip, reg) & (1 << bit)) ? 1 : 0) ^ inv; + return 0; +} + +static int snd_ak4113_rx_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 5; + return 0; +} + +static int snd_ak4113_rx_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = + (AK4113_IPS(chip->regmap[AK4113_REG_IO1])); + return 0; +} + +static int snd_ak4113_rx_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + int change; + u8 old_val; + + spin_lock_irq(&chip->lock); + old_val = chip->regmap[AK4113_REG_IO1]; + change = ucontrol->value.integer.value[0] != AK4113_IPS(old_val); + if (change) + reg_write(chip, AK4113_REG_IO1, + (old_val & (~AK4113_IPS(0xff))) | + (AK4113_IPS(ucontrol->value.integer.value[0]))); + spin_unlock_irq(&chip->lock); + return change; +} + +static int snd_ak4113_rate_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 192000; + return 0; +} + +static int snd_ak4113_rate_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + + ucontrol->value.integer.value[0] = external_rate(reg_read(chip, + AK4113_REG_RCS1)); + return 0; +} + +static int snd_ak4113_spdif_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4113_spdif_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4113_REG_RXCSB_SIZE; i++) + ucontrol->value.iec958.status[i] = reg_read(chip, + AK4113_REG_RXCSB0 + i); + return 0; +} + +static int snd_ak4113_spdif_mask_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int snd_ak4113_spdif_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, AK4113_REG_RXCSB_SIZE); + return 0; +} + +static int snd_ak4113_spdif_pinfo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffff; + uinfo->count = 4; + return 0; +} + +static int snd_ak4113_spdif_pget(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + unsigned short tmp; + + ucontrol->value.integer.value[0] = 0xf8f2; + ucontrol->value.integer.value[1] = 0x4e1f; + tmp = reg_read(chip, AK4113_REG_Pc0) | + (reg_read(chip, AK4113_REG_Pc1) << 8); + ucontrol->value.integer.value[2] = tmp; + tmp = reg_read(chip, AK4113_REG_Pd0) | + (reg_read(chip, AK4113_REG_Pd1) << 8); + ucontrol->value.integer.value[3] = tmp; + return 0; +} + +static int snd_ak4113_spdif_qinfo(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = AK4113_REG_QSUB_SIZE; + return 0; +} + +static int snd_ak4113_spdif_qget(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct ak4113 *chip = snd_kcontrol_chip(kcontrol); + unsigned i; + + for (i = 0; i < AK4113_REG_QSUB_SIZE; i++) + ucontrol->value.bytes.data[i] = reg_read(chip, + AK4113_REG_QSUB_ADDR + i); + return 0; +} + +/* Don't forget to change AK4113_CONTROLS define!!! */ +static struct snd_kcontrol_new snd_ak4113_iec958_controls[] = { +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Parity Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_error_info, + .get = snd_ak4113_in_error_get, + .private_value = offsetof(struct ak4113, parity_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 V-Bit Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_error_info, + .get = snd_ak4113_in_error_get, + .private_value = offsetof(struct ak4113, v_bit_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 C-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_error_info, + .get = snd_ak4113_in_error_get, + .private_value = offsetof(struct ak4113, ccrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-CRC Errors", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_error_info, + .get = snd_ak4113_in_error_get, + .private_value = offsetof(struct ak4113, qcrc_errors), +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 External Rate", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_rate_info, + .get = snd_ak4113_rate_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, MASK), + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .info = snd_ak4113_spdif_mask_info, + .get = snd_ak4113_spdif_mask_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_spdif_info, + .get = snd_ak4113_spdif_get, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Preample Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_spdif_pinfo, + .get = snd_ak4113_spdif_pget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Q-subcode Capture Default", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_spdif_qinfo, + .get = snd_ak4113_spdif_qget, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Audio", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_bit_info, + .get = snd_ak4113_in_bit_get, + .private_value = (1<<31) | (1<<8) | AK4113_REG_RCS0, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 Non-PCM Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_bit_info, + .get = snd_ak4113_in_bit_get, + .private_value = (0<<8) | AK4113_REG_RCS1, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "IEC958 DTS Bitstream", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_VOLATILE, + .info = snd_ak4113_in_bit_info, + .get = snd_ak4113_in_bit_get, + .private_value = (1<<8) | AK4113_REG_RCS1, +}, +{ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = "AK4113 Input Select", + .access = SNDRV_CTL_ELEM_ACCESS_READ | + SNDRV_CTL_ELEM_ACCESS_WRITE, + .info = snd_ak4113_rx_info, + .get = snd_ak4113_rx_get, + .put = snd_ak4113_rx_put, +} +}; + +static void snd_ak4113_proc_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct ak4113 *ak4113 = entry->private_data; + int reg, val; + /* all ak4113 registers 0x00 - 0x1c */ + for (reg = 0; reg < 0x1d; reg++) { + val = reg_read(ak4113, reg); + snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); + } +} + +static void snd_ak4113_proc_init(struct ak4113 *ak4113) +{ + struct snd_info_entry *entry; + if (!snd_card_proc_new(ak4113->card, "ak4113", &entry)) + snd_info_set_text_ops(entry, ak4113, snd_ak4113_proc_regs_read); +} + +int snd_ak4113_build(struct ak4113 *ak4113, + struct snd_pcm_substream *cap_substream) +{ + struct snd_kcontrol *kctl; + unsigned int idx; + int err; + + if (snd_BUG_ON(!cap_substream)) + return -EINVAL; + ak4113->substream = cap_substream; + for (idx = 0; idx < AK4113_CONTROLS; idx++) { + kctl = snd_ctl_new1(&snd_ak4113_iec958_controls[idx], ak4113); + if (kctl == NULL) + return -ENOMEM; + kctl->id.device = cap_substream->pcm->device; + kctl->id.subdevice = cap_substream->number; + err = snd_ctl_add(ak4113->card, kctl); + if (err < 0) + return err; + ak4113->kctls[idx] = kctl; + } + snd_ak4113_proc_init(ak4113); + /* trigger workq */ + schedule_delayed_work(&ak4113->work, HZ / 10); + return 0; +} +EXPORT_SYMBOL_GPL(snd_ak4113_build); + +int snd_ak4113_external_rate(struct ak4113 *ak4113) +{ + unsigned char rcs1; + + rcs1 = reg_read(ak4113, AK4113_REG_RCS1); + return external_rate(rcs1); +} +EXPORT_SYMBOL_GPL(snd_ak4113_external_rate); + +int snd_ak4113_check_rate_and_errors(struct ak4113 *ak4113, unsigned int flags) +{ + struct snd_pcm_runtime *runtime = + ak4113->substream ? ak4113->substream->runtime : NULL; + unsigned long _flags; + int res = 0; + unsigned char rcs0, rcs1, rcs2; + unsigned char c0, c1; + + rcs1 = reg_read(ak4113, AK4113_REG_RCS1); + if (flags & AK4113_CHECK_NO_STAT) + goto __rate; + rcs0 = reg_read(ak4113, AK4113_REG_RCS0); + rcs2 = reg_read(ak4113, AK4113_REG_RCS2); + spin_lock_irqsave(&ak4113->lock, _flags); + if (rcs0 & AK4113_PAR) + ak4113->parity_errors++; + if (rcs0 & AK4113_V) + ak4113->v_bit_errors++; + if (rcs2 & AK4113_CCRC) + ak4113->ccrc_errors++; + if (rcs2 & AK4113_QCRC) + ak4113->qcrc_errors++; + c0 = (ak4113->rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | + AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)) ^ + (rcs0 & (AK4113_QINT | AK4113_CINT | AK4113_STC | + AK4113_AUDION | AK4113_AUTO | AK4113_UNLCK)); + c1 = (ak4113->rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | + AK4113_DAT | 0xf0)) ^ + (rcs1 & (AK4113_DTSCD | AK4113_NPCM | AK4113_PEM | + AK4113_DAT | 0xf0)); + ak4113->rcs0 = rcs0 & ~(AK4113_QINT | AK4113_CINT | AK4113_STC); + ak4113->rcs1 = rcs1; + ak4113->rcs2 = rcs2; + spin_unlock_irqrestore(&ak4113->lock, _flags); + + if (rcs0 & AK4113_PAR) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[0]->id); + if (rcs0 & AK4113_V) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[1]->id); + if (rcs2 & AK4113_CCRC) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[2]->id); + if (rcs2 & AK4113_QCRC) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[3]->id); + + /* rate change */ + if (c1 & 0xf0) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[4]->id); + + if ((c1 & AK4113_PEM) | (c0 & AK4113_CINT)) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[6]->id); + if (c0 & AK4113_QINT) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[8]->id); + + if (c0 & AK4113_AUDION) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[9]->id); + if (c1 & AK4113_NPCM) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[10]->id); + if (c1 & AK4113_DTSCD) + snd_ctl_notify(ak4113->card, SNDRV_CTL_EVENT_MASK_VALUE, + &ak4113->kctls[11]->id); + + if (ak4113->change_callback && (c0 | c1) != 0) + ak4113->change_callback(ak4113, c0, c1); + +__rate: + /* compare rate */ + res = external_rate(rcs1); + if (!(flags & AK4113_CHECK_NO_RATE) && runtime && + (runtime->rate != res)) { + snd_pcm_stream_lock_irqsave(ak4113->substream, _flags); + if (snd_pcm_running(ak4113->substream)) { + /*printk(KERN_DEBUG "rate changed (%i <- %i)\n", + * runtime->rate, res); */ + snd_pcm_stop(ak4113->substream, + SNDRV_PCM_STATE_DRAINING); + wake_up(&runtime->sleep); + res = 1; + } + snd_pcm_stream_unlock_irqrestore(ak4113->substream, _flags); + } + return res; +} +EXPORT_SYMBOL_GPL(snd_ak4113_check_rate_and_errors); + +static void ak4113_stats(struct work_struct *work) +{ + struct ak4113 *chip = container_of(work, struct ak4113, work.work); + + if (!chip->init) + snd_ak4113_check_rate_and_errors(chip, chip->check_flags); + + schedule_delayed_work(&chip->work, HZ / 10); +} -- cgit v1.2.3 From 494703062b6e6ef5e72364aafc9bcbc172d53dea Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:38 +0200 Subject: ALSA: ice1724 - adding GPIO routines for mask and direction * get/set routines for GPIO mask and direction Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.c | 12 ++++++++++++ sound/pci/ice1712/ice1712.h | 7 +++++++ sound/pci/ice1712/ice1724.c | 19 +++++++++++++++++++ 3 files changed, 38 insertions(+) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index cecf1ffeeaaa..56d8d67f1ac3 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c @@ -298,6 +298,16 @@ static void snd_ice1712_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data) inb(ICEREG(ice, DATA)); /* dummy read for pci-posting */ } +static unsigned int snd_ice1712_get_gpio_dir(struct snd_ice1712 *ice) +{ + return snd_ice1712_read(ice, ICE1712_IREG_GPIO_DIRECTION); +} + +static unsigned int snd_ice1712_get_gpio_mask(struct snd_ice1712 *ice) +{ + return snd_ice1712_read(ice, ICE1712_IREG_GPIO_WRITE_MASK); +} + static void snd_ice1712_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data) { snd_ice1712_write(ice, ICE1712_IREG_GPIO_WRITE_MASK, data); @@ -2557,7 +2567,9 @@ static int __devinit snd_ice1712_create(struct snd_card *card, mutex_init(&ice->i2c_mutex); mutex_init(&ice->open_mutex); ice->gpio.set_mask = snd_ice1712_set_gpio_mask; + ice->gpio.get_mask = snd_ice1712_get_gpio_mask; ice->gpio.set_dir = snd_ice1712_set_gpio_dir; + ice->gpio.get_dir = snd_ice1712_get_gpio_dir; ice->gpio.set_data = snd_ice1712_set_gpio_data; ice->gpio.get_data = snd_ice1712_get_gpio_data; diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 9da2dae64c5b..b31a59d0625c 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -359,7 +359,9 @@ struct snd_ice1712 { unsigned int saved[2]; /* for ewx_i2c */ /* operators */ void (*set_mask)(struct snd_ice1712 *ice, unsigned int data); + unsigned int (*get_mask)(struct snd_ice1712 *ice); void (*set_dir)(struct snd_ice1712 *ice, unsigned int data); + unsigned int (*get_dir)(struct snd_ice1712 *ice); void (*set_data)(struct snd_ice1712 *ice, unsigned int data); unsigned int (*get_data)(struct snd_ice1712 *ice); /* misc operators - move to another place? */ @@ -399,6 +401,11 @@ static inline void snd_ice1712_gpio_set_dir(struct snd_ice1712 *ice, unsigned in ice->gpio.set_dir(ice, bits); } +static inline unsigned int snd_ice1712_gpio_get_dir(struct snd_ice1712 *ice) +{ + return ice->gpio.get_dir(ice); +} + static inline void snd_ice1712_gpio_set_mask(struct snd_ice1712 *ice, unsigned int bits) { ice->gpio.set_mask(ice, bits); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index af6e00148621..2213beec009a 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -196,6 +196,12 @@ static void snd_vt1724_set_gpio_dir(struct snd_ice1712 *ice, unsigned int data) inw(ICEREG1724(ice, GPIO_DIRECTION)); /* dummy read for pci-posting */ } +/* get gpio direction 0 = read, 1 = write */ +static unsigned int snd_vt1724_get_gpio_dir(struct snd_ice1712 *ice) +{ + return inl(ICEREG1724(ice, GPIO_DIRECTION)); +} + /* set the gpio mask (0 = writable) */ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data) { @@ -205,6 +211,17 @@ static void snd_vt1724_set_gpio_mask(struct snd_ice1712 *ice, unsigned int data) inw(ICEREG1724(ice, GPIO_WRITE_MASK)); /* dummy read for pci-posting */ } +static unsigned int snd_vt1724_get_gpio_mask(struct snd_ice1712 *ice) +{ + unsigned int mask; + if (!ice->vt1720) + mask = (unsigned int)inb(ICEREG1724(ice, GPIO_WRITE_MASK_22)); + else + mask = 0; + mask = (mask << 16) | inw(ICEREG1724(ice, GPIO_WRITE_MASK)); + return mask; +} + static void snd_vt1724_set_gpio_data(struct snd_ice1712 *ice, unsigned int data) { outw(data, ICEREG1724(ice, GPIO_DATA)); @@ -2434,7 +2451,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card, mutex_init(&ice->open_mutex); mutex_init(&ice->i2c_mutex); ice->gpio.set_mask = snd_vt1724_set_gpio_mask; + ice->gpio.get_mask = snd_vt1724_get_gpio_mask; ice->gpio.set_dir = snd_vt1724_set_gpio_dir; + ice->gpio.get_dir = snd_vt1724_get_gpio_dir; ice->gpio.set_data = snd_vt1724_set_gpio_data; ice->gpio.get_data = snd_vt1724_get_gpio_data; ice->card = card; -- cgit v1.2.3 From 6796d5a05f4d3caad17d2586b3e5776fda50ef82 Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:39 +0200 Subject: ALSA: ice1724 - pro-rate-locking makes sense only for internal clock mode * pro-rate-locking applies to internal clock mode only * required rate and current rate are compared for internal clock mode only Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1724.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 2213beec009a..514e15385f7a 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -118,9 +118,12 @@ static inline int stdclock_is_spdif_master(struct snd_ice1712 *ice) return (inb(ICEMT1724(ice, RATE)) & VT1724_SPDIF_MASTER) ? 1 : 0; } +/* + * locking rate makes sense only for internal clock mode + */ static inline int is_pro_rate_locked(struct snd_ice1712 *ice) { - return ice->is_spdif_master(ice) || PRO_RATE_LOCKED; + return (!ice->is_spdif_master(ice)) && PRO_RATE_LOCKED; } /* @@ -668,16 +671,22 @@ static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, return -EBUSY; } if (!force && is_pro_rate_locked(ice)) { + /* comparing required and current rate - makes sense for + * internal clock only */ spin_unlock_irqrestore(&ice->reg_lock, flags); return (rate == ice->cur_rate) ? 0 : -EBUSY; } - old_rate = ice->get_rate(ice); - if (force || (old_rate != rate)) - ice->set_rate(ice, rate); - else if (rate == ice->cur_rate) { - spin_unlock_irqrestore(&ice->reg_lock, flags); - return 0; + if (force || !ice->is_spdif_master(ice)) { + /* force means the rate was switched by ucontrol, otherwise + * setting clock rate for internal clock mode */ + old_rate = ice->get_rate(ice); + if (force || (old_rate != rate)) + ice->set_rate(ice, rate); + else if (rate == ice->cur_rate) { + spin_unlock_irqrestore(&ice->reg_lock, flags); + return 0; + } } ice->cur_rate = rate; -- cgit v1.2.3 From 1ff97cb9dd9f53b33ce6710a4f861f43e70e8ca4 Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:40 +0200 Subject: ALSA: ice1724 - Support for multiple external clock types * Support for customization of the external clock names * Adding hooks to playback_pro_open and capture_pro_open, allowing e.g. limiting available stream rates to a single value when the external clock rate is detected Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.h | 7 ++++-- sound/pci/ice1712/ice1724.c | 58 +++++++++++++++++++++++++++++++++++---------- sound/pci/ice1712/juli.c | 3 ++- 3 files changed, 52 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index b31a59d0625c..4615bca39e18 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -379,8 +379,11 @@ struct snd_ice1712 { unsigned int (*get_rate)(struct snd_ice1712 *ice); void (*set_rate)(struct snd_ice1712 *ice, unsigned int rate); unsigned char (*set_mclk)(struct snd_ice1712 *ice, unsigned int rate); - void (*set_spdif_clock)(struct snd_ice1712 *ice); - + int (*set_spdif_clock)(struct snd_ice1712 *ice, int type); + int (*get_spdif_master_type)(struct snd_ice1712 *ice); + char **ext_clock_names; + int ext_clock_count; + void (*pro_open)(struct snd_ice1712 *, struct snd_pcm_substream *); #ifdef CONFIG_PM int (*pm_suspend)(struct snd_ice1712 *); int (*pm_resume)(struct snd_ice1712 *); diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 514e15385f7a..3f11195b2631 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -104,6 +104,8 @@ 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" }; + /* * Basic I/O */ @@ -1042,6 +1044,8 @@ static int snd_vt1724_playback_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + if (ice->pro_open) + ice->pro_open(ice, substream); return 0; } @@ -1060,6 +1064,8 @@ static int snd_vt1724_capture_pro_open(struct snd_pcm_substream *substream) VT1724_BUFFER_ALIGN); snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, VT1724_BUFFER_ALIGN); + if (ice->pro_open) + ice->pro_open(ice, substream); return 0; } @@ -1813,15 +1819,21 @@ static int snd_vt1724_pro_internal_clock_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); - + int hw_rates_count = ice->hw_rates->count; uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; uinfo->count = 1; - uinfo->value.enumerated.items = ice->hw_rates->count + 1; + + uinfo->value.enumerated.items = hw_rates_count + ice->ext_clock_count; + /* upper limit - keep at top */ if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; - if (uinfo->value.enumerated.item == uinfo->value.enumerated.items - 1) - strcpy(uinfo->value.enumerated.name, "IEC958 Input"); + if (uinfo->value.enumerated.item >= hw_rates_count) + /* ext_clock items */ + strcpy(uinfo->value.enumerated.name, + ice->ext_clock_names[ + uinfo->value.enumerated.item - hw_rates_count]); else + /* int clock items */ sprintf(uinfo->value.enumerated.name, "%d", ice->hw_rates->list[uinfo->value.enumerated.item]); return 0; @@ -1835,7 +1847,8 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, spin_lock_irq(&ice->reg_lock); if (ice->is_spdif_master(ice)) { - ucontrol->value.enumerated.item[0] = ice->hw_rates->count; + ucontrol->value.enumerated.item[0] = ice->hw_rates->count + + ice->get_spdif_master_type(ice); } else { rate = ice->get_rate(ice); ucontrol->value.enumerated.item[0] = 0; @@ -1850,8 +1863,14 @@ static int snd_vt1724_pro_internal_clock_get(struct snd_kcontrol *kcontrol, return 0; } +static int stdclock_get_spdif_master_type(struct snd_ice1712 *ice) +{ + /* standard external clock - only single type - SPDIF IN */ + return 0; +} + /* setting clock to external - SPDIF */ -static void stdclock_set_spdif_clock(struct snd_ice1712 *ice) +static int stdclock_set_spdif_clock(struct snd_ice1712 *ice, int type) { unsigned char oval; unsigned char i2s_oval; @@ -1860,27 +1879,30 @@ static void stdclock_set_spdif_clock(struct snd_ice1712 *ice) /* setting 256fs */ i2s_oval = inb(ICEMT1724(ice, I2S_FORMAT)); outb(i2s_oval & ~VT1724_MT_I2S_MCLK_128X, ICEMT1724(ice, I2S_FORMAT)); + return 0; } + static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); unsigned int old_rate, new_rate; unsigned int item = ucontrol->value.enumerated.item[0]; - unsigned int spdif = ice->hw_rates->count; + unsigned int first_ext_clock = ice->hw_rates->count; - if (item > spdif) + if (item > first_ext_clock + ice->ext_clock_count - 1) return -EINVAL; + /* if rate = 0 => external clock */ spin_lock_irq(&ice->reg_lock); if (ice->is_spdif_master(ice)) old_rate = 0; else old_rate = ice->get_rate(ice); - if (item == spdif) { - /* switching to external clock via SPDIF */ - ice->set_spdif_clock(ice); + if (item >= first_ext_clock) { + /* switching to external clock */ + ice->set_spdif_clock(ice, item - first_ext_clock); new_rate = 0; } else { /* internal on-card clock */ @@ -1892,7 +1914,7 @@ static int snd_vt1724_pro_internal_clock_put(struct snd_kcontrol *kcontrol, } spin_unlock_irq(&ice->reg_lock); - /* the first reset to the SPDIF master mode? */ + /* the first switch to the ext. clock mode? */ if (old_rate != new_rate && !new_rate) { /* notify akm chips as well */ unsigned int i; @@ -2550,6 +2572,9 @@ static int __devinit snd_vt1724_probe(struct pci_dev *pci, return err; } + /* field init before calling chip_init */ + ice->ext_clock_count = 0; + for (tbl = card_tables; *tbl; tbl++) { for (c = *tbl; c->subvendor; c++) { if (c->subvendor == ice->eeprom.subvendor) { @@ -2588,6 +2613,13 @@ __found: ice->set_mclk = stdclock_set_mclk; if (!ice->set_spdif_clock) ice->set_spdif_clock = stdclock_set_spdif_clock; + if (!ice->get_spdif_master_type) + ice->get_spdif_master_type = stdclock_get_spdif_master_type; + if (!ice->ext_clock_names) + ice->ext_clock_names = ext_clock_names; + if (!ice->ext_clock_count) + ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); + if (!ice->hw_rates) set_std_hw_rates(ice); @@ -2747,7 +2779,7 @@ static int snd_vt1724_resume(struct pci_dev *pci) if (ice->pm_saved_is_spdif_master) { /* switching to external clock via SPDIF */ - ice->set_spdif_clock(ice); + ice->set_spdif_clock(ice, 0); } else { /* internal on-card clock */ snd_vt1724_set_pro_rate(ice, ice->pro_rate_default, 1); diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index 4789e8bfdc17..4bed9633a4cd 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -529,13 +529,14 @@ static inline unsigned char juli_set_mclk(struct snd_ice1712 *ice, } /* setting clock to external - SPDIF */ -static void juli_set_spdif_clock(struct snd_ice1712 *ice) +static int juli_set_spdif_clock(struct snd_ice1712 *ice, int type) { unsigned int old; old = ice->gpio.get_data(ice); /* external clock (= 0), multiply 1x, 48kHz */ ice->gpio.set_data(ice, (old & ~GPIO_RATE_MASK) | GPIO_MULTI_1X | GPIO_FREQ_48KHZ); + return 0; } /* Called when ak4114 detects change in the input SPDIF stream */ -- cgit v1.2.3 From 6ef80706184be792499a4485a7957f2660b6a076 Mon Sep 17 00:00:00 2001 From: Pavel Hofman Date: Wed, 16 Sep 2009 22:25:41 +0200 Subject: ALSA: ice1724 - Infrasonic Quartet support * three external clock types * all controls supported Signed-off-by: Pavel Hofman Signed-off-by: Takashi Iwai --- sound/pci/ice1712/Makefile | 2 +- sound/pci/ice1712/ice1724.c | 3 + sound/pci/ice1712/quartet.c | 1130 +++++++++++++++++++++++++++++++++++++++++++ sound/pci/ice1712/quartet.h | 10 + 4 files changed, 1144 insertions(+), 1 deletion(-) create mode 100644 sound/pci/ice1712/quartet.c create mode 100644 sound/pci/ice1712/quartet.h (limited to 'sound') diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index 536eae2ccf94..f7ce33f00ea5 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 +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 # Toplevel Module Dependency obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 3f11195b2631..3896fb931de1 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c @@ -53,6 +53,7 @@ #include "phase.h" #include "wtm.h" #include "se.h" +#include "quartet.h" MODULE_AUTHOR("Jaroslav Kysela "); MODULE_DESCRIPTION("VIA ICEnsemble ICE1724/1720 (Envy24HT/PT)"); @@ -70,6 +71,7 @@ MODULE_SUPPORTED_DEVICE("{" PHASE_DEVICE_DESC WTM_DEVICE_DESC SE_DEVICE_DESC + QTET_DEVICE_DESC "{VIA,VT1720}," "{VIA,VT1724}," "{ICEnsemble,Generic ICE1724}," @@ -2184,6 +2186,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { snd_vt1724_phase_cards, snd_vt1724_wtm_cards, snd_vt1724_se_cards, + snd_vt1724_qtet_cards, NULL, }; diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c new file mode 100644 index 000000000000..1948632787e6 --- /dev/null +++ b/sound/pci/ice1712/quartet.c @@ -0,0 +1,1130 @@ +/* + * ALSA driver for ICEnsemble VT1724 (Envy24HT) + * + * Lowlevel functions for Infrasonic Quartet + * + * Copyright (c) 2009 Pavel Hofman + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +#include "ice1712.h" +#include "envy24ht.h" +#include +#include "quartet.h" + +struct qtet_spec { + struct ak4113 *ak4113; + unsigned int scr; /* system control register */ + unsigned int mcr; /* monitoring control register */ + unsigned int cpld; /* cpld register */ +}; + +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]; +}; + +enum { + IN12_SEL = 0, + IN34_SEL, + AIN34_SEL, + COAX_OUT, + IN12_MON12, + IN12_MON34, + IN34_MON12, + IN34_MON34, + OUT12_MON34, + OUT34_MON12, +}; + +static char *ext_clock_names[3] = {"IEC958 In", "Word Clock 1xFS", + "Word Clock 256xFS"}; + +/* chip address on I2C bus */ +#define AK4113_ADDR 0x26 /* S/PDIF receiver */ + +/* chip address on SPI bus */ +#define AK4620_ADDR 0x02 /* ADC/DAC */ + + +/* + * GPIO pins + */ + +/* GPIO0 - O - DATA0, def. 0 */ +#define GPIO_D0 (1<<0) +/* GPIO1 - I/O - DATA1, Jack Detect Input0 (0:present, 1:missing), def. 1 */ +#define GPIO_D1_JACKDTC0 (1<<1) +/* GPIO2 - I/O - DATA2, Jack Detect Input1 (0:present, 1:missing), def. 1 */ +#define GPIO_D2_JACKDTC1 (1<<2) +/* GPIO3 - I/O - DATA3, def. 1 */ +#define GPIO_D3 (1<<3) +/* GPIO4 - I/O - DATA4, SPI CDTO, def. 1 */ +#define GPIO_D4_SPI_CDTO (1<<4) +/* GPIO5 - I/O - DATA5, SPI CCLK, def. 1 */ +#define GPIO_D5_SPI_CCLK (1<<5) +/* GPIO6 - I/O - DATA6, Cable Detect Input (0:detected, 1:not detected */ +#define GPIO_D6_CD (1<<6) +/* GPIO7 - I/O - DATA7, Device Detect Input (0:detected, 1:not detected */ +#define GPIO_D7_DD (1<<7) +/* GPIO8 - O - CPLD Chip Select, def. 1 */ +#define GPIO_CPLD_CSN (1<<8) +/* GPIO9 - O - CPLD register read/write (0:write, 1:read), def. 0 */ +#define GPIO_CPLD_RW (1<<9) +/* GPIO10 - O - SPI Chip Select for CODEC#0, def. 1 */ +#define GPIO_SPI_CSN0 (1<<10) +/* GPIO11 - O - SPI Chip Select for CODEC#1, def. 1 */ +#define GPIO_SPI_CSN1 (1<<11) +/* GPIO12 - O - Ex. Register Output Enable (0:enable, 1:disable), def. 1, + * init 0 */ +#define GPIO_EX_GPIOE (1<<12) +/* GPIO13 - O - Ex. Register0 Chip Select for System Control Register, + * def. 1 */ +#define GPIO_SCR (1<<13) +/* GPIO14 - O - Ex. Register1 Chip Select for Monitor Control Register, + * def. 1 */ +#define GPIO_MCR (1<<14) + +#define GPIO_SPI_ALL (GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK |\ + GPIO_SPI_CSN0 | GPIO_SPI_CSN1) + +#define GPIO_DATA_MASK (GPIO_D0 | GPIO_D1_JACKDTC0 | \ + GPIO_D2_JACKDTC1 | GPIO_D3 | \ + GPIO_D4_SPI_CDTO | GPIO_D5_SPI_CCLK | \ + GPIO_D6_CD | GPIO_D7_DD) + +/* System Control Register GPIO_SCR data bits */ +/* Mic/Line select relay (0:line, 1:mic) */ +#define SCR_RELAY GPIO_D0 +/* Phantom power drive control (0:5V, 1:48V) */ +#define SCR_PHP_V GPIO_D1_JACKDTC0 +/* H/W mute control (0:Normal, 1:Mute) */ +#define SCR_MUTE GPIO_D2_JACKDTC1 +/* Phantom power control (0:Phantom on, 1:off) */ +#define SCR_PHP GPIO_D3 +/* Analog input 1/2 Source Select */ +#define SCR_AIN12_SEL0 GPIO_D4_SPI_CDTO +#define SCR_AIN12_SEL1 GPIO_D5_SPI_CCLK +/* Analog input 3/4 Source Select (0:line, 1:hi-z) */ +#define SCR_AIN34_SEL GPIO_D6_CD +/* Codec Power Down (0:power down, 1:normal) */ +#define SCR_CODEC_PDN GPIO_D7_DD + +#define SCR_AIN12_LINE (0) +#define SCR_AIN12_MIC (SCR_AIN12_SEL0) +#define SCR_AIN12_LOWCUT (SCR_AIN12_SEL1 | SCR_AIN12_SEL0) + +/* Monitor Control Register GPIO_MCR data bits */ +/* Input 1/2 to Monitor 1/2 (0:off, 1:on) */ +#define MCR_IN12_MON12 GPIO_D0 +/* Input 1/2 to Monitor 3/4 (0:off, 1:on) */ +#define MCR_IN12_MON34 GPIO_D1_JACKDTC0 +/* Input 3/4 to Monitor 1/2 (0:off, 1:on) */ +#define MCR_IN34_MON12 GPIO_D2_JACKDTC1 +/* Input 3/4 to Monitor 3/4 (0:off, 1:on) */ +#define MCR_IN34_MON34 GPIO_D3 +/* Output to Monitor 1/2 (0:off, 1:on) */ +#define MCR_OUT34_MON12 GPIO_D4_SPI_CDTO +/* Output to Monitor 3/4 (0:off, 1:on) */ +#define MCR_OUT12_MON34 GPIO_D5_SPI_CCLK + +/* CPLD Register DATA bits */ +/* Clock Rate Select */ +#define CPLD_CKS0 GPIO_D0 +#define CPLD_CKS1 GPIO_D1_JACKDTC0 +#define CPLD_CKS2 GPIO_D2_JACKDTC1 +/* Sync Source Select (0:Internal, 1:External) */ +#define CPLD_SYNC_SEL GPIO_D3 +/* Word Clock FS Select (0:FS, 1:256FS) */ +#define CPLD_WORD_SEL GPIO_D4_SPI_CDTO +/* Coaxial Output Source (IS-Link) (0:SPDIF, 1:I2S) */ +#define CPLD_COAX_OUT GPIO_D5_SPI_CCLK +/* Input 1/2 Source Select (0:Analog12, 1:An34) */ +#define CPLD_IN12_SEL GPIO_D6_CD +/* Input 3/4 Source Select (0:Analog34, 1:Digital In) */ +#define CPLD_IN34_SEL GPIO_D7_DD + +/* internal clock (CPLD_SYNC_SEL = 0) options */ +#define CPLD_CKS_44100HZ (0) +#define CPLD_CKS_48000HZ (CPLD_CKS0) +#define CPLD_CKS_88200HZ (CPLD_CKS1) +#define CPLD_CKS_96000HZ (CPLD_CKS1 | CPLD_CKS0) +#define CPLD_CKS_176400HZ (CPLD_CKS2) +#define CPLD_CKS_192000HZ (CPLD_CKS2 | CPLD_CKS0) + +#define CPLD_CKS_MASK (CPLD_CKS0 | CPLD_CKS1 | CPLD_CKS2) + +/* external clock (CPLD_SYNC_SEL = 1) options */ +/* external clock - SPDIF */ +#define CPLD_EXT_SPDIF (0 | CPLD_SYNC_SEL) +/* external clock - WordClock 1xfs */ +#define CPLD_EXT_WORDCLOCK_1FS (CPLD_CKS1 | CPLD_SYNC_SEL) +/* external clock - WordClock 256xfs */ +#define CPLD_EXT_WORDCLOCK_256FS (CPLD_CKS1 | CPLD_WORD_SEL |\ + CPLD_SYNC_SEL) + +#define EXT_SPDIF_TYPE 0 +#define EXT_WORDCLOCK_1FS_TYPE 1 +#define EXT_WORDCLOCK_256FS_TYPE 2 + +#define AK4620_DFS0 (1<<0) +#define AK4620_DFS1 (1<<1) +#define AK4620_CKS0 (1<<2) +#define AK4620_CKS1 (1<<3) +/* Clock and Format Control register */ +#define AK4620_DFS_REG 0x02 + +/* Deem and Volume Control register */ +#define AK4620_DEEMVOL_REG 0x03 +#define AK4620_SMUTE (1<<7) + +/* + * Conversion from int value to its binary form. Used for debugging. + * The output buffer must be allocated prior to calling the function. + */ +static char *get_binary(char *buffer, int value) +{ + int i, j, pos; + pos = 0; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 8; ++j) { + if (value & (1 << (31-(i*8 + j)))) + buffer[pos] = '1'; + else + buffer[pos] = '0'; + pos++; + } + if (i < 3) { + buffer[pos] = ' '; + pos++; + } + } + buffer[pos] = '\0'; + return buffer; +} + +/* + * Initial setup of the conversion array GPIO <-> rate + */ +static unsigned int qtet_rates[] = { + 44100, 48000, 88200, + 96000, 176400, 192000, +}; + +static unsigned int cks_vals[] = { + CPLD_CKS_44100HZ, CPLD_CKS_48000HZ, CPLD_CKS_88200HZ, + CPLD_CKS_96000HZ, CPLD_CKS_176400HZ, CPLD_CKS_192000HZ, +}; + +static struct snd_pcm_hw_constraint_list qtet_rates_info = { + .count = ARRAY_SIZE(qtet_rates), + .list = qtet_rates, + .mask = 0, +}; + +static void qtet_ak4113_write(void *private_data, unsigned char reg, + unsigned char val) +{ + snd_vt1724_write_i2c((struct snd_ice1712 *)private_data, AK4113_ADDR, + reg, val); +} + +static unsigned char qtet_ak4113_read(void *private_data, unsigned char reg) +{ + return snd_vt1724_read_i2c((struct snd_ice1712 *)private_data, + AK4113_ADDR, reg); +} + + +/* + * AK4620 section + */ + +/* + * Write data to addr register of ak4620 + */ +static void qtet_akm_write(struct snd_akm4xxx *ak, int chip, + unsigned char addr, unsigned char data) +{ + unsigned int tmp, orig_dir; + int idx; + unsigned int addrdata; + struct snd_ice1712 *ice = ak->private_data[0]; + + if (snd_BUG_ON(chip < 0 || chip >= 4)) + return; + /*printk(KERN_DEBUG "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); + /* set mask - only SPI bits */ + ice->gpio.set_mask(ice, ~GPIO_SPI_ALL); + + tmp = ice->gpio.get_data(ice); + /* high all */ + tmp |= GPIO_SPI_ALL; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* drop chip select */ + if (chip) + /* CODEC 1 */ + tmp &= ~GPIO_SPI_CSN1; + else + tmp &= ~GPIO_SPI_CSN0; + ice->gpio.set_data(ice, tmp); + udelay(100); + + /* build I2C address + data byte */ + addrdata = (AK4620_ADDR << 6) | 0x20 | (addr & 0x1f); + addrdata = (addrdata << 8) | data; + for (idx = 15; idx >= 0; idx--) { + /* drop clock */ + tmp &= ~GPIO_D5_SPI_CCLK; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* set data */ + if (addrdata & (1 << idx)) + tmp |= GPIO_D4_SPI_CDTO; + else + tmp &= ~GPIO_D4_SPI_CDTO; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* raise clock */ + tmp |= GPIO_D5_SPI_CCLK; + ice->gpio.set_data(ice, tmp); + udelay(100); + } + /* all back to 1 */ + tmp |= GPIO_SPI_ALL; + ice->gpio.set_data(ice, tmp); + udelay(100); + + /* return all gpios to non-writable */ + ice->gpio.set_mask(ice, 0xffffff); + /* restore GPIOs direction */ + ice->gpio.set_dir(ice, orig_dir); +} + +static void qtet_akm_set_regs(struct snd_akm4xxx *ak, unsigned char addr, + unsigned char mask, unsigned char value) +{ + unsigned char tmp; + int chip; + for (chip = 0; chip < ak->num_chips; chip++) { + tmp = snd_akm4xxx_get(ak, chip, addr); + /* clear the bits */ + tmp &= ~mask; + /* set the new bits */ + tmp |= value; + snd_akm4xxx_write(ak, chip, addr, tmp); + } +} + +/* + * change the rate of AK4620 + */ +static void qtet_akm_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) +{ + unsigned char ak4620_dfs; + + if (rate == 0) /* no hint - S/PDIF input is master or the new spdif + input rate undetected, simply return */ + return; + + /* adjust DFS on codecs - see datasheet */ + if (rate > 108000) + ak4620_dfs = AK4620_DFS1 | AK4620_CKS1; + else if (rate > 54000) + ak4620_dfs = AK4620_DFS0 | AK4620_CKS0; + else + ak4620_dfs = 0; + + /* set new value */ + qtet_akm_set_regs(ak, AK4620_DFS_REG, AK4620_DFS0 | AK4620_DFS1 | + AK4620_CKS0 | AK4620_CKS1, ak4620_dfs); +} + +#define AK_CONTROL(xname, xch) { .name = xname, .num_channels = xch } + +#define PCM_12_PLAYBACK_VOLUME "PCM 1/2 Playback Volume" +#define PCM_34_PLAYBACK_VOLUME "PCM 3/4 Playback Volume" +#define PCM_12_CAPTURE_VOLUME "PCM 1/2 Capture Volume" +#define PCM_34_CAPTURE_VOLUME "PCM 3/4 Capture Volume" + +static const struct snd_akm4xxx_dac_channel qtet_dac[] = { + AK_CONTROL(PCM_12_PLAYBACK_VOLUME, 2), + AK_CONTROL(PCM_34_PLAYBACK_VOLUME, 2), +}; + +static const struct snd_akm4xxx_adc_channel qtet_adc[] = { + AK_CONTROL(PCM_12_CAPTURE_VOLUME, 2), + AK_CONTROL(PCM_34_CAPTURE_VOLUME, 2), +}; + +static struct snd_akm4xxx akm_qtet_dac __devinitdata = { + .type = SND_AK4620, + .num_dacs = 4, /* DAC1 - Output 12 + */ + .num_adcs = 4, /* ADC1 - Input 12 + */ + .ops = { + .write = qtet_akm_write, + .set_rate_val = qtet_akm_set_rate_val, + }, + .dac_info = qtet_dac, + .adc_info = qtet_adc, +}; + +/* Communication routines with the CPLD */ + + +/* Writes data to external register reg, both reg and data are + * GPIO representations */ +static void reg_write(struct snd_ice1712 *ice, unsigned int reg, + unsigned int data) +{ + unsigned int tmp; + + mutex_lock(&ice->gpio_mutex); + /* set direction of used GPIOs*/ + /* all outputs */ + tmp = 0x00ffff; + ice->gpio.set_dir(ice, tmp); + /* mask - writable bits */ + ice->gpio.set_mask(ice, ~(tmp)); + /* write the data */ + tmp = ice->gpio.get_data(ice); + tmp &= ~GPIO_DATA_MASK; + tmp |= data; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* drop output enable */ + tmp &= ~GPIO_EX_GPIOE; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* drop the register gpio */ + tmp &= ~reg; + ice->gpio.set_data(ice, tmp); + udelay(100); + /* raise the register GPIO */ + tmp |= reg; + ice->gpio.set_data(ice, tmp); + udelay(100); + + /* raise all data gpios */ + tmp |= GPIO_DATA_MASK; + ice->gpio.set_data(ice, tmp); + /* mask - immutable bits */ + ice->gpio.set_mask(ice, 0xffffff); + /* outputs only 8-15 */ + ice->gpio.set_dir(ice, 0x00ff00); + mutex_unlock(&ice->gpio_mutex); +} + +static unsigned int get_scr(struct snd_ice1712 *ice) +{ + struct qtet_spec *spec = ice->spec; + return spec->scr; +} + +static unsigned int get_mcr(struct snd_ice1712 *ice) +{ + struct qtet_spec *spec = ice->spec; + return spec->mcr; +} + +static unsigned int get_cpld(struct snd_ice1712 *ice) +{ + struct qtet_spec *spec = ice->spec; + return spec->cpld; +} + +static void set_scr(struct snd_ice1712 *ice, unsigned int val) +{ + struct qtet_spec *spec = ice->spec; + reg_write(ice, GPIO_SCR, val); + spec->scr = val; +} + +static void set_mcr(struct snd_ice1712 *ice, unsigned int val) +{ + struct qtet_spec *spec = ice->spec; + reg_write(ice, GPIO_MCR, val); + spec->mcr = val; +} + +static void set_cpld(struct snd_ice1712 *ice, unsigned int val) +{ + struct qtet_spec *spec = ice->spec; + reg_write(ice, GPIO_CPLD_CSN, val); + spec->cpld = val; +} +#ifdef CONFIG_PROC_FS +static void proc_regs_read(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct snd_ice1712 *ice = entry->private_data; + char bin_buffer[36]; + + snd_iprintf(buffer, "SCR: %s\n", get_binary(bin_buffer, + get_scr(ice))); + snd_iprintf(buffer, "MCR: %s\n", get_binary(bin_buffer, + get_mcr(ice))); + snd_iprintf(buffer, "CPLD: %s\n", get_binary(bin_buffer, + get_cpld(ice))); +} + +static void proc_init(struct snd_ice1712 *ice) +{ + struct snd_info_entry *entry; + if (!snd_card_proc_new(ice->card, "quartet", &entry)) + snd_info_set_text_ops(entry, ice, proc_regs_read); +} +#else /* !CONFIG_PROC_FS */ +static void proc_init(struct snd_ice1712 *ice) {} +#endif + +static int qtet_mute_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int val; + val = get_scr(ice) & SCR_MUTE; + ucontrol->value.integer.value[0] = (val) ? 0 : 1; + return 0; +} + +static int qtet_mute_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int old, new, smute; + old = get_scr(ice) & SCR_MUTE; + if (ucontrol->value.integer.value[0]) { + /* unmute */ + new = 0; + /* un-smuting DAC */ + smute = 0; + } else { + /* mute */ + new = SCR_MUTE; + /* smuting DAC */ + smute = AK4620_SMUTE; + } + if (old != new) { + struct snd_akm4xxx *ak = ice->akm; + set_scr(ice, (get_scr(ice) & ~SCR_MUTE) | new); + /* set smute */ + qtet_akm_set_regs(ak, AK4620_DEEMVOL_REG, AK4620_SMUTE, smute); + return 1; + } + /* no change */ + return 0; +} + +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"}; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(texts); + + 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 qtet_ain12_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int val, result; + val = get_scr(ice) & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); + switch (val) { + case SCR_AIN12_LINE: + result = 0; + break; + case SCR_AIN12_MIC: + result = 1; + break; + case SCR_AIN12_LOWCUT: + result = 2; + break; + default: + /* BUG - no other combinations allowed */ + snd_BUG(); + result = 0; + } + ucontrol->value.integer.value[0] = result; + return 0; +} + +static int qtet_ain12_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int old, new, tmp, masked_old; + old = new = get_scr(ice); + masked_old = old & (SCR_AIN12_SEL1 | SCR_AIN12_SEL0); + tmp = ucontrol->value.integer.value[0]; + if (tmp == 2) + tmp = 3; /* binary 10 is not supported */ + tmp <<= 4; /* shifting to SCR_AIN12_SEL0 */ + if (tmp != masked_old) { + /* change requested */ + switch (tmp) { + case SCR_AIN12_LINE: + new = old & ~(SCR_AIN12_SEL1 | SCR_AIN12_SEL0); + set_scr(ice, new); + /* turn off relay */ + new &= ~SCR_RELAY; + set_scr(ice, new); + break; + case SCR_AIN12_MIC: + /* turn on relay */ + new = old | SCR_RELAY; + set_scr(ice, new); + new = (new & ~SCR_AIN12_SEL1) | SCR_AIN12_SEL0; + set_scr(ice, new); + break; + case SCR_AIN12_LOWCUT: + /* turn on relay */ + new = old | SCR_RELAY; + set_scr(ice, new); + new |= SCR_AIN12_SEL1 | SCR_AIN12_SEL0; + set_scr(ice, new); + break; + default: + snd_BUG(); + } + return 1; + } + /* no change */ + return 0; +} + +static int qtet_php_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int val; + /* if phantom voltage =48V, phantom on */ + val = get_scr(ice) & SCR_PHP_V; + ucontrol->value.integer.value[0] = val ? 1 : 0; + return 0; +} + +static int qtet_php_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int old, new; + old = new = get_scr(ice); + if (ucontrol->value.integer.value[0] /* phantom on requested */ + && (~old & SCR_PHP_V)) /* 0 = voltage 5V */ { + /* is off, turn on */ + /* turn voltage on first, = 1 */ + new = old | SCR_PHP_V; + set_scr(ice, new); + /* turn phantom on, = 0 */ + new &= ~SCR_PHP; + set_scr(ice, new); + } else if (!ucontrol->value.integer.value[0] && (old & SCR_PHP_V)) { + /* phantom off requested and 1 = voltage 48V */ + /* is on, turn off */ + /* turn voltage off first, = 0 */ + new = old & ~SCR_PHP_V; + set_scr(ice, new); + /* turn phantom off, = 1 */ + new |= SCR_PHP; + set_scr(ice, new); + } + if (old != new) + return 1; + /* no change */ + return 0; +} + +#define PRIV_SW(xid, xbit, xreg) [xid] = {.bit = xbit,\ + .set_register = set_##xreg,\ + .get_register = get_##xreg, } + + +#define PRIV_ENUM2(xid, xbit, xreg, xtext1, xtext2) [xid] = {.bit = xbit,\ + .set_register = set_##xreg,\ + .get_register = get_##xreg,\ + .texts = {xtext1, xtext2} } + +static struct qtet_kcontrol_private qtet_privates[] = { + PRIV_ENUM2(IN12_SEL, CPLD_IN12_SEL, cpld, "An In 1/2", "An In 3/4"), + PRIV_ENUM2(IN34_SEL, CPLD_IN34_SEL, cpld, "An In 3/4", "IEC958 In"), + PRIV_ENUM2(AIN34_SEL, SCR_AIN34_SEL, scr, "Line In 3/4", "Hi-Z"), + PRIV_ENUM2(COAX_OUT, CPLD_COAX_OUT, cpld, "IEC958", "I2S"), + PRIV_SW(IN12_MON12, MCR_IN12_MON12, mcr), + PRIV_SW(IN12_MON34, MCR_IN12_MON34, mcr), + PRIV_SW(IN34_MON12, MCR_IN34_MON12, mcr), + PRIV_SW(IN34_MON34, MCR_IN34_MON34, mcr), + PRIV_SW(OUT12_MON34, MCR_OUT12_MON34, mcr), + PRIV_SW(OUT34_MON12, MCR_OUT34_MON12, mcr), +}; + +static int qtet_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct qtet_kcontrol_private private = + qtet_privates[kcontrol->private_value]; + uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + uinfo->count = 1; + uinfo->value.enumerated.items = ARRAY_SIZE(private.texts); + + if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) + uinfo->value.enumerated.item = + uinfo->value.enumerated.items - 1; + strcpy(uinfo->value.enumerated.name, + private.texts[uinfo->value.enumerated.item]); + + return 0; +} + +static int qtet_sw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct qtet_kcontrol_private private = + qtet_privates[kcontrol->private_value]; + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + ucontrol->value.integer.value[0] = + (private.get_register(ice) & private.bit) ? 1 : 0; + return 0; +} + +static int qtet_sw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct qtet_kcontrol_private private = + qtet_privates[kcontrol->private_value]; + struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); + unsigned int old, new; + old = private.get_register(ice); + if (ucontrol->value.integer.value[0]) + new = old | private.bit; + else + new = old & ~private.bit; + if (old != new) { + private.set_register(ice, new); + return 1; + } + /* no change */ + return 0; +} + +#define qtet_sw_info snd_ctl_boolean_mono_info + +#define QTET_CONTROL(xname, xtype, xpriv) \ + {.iface = SNDRV_CTL_ELEM_IFACE_MIXER,\ + .name = xname,\ + .info = qtet_##xtype##_info,\ + .get = qtet_sw_get,\ + .put = qtet_sw_put,\ + .private_value = xpriv } + +static struct snd_kcontrol_new qtet_controls[] __devinitdata = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Master Playback Switch", + .info = qtet_sw_info, + .get = qtet_mute_get, + .put = qtet_mute_put, + .private_value = 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Phantom Power", + .info = qtet_sw_info, + .get = qtet_php_get, + .put = qtet_php_put, + .private_value = 0 + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog In 1/2 Capture Switch", + .info = qtet_ain12_enum_info, + .get = qtet_ain12_sw_get, + .put = qtet_ain12_sw_put, + .private_value = 0 + }, + QTET_CONTROL("Analog In 3/4 Capture Switch", enum, AIN34_SEL), + QTET_CONTROL("PCM In 1/2 Capture Switch", enum, IN12_SEL), + QTET_CONTROL("PCM In 3/4 Capture Switch", enum, IN34_SEL), + QTET_CONTROL("Coax Output Source", enum, COAX_OUT), + QTET_CONTROL("Analog In 1/2 to Monitor 1/2", sw, IN12_MON12), + QTET_CONTROL("Analog In 1/2 to Monitor 3/4", sw, IN12_MON34), + QTET_CONTROL("Analog In 3/4 to Monitor 1/2", sw, IN34_MON12), + QTET_CONTROL("Analog In 3/4 to Monitor 3/4", sw, IN34_MON34), + QTET_CONTROL("Output 1/2 to Monitor 3/4", sw, OUT12_MON34), + QTET_CONTROL("Output 3/4 to Monitor 1/2", sw, OUT34_MON12), +}; + +static char *slave_vols[] __devinitdata = { + PCM_12_PLAYBACK_VOLUME, + PCM_34_PLAYBACK_VOLUME, + NULL +}; + +static __devinitdata +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) +{ + struct snd_ctl_elem_id sid; + memset(&sid, 0, sizeof(sid)); + /* FIXME: strcpy is bad. */ + strcpy(sid.name, name); + sid.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + return snd_ctl_find_id(card, &sid); +} + +static void __devinit add_slaves(struct snd_card *card, + struct snd_kcontrol *master, char **list) +{ + for (; *list; list++) { + struct snd_kcontrol *slave = ctl_find(card, *list); + if (slave) + snd_ctl_add_slave(master, slave); + } +} + +static int __devinit qtet_add_controls(struct snd_ice1712 *ice) +{ + struct qtet_spec *spec = ice->spec; + int err, i; + struct snd_kcontrol *vmaster; + err = snd_ice1712_akm4xxx_build_controls(ice); + if (err < 0) + return err; + for (i = 0; i < ARRAY_SIZE(qtet_controls); i++) { + err = snd_ctl_add(ice->card, + snd_ctl_new1(&qtet_controls[i], ice)); + if (err < 0) + return err; + } + + /* Create virtual master control */ + vmaster = snd_ctl_make_virtual_master("Master Playback Volume", + qtet_master_db_scale); + if (!vmaster) + return -ENOMEM; + add_slaves(ice->card, vmaster, slave_vols); + err = snd_ctl_add(ice->card, vmaster); + if (err < 0) + return err; + /* only capture SPDIF over AK4113 */ + err = snd_ak4113_build(spec->ak4113, + ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream); + if (err < 0) + return err; + return 0; +} + +static inline int qtet_is_spdif_master(struct snd_ice1712 *ice) +{ + /* CPLD_SYNC_SEL: 0 = internal, 1 = external (i.e. spdif master) */ + return (get_cpld(ice) & CPLD_SYNC_SEL) ? 1 : 0; +} + +static unsigned int qtet_get_rate(struct snd_ice1712 *ice) +{ + int i; + unsigned char result; + + result = get_cpld(ice) & CPLD_CKS_MASK; + for (i = 0; i < ARRAY_SIZE(cks_vals); i++) + if (cks_vals[i] == result) + return qtet_rates[i]; + return 0; +} + +static int get_cks_val(int rate) +{ + int i; + for (i = 0; i < ARRAY_SIZE(qtet_rates); i++) + if (qtet_rates[i] == rate) + return cks_vals[i]; + return 0; +} + +/* setting new rate */ +static void qtet_set_rate(struct snd_ice1712 *ice, unsigned int rate) +{ + unsigned int new; + unsigned char val; + /* switching ice1724 to external clock - supplied by ext. circuits */ + val = inb(ICEMT1724(ice, RATE)); + outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, 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", + get_cpld(ice), new); */ + set_cpld(ice, new); +} + +static inline unsigned char qtet_set_mclk(struct snd_ice1712 *ice, + unsigned int rate) +{ + /* no change in master clock */ + return 0; +} + +/* setting clock to external - SPDIF */ +static int qtet_set_spdif_clock(struct snd_ice1712 *ice, int type) +{ + unsigned int old, new; + + old = new = get_cpld(ice); + new &= ~(CPLD_CKS_MASK | CPLD_WORD_SEL); + switch (type) { + case EXT_SPDIF_TYPE: + new |= CPLD_EXT_SPDIF; + break; + case EXT_WORDCLOCK_1FS_TYPE: + new |= CPLD_EXT_WORDCLOCK_1FS; + break; + case EXT_WORDCLOCK_256FS_TYPE: + new |= CPLD_EXT_WORDCLOCK_256FS; + break; + default: + snd_BUG(); + } + if (old != new) { + set_cpld(ice, new); + /* changed */ + return 1; + } + return 0; +} + +static int qtet_get_spdif_master_type(struct snd_ice1712 *ice) +{ + unsigned int val; + int result; + val = get_cpld(ice); + /* checking only rate/clock-related bits */ + val &= (CPLD_CKS_MASK | CPLD_WORD_SEL | CPLD_SYNC_SEL); + if (!(val & CPLD_SYNC_SEL)) { + /* switched to internal clock, is not any external type */ + result = -1; + } else { + switch (val) { + case (CPLD_EXT_SPDIF): + result = EXT_SPDIF_TYPE; + break; + case (CPLD_EXT_WORDCLOCK_1FS): + result = EXT_WORDCLOCK_1FS_TYPE; + break; + case (CPLD_EXT_WORDCLOCK_256FS): + result = EXT_WORDCLOCK_256FS_TYPE; + break; + default: + /* undefined combination of external clock setup */ + snd_BUG(); + result = 0; + } + } + return result; +} + +/* Called when ak4113 detects change in the input SPDIF stream */ +static void qtet_ak4113_change(struct ak4113 *ak4113, unsigned char c0, + unsigned char c1) +{ + struct snd_ice1712 *ice = ak4113->change_callback_private; + int rate; + if ((qtet_get_spdif_master_type(ice) == EXT_SPDIF_TYPE) && + 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", + rate); */ + qtet_akm_set_rate_val(ice->akm, rate); + } +} + +/* + * If clock slaved to SPDIF-IN, setting runtime rate + * to the detected external rate + */ +static void qtet_spdif_in_open(struct snd_ice1712 *ice, + struct snd_pcm_substream *substream) +{ + struct qtet_spec *spec = ice->spec; + struct snd_pcm_runtime *runtime = substream->runtime; + int rate; + + if (qtet_get_spdif_master_type(ice) != EXT_SPDIF_TYPE) + /* not external SPDIF, no rate limitation */ + return; + /* only external SPDIF can detect incoming sample rate */ + rate = snd_ak4113_external_rate(spec->ak4113); + if (rate >= runtime->hw.rate_min && rate <= runtime->hw.rate_max) { + runtime->hw.rate_min = rate; + runtime->hw.rate_max = rate; + } +} + +/* + * initialize the chip + */ +static int __devinit qtet_init(struct snd_ice1712 *ice) +{ + static const unsigned char ak4113_init_vals[] = { + /* AK4113_REG_PWRDN */ AK4113_RST | AK4113_PWN | + AK4113_OCKS0 | AK4113_OCKS1, + /* AK4113_REQ_FORMAT */ AK4113_DIF_I24I2S | AK4113_VTX | + AK4113_DEM_OFF | AK4113_DEAU, + /* AK4113_REG_IO0 */ AK4113_OPS2 | AK4113_TXE | + AK4113_XTL_24_576M, + /* AK4113_REG_IO1 */ AK4113_EFH_1024LRCLK | AK4113_IPS(0), + /* AK4113_REG_INT0_MASK */ 0, + /* AK4113_REG_INT1_MASK */ 0, + /* AK4113_REG_DATDTS */ 0, + }; + int err; + struct qtet_spec *spec; + struct snd_akm4xxx *ak; + unsigned char val; + + /* switching ice1724 to external clock - supplied by ext. circuits */ + val = inb(ICEMT1724(ice, RATE)); + outb(val | VT1724_SPDIF_MASTER, ICEMT1724(ice, RATE)); + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; + /* qtet is clocked by Xilinx array */ + ice->hw_rates = &qtet_rates_info; + ice->is_spdif_master = qtet_is_spdif_master; + ice->get_rate = qtet_get_rate; + ice->set_rate = qtet_set_rate; + ice->set_mclk = qtet_set_mclk; + ice->set_spdif_clock = qtet_set_spdif_clock; + ice->get_spdif_master_type = qtet_get_spdif_master_type; + ice->ext_clock_names = ext_clock_names; + ice->ext_clock_count = ARRAY_SIZE(ext_clock_names); + /* since Qtet can detect correct SPDIF-in rate, all streams can be + * limited to this specific rate */ + ice->spdif.ops.open = ice->pro_open = qtet_spdif_in_open; + ice->spec = spec; + + /* Mute Off */ + /* SCR Initialize*/ + /* keep codec power down first */ + set_scr(ice, SCR_PHP); + udelay(1); + /* codec power up */ + set_scr(ice, SCR_PHP | SCR_CODEC_PDN); + + /* MCR Initialize */ + set_mcr(ice, 0); + + /* CPLD Initialize */ + set_cpld(ice, 0); + + + ice->num_total_dacs = 2; + ice->num_total_adcs = 2; + + ice->akm = kcalloc(2, sizeof(struct snd_akm4xxx), GFP_KERNEL); + ak = ice->akm; + if (!ak) + return -ENOMEM; + /* only one codec with two chips */ + ice->akm_codecs = 1; + err = snd_ice1712_akm4xxx_init(ak, &akm_qtet_dac, NULL, ice); + if (err < 0) + return err; + err = snd_ak4113_create(ice->card, + qtet_ak4113_read, + qtet_ak4113_write, + ak4113_init_vals, + ice, &spec->ak4113); + if (err < 0) + return err; + /* callback for codecs rate setting */ + spec->ak4113->change_callback = qtet_ak4113_change; + spec->ak4113->change_callback_private = ice; + /* AK41143 in Quartet can detect external rate correctly + * (i.e. check_flags = 0) */ + spec->ak4113->check_flags = 0; + + proc_init(ice); + + qtet_set_rate(ice, 44100); + return 0; +} + +static unsigned char qtet_eeprom[] __devinitdata = { + [ICE_EEP2_SYSCONF] = 0x28, /* clock 256(24MHz), mpu401, 1xADC, + 1xDACs, SPDIF in */ + [ICE_EEP2_ACLINK] = 0x80, /* I2S */ + [ICE_EEP2_I2S] = 0x78, /* 96k, 24bit, 192k */ + [ICE_EEP2_SPDIF] = 0xc3, /* out-en, out-int, in, out-ext */ + [ICE_EEP2_GPIO_DIR] = 0x00, /* 0-7 inputs, switched to output + only during output operations */ + [ICE_EEP2_GPIO_DIR1] = 0xff, /* 8-15 outputs */ + [ICE_EEP2_GPIO_DIR2] = 0x00, + [ICE_EEP2_GPIO_MASK] = 0xff, /* changed only for OUT operations */ + [ICE_EEP2_GPIO_MASK1] = 0x00, + [ICE_EEP2_GPIO_MASK2] = 0xff, + + [ICE_EEP2_GPIO_STATE] = 0x00, /* inputs */ + [ICE_EEP2_GPIO_STATE1] = 0x7d, /* all 1, but GPIO_CPLD_RW + and GPIO15 always zero */ + [ICE_EEP2_GPIO_STATE2] = 0x00, /* inputs */ +}; + +/* entry point */ +struct snd_ice1712_card_info snd_vt1724_qtet_cards[] __devinitdata = { + { + .subvendor = VT1724_SUBDEVICE_QTET, + .name = "Infrasonic Quartet", + .model = "quartet", + .chip_init = qtet_init, + .build_controls = qtet_add_controls, + .eeprom_size = sizeof(qtet_eeprom), + .eeprom_data = qtet_eeprom, + }, + { } /* terminator */ +}; diff --git a/sound/pci/ice1712/quartet.h b/sound/pci/ice1712/quartet.h new file mode 100644 index 000000000000..80809b72439a --- /dev/null +++ b/sound/pci/ice1712/quartet.h @@ -0,0 +1,10 @@ +#ifndef __SOUND_QTET_H +#define __SOUND_QTET_H + +#define QTET_DEVICE_DESC "{Infrasonic,Quartet}," + +#define VT1724_SUBDEVICE_QTET 0x30305349 /* Infrasonic Quartet */ + +extern struct snd_ice1712_card_info snd_vt1724_qtet_cards[]; + +#endif /* __SOUND_QTET_H */ -- cgit v1.2.3 From 4f272341c7a42a71586523f196b242bccde3be8c Mon Sep 17 00:00:00 2001 From: Tobias Hansen Date: Tue, 22 Sep 2009 16:52:08 +0200 Subject: ALSA: snd-usb-us122l: add support for US-144 Adds support for US-144 when attached on USB1.1. Unlike the US-122L it uses both USB interfaces 0 and 1. Signed-off-by: Tobias Hansen Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 75 ++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 67 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index fd44946ce4b3..6c7b64a23c13 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -66,6 +66,28 @@ static int us122l_create_usbmidi(struct snd_card *card) iface, &quirk); } +static int us144_create_usbmidi(struct snd_card *card) +{ + static struct snd_usb_midi_endpoint_info quirk_data = { + .out_ep = 4, + .in_ep = 3, + .out_cables = 0x001, + .in_cables = 0x001 + }; + static struct snd_usb_audio_quirk quirk = { + .vendor_name = "US144", + .product_name = NAME_ALLCAPS, + .ifnum = 0, + .type = QUIRK_MIDI_US122L, + .data = &quirk_data + }; + struct usb_device *dev = US122L(card)->chip.dev; + struct usb_interface *iface = usb_ifnum_to_if(dev, 0); + + return snd_usb_create_midi_interface(&US122L(card)->chip, + iface, &quirk); +} + /* * Wrapper for usb_control_msg(). * Allocates a temp buffer to prevent dmaing from/to the stack. @@ -171,6 +193,11 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; + + if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->chip.dev, 0); + usb_autopm_get_interface(iface); + } iface = usb_ifnum_to_if(us122l->chip.dev, 1); usb_autopm_get_interface(iface); return 0; @@ -179,8 +206,14 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) { struct us122l *us122l = hw->private_data; - struct usb_interface *iface = usb_ifnum_to_if(us122l->chip.dev, 1); + struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); + + if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->chip.dev, 0); + usb_autopm_put_interface(iface); + } + iface = usb_ifnum_to_if(us122l->chip.dev, 1); usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; @@ -443,6 +476,13 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); + if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->chip.dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + return false; + } + } err = usb_set_interface(us122l->chip.dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -455,7 +495,10 @@ static bool us122l_create_card(struct snd_card *card) if (!us122l_start(us122l, 44100, 256)) return false; - err = us122l_create_usbmidi(card); + if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) + err = us144_create_usbmidi(card); + else + err = us122l_create_usbmidi(card); if (err < 0) { snd_printk(KERN_ERR "us122l_create_usbmidi error %i \n", err); us122l_stop(us122l); @@ -542,6 +585,7 @@ static int us122l_usb_probe(struct usb_interface *intf, return err; } + usb_get_intf(usb_ifnum_to_if(device, 0)); usb_get_dev(device); *cardp = card; return 0; @@ -550,9 +594,16 @@ static int us122l_usb_probe(struct usb_interface *intf, static int snd_us122l_probe(struct usb_interface *intf, const struct usb_device_id *id) { + struct usb_device *device = interface_to_usbdev(intf); struct snd_card *card; int err; + if (device->descriptor.idProduct == USB_ID_US144 + && device->speed == USB_SPEED_HIGH) { + snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); + return -ENOENT; + } + snd_printdd(KERN_DEBUG"%p:%i\n", intf, intf->cur_altsetting->desc.bInterfaceNumber); if (intf->cur_altsetting->desc.bInterfaceNumber != 1) @@ -591,7 +642,8 @@ static void snd_us122l_disconnect(struct usb_interface *intf) snd_usbmidi_disconnect(p); } - usb_put_intf(intf); + usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 0)); + usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 1)); usb_put_dev(us122l->chip.dev); while (atomic_read(&us122l->mmap_count)) @@ -642,6 +694,13 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ + if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->chip.dev, 0, 1); + if (err) { + snd_printk(KERN_ERR "usb_set_interface error \n"); + goto unlock; + } + } err = usb_set_interface(us122l->chip.dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -675,11 +734,11 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US122L }, -/* { */ /* US-144 maybe works when @USB1.1. Untested. */ -/* .match_flags = USB_DEVICE_ID_MATCH_DEVICE, */ -/* .idVendor = 0x0644, */ -/* .idProduct = USB_ID_US144 */ -/* }, */ + { /* US-144 only works at USB1.1! Disable module ehci-hcd. */ + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US144 + }, { /* terminator */ } }; -- cgit v1.2.3 From f0968e3f7a8ea30728d2580d3043a30ea9994ec6 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 27 Sep 2009 23:08:40 +0200 Subject: ALSA: sscape: add supoort for SPEA Media FX/Reveal SC-600 Move code from the OSS sscape driver in order to support old Soundscape OEM models. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/Kconfig | 6 ++- sound/isa/sscape.c | 116 +++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 86 insertions(+), 36 deletions(-) (limited to 'sound') diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 51a7e3777e17..b90fc164a79c 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -377,10 +377,12 @@ config SND_SSCAPE select SND_WSS_LIB help Say Y here to include support for Ensoniq SoundScape - soundcards. + and Ensoniq OEM soundcards. The PCM audio is supported on SoundScape Classic, Elite, PnP - and VIVO cards. The MIDI support is very experimental. + and VIVO cards. The supported OEM cards are SPEA Media FX and + Reveal SC-600. + The MIDI support is very experimental. To compile this driver as a module, choose M here: the module will be called snd-sscape. diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 66187122377c..b11c35f6aefe 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -127,7 +127,8 @@ enum GA_REG { enum card_type { - SSCAPE, + MEDIA_FX, /* Sequoia S-1000 */ + SSCAPE, /* Sequoia S-2000 */ SSCAPE_PNP, SSCAPE_VIVO, }; @@ -784,20 +785,25 @@ static struct snd_kcontrol_new midi_mixer_ctl = { * These IRQs are encoded as bit patterns so that they can be * written to the control registers. */ -static unsigned __devinit get_irq_config(int irq) +static unsigned __devinit get_irq_config(int sscape_type, int irq) { static const int valid_irq[] = { 9, 5, 7, 10 }; + static const int old_irq[] = { 9, 7, 5, 15 }; unsigned cfg; - for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) { - if (irq == valid_irq[cfg]) - return cfg; - } /* for */ + if (sscape_type == MEDIA_FX) { + for (cfg = 0; cfg < ARRAY_SIZE(old_irq); ++cfg) + if (irq == old_irq[cfg]) + return cfg; + } else { + for (cfg = 0; cfg < ARRAY_SIZE(valid_irq); ++cfg) + if (irq == valid_irq[cfg]) + return cfg; + } return INVALID_IRQ; } - /* * Perform certain arcane port-checks to see whether there * is a SoundScape board lurking behind the given ports. @@ -842,11 +848,39 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) if (s->type != SSCAPE_VIVO && (d & 0x9f) != 0x0e) goto _done; - d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + if (s->ic_type == IC_OPUS) + activate_ad1845_unsafe(s->io_base); if (s->type == SSCAPE_VIVO) wss_io += 4; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); + + /* wait for WSS codec */ + for (d = 0; d < 500; d++) { + if ((inb(wss_io) & 0x80) == 0) + break; + spin_unlock_irqrestore(&s->lock, flags); + msleep(1); + spin_lock_irqsave(&s->lock, flags); + } + snd_printd(KERN_INFO "init delay = %d ms\n", d); + + if ((inb(wss_io) & 0x80) != 0) + goto _done; + + if (inb(wss_io + 2) == 0xff) + goto _done; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d); + + if ((inb(wss_io) & 0x80) != 0) + s->type = MEDIA_FX; + + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ for (d = 0; d < 500; d++) { if ((inb(wss_io) & 0x80) == 0) @@ -954,9 +988,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, if (sscape->type == SSCAPE_VIVO) port += 4; - if (dma1 == dma2) - dma2 = -1; - err = snd_wss_create(card, port, -1, irq, dma1, dma2, WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); if (!err) { @@ -1051,21 +1082,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card) struct resource *wss_res; unsigned long flags; int err; - - /* - * Check that the user didn't pass us garbage data ... - */ - irq_cfg = get_irq_config(irq[dev]); - if (irq_cfg == INVALID_IRQ) { - snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); - return -ENXIO; - } - - mpu_irq_cfg = get_irq_config(mpu_irq[dev]); - if (mpu_irq_cfg == INVALID_IRQ) { - printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); - return -ENXIO; - } + const char *name; /* * Grab IO ports that we will need to probe so that we @@ -1109,8 +1126,41 @@ static int __devinit create_sscape(int dev, struct snd_card *card) goto _release_dma; } - printk(KERN_INFO "sscape: hardware detected at 0x%x, using IRQ %d, DMA %d\n", - sscape->io_base, irq[dev], dma[dev]); + switch (sscape->type) { + case MEDIA_FX: + name = "MediaFX/SoundFX"; + break; + case SSCAPE: + name = "Soundscape"; + break; + case SSCAPE_PNP: + name = "Soundscape PnP"; + break; + case SSCAPE_VIVO: + name = "Soundscape VIVO"; + break; + default: + name = "unknown Soundscape"; + break; + } + + printk(KERN_INFO "sscape: %s card detected at 0x%x, using IRQ %d, DMA %d\n", + name, sscape->io_base, irq[dev], dma[dev]); + + /* + * Check that the user didn't pass us garbage data ... + */ + irq_cfg = get_irq_config(sscape->type, irq[dev]); + if (irq_cfg == INVALID_IRQ) { + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", irq[dev]); + return -ENXIO; + } + + mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); + if (mpu_irq_cfg == INVALID_IRQ) { + printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); + return -ENXIO; + } if (sscape->type != SSCAPE_VIVO) { /* @@ -1141,8 +1191,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) */ spin_lock_irqsave(&sscape->lock, flags); - activate_ad1845_unsafe(sscape->io_base); - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); @@ -1151,12 +1199,12 @@ static int __devinit create_sscape(int dev, struct snd_card *card) * Enable and configure the DMA channels ... */ sscape_write_unsafe(sscape->io_base, GA_DMACFG_REG, 0x50); - dma_cfg = (sscape->ic_type == IC_ODIE ? 0x70 : 0x40); + dma_cfg = (sscape->ic_type == IC_OPUS ? 0x40 : 0x70); sscape_write_unsafe(sscape->io_base, GA_DMAA_REG, dma_cfg); sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); - sscape_write_unsafe(sscape->io_base, - GA_INTCFG_REG, 0xf0 | (mpu_irq_cfg << 2) | mpu_irq_cfg); + mpu_irq_cfg |= mpu_irq_cfg << 2; + sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); -- cgit v1.2.3 From 87b61902ce3dec23a2d8256b9cfcf4e28786a320 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:05:18 +0200 Subject: sound: oxygen: do not try to restore nonexistent EEPROM On cards where the EEPROM was deliberately omitted, we do not need to try to restore the EEPROM's contents. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index 9a8936e20744..c9f271419eb8 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -278,7 +278,11 @@ oxygen_search_pci_id(struct oxygen *chip, const struct pci_device_id ids[]) static void oxygen_restore_eeprom(struct oxygen *chip, const struct pci_device_id *id) { - if (oxygen_read_eeprom(chip, 0) != OXYGEN_EEPROM_ID) { + u16 eeprom_id; + + eeprom_id = oxygen_read_eeprom(chip, 0); + if (eeprom_id != OXYGEN_EEPROM_ID && + (eeprom_id != 0xffff || id->subdevice != 0x8788)) { /* * This function gets called only when a known card model has * been detected, i.e., we know there is a valid subsystem -- cgit v1.2.3 From 362bc24d6746bcd49bb4853fc5aa7d4c728b3f9e Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:05:58 +0200 Subject: sound: oxygen: fix for PI7C9X110 compatibility If the card is used with a Pericom PI7C9X110 PCI-E/PCI bridge, reconfigure the latter's PCI buffering to fix an unknown problem. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_lib.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen_lib.c b/sound/pci/oxygen/oxygen_lib.c index c9f271419eb8..9c5e6450eebb 100644 --- a/sound/pci/oxygen/oxygen_lib.c +++ b/sound/pci/oxygen/oxygen_lib.c @@ -307,6 +307,28 @@ static void oxygen_restore_eeprom(struct oxygen *chip, } } +static void pci_bridge_magic(void) +{ + struct pci_dev *pci = NULL; + u32 tmp; + + for (;;) { + /* If there is any Pericom PI7C9X110 PCI-E/PCI bridge ... */ + pci = pci_get_device(0x12d8, 0xe110, pci); + if (!pci) + break; + /* + * ... configure its secondary internal arbiter to park to + * the secondary port, instead of to the last master. + */ + if (!pci_read_config_dword(pci, 0x40, &tmp)) { + tmp |= 1; + pci_write_config_dword(pci, 0x40, tmp); + } + /* Why? Try asking C-Media. */ + } +} + static void oxygen_init(struct oxygen *chip) { unsigned int i; @@ -585,6 +607,7 @@ int oxygen_pci_probe(struct pci_dev *pci, int index, char *id, snd_card_set_dev(card, &pci->dev); card->private_free = oxygen_card_free; + pci_bridge_magic(); oxygen_init(chip); chip->model.init(chip); -- cgit v1.2.3 From 65c3ac885ce9852852b895a4a62212f62cb5f2e9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:11:27 +0200 Subject: sound: virtuoso: split virtuoso.c The virtuoso.c file has become rather big. This patch splits it up so that only code for very similar card models is in one file. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/Makefile | 3 +- sound/pci/oxygen/virtuoso.c | 1105 +------------------------------------- sound/pci/oxygen/xonar.h | 50 ++ sound/pci/oxygen/xonar_cs43xx.c | 304 +++++++++++ sound/pci/oxygen/xonar_hdmi.c | 128 +++++ sound/pci/oxygen/xonar_lib.c | 132 +++++ sound/pci/oxygen/xonar_pcm179x.c | 660 +++++++++++++++++++++++ 7 files changed, 1290 insertions(+), 1092 deletions(-) create mode 100644 sound/pci/oxygen/xonar.h create mode 100644 sound/pci/oxygen/xonar_cs43xx.c create mode 100644 sound/pci/oxygen/xonar_hdmi.c create mode 100644 sound/pci/oxygen/xonar_lib.c create mode 100644 sound/pci/oxygen/xonar_pcm179x.c (limited to 'sound') diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 4ba07d42fd1d..389941cf6100 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile @@ -1,7 +1,8 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o snd-hifier-objs := hifier.o snd-oxygen-objs := oxygen.o -snd-virtuoso-objs := virtuoso.o +snd-virtuoso-objs := virtuoso.o xonar_lib.o \ + xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o obj-$(CONFIG_SND_HIFIER) += snd-hifier.o diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 6ebcb6bdd712..6accaf9580b2 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c @@ -17,145 +17,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* - * Xonar D2/D2X - * ------------ - * - * CMI8788: - * - * SPI 0 -> 1st PCM1796 (front) - * SPI 1 -> 2nd PCM1796 (surround) - * SPI 2 -> 3rd PCM1796 (center/LFE) - * SPI 4 -> 4th PCM1796 (back) - * - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 5 <- external power present (D2X only) - * GPIO 7 -> ALT - * GPIO 8 -> enable output to speakers - */ - -/* - * Xonar D1/DX - * ----------- - * - * CMI8788: - * - * I²C <-> CS4398 (front) - * <-> CS4362A (surround, center/LFE, back) - * - * GPI 0 <- external power present (DX only) - * - * GPIO 0 -> enable output to speakers - * GPIO 1 -> enable front panel I/O - * GPIO 2 -> M0 of CS5361 - * GPIO 3 -> M1 of CS5361 - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) - * - * CS4398: - * - * AD0 <- 1 - * AD1 <- 1 - * - * CS4362A: - * - * AD0 <- 0 - */ - -/* - * Xonar HDAV1.3 (Deluxe) - * ---------------------- - * - * CMI8788: - * - * I²C <-> PCM1796 (front) - * - * GPI 0 <- external power present - * - * GPIO 0 -> enable output to speakers - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) - * - * TXD -> HDMI controller - * RXD <- HDMI controller - * - * PCM1796 front: AD1,0 <- 0,0 - * - * no daughterboard - * ---------------- - * - * GPIO 4 <- 1 - * - * H6 daughterboard - * ---------------- - * - * GPIO 4 <- 0 - * GPIO 5 <- 0 - * - * I²C <-> PCM1796 (surround) - * <-> PCM1796 (center/LFE) - * <-> PCM1796 (back) - * - * PCM1796 surround: AD1,0 <- 0,1 - * PCM1796 center/LFE: AD1,0 <- 1,0 - * PCM1796 back: AD1,0 <- 1,1 - * - * unknown daughterboard - * --------------------- - * - * GPIO 4 <- 0 - * GPIO 5 <- 1 - * - * I²C <-> CS4362A (surround, center/LFE, back) - * - * CS4362A: AD0 <- 0 - */ - -/* - * Xonar Essence ST (Deluxe)/STX - * ----------------------------- - * - * CMI8788: - * - * I²C <-> PCM1792A - * - * GPI 0 <- external power present - * - * GPIO 0 -> enable output to speakers - * GPIO 1 -> route HP to front panel (0) or rear jack (1) - * GPIO 2 -> M0 of CS5381 - * GPIO 3 -> M1 of CS5381 - * GPIO 7 -> route output to speaker jacks (0) or HP (1) - * GPIO 8 -> route input jack to line-in (0) or mic-in (1) - * - * PCM1792A: - * - * AD0 <- 0 - * - * H6 daughterboard - * ---------------- - * - * GPIO 4 <- 0 - * GPIO 5 <- 0 - */ - #include #include -#include -#include -#include -#include #include #include #include -#include -#include -#include "oxygen.h" -#include "cm9780.h" -#include "pcm1796.h" -#include "cs4398.h" -#include "cs4362a.h" +#include "xonar.h" MODULE_AUTHOR("Clemens Ladisch "); MODULE_DESCRIPTION("Asus AVx00 driver"); @@ -173,972 +40,28 @@ MODULE_PARM_DESC(id, "ID string"); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "enable card"); -enum { - MODEL_D2, - MODEL_D2X, - MODEL_D1, - MODEL_DX, - MODEL_HDAV, /* without daughterboard */ - MODEL_HDAV_H6, /* with H6 daughterboard */ - MODEL_ST, - MODEL_ST_H6, - MODEL_STX, -}; - static struct pci_device_id xonar_ids[] __devinitdata = { - { OXYGEN_PCI_SUBID(0x1043, 0x8269), .driver_data = MODEL_D2 }, - { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, - { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, - { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, - { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX }, - { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, - { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, - { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST }, + { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, + { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8314) }, + { OXYGEN_PCI_SUBID(0x1043, 0x8327) }, + { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, + { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, + { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, { } }; MODULE_DEVICE_TABLE(pci, xonar_ids); - -#define GPIO_CS53x1_M_MASK 0x000c -#define GPIO_CS53x1_M_SINGLE 0x0000 -#define GPIO_CS53x1_M_DOUBLE 0x0004 -#define GPIO_CS53x1_M_QUAD 0x0008 - -#define GPIO_D2X_EXT_POWER 0x0020 -#define GPIO_D2_ALT 0x0080 -#define GPIO_D2_OUTPUT_ENABLE 0x0100 - -#define GPI_DX_EXT_POWER 0x01 -#define GPIO_DX_OUTPUT_ENABLE 0x0001 -#define GPIO_DX_FRONT_PANEL 0x0002 -#define GPIO_DX_INPUT_ROUTE 0x0100 - -#define GPIO_DB_MASK 0x0030 -#define GPIO_DB_H6 0x0000 -#define GPIO_DB_XX 0x0020 - -#define GPIO_ST_HP_REAR 0x0002 -#define GPIO_ST_HP 0x0080 - -#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ADx=i, /W=0 */ -#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ -#define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ - -struct xonar_data { - unsigned int anti_pop_delay; - unsigned int dacs; - u16 output_enable_bit; - u8 ext_power_reg; - u8 ext_power_int_reg; - u8 ext_power_bit; - u8 has_power; - u8 pcm1796_oversampling; - u8 cs4398_fm; - u8 cs4362a_fm; - u8 hdmi_params[5]; -}; - -static void xonar_gpio_changed(struct oxygen *chip); - -static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec, - u8 reg, u8 value) -{ - /* maps ALSA channel pair number to SPI output */ - static const u8 codec_map[4] = { - 0, 1, 2, 4 - }; - oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | - OXYGEN_SPI_DATA_LENGTH_2 | - OXYGEN_SPI_CLOCK_160 | - (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | - OXYGEN_SPI_CEN_LATCH_CLOCK_HI, - (reg << 8) | value); -} - -static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec, - u8 reg, u8 value) -{ - oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value); -} - -static void pcm1796_write(struct oxygen *chip, unsigned int codec, - u8 reg, u8 value) -{ - if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == - OXYGEN_FUNCTION_SPI) - pcm1796_write_spi(chip, codec, reg, value); - else - pcm1796_write_i2c(chip, codec, reg, value); -} - -static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) -{ - oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); -} - -static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) -{ - oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); -} - -static void hdmi_write_command(struct oxygen *chip, u8 command, - unsigned int count, const u8 *params) -{ - unsigned int i; - u8 checksum; - - oxygen_write_uart(chip, 0xfb); - oxygen_write_uart(chip, 0xef); - oxygen_write_uart(chip, command); - oxygen_write_uart(chip, count); - for (i = 0; i < count; ++i) - oxygen_write_uart(chip, params[i]); - checksum = 0xfb + 0xef + command + count; - for (i = 0; i < count; ++i) - checksum += params[i]; - oxygen_write_uart(chip, checksum); -} - -static void xonar_enable_output(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - msleep(data->anti_pop_delay); - oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); -} - -static void xonar_common_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - if (data->ext_power_reg) { - oxygen_set_bits8(chip, data->ext_power_int_reg, - data->ext_power_bit); - chip->interrupt_mask |= OXYGEN_INT_GPIO; - chip->model.gpio_changed = xonar_gpio_changed; - data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) - & data->ext_power_bit); - } - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_CS53x1_M_MASK | data->output_enable_bit); - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); - oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); - xonar_enable_output(chip); -} - -static void update_pcm1796_volume(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - unsigned int i; - - for (i = 0; i < data->dacs; ++i) { - pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); - pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); - } -} - -static void update_pcm1796_mute(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - unsigned int i; - u8 value; - - value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; - if (chip->dac_mute) - value |= PCM1796_MUTE; - for (i = 0; i < data->dacs; ++i) - pcm1796_write(chip, i, 18, value); -} - -static void pcm1796_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - unsigned int i; - - for (i = 0; i < data->dacs; ++i) { - pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); - pcm1796_write(chip, i, 20, data->pcm1796_oversampling); - pcm1796_write(chip, i, 21, 0); - } - update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ - update_pcm1796_volume(chip); -} - -static void xonar_d2_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->anti_pop_delay = 300; - data->dacs = 4; - data->output_enable_bit = GPIO_D2_OUTPUT_ENABLE; - data->pcm1796_oversampling = PCM1796_OS_64; - - pcm1796_init(chip); - - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); - - xonar_common_init(chip); - - snd_component_add(chip->card, "PCM1796"); - snd_component_add(chip->card, "CS5381"); -} - -static void xonar_d2x_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->ext_power_reg = OXYGEN_GPIO_DATA; - data->ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; - data->ext_power_bit = GPIO_D2X_EXT_POWER; - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); - - xonar_d2_init(chip); -} - -static void update_cs4362a_volumes(struct oxygen *chip) -{ - u8 mute; - - mute = chip->dac_mute ? CS4362A_MUTE : 0; - cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); - cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); - cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); - cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); - cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); - cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); -} - -static void update_cs43xx_volume(struct oxygen *chip) -{ - cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); - cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); - update_cs4362a_volumes(chip); -} - -static void update_cs43xx_mute(struct oxygen *chip) -{ - u8 reg; - - reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; - if (chip->dac_mute) - reg |= CS4398_MUTE_B | CS4398_MUTE_A; - cs4398_write(chip, 4, reg); - update_cs4362a_volumes(chip); -} - -static void cs43xx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - /* set CPEN (control port mode) and power down */ - cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); - cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); - /* configure */ - cs4398_write(chip, 2, data->cs4398_fm); - cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); - cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | - CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); - cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); - cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | - CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); - cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); - cs4362a_write(chip, 0x05, 0); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); - update_cs43xx_volume(chip); - update_cs43xx_mute(chip); - /* clear power down */ - cs4398_write(chip, 8, CS4398_CPEN); - cs4362a_write(chip, 0x01, CS4362A_CPEN); -} - -static void xonar_d1_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->anti_pop_delay = 800; - data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; - data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_FM_SINGLE | - CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, - OXYGEN_2WIRE_LENGTH_8 | - OXYGEN_2WIRE_INTERRUPT_MASK | - OXYGEN_2WIRE_SPEED_FAST); - - cs43xx_init(chip); - - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, - GPIO_DX_FRONT_PANEL | GPIO_DX_INPUT_ROUTE); - - xonar_common_init(chip); - - snd_component_add(chip->card, "CS4398"); - snd_component_add(chip->card, "CS4362A"); - snd_component_add(chip->card, "CS5361"); -} - -static void xonar_dx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - - xonar_d1_init(chip); -} - -static void xonar_hdav_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - u8 param; - - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, - OXYGEN_2WIRE_LENGTH_8 | - OXYGEN_2WIRE_INTERRUPT_MASK | - OXYGEN_2WIRE_SPEED_FAST); - - data->anti_pop_delay = 100; - data->dacs = chip->model.private_data == MODEL_HDAV_H6 ? 4 : 1; - data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - data->pcm1796_oversampling = PCM1796_OS_64; - - pcm1796_init(chip); - - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DX_INPUT_ROUTE); - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DX_INPUT_ROUTE); - - oxygen_reset_uart(chip); - param = 0; - hdmi_write_command(chip, 0x61, 1, ¶m); - param = 1; - hdmi_write_command(chip, 0x74, 1, ¶m); - data->hdmi_params[1] = IEC958_AES3_CON_FS_48000; - data->hdmi_params[4] = 1; - hdmi_write_command(chip, 0x54, 5, data->hdmi_params); - - xonar_common_init(chip); - - snd_component_add(chip->card, "PCM1796"); - snd_component_add(chip->card, "CS5381"); -} - -static void xonar_st_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, - OXYGEN_2WIRE_LENGTH_8 | - OXYGEN_2WIRE_INTERRUPT_MASK | - OXYGEN_2WIRE_SPEED_FAST); - - if (chip->model.private_data == MODEL_ST_H6) - chip->model.dac_channels = 8; - data->anti_pop_delay = 100; - data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1; - data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; - data->pcm1796_oversampling = PCM1796_OS_64; - - pcm1796_init(chip); - - oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, - GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, - GPIO_DX_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); - - xonar_common_init(chip); - - snd_component_add(chip->card, "PCM1792A"); - snd_component_add(chip->card, "CS5381"); -} - -static void xonar_stx_init(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - data->ext_power_reg = OXYGEN_GPI_DATA; - data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; - data->ext_power_bit = GPI_DX_EXT_POWER; - - xonar_st_init(chip); -} - -static void xonar_disable_output(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - - oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); -} - -static void xonar_d2_cleanup(struct oxygen *chip) -{ - xonar_disable_output(chip); -} - -static void xonar_d1_cleanup(struct oxygen *chip) -{ - xonar_disable_output(chip); - cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); - oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); -} - -static void xonar_hdav_cleanup(struct oxygen *chip) -{ - u8 param = 0; - - hdmi_write_command(chip, 0x74, 1, ¶m); - xonar_disable_output(chip); -} - -static void xonar_st_cleanup(struct oxygen *chip) -{ - xonar_disable_output(chip); -} - -static void xonar_d2_suspend(struct oxygen *chip) -{ - xonar_d2_cleanup(chip); -} - -static void xonar_d1_suspend(struct oxygen *chip) -{ - xonar_d1_cleanup(chip); -} - -static void xonar_hdav_suspend(struct oxygen *chip) -{ - xonar_hdav_cleanup(chip); - msleep(2); -} - -static void xonar_st_suspend(struct oxygen *chip) -{ - xonar_st_cleanup(chip); -} - -static void xonar_d2_resume(struct oxygen *chip) -{ - pcm1796_init(chip); - xonar_enable_output(chip); -} - -static void xonar_d1_resume(struct oxygen *chip) -{ - oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); - msleep(1); - cs43xx_init(chip); - xonar_enable_output(chip); -} - -static void xonar_hdav_resume(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - u8 param; - - oxygen_reset_uart(chip); - param = 0; - hdmi_write_command(chip, 0x61, 1, ¶m); - param = 1; - hdmi_write_command(chip, 0x74, 1, ¶m); - hdmi_write_command(chip, 0x54, 5, data->hdmi_params); - pcm1796_init(chip); - xonar_enable_output(chip); -} - -static void xonar_st_resume(struct oxygen *chip) -{ - pcm1796_init(chip); - xonar_enable_output(chip); -} - -static void xonar_hdav_pcm_hardware_filter(unsigned int channel, - struct snd_pcm_hardware *hardware) -{ - if (channel == PCM_MULTICH) { - hardware->rates = SNDRV_PCM_RATE_44100 | - SNDRV_PCM_RATE_48000 | - SNDRV_PCM_RATE_96000 | - SNDRV_PCM_RATE_192000; - hardware->rate_min = 44100; - } -} - -static void set_pcm1796_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - struct xonar_data *data = chip->model_data; - unsigned int i; - - data->pcm1796_oversampling = - params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; - for (i = 0; i < data->dacs; ++i) - pcm1796_write(chip, i, 20, data->pcm1796_oversampling); -} - -static void set_cs53x1_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - unsigned int value; - - if (params_rate(params) <= 54000) - value = GPIO_CS53x1_M_SINGLE; - else if (params_rate(params) <= 108000) - value = GPIO_CS53x1_M_DOUBLE; - else - value = GPIO_CS53x1_M_QUAD; - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - value, GPIO_CS53x1_M_MASK); -} - -static void set_cs43xx_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - struct xonar_data *data = chip->model_data; - - data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - if (params_rate(params) <= 50000) { - data->cs4398_fm |= CS4398_FM_SINGLE; - data->cs4362a_fm |= CS4362A_FM_SINGLE; - } else if (params_rate(params) <= 100000) { - data->cs4398_fm |= CS4398_FM_DOUBLE; - data->cs4362a_fm |= CS4362A_FM_DOUBLE; - } else { - data->cs4398_fm |= CS4398_FM_QUAD; - data->cs4362a_fm |= CS4362A_FM_QUAD; - } - cs4398_write(chip, 2, data->cs4398_fm); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); -} - -static void set_hdmi_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - struct xonar_data *data = chip->model_data; - - data->hdmi_params[0] = 0; /* 1 = non-audio */ - switch (params_rate(params)) { - case 44100: - data->hdmi_params[1] = IEC958_AES3_CON_FS_44100; - break; - case 48000: - data->hdmi_params[1] = IEC958_AES3_CON_FS_48000; - break; - default: /* 96000 */ - data->hdmi_params[1] = IEC958_AES3_CON_FS_96000; - break; - case 192000: - data->hdmi_params[1] = IEC958_AES3_CON_FS_192000; - break; - } - data->hdmi_params[2] = params_channels(params) / 2 - 1; - if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) - data->hdmi_params[3] = 0; - else - data->hdmi_params[3] = 0xc0; - data->hdmi_params[4] = 1; /* ? */ - hdmi_write_command(chip, 0x54, 5, data->hdmi_params); -} - -static void set_hdav_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) -{ - set_pcm1796_params(chip, params); - set_hdmi_params(chip, params); -} - -static void xonar_gpio_changed(struct oxygen *chip) -{ - struct xonar_data *data = chip->model_data; - u8 has_power; - - has_power = !!(oxygen_read8(chip, data->ext_power_reg) - & data->ext_power_bit); - if (has_power != data->has_power) { - data->has_power = has_power; - if (has_power) { - snd_printk(KERN_NOTICE "power restored\n"); - } else { - snd_printk(KERN_CRIT - "Hey! Don't unplug the power cable!\n"); - /* TODO: stop PCMs */ - } - } -} - -static void xonar_hdav_uart_input(struct oxygen *chip) -{ - if (chip->uart_input_count >= 2 && - chip->uart_input[chip->uart_input_count - 2] == 'O' && - chip->uart_input[chip->uart_input_count - 1] == 'K') { - printk(KERN_DEBUG "message from Xonar HDAV HDMI chip received:\n"); - print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, - chip->uart_input, chip->uart_input_count); - chip->uart_input_count = 0; - } -} - -static int gpio_bit_switch_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - u16 bit = ctl->private_value; - - value->value.integer.value[0] = - !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit); - return 0; -} - -static int gpio_bit_switch_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - u16 bit = ctl->private_value; - u16 old_bits, new_bits; - int changed; - - spin_lock_irq(&chip->reg_lock); - old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); - if (value->value.integer.value[0]) - new_bits = old_bits | bit; - else - new_bits = old_bits & ~bit; - changed = new_bits != old_bits; - if (changed) - oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); - spin_unlock_irq(&chip->reg_lock); - return changed; -} - -static const struct snd_kcontrol_new alt_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Loopback Switch", - .info = snd_ctl_boolean_mono_info, - .get = gpio_bit_switch_get, - .put = gpio_bit_switch_put, - .private_value = GPIO_D2_ALT, -}; - -static const struct snd_kcontrol_new front_panel_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Front Panel Switch", - .info = snd_ctl_boolean_mono_info, - .get = gpio_bit_switch_get, - .put = gpio_bit_switch_put, - .private_value = GPIO_DX_FRONT_PANEL, -}; - -static int st_output_switch_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *info) -{ - static const char *const names[3] = { - "Speakers", "Headphones", "FP Headphones" - }; - - info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - info->count = 1; - info->value.enumerated.items = 3; - if (info->value.enumerated.item >= 3) - info->value.enumerated.item = 2; - strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); - return 0; -} - -static int st_output_switch_get(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - u16 gpio; - - gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); - if (!(gpio & GPIO_ST_HP)) - value->value.enumerated.item[0] = 0; - else if (gpio & GPIO_ST_HP_REAR) - value->value.enumerated.item[0] = 1; - else - value->value.enumerated.item[0] = 2; - return 0; -} - - -static int st_output_switch_put(struct snd_kcontrol *ctl, - struct snd_ctl_elem_value *value) -{ - struct oxygen *chip = ctl->private_data; - u16 gpio_old, gpio; - - mutex_lock(&chip->mutex); - gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); - gpio = gpio_old; - switch (value->value.enumerated.item[0]) { - case 0: - gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR); - break; - case 1: - gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR; - break; - case 2: - gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR; - break; - } - oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); - mutex_unlock(&chip->mutex); - return gpio != gpio_old; -} - -static const struct snd_kcontrol_new st_output_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Output", - .info = st_output_switch_info, - .get = st_output_switch_get, - .put = st_output_switch_put, -}; - -static void xonar_line_mic_ac97_switch(struct oxygen *chip, - unsigned int reg, unsigned int mute) -{ - if (reg == AC97_LINE) { - spin_lock_irq(&chip->reg_lock); - oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, - mute ? GPIO_DX_INPUT_ROUTE : 0, - GPIO_DX_INPUT_ROUTE); - spin_unlock_irq(&chip->reg_lock); - } -} - -static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0); -static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); - -static int xonar_d2_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - /* CD in is actually connected to the video in pin */ - template->private_value ^= AC97_CD ^ AC97_VIDEO; - return 0; -} - -static int xonar_d1_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - return 0; -} - -static int xonar_st_control_filter(struct snd_kcontrol_new *template) -{ - if (!strncmp(template->name, "CD Capture ", 11)) - return 1; /* no CD input */ - if (!strcmp(template->name, "Stereo Upmixing")) - return 1; /* stereo only - we don't need upmixing */ - return 0; -} - -static int xonar_d2_mixer_init(struct oxygen *chip) -{ - return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); -} - -static int xonar_d1_mixer_init(struct oxygen *chip) -{ - return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); -} - -static int xonar_st_mixer_init(struct oxygen *chip) -{ - return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip)); -} - -static const struct oxygen_model model_xonar_d2 = { - .longname = "Asus Virtuoso 200", - .chip = "AV200", - .init = xonar_d2_init, - .control_filter = xonar_d2_control_filter, - .mixer_init = xonar_d2_mixer_init, - .cleanup = xonar_d2_cleanup, - .suspend = xonar_d2_suspend, - .resume = xonar_d2_resume, - .set_dac_params = set_pcm1796_params, - .set_adc_params = set_cs53x1_params, - .update_dac_volume = update_pcm1796_volume, - .update_dac_mute = update_pcm1796_mute, - .dac_tlv = pcm1796_db_scale, - .model_data_size = sizeof(struct xonar_data), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF | - MIDI_OUTPUT | - MIDI_INPUT, - .dac_channels = 8, - .dac_volume_min = 255 - 2*60, - .dac_volume_max = 255, - .misc_flags = OXYGEN_MISC_MIDI, - .function_flags = OXYGEN_FUNCTION_SPI | - OXYGEN_FUNCTION_ENABLE_SPI_4_5, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - -static const struct oxygen_model model_xonar_d1 = { - .longname = "Asus Virtuoso 100", - .chip = "AV200", - .init = xonar_d1_init, - .control_filter = xonar_d1_control_filter, - .mixer_init = xonar_d1_mixer_init, - .cleanup = xonar_d1_cleanup, - .suspend = xonar_d1_suspend, - .resume = xonar_d1_resume, - .set_dac_params = set_cs43xx_params, - .set_adc_params = set_cs53x1_params, - .update_dac_volume = update_cs43xx_volume, - .update_dac_mute = update_cs43xx_mute, - .ac97_switch = xonar_line_mic_ac97_switch, - .dac_tlv = cs4362a_db_scale, - .model_data_size = sizeof(struct xonar_data), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2, - .dac_channels = 8, - .dac_volume_min = 127 - 60, - .dac_volume_max = 127, - .function_flags = OXYGEN_FUNCTION_2WIRE, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - -static const struct oxygen_model model_xonar_hdav = { - .longname = "Asus Virtuoso 200", - .chip = "AV200", - .init = xonar_hdav_init, - .cleanup = xonar_hdav_cleanup, - .suspend = xonar_hdav_suspend, - .resume = xonar_hdav_resume, - .pcm_hardware_filter = xonar_hdav_pcm_hardware_filter, - .set_dac_params = set_hdav_params, - .set_adc_params = set_cs53x1_params, - .update_dac_volume = update_pcm1796_volume, - .update_dac_mute = update_pcm1796_mute, - .uart_input = xonar_hdav_uart_input, - .ac97_switch = xonar_line_mic_ac97_switch, - .dac_tlv = pcm1796_db_scale, - .model_data_size = sizeof(struct xonar_data), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2 | - CAPTURE_1_FROM_SPDIF, - .dac_channels = 8, - .dac_volume_min = 255 - 2*60, - .dac_volume_max = 255, - .misc_flags = OXYGEN_MISC_MIDI, - .function_flags = OXYGEN_FUNCTION_2WIRE, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - -static const struct oxygen_model model_xonar_st = { - .longname = "Asus Virtuoso 100", - .chip = "AV200", - .init = xonar_st_init, - .control_filter = xonar_st_control_filter, - .mixer_init = xonar_st_mixer_init, - .cleanup = xonar_st_cleanup, - .suspend = xonar_st_suspend, - .resume = xonar_st_resume, - .set_dac_params = set_pcm1796_params, - .set_adc_params = set_cs53x1_params, - .update_dac_volume = update_pcm1796_volume, - .update_dac_mute = update_pcm1796_mute, - .ac97_switch = xonar_line_mic_ac97_switch, - .dac_tlv = pcm1796_db_scale, - .model_data_size = sizeof(struct xonar_data), - .device_config = PLAYBACK_0_TO_I2S | - PLAYBACK_1_TO_SPDIF | - CAPTURE_0_FROM_I2S_2, - .dac_channels = 2, - .dac_volume_min = 255 - 2*60, - .dac_volume_max = 255, - .function_flags = OXYGEN_FUNCTION_2WIRE, - .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, - .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, -}; - static int __devinit get_xonar_model(struct oxygen *chip, const struct pci_device_id *id) { - static const struct oxygen_model *const models[] = { - [MODEL_D1] = &model_xonar_d1, - [MODEL_DX] = &model_xonar_d1, - [MODEL_D2] = &model_xonar_d2, - [MODEL_D2X] = &model_xonar_d2, - [MODEL_HDAV] = &model_xonar_hdav, - [MODEL_ST] = &model_xonar_st, - [MODEL_STX] = &model_xonar_st, - }; - static const char *const names[] = { - [MODEL_D1] = "Xonar D1", - [MODEL_DX] = "Xonar DX", - [MODEL_D2] = "Xonar D2", - [MODEL_D2X] = "Xonar D2X", - [MODEL_HDAV] = "Xonar HDAV1.3", - [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", - [MODEL_ST] = "Xonar Essence ST", - [MODEL_ST_H6] = "Xonar Essence ST+H6", - [MODEL_STX] = "Xonar Essence STX", - }; - unsigned int model = id->driver_data; - - if (model >= ARRAY_SIZE(models) || !models[model]) - return -EINVAL; - chip->model = *models[model]; - - switch (model) { - case MODEL_D2X: - chip->model.init = xonar_d2x_init; - break; - case MODEL_DX: - chip->model.init = xonar_dx_init; - break; - case MODEL_HDAV: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { - case GPIO_DB_H6: - model = MODEL_HDAV_H6; - break; - case GPIO_DB_XX: - snd_printk(KERN_ERR "unknown daughterboard\n"); - return -ENODEV; - } - break; - case MODEL_ST: - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); - switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { - case GPIO_DB_H6: - model = MODEL_ST_H6; - break; - } - break; - case MODEL_STX: - chip->model.init = xonar_stx_init; - oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); - break; - } - - chip->model.shortname = names[model]; - chip->model.private_data = model; - return 0; + if (get_xonar_pcm179x_model(chip, id) >= 0) + return 0; + if (get_xonar_cs43xx_model(chip, id) >= 0) + return 0; + return -EINVAL; } static int __devinit xonar_probe(struct pci_dev *pci, diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h new file mode 100644 index 000000000000..89b3ed814d64 --- /dev/null +++ b/sound/pci/oxygen/xonar.h @@ -0,0 +1,50 @@ +#ifndef XONAR_H_INCLUDED +#define XONAR_H_INCLUDED + +#include "oxygen.h" + +struct xonar_generic { + unsigned int anti_pop_delay; + u16 output_enable_bit; + u8 ext_power_reg; + u8 ext_power_int_reg; + u8 ext_power_bit; + u8 has_power; +}; + +struct xonar_hdmi { + u8 params[5]; +}; + +/* generic helper functions */ + +void xonar_enable_output(struct oxygen *chip); +void xonar_disable_output(struct oxygen *chip); +void xonar_init_ext_power(struct oxygen *chip); +void xonar_init_cs53x1(struct oxygen *chip); +void xonar_set_cs53x1_params(struct oxygen *chip, + struct snd_pcm_hw_params *params); +int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value); +int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value); + +/* model-specific card drivers */ + +int get_xonar_pcm179x_model(struct oxygen *chip, + const struct pci_device_id *id); +int get_xonar_cs43xx_model(struct oxygen *chip, + const struct pci_device_id *id); + +/* HDMI helper functions */ + +void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *data); +void xonar_hdmi_cleanup(struct oxygen *chip); +void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi); +void xonar_hdmi_pcm_hardware_filter(unsigned int channel, + struct snd_pcm_hardware *hardware); +void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi, + struct snd_pcm_hw_params *params); +void xonar_hdmi_uart_input(struct oxygen *chip); + +#endif diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c new file mode 100644 index 000000000000..8fb5797577dd --- /dev/null +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -0,0 +1,304 @@ +/* + * card driver for models with CS4398/CS4362A DACs (Xonar D1/DX) + * + * Copyright (c) Clemens Ladisch + * + * + * 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 . + */ + +/* + * Xonar D1/DX + * ----------- + * + * CMI8788: + * + * I²C <-> CS4398 (front) + * <-> CS4362A (surround, center/LFE, back) + * + * GPI 0 <- external power present (DX only) + * + * GPIO 0 -> enable output to speakers + * GPIO 1 -> enable front panel I/O + * GPIO 2 -> M0 of CS5361 + * GPIO 3 -> M1 of CS5361 + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * + * CS4398: + * + * AD0 <- 1 + * AD1 <- 1 + * + * CS4362A: + * + * AD0 <- 0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xonar.h" +#include "cs4398.h" +#include "cs4362a.h" + +#define GPI_EXT_POWER 0x01 +#define GPIO_D1_OUTPUT_ENABLE 0x0001 +#define GPIO_D1_FRONT_PANEL 0x0002 +#define GPIO_D1_INPUT_ROUTE 0x0100 + +#define I2C_DEVICE_CS4398 0x9e /* 10011, AD1=1, AD0=1, /W=0 */ +#define I2C_DEVICE_CS4362A 0x30 /* 001100, AD0=0, /W=0 */ + +struct xonar_cs43xx { + struct xonar_generic generic; + u8 cs4398_fm; + u8 cs4362a_fm; +}; + +static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) +{ + oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); +} + +static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) +{ + oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); +} + +static void update_cs4362a_volumes(struct oxygen *chip) +{ + u8 mute; + + mute = chip->dac_mute ? CS4362A_MUTE : 0; + cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); + cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); + cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); + cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); + cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); + cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); +} + +static void update_cs43xx_volume(struct oxygen *chip) +{ + cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); + cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); + update_cs4362a_volumes(chip); +} + +static void update_cs43xx_mute(struct oxygen *chip) +{ + u8 reg; + + reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; + if (chip->dac_mute) + reg |= CS4398_MUTE_B | CS4398_MUTE_A; + cs4398_write(chip, 4, reg); + update_cs4362a_volumes(chip); +} + +static void cs43xx_init(struct oxygen *chip) +{ + struct xonar_cs43xx *data = chip->model_data; + + /* set CPEN (control port mode) and power down */ + cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); + cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); + /* configure */ + cs4398_write(chip, 2, data->cs4398_fm); + cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); + cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | + CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); + cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); + cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | + CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); + cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); + cs4362a_write(chip, 0x05, 0); + cs4362a_write(chip, 0x06, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x0c, data->cs4362a_fm); + update_cs43xx_volume(chip); + update_cs43xx_mute(chip); + /* clear power down */ + cs4398_write(chip, 8, CS4398_CPEN); + cs4362a_write(chip, 0x01, CS4362A_CPEN); +} + +static void xonar_d1_init(struct oxygen *chip) +{ + struct xonar_cs43xx *data = chip->model_data; + + data->generic.anti_pop_delay = 800; + data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE; + data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; + data->cs4362a_fm = CS4362A_FM_SINGLE | + CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + + oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, + OXYGEN_2WIRE_LENGTH_8 | + OXYGEN_2WIRE_INTERRUPT_MASK | + OXYGEN_2WIRE_SPEED_FAST); + + cs43xx_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, + GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); + + xonar_init_cs53x1(chip); + xonar_enable_output(chip); + + snd_component_add(chip->card, "CS4398"); + snd_component_add(chip->card, "CS4362A"); + snd_component_add(chip->card, "CS5361"); +} + +static void xonar_dx_init(struct oxygen *chip) +{ + struct xonar_cs43xx *data = chip->model_data; + + data->generic.ext_power_reg = OXYGEN_GPI_DATA; + data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->generic.ext_power_bit = GPI_EXT_POWER; + xonar_init_ext_power(chip); + xonar_d1_init(chip); +} + +static void xonar_d1_cleanup(struct oxygen *chip) +{ + xonar_disable_output(chip); + cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); + oxygen_clear_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); +} + +static void xonar_d1_suspend(struct oxygen *chip) +{ + xonar_d1_cleanup(chip); +} + +static void xonar_d1_resume(struct oxygen *chip) +{ + oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); + msleep(1); + cs43xx_init(chip); + xonar_enable_output(chip); +} + +static void set_cs43xx_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct xonar_cs43xx *data = chip->model_data; + + data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; + data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + if (params_rate(params) <= 50000) { + data->cs4398_fm |= CS4398_FM_SINGLE; + data->cs4362a_fm |= CS4362A_FM_SINGLE; + } else if (params_rate(params) <= 100000) { + data->cs4398_fm |= CS4398_FM_DOUBLE; + data->cs4362a_fm |= CS4362A_FM_DOUBLE; + } else { + data->cs4398_fm |= CS4398_FM_QUAD; + data->cs4362a_fm |= CS4362A_FM_QUAD; + } + cs4398_write(chip, 2, data->cs4398_fm); + cs4362a_write(chip, 0x06, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x0c, data->cs4362a_fm); +} + +static const struct snd_kcontrol_new front_panel_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Front Panel Switch", + .info = snd_ctl_boolean_mono_info, + .get = xonar_gpio_bit_switch_get, + .put = xonar_gpio_bit_switch_put, + .private_value = GPIO_D1_FRONT_PANEL, +}; + +static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, + unsigned int reg, unsigned int mute) +{ + if (reg == AC97_LINE) { + spin_lock_irq(&chip->reg_lock); + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + mute ? GPIO_D1_INPUT_ROUTE : 0, + GPIO_D1_INPUT_ROUTE); + spin_unlock_irq(&chip->reg_lock); + } +} + +static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -6000, 100, 0); + +static int xonar_d1_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "CD Capture ", 11)) + return 1; /* no CD input */ + return 0; +} + +static int xonar_d1_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); +} + +static const struct oxygen_model model_xonar_d1 = { + .longname = "Asus Virtuoso 100", + .chip = "AV200", + .init = xonar_d1_init, + .control_filter = xonar_d1_control_filter, + .mixer_init = xonar_d1_mixer_init, + .cleanup = xonar_d1_cleanup, + .suspend = xonar_d1_suspend, + .resume = xonar_d1_resume, + .set_dac_params = set_cs43xx_params, + .set_adc_params = xonar_set_cs53x1_params, + .update_dac_volume = update_cs43xx_volume, + .update_dac_mute = update_cs43xx_mute, + .ac97_switch = xonar_d1_line_mic_ac97_switch, + .dac_tlv = cs4362a_db_scale, + .model_data_size = sizeof(struct xonar_cs43xx), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2, + .dac_channels = 8, + .dac_volume_min = 127 - 60, + .dac_volume_max = 127, + .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +int __devinit get_xonar_cs43xx_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + switch (id->subdevice) { + case 0x834f: + chip->model = model_xonar_d1; + chip->model.shortname = "Xonar D1"; + break; + case 0x8275: + case 0x8327: + chip->model = model_xonar_d1; + chip->model.shortname = "Xonar DX"; + chip->model.init = xonar_dx_init; + break; + default: + return -EINVAL; + } + return 0; +} diff --git a/sound/pci/oxygen/xonar_hdmi.c b/sound/pci/oxygen/xonar_hdmi.c new file mode 100644 index 000000000000..b12db1f1cea9 --- /dev/null +++ b/sound/pci/oxygen/xonar_hdmi.c @@ -0,0 +1,128 @@ +/* + * helper functions for HDMI models (Xonar HDAV1.3) + * + * Copyright (c) Clemens Ladisch + * + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "xonar.h" + +static void hdmi_write_command(struct oxygen *chip, u8 command, + unsigned int count, const u8 *params) +{ + unsigned int i; + u8 checksum; + + oxygen_write_uart(chip, 0xfb); + oxygen_write_uart(chip, 0xef); + oxygen_write_uart(chip, command); + oxygen_write_uart(chip, count); + for (i = 0; i < count; ++i) + oxygen_write_uart(chip, params[i]); + checksum = 0xfb + 0xef + command + count; + for (i = 0; i < count; ++i) + checksum += params[i]; + oxygen_write_uart(chip, checksum); +} + +static void xonar_hdmi_init_commands(struct oxygen *chip, + struct xonar_hdmi *hdmi) +{ + u8 param; + + oxygen_reset_uart(chip); + param = 0; + hdmi_write_command(chip, 0x61, 1, ¶m); + param = 1; + hdmi_write_command(chip, 0x74, 1, ¶m); + hdmi_write_command(chip, 0x54, 5, hdmi->params); +} + +void xonar_hdmi_init(struct oxygen *chip, struct xonar_hdmi *hdmi) +{ + hdmi->params[1] = IEC958_AES3_CON_FS_48000; + hdmi->params[4] = 1; + xonar_hdmi_init_commands(chip, hdmi); +} + +void xonar_hdmi_cleanup(struct oxygen *chip) +{ + u8 param = 0; + + hdmi_write_command(chip, 0x74, 1, ¶m); +} + +void xonar_hdmi_resume(struct oxygen *chip, struct xonar_hdmi *hdmi) +{ + xonar_hdmi_init_commands(chip, hdmi); +} + +void xonar_hdmi_pcm_hardware_filter(unsigned int channel, + struct snd_pcm_hardware *hardware) +{ + if (channel == PCM_MULTICH) { + hardware->rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000; + hardware->rate_min = 44100; + } +} + +void xonar_set_hdmi_params(struct oxygen *chip, struct xonar_hdmi *hdmi, + struct snd_pcm_hw_params *params) +{ + hdmi->params[0] = 0; /* 1 = non-audio */ + switch (params_rate(params)) { + case 44100: + hdmi->params[1] = IEC958_AES3_CON_FS_44100; + break; + case 48000: + hdmi->params[1] = IEC958_AES3_CON_FS_48000; + break; + default: /* 96000 */ + hdmi->params[1] = IEC958_AES3_CON_FS_96000; + break; + case 192000: + hdmi->params[1] = IEC958_AES3_CON_FS_192000; + break; + } + hdmi->params[2] = params_channels(params) / 2 - 1; + if (params_format(params) == SNDRV_PCM_FORMAT_S16_LE) + hdmi->params[3] = 0; + else + hdmi->params[3] = 0xc0; + hdmi->params[4] = 1; /* ? */ + hdmi_write_command(chip, 0x54, 5, hdmi->params); +} + +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"); + 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 new file mode 100644 index 000000000000..b3ff71316653 --- /dev/null +++ b/sound/pci/oxygen/xonar_lib.c @@ -0,0 +1,132 @@ +/* + * helper functions for Asus Xonar cards + * + * Copyright (c) Clemens Ladisch + * + * + * 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 . + */ + +#include +#include +#include +#include +#include +#include "xonar.h" + + +#define GPIO_CS53x1_M_MASK 0x000c +#define GPIO_CS53x1_M_SINGLE 0x0000 +#define GPIO_CS53x1_M_DOUBLE 0x0004 +#define GPIO_CS53x1_M_QUAD 0x0008 + + +void xonar_enable_output(struct oxygen *chip) +{ + struct xonar_generic *data = chip->model_data; + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, data->output_enable_bit); + msleep(data->anti_pop_delay); + oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); +} + +void xonar_disable_output(struct oxygen *chip) +{ + struct xonar_generic *data = chip->model_data; + + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, data->output_enable_bit); +} + +static void xonar_ext_power_gpio_changed(struct oxygen *chip) +{ + struct xonar_generic *data = chip->model_data; + u8 has_power; + + has_power = !!(oxygen_read8(chip, data->ext_power_reg) + & data->ext_power_bit); + if (has_power != data->has_power) { + data->has_power = has_power; + if (has_power) { + snd_printk(KERN_NOTICE "power restored\n"); + } else { + snd_printk(KERN_CRIT + "Hey! Don't unplug the power cable!\n"); + /* TODO: stop PCMs */ + } + } +} + +void xonar_init_ext_power(struct oxygen *chip) +{ + struct xonar_generic *data = chip->model_data; + + oxygen_set_bits8(chip, data->ext_power_int_reg, + data->ext_power_bit); + chip->interrupt_mask |= OXYGEN_INT_GPIO; + chip->model.gpio_changed = xonar_ext_power_gpio_changed; + data->has_power = !!(oxygen_read8(chip, data->ext_power_reg) + & data->ext_power_bit); +} + +void xonar_init_cs53x1(struct oxygen *chip) +{ + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_CS53x1_M_MASK); + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + GPIO_CS53x1_M_SINGLE, GPIO_CS53x1_M_MASK); +} + +void xonar_set_cs53x1_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + unsigned int value; + + if (params_rate(params) <= 54000) + value = GPIO_CS53x1_M_SINGLE; + else if (params_rate(params) <= 108000) + value = GPIO_CS53x1_M_DOUBLE; + else + value = GPIO_CS53x1_M_QUAD; + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + value, GPIO_CS53x1_M_MASK); +} + +int xonar_gpio_bit_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 bit = ctl->private_value; + + value->value.integer.value[0] = + !!(oxygen_read16(chip, OXYGEN_GPIO_DATA) & bit); + return 0; +} + +int xonar_gpio_bit_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 bit = ctl->private_value; + u16 old_bits, new_bits; + int changed; + + spin_lock_irq(&chip->reg_lock); + old_bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); + if (value->value.integer.value[0]) + new_bits = old_bits | bit; + else + new_bits = old_bits & ~bit; + changed = new_bits != old_bits; + if (changed) + oxygen_write16(chip, OXYGEN_GPIO_DATA, new_bits); + spin_unlock_irq(&chip->reg_lock); + return changed; +} diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c new file mode 100644 index 000000000000..eb5f015fcd23 --- /dev/null +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -0,0 +1,660 @@ +/* + * card driver for models with PCM1796 DACs (Xonar D2/D2X/HDAV1.3/ST/STX) + * + * Copyright (c) Clemens Ladisch + * + * + * 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 . + */ + +/* + * Xonar D2/D2X + * ------------ + * + * CMI8788: + * + * SPI 0 -> 1st PCM1796 (front) + * SPI 1 -> 2nd PCM1796 (surround) + * SPI 2 -> 3rd PCM1796 (center/LFE) + * SPI 4 -> 4th PCM1796 (back) + * + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 5 <- external power present (D2X only) + * GPIO 7 -> ALT + * GPIO 8 -> enable output to speakers + */ + +/* + * Xonar HDAV1.3 (Deluxe) + * ---------------------- + * + * CMI8788: + * + * I²C <-> PCM1796 (front) + * + * GPI 0 <- external power present + * + * GPIO 0 -> enable output to speakers + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * + * TXD -> HDMI controller + * RXD <- HDMI controller + * + * PCM1796 front: AD1,0 <- 0,0 + * + * no daughterboard + * ---------------- + * + * GPIO 4 <- 1 + * + * H6 daughterboard + * ---------------- + * + * GPIO 4 <- 0 + * GPIO 5 <- 0 + * + * I²C <-> PCM1796 (surround) + * <-> PCM1796 (center/LFE) + * <-> PCM1796 (back) + * + * PCM1796 surround: AD1,0 <- 0,1 + * PCM1796 center/LFE: AD1,0 <- 1,0 + * PCM1796 back: AD1,0 <- 1,1 + * + * unknown daughterboard + * --------------------- + * + * GPIO 4 <- 0 + * GPIO 5 <- 1 + * + * I²C <-> CS4362A (surround, center/LFE, back) + * + * CS4362A: AD0 <- 0 + */ + +/* + * Xonar Essence ST (Deluxe)/STX + * ----------------------------- + * + * CMI8788: + * + * I²C <-> PCM1792A + * + * GPI 0 <- external power present (STX only) + * + * GPIO 0 -> enable output to speakers + * GPIO 1 -> route HP to front panel (0) or rear jack (1) + * GPIO 2 -> M0 of CS5381 + * GPIO 3 -> M1 of CS5381 + * GPIO 7 -> route output to speaker jacks (0) or HP (1) + * GPIO 8 -> route input jack to line-in (0) or mic-in (1) + * + * PCM1792A: + * + * AD1,0 <- 0,0 + * + * H6 daughterboard + * ---------------- + * + * GPIO 4 <- 0 + * GPIO 5 <- 0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xonar.h" +#include "cm9780.h" +#include "pcm1796.h" + + +#define GPIO_D2X_EXT_POWER 0x0020 +#define GPIO_D2_ALT 0x0080 +#define GPIO_D2_OUTPUT_ENABLE 0x0100 + +#define GPI_EXT_POWER 0x01 +#define GPIO_INPUT_ROUTE 0x0100 + +#define GPIO_HDAV_OUTPUT_ENABLE 0x0001 + +#define GPIO_DB_MASK 0x0030 +#define GPIO_DB_H6 0x0000 + +#define GPIO_ST_OUTPUT_ENABLE 0x0001 +#define GPIO_ST_HP_REAR 0x0002 +#define GPIO_ST_HP 0x0080 + +#define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ + + +struct xonar_pcm179x { + struct xonar_generic generic; + unsigned int dacs; + u8 oversampling; +}; + +struct xonar_hdav { + struct xonar_pcm179x pcm179x; + struct xonar_hdmi hdmi; +}; + + +static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec, + u8 reg, u8 value) +{ + /* maps ALSA channel pair number to SPI output */ + static const u8 codec_map[4] = { + 0, 1, 2, 4 + }; + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | + OXYGEN_SPI_DATA_LENGTH_2 | + OXYGEN_SPI_CLOCK_160 | + (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | + OXYGEN_SPI_CEN_LATCH_CLOCK_HI, + (reg << 8) | value); +} + +static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec, + u8 reg, u8 value) +{ + oxygen_write_i2c(chip, I2C_DEVICE_PCM1796(codec), reg, value); +} + +static void pcm1796_write(struct oxygen *chip, unsigned int codec, + u8 reg, u8 value) +{ + if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == + OXYGEN_FUNCTION_SPI) + pcm1796_write_spi(chip, codec, reg, value); + else + pcm1796_write_i2c(chip, codec, reg, value); +} + +static void update_pcm1796_volume(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + + for (i = 0; i < data->dacs; ++i) { + pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); + pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); + } +} + +static void update_pcm1796_mute(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + u8 value; + + value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; + if (chip->dac_mute) + value |= PCM1796_MUTE; + for (i = 0; i < data->dacs; ++i) + pcm1796_write(chip, i, 18, value); +} + +static void pcm1796_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + + for (i = 0; i < data->dacs; ++i) { + pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); + pcm1796_write(chip, i, 20, data->oversampling); + pcm1796_write(chip, i, 21, 0); + } + update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ + update_pcm1796_volume(chip); +} + +static void xonar_d2_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->generic.anti_pop_delay = 300; + data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE; + data->dacs = 4; + data->oversampling = PCM1796_OS_64; + + pcm1796_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2_ALT); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_D2_ALT); + + oxygen_ac97_set_bits(chip, 0, CM9780_JACK, CM9780_FMIC2MIC); + + xonar_init_cs53x1(chip); + xonar_enable_output(chip); + + snd_component_add(chip->card, "PCM1796"); + snd_component_add(chip->card, "CS5381"); +} + +static void xonar_d2x_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->generic.ext_power_reg = OXYGEN_GPIO_DATA; + data->generic.ext_power_int_reg = OXYGEN_GPIO_INTERRUPT_MASK; + data->generic.ext_power_bit = GPIO_D2X_EXT_POWER; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D2X_EXT_POWER); + xonar_init_ext_power(chip); + xonar_d2_init(chip); +} + +static void xonar_hdav_init(struct oxygen *chip) +{ + struct xonar_hdav *data = chip->model_data; + + oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, + OXYGEN_2WIRE_LENGTH_8 | + OXYGEN_2WIRE_INTERRUPT_MASK | + OXYGEN_2WIRE_SPEED_FAST); + + data->pcm179x.generic.anti_pop_delay = 100; + data->pcm179x.generic.output_enable_bit = GPIO_HDAV_OUTPUT_ENABLE; + data->pcm179x.generic.ext_power_reg = OXYGEN_GPI_DATA; + data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; + data->pcm179x.dacs = chip->model.private_data ? 4 : 1; + data->pcm179x.oversampling = PCM1796_OS_64; + + pcm1796_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_INPUT_ROUTE); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_INPUT_ROUTE); + + xonar_init_cs53x1(chip); + xonar_init_ext_power(chip); + xonar_hdmi_init(chip, &data->hdmi); + xonar_enable_output(chip); + + snd_component_add(chip->card, "PCM1796"); + snd_component_add(chip->card, "CS5381"); +} + +static void xonar_st_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, + OXYGEN_2WIRE_LENGTH_8 | + OXYGEN_2WIRE_INTERRUPT_MASK | + OXYGEN_2WIRE_SPEED_FAST); + + data->generic.anti_pop_delay = 100; + data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; + data->dacs = chip->model.private_data ? 4 : 1; + data->oversampling = PCM1796_OS_64; + + pcm1796_init(chip); + + oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, + GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); + oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, + GPIO_INPUT_ROUTE | GPIO_ST_HP_REAR | GPIO_ST_HP); + + xonar_init_cs53x1(chip); + xonar_enable_output(chip); + + snd_component_add(chip->card, "PCM1792A"); + snd_component_add(chip->card, "CS5381"); +} + +static void xonar_stx_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->generic.ext_power_reg = OXYGEN_GPI_DATA; + data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; + data->generic.ext_power_bit = GPI_EXT_POWER; + xonar_init_ext_power(chip); + xonar_st_init(chip); +} + +static void xonar_d2_cleanup(struct oxygen *chip) +{ + xonar_disable_output(chip); +} + +static void xonar_hdav_cleanup(struct oxygen *chip) +{ + xonar_hdmi_cleanup(chip); + xonar_disable_output(chip); + msleep(2); +} + +static void xonar_st_cleanup(struct oxygen *chip) +{ + xonar_disable_output(chip); +} + +static void xonar_d2_suspend(struct oxygen *chip) +{ + xonar_d2_cleanup(chip); +} + +static void xonar_hdav_suspend(struct oxygen *chip) +{ + xonar_hdav_cleanup(chip); +} + +static void xonar_st_suspend(struct oxygen *chip) +{ + xonar_st_cleanup(chip); +} + +static void xonar_d2_resume(struct oxygen *chip) +{ + pcm1796_init(chip); + xonar_enable_output(chip); +} + +static void xonar_hdav_resume(struct oxygen *chip) +{ + struct xonar_hdav *data = chip->model_data; + + pcm1796_init(chip); + xonar_hdmi_resume(chip, &data->hdmi); + xonar_enable_output(chip); +} + +static void xonar_st_resume(struct oxygen *chip) +{ + pcm1796_init(chip); + xonar_enable_output(chip); +} + +static void set_pcm1796_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + + data->oversampling = + params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + for (i = 0; i < data->dacs; ++i) + pcm1796_write(chip, i, 20, data->oversampling); +} + +static void set_hdav_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct xonar_hdav *data = chip->model_data; + + set_pcm1796_params(chip, params); + xonar_set_hdmi_params(chip, &data->hdmi, params); +} + +static const struct snd_kcontrol_new alt_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Loopback Switch", + .info = snd_ctl_boolean_mono_info, + .get = xonar_gpio_bit_switch_get, + .put = xonar_gpio_bit_switch_put, + .private_value = GPIO_D2_ALT, +}; + +static int st_output_switch_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "Speakers", "Headphones", "FP Headphones" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item >= 3) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int st_output_switch_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 gpio; + + gpio = oxygen_read16(chip, OXYGEN_GPIO_DATA); + if (!(gpio & GPIO_ST_HP)) + value->value.enumerated.item[0] = 0; + else if (gpio & GPIO_ST_HP_REAR) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + return 0; +} + + +static int st_output_switch_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + u16 gpio_old, gpio; + + mutex_lock(&chip->mutex); + gpio_old = oxygen_read16(chip, OXYGEN_GPIO_DATA); + gpio = gpio_old; + switch (value->value.enumerated.item[0]) { + case 0: + gpio &= ~(GPIO_ST_HP | GPIO_ST_HP_REAR); + break; + case 1: + gpio |= GPIO_ST_HP | GPIO_ST_HP_REAR; + break; + case 2: + gpio = (gpio | GPIO_ST_HP) & ~GPIO_ST_HP_REAR; + break; + } + oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); + mutex_unlock(&chip->mutex); + return gpio != gpio_old; +} + +static const struct snd_kcontrol_new st_output_switch = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Output", + .info = st_output_switch_info, + .get = st_output_switch_get, + .put = st_output_switch_put, +}; + +static void xonar_line_mic_ac97_switch(struct oxygen *chip, + unsigned int reg, unsigned int mute) +{ + if (reg == AC97_LINE) { + spin_lock_irq(&chip->reg_lock); + oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, + mute ? GPIO_INPUT_ROUTE : 0, + GPIO_INPUT_ROUTE); + spin_unlock_irq(&chip->reg_lock); + } +} + +static const DECLARE_TLV_DB_SCALE(pcm1796_db_scale, -6000, 50, 0); + +static int xonar_d2_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "CD Capture ", 11)) + /* CD in is actually connected to the video in pin */ + template->private_value ^= AC97_CD ^ AC97_VIDEO; + return 0; +} + +static int xonar_st_control_filter(struct snd_kcontrol_new *template) +{ + if (!strncmp(template->name, "CD Capture ", 11)) + return 1; /* no CD input */ + if (!strcmp(template->name, "Stereo Upmixing")) + return 1; /* stereo only - we don't need upmixing */ + return 0; +} + +static int xonar_d2_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); +} + +static int xonar_st_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip)); +} + +static const struct oxygen_model model_xonar_d2 = { + .longname = "Asus Virtuoso 200", + .chip = "AV200", + .init = xonar_d2_init, + .control_filter = xonar_d2_control_filter, + .mixer_init = xonar_d2_mixer_init, + .cleanup = xonar_d2_cleanup, + .suspend = xonar_d2_suspend, + .resume = xonar_d2_resume, + .set_dac_params = set_pcm1796_params, + .set_adc_params = xonar_set_cs53x1_params, + .update_dac_volume = update_pcm1796_volume, + .update_dac_mute = update_pcm1796_mute, + .dac_tlv = pcm1796_db_scale, + .model_data_size = sizeof(struct xonar_pcm179x), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF | + MIDI_OUTPUT | + MIDI_INPUT, + .dac_channels = 8, + .dac_volume_min = 255 - 2*60, + .dac_volume_max = 255, + .misc_flags = OXYGEN_MISC_MIDI, + .function_flags = OXYGEN_FUNCTION_SPI | + OXYGEN_FUNCTION_ENABLE_SPI_4_5, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +static const struct oxygen_model model_xonar_hdav = { + .longname = "Asus Virtuoso 200", + .chip = "AV200", + .init = xonar_hdav_init, + .cleanup = xonar_hdav_cleanup, + .suspend = xonar_hdav_suspend, + .resume = xonar_hdav_resume, + .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, + .set_dac_params = set_hdav_params, + .set_adc_params = xonar_set_cs53x1_params, + .update_dac_volume = update_pcm1796_volume, + .update_dac_mute = update_pcm1796_mute, + .uart_input = xonar_hdmi_uart_input, + .ac97_switch = xonar_line_mic_ac97_switch, + .dac_tlv = pcm1796_db_scale, + .model_data_size = sizeof(struct xonar_hdav), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2 | + CAPTURE_1_FROM_SPDIF, + .dac_channels = 8, + .dac_volume_min = 255 - 2*60, + .dac_volume_max = 255, + .misc_flags = OXYGEN_MISC_MIDI, + .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +static const struct oxygen_model model_xonar_st = { + .longname = "Asus Virtuoso 100", + .chip = "AV200", + .init = xonar_st_init, + .control_filter = xonar_st_control_filter, + .mixer_init = xonar_st_mixer_init, + .cleanup = xonar_st_cleanup, + .suspend = xonar_st_suspend, + .resume = xonar_st_resume, + .set_dac_params = set_pcm1796_params, + .set_adc_params = xonar_set_cs53x1_params, + .update_dac_volume = update_pcm1796_volume, + .update_dac_mute = update_pcm1796_mute, + .ac97_switch = xonar_line_mic_ac97_switch, + .dac_tlv = pcm1796_db_scale, + .model_data_size = sizeof(struct xonar_pcm179x), + .device_config = PLAYBACK_0_TO_I2S | + PLAYBACK_1_TO_SPDIF | + CAPTURE_0_FROM_I2S_2, + .dac_channels = 2, + .dac_volume_min = 255 - 2*60, + .dac_volume_max = 255, + .function_flags = OXYGEN_FUNCTION_2WIRE, + .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, + .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, +}; + +int __devinit get_xonar_pcm179x_model(struct oxygen *chip, + const struct pci_device_id *id) +{ + switch (id->subdevice) { + case 0x8269: + chip->model = model_xonar_d2; + chip->model.shortname = "Xonar D2"; + break; + case 0x82b7: + chip->model = model_xonar_d2; + chip->model.shortname = "Xonar D2X"; + chip->model.init = xonar_d2x_init; + break; + case 0x8314: + chip->model = model_xonar_hdav; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + default: + chip->model.shortname = "Xonar HDAV1.3"; + break; + case GPIO_DB_H6: + chip->model.shortname = "Xonar HDAV1.3+H6"; + chip->model.private_data = 1; + break; + } + break; + case 0x835d: + chip->model = model_xonar_st; + oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); + switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { + default: + chip->model.shortname = "Xonar ST"; + break; + case GPIO_DB_H6: + chip->model.shortname = "Xonar ST+H6"; + chip->model.dac_channels = 8; + chip->model.private_data = 1; + break; + } + break; + case 0x835c: + chip->model = model_xonar_st; + chip->model.shortname = "Xonar STX"; + chip->model.init = xonar_stx_init; + break; + default: + return -EINVAL; + } + return 0; +} -- cgit v1.2.3 From 268304f4c4f0b8677d67400f04ad4e0271ec3742 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:15:01 +0200 Subject: sound: virtuoso: fix Xonar Essence ST support The Essence ST uses the CS2000 chip to generate the DAC master clock, so we better initialize and program it appropriately. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/cs2000.h | 83 ++++++++++++++++++++++++++++ sound/pci/oxygen/xonar_pcm179x.c | 113 ++++++++++++++++++++++++++++++++++++--- 2 files changed, 190 insertions(+), 6 deletions(-) create mode 100644 sound/pci/oxygen/cs2000.h (limited to 'sound') diff --git a/sound/pci/oxygen/cs2000.h b/sound/pci/oxygen/cs2000.h new file mode 100644 index 000000000000..c3501bdb5edc --- /dev/null +++ b/sound/pci/oxygen/cs2000.h @@ -0,0 +1,83 @@ +#ifndef CS2000_H_INCLUDED +#define CS2000_H_INCLUDED + +#define CS2000_DEV_ID 0x01 +#define CS2000_DEV_CTRL 0x02 +#define CS2000_DEV_CFG_1 0x03 +#define CS2000_DEV_CFG_2 0x04 +#define CS2000_GLOBAL_CFG 0x05 +#define CS2000_RATIO_0 0x06 /* 32 bits, big endian */ +#define CS2000_RATIO_1 0x0a +#define CS2000_RATIO_2 0x0e +#define CS2000_RATIO_3 0x12 +#define CS2000_FUN_CFG_1 0x16 +#define CS2000_FUN_CFG_2 0x17 +#define CS2000_FUN_CFG_3 0x1e + +/* DEV_ID */ +#define CS2000_DEVICE_MASK 0xf8 +#define CS2000_REVISION_MASK 0x07 + +/* DEV_CTRL */ +#define CS2000_UNLOCK 0x80 +#define CS2000_AUX_OUT_DIS 0x02 +#define CS2000_CLK_OUT_DIS 0x01 + +/* DEV_CFG_1 */ +#define CS2000_R_MOD_SEL_MASK 0xe0 +#define CS2000_R_MOD_SEL_1 0x00 +#define CS2000_R_MOD_SEL_2 0x20 +#define CS2000_R_MOD_SEL_4 0x40 +#define CS2000_R_MOD_SEL_8 0x60 +#define CS2000_R_MOD_SEL_1_2 0x80 +#define CS2000_R_MOD_SEL_1_4 0xa0 +#define CS2000_R_MOD_SEL_1_8 0xc0 +#define CS2000_R_MOD_SEL_1_16 0xe0 +#define CS2000_R_SEL_MASK 0x18 +#define CS2000_R_SEL_SHIFT 3 +#define CS2000_AUX_OUT_SRC_MASK 0x06 +#define CS2000_AUX_OUT_SRC_REF_CLK 0x00 +#define CS2000_AUX_OUT_SRC_CLK_IN 0x02 +#define CS2000_AUX_OUT_SRC_CLK_OUT 0x04 +#define CS2000_AUX_OUT_SRC_PLL_LOCK 0x06 +#define CS2000_EN_DEV_CFG_1 0x01 + +/* DEV_CFG_2 */ +#define CS2000_LOCK_CLK_MASK 0x06 +#define CS2000_LOCK_CLK_SHIFT 1 +#define CS2000_FRAC_N_SRC_MASK 0x01 +#define CS2000_FRAC_N_SRC_STATIC 0x00 +#define CS2000_FRAC_N_SRC_DYNAMIC 0x01 + +/* GLOBAL_CFG */ +#define CS2000_FREEZE 0x08 +#define CS2000_EN_DEV_CFG_2 0x01 + +/* FUN_CFG_1 */ +#define CS2000_CLK_SKIP_EN 0x80 +#define CS2000_AUX_LOCK_CFG_MASK 0x40 +#define CS2000_AUX_LOCK_CFG_PP_HIGH 0x00 +#define CS2000_AUX_LOCK_CFG_OD_LOW 0x40 +#define CS2000_REF_CLK_DIV_MASK 0x18 +#define CS2000_REF_CLK_DIV_4 0x00 +#define CS2000_REF_CLK_DIV_2 0x08 +#define CS2000_REF_CLK_DIV_1 0x10 + +/* FUN_CFG_2 */ +#define CS2000_CLK_OUT_UNL 0x10 +#define CS2000_L_F_RATIO_CFG_MASK 0x08 +#define CS2000_L_F_RATIO_CFG_20_12 0x00 +#define CS2000_L_F_RATIO_CFG_12_20 0x08 + +/* FUN_CFG_3 */ +#define CS2000_CLK_IN_BW_MASK 0x70 +#define CS2000_CLK_IN_BW_1 0x00 +#define CS2000_CLK_IN_BW_2 0x10 +#define CS2000_CLK_IN_BW_4 0x20 +#define CS2000_CLK_IN_BW_8 0x30 +#define CS2000_CLK_IN_BW_16 0x40 +#define CS2000_CLK_IN_BW_32 0x50 +#define CS2000_CLK_IN_BW_64 0x60 +#define CS2000_CLK_IN_BW_128 0x70 + +#endif diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index eb5f015fcd23..522efde0d52e 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -91,6 +91,9 @@ * CMI8788: * * I²C <-> PCM1792A + * <-> CS2000 (ST only) + * + * ADC1 MCLK -> REF_CLK of CS2000 (ST only) * * GPI 0 <- external power present (STX only) * @@ -124,6 +127,7 @@ #include "xonar.h" #include "cm9780.h" #include "pcm1796.h" +#include "cs2000.h" #define GPIO_D2X_EXT_POWER 0x0020 @@ -143,12 +147,14 @@ #define GPIO_ST_HP 0x0080 #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ +#define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */ struct xonar_pcm179x { struct xonar_generic generic; unsigned int dacs; u8 oversampling; + u8 cs2000_fun_cfg_1; }; struct xonar_hdav { @@ -188,6 +194,11 @@ static void pcm1796_write(struct oxygen *chip, unsigned int codec, pcm1796_write_i2c(chip, codec, reg, value); } +static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) +{ + oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); +} + static void update_pcm1796_volume(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; @@ -292,14 +303,17 @@ static void xonar_hdav_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } -static void xonar_st_init(struct oxygen *chip) +static void xonar_st_init_i2c(struct oxygen *chip) { - struct xonar_pcm179x *data = chip->model_data; - oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, OXYGEN_2WIRE_LENGTH_8 | OXYGEN_2WIRE_INTERRUPT_MASK | OXYGEN_2WIRE_SPEED_FAST); +} + +static void xonar_st_init_common(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; data->generic.anti_pop_delay = 100; data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; @@ -320,15 +334,57 @@ static void xonar_st_init(struct oxygen *chip) snd_component_add(chip->card, "CS5381"); } +static void cs2000_registers_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_FREEZE); + cs2000_write(chip, CS2000_DEV_CTRL, 0); + cs2000_write(chip, CS2000_DEV_CFG_1, + CS2000_R_MOD_SEL_1 | + (0 << CS2000_R_SEL_SHIFT) | + CS2000_AUX_OUT_SRC_REF_CLK | + CS2000_EN_DEV_CFG_1); + cs2000_write(chip, CS2000_DEV_CFG_2, + (0 << CS2000_LOCK_CLK_SHIFT) | + CS2000_FRAC_N_SRC_STATIC); + cs2000_write(chip, CS2000_RATIO_0 + 0, 0x00); /* 1.0 */ + cs2000_write(chip, CS2000_RATIO_0 + 1, 0x10); + cs2000_write(chip, CS2000_RATIO_0 + 2, 0x00); + cs2000_write(chip, CS2000_RATIO_0 + 3, 0x00); + cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); + cs2000_write(chip, CS2000_FUN_CFG_2, 0); + cs2000_write(chip, CS2000_GLOBAL_CFG, CS2000_EN_DEV_CFG_2); +} + +static void xonar_st_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; + + oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, + OXYGEN_RATE_48000 | OXYGEN_I2S_FORMAT_I2S | + OXYGEN_I2S_MCLK_128 | OXYGEN_I2S_BITS_16 | + OXYGEN_I2S_MASTER | OXYGEN_I2S_BCLK_64); + + xonar_st_init_i2c(chip); + cs2000_registers_init(chip); + xonar_st_init_common(chip); + + snd_component_add(chip->card, "CS2000"); +} + static void xonar_stx_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; + xonar_st_init_i2c(chip); data->generic.ext_power_reg = OXYGEN_GPI_DATA; data->generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; data->generic.ext_power_bit = GPI_EXT_POWER; xonar_init_ext_power(chip); - xonar_st_init(chip); + xonar_st_init_common(chip); } static void xonar_d2_cleanup(struct oxygen *chip) @@ -378,12 +434,18 @@ static void xonar_hdav_resume(struct oxygen *chip) xonar_enable_output(chip); } -static void xonar_st_resume(struct oxygen *chip) +static void xonar_stx_resume(struct oxygen *chip) { pcm1796_init(chip); xonar_enable_output(chip); } +static void xonar_st_resume(struct oxygen *chip) +{ + cs2000_registers_init(chip); + xonar_stx_resume(chip); +} + static void set_pcm1796_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -396,6 +458,43 @@ static void set_pcm1796_params(struct oxygen *chip, pcm1796_write(chip, i, 20, data->oversampling); } +static void set_cs2000_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + /* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */ + static const u8 rate_mclks[] = { + [OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128, + [OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128, + [OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128, + [OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256, + [OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, + [OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, + [OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, + [OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, + }; + struct xonar_pcm179x *data = chip->model_data; + unsigned int rate_index; + u8 rate_mclk; + + rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) + & OXYGEN_I2S_RATE_MASK; + rate_mclk = rate_mclks[rate_index]; + oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, + OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); + if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) + data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; + else + data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_2; + cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); +} + +static void set_st_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + set_cs2000_params(chip, params); + set_pcm1796_params(chip, params); +} + static void set_hdav_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { @@ -590,7 +689,7 @@ static const struct oxygen_model model_xonar_st = { .cleanup = xonar_st_cleanup, .suspend = xonar_st_suspend, .resume = xonar_st_resume, - .set_dac_params = set_pcm1796_params, + .set_dac_params = set_st_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, .update_dac_mute = update_pcm1796_mute, @@ -652,6 +751,8 @@ int __devinit get_xonar_pcm179x_model(struct oxygen *chip, chip->model = model_xonar_st; chip->model.shortname = "Xonar STX"; chip->model.init = xonar_stx_init; + chip->model.resume = xonar_stx_resume; + chip->model.set_dac_params = set_pcm1796_params; break; default: return -EINVAL; -- cgit v1.2.3 From 75919d7c057be888c7cd7b192fad02182260b04a Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:15:49 +0200 Subject: sound: oxygen: better defaults for upmixing control On card models with two-channel outputs, the base driver can automatically disable the upmixing control so that the model drivers do not need to do this. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 8 -------- sound/pci/oxygen/oxygen_mixer.c | 3 +++ sound/pci/oxygen/xonar_pcm179x.c | 2 -- 3 files changed, 3 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 84ef13183419..9026a143a5ec 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -141,19 +141,11 @@ static void set_cs5340_params(struct oxygen *chip, static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); -static int hifier_control_filter(struct snd_kcontrol_new *template) -{ - if (!strcmp(template->name, "Stereo Upmixing")) - return 1; /* stereo only - we don't need upmixing */ - return 0; -} - static const struct oxygen_model model_hifier = { .shortname = "C-Media CMI8787", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", .init = hifier_init, - .control_filter = hifier_control_filter, .cleanup = hifier_cleanup, .resume = hifier_resume, .set_dac_params = set_ak4396_params, diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 5401c547c4e3..e8e911a86c8e 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -954,6 +954,9 @@ static int add_controls(struct oxygen *chip, if (err == 1) continue; } + if (!strcmp(template.name, "Stereo Upmixing") && + chip->model.dac_channels == 2) + continue; if (!strcmp(template.name, "Master Playback Volume") && chip->model.dac_tlv) { template.tlv.p = chip->model.dac_tlv; diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 522efde0d52e..07aaa893d323 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -605,8 +605,6 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) { if (!strncmp(template->name, "CD Capture ", 11)) return 1; /* no CD input */ - if (!strcmp(template->name, "Stereo Upmixing")) - return 1; /* stereo only - we don't need upmixing */ return 0; } -- cgit v1.2.3 From 3d8bb454c4fbe18cea1adfd4183a4a9ef5f0ef04 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:16:41 +0200 Subject: sound: oxygen: add stereo upmixing to center/LFE channels Add the possibility to route a mix of the two channels of stereo data to the center and LFE outputs. This is implemented only for models where the DACs support this, i.e., for the Xonar D1 and DX. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.h | 1 + sound/pci/oxygen/oxygen_mixer.c | 33 ++++++++++++++++++++++++--------- sound/pci/oxygen/oxygen_pcm.c | 6 ++++-- sound/pci/oxygen/xonar_cs43xx.c | 39 +++++++++++++++++++++++++++++---------- 4 files changed, 58 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index bd615dbffadb..2ac3b3c8253f 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -84,6 +84,7 @@ struct oxygen_model { struct snd_pcm_hw_params *params); void (*update_dac_volume)(struct oxygen *chip); void (*update_dac_mute)(struct oxygen *chip); + void (*update_center_lfe_mix)(struct oxygen *chip, bool mixed); void (*gpio_changed)(struct oxygen *chip); void (*uart_input)(struct oxygen *chip); void (*ac97_switch)(struct oxygen *chip, diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index e8e911a86c8e..5dfb5fb73381 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -99,11 +99,15 @@ static int dac_mute_put(struct snd_kcontrol *ctl, static int upmix_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { - static const char *const names[3] = { - "Front", "Front+Surround", "Front+Surround+Back" + static const char *const names[5] = { + "Front", + "Front+Surround", + "Front+Surround+Back", + "Front+Surround+Center/LFE", + "Front+Surround+Center/LFE+Back", }; struct oxygen *chip = ctl->private_data; - unsigned int count = 2 + (chip->model.dac_channels == 8); + unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; info->count = 1; @@ -127,7 +131,7 @@ static int upmix_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) void oxygen_update_dac_routing(struct oxygen *chip) { /* DAC 0: front, DAC 1: surround, DAC 2: center/LFE, DAC 3: back */ - static const unsigned int reg_values[3] = { + static const unsigned int reg_values[5] = { /* stereo -> front */ (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | (1 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | @@ -143,6 +147,16 @@ void oxygen_update_dac_routing(struct oxygen *chip) (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | (2 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround+center/LFE */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (3 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), + /* stereo -> front+surround+center/LFE+back */ + (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) | + (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT), }; u8 channels; unsigned int reg_value; @@ -167,22 +181,23 @@ void oxygen_update_dac_routing(struct oxygen *chip) OXYGEN_PLAY_DAC1_SOURCE_MASK | OXYGEN_PLAY_DAC2_SOURCE_MASK | OXYGEN_PLAY_DAC3_SOURCE_MASK); + if (chip->model.update_center_lfe_mix) + chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2); } static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; - unsigned int count = 2 + (chip->model.dac_channels == 8); + unsigned int count = chip->model.update_center_lfe_mix ? 5 : 3; int changed; + if (value->value.enumerated.item[0] >= count) + return -EINVAL; mutex_lock(&chip->mutex); changed = value->value.enumerated.item[0] != chip->dac_routing; if (changed) { - chip->dac_routing = min(value->value.enumerated.item[0], - count - 1); - spin_lock_irq(&chip->reg_lock); + chip->dac_routing = value->value.enumerated.item[0]; oxygen_update_dac_routing(chip); - spin_unlock_irq(&chip->reg_lock); } mutex_unlock(&chip->mutex); return changed; diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index ef2345d82b86..1e98333366df 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -435,6 +435,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; + mutex_lock(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_clear_bits32(chip, OXYGEN_SPDIF_CONTROL, OXYGEN_SPDIF_OUT_ENABLE); @@ -446,6 +447,7 @@ static int oxygen_spdif_hw_params(struct snd_pcm_substream *substream, OXYGEN_SPDIF_OUT_RATE_MASK); oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); + mutex_unlock(&chip->mutex); return 0; } @@ -459,6 +461,7 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, if (err < 0) return err; + mutex_lock(&chip->mutex); spin_lock_irq(&chip->reg_lock); oxygen_write8_masked(chip, OXYGEN_PLAY_CHANNELS, oxygen_play_channels(hw_params), @@ -475,12 +478,11 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, OXYGEN_I2S_FORMAT_MASK | OXYGEN_I2S_MCLK_MASK | OXYGEN_I2S_BITS_MASK); - oxygen_update_dac_routing(chip); oxygen_update_spdif_source(chip); spin_unlock_irq(&chip->reg_lock); - mutex_lock(&chip->mutex); chip->model.set_dac_params(chip, hw_params); + oxygen_update_dac_routing(chip); mutex_unlock(&chip->mutex); return 0; } diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 8fb5797577dd..0fa05ed6681d 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -67,6 +67,7 @@ struct xonar_cs43xx { struct xonar_generic generic; u8 cs4398_fm; u8 cs4362a_fm; + u8 cs4362a_fm_c; }; static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) @@ -128,7 +129,7 @@ static void cs43xx_init(struct oxygen *chip) cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); cs4362a_write(chip, 0x05, 0); cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); cs4362a_write(chip, 0x0c, data->cs4362a_fm); update_cs43xx_volume(chip); update_cs43xx_mute(chip); @@ -146,6 +147,7 @@ static void xonar_d1_init(struct oxygen *chip) data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; data->cs4362a_fm = CS4362A_FM_SINGLE | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + data->cs4362a_fm_c = data->cs4362a_fm; oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, OXYGEN_2WIRE_LENGTH_8 | @@ -202,25 +204,41 @@ static void set_cs43xx_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { struct xonar_cs43xx *data = chip->model_data; + u8 cs4398_fm, cs4362a_fm; - data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; if (params_rate(params) <= 50000) { - data->cs4398_fm |= CS4398_FM_SINGLE; - data->cs4362a_fm |= CS4362A_FM_SINGLE; + cs4398_fm = CS4398_FM_SINGLE; + cs4362a_fm = CS4362A_FM_SINGLE; } else if (params_rate(params) <= 100000) { - data->cs4398_fm |= CS4398_FM_DOUBLE; - data->cs4362a_fm |= CS4362A_FM_DOUBLE; + cs4398_fm = CS4398_FM_DOUBLE; + cs4362a_fm = CS4362A_FM_DOUBLE; } else { - data->cs4398_fm |= CS4398_FM_QUAD; - data->cs4362a_fm |= CS4362A_FM_QUAD; + cs4398_fm = CS4398_FM_QUAD; + cs4362a_fm = CS4362A_FM_QUAD; } + data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST | cs4398_fm; + data->cs4362a_fm = + (data->cs4362a_fm & ~CS4362A_FM_MASK) | cs4362a_fm; + data->cs4362a_fm_c = + (data->cs4362a_fm_c & ~CS4362A_FM_MASK) | cs4362a_fm; cs4398_write(chip, 2, data->cs4398_fm); cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm); + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); cs4362a_write(chip, 0x0c, data->cs4362a_fm); } +static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) +{ + struct xonar_cs43xx *data = chip->model_data; + + data->cs4362a_fm_c &= ~CS4362A_ATAPI_MASK; + if (mixed) + data->cs4362a_fm_c |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; + else + data->cs4362a_fm_c |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + cs4362a_write(chip, 0x09, data->cs4362a_fm_c); +} + static const struct snd_kcontrol_new front_panel_switch = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Front Panel Switch", @@ -269,6 +287,7 @@ static const struct oxygen_model model_xonar_d1 = { .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_cs43xx_volume, .update_dac_mute = update_cs43xx_mute, + .update_center_lfe_mix = update_cs43xx_center_lfe_mix, .ac97_switch = xonar_d1_line_mic_ac97_switch, .dac_tlv = cs4362a_db_scale, .model_data_size = sizeof(struct xonar_cs43xx), -- cgit v1.2.3 From dc0adf48daa81b05765d3c5ebab76321f77e9d21 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:17:36 +0200 Subject: sound: oxygen: more hardware documentation Add some comments describing the hardware pin routing. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 6 ++++++ sound/pci/oxygen/oxygen.c | 6 ++++++ sound/pci/oxygen/xonar_cs43xx.c | 4 ++++ sound/pci/oxygen/xonar_pcm179x.c | 17 +++++++++++++++++ 4 files changed, 33 insertions(+) (limited to 'sound') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 9026a143a5ec..19e9e0123304 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -17,6 +17,12 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ +/* + * CMI8788: + * + * SPI 0 -> AK4396 + */ + #include #include #include diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 72db4c39007f..53dff7193f31 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -18,6 +18,8 @@ */ /* + * CMI8788: + * * SPI 0 -> 1st AK4396 (front) * SPI 1 -> 2nd AK4396 (surround) * SPI 2 -> 3rd AK4396 (center/LFE) @@ -27,6 +29,10 @@ * GPIO 0 -> DFS0 of AK5385 * GPIO 1 -> DFS1 of AK5385 * GPIO 8 -> enable headphone amplifier on HT-Omega models + * + * CM9780: + * + * GPO 0 -> route line-in (0) or AC97 output (1) to ADC input */ #include diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 0fa05ed6681d..a8ec4e8271a4 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -41,6 +41,10 @@ * CS4362A: * * AD0 <- 0 + * + * CM9780: + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5361 input */ #include diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 07aaa893d323..97574dbec2b6 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -32,6 +32,10 @@ * GPIO 5 <- external power present (D2X only) * GPIO 7 -> ALT * GPIO 8 -> enable output to speakers + * + * CM9780: + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input */ /* @@ -54,6 +58,10 @@ * * PCM1796 front: AD1,0 <- 0,0 * + * CM9780: + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input + * * no daughterboard * ---------------- * @@ -107,6 +115,15 @@ * PCM1792A: * * AD1,0 <- 0,0 + * SCK <- CLK_OUT of CS2000 (ST only) + * + * CS2000: + * + * AD0 <- 0 + * + * CM9780: + * + * GPO 0 -> route line-in (0) or AC97 output (1) to CS5381 input * * H6 daughterboard * ---------------- -- cgit v1.2.3 From 6f0de3ce068e48b033b5e4d0822b47218e9d206c Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:18:45 +0200 Subject: sound: oxygen: cache codec registers Keep a cache of codec registers to avoid unnecessary writes. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 46 ++++++++----- sound/pci/oxygen/oxygen.c | 107 ++++++++++++++++-------------- sound/pci/oxygen/xonar_cs43xx.c | 140 ++++++++++++++++++++++++--------------- sound/pci/oxygen/xonar_pcm179x.c | 109 ++++++++++++++++++++---------- 4 files changed, 250 insertions(+), 152 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 19e9e0123304..2079c100aabc 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -57,23 +57,28 @@ static struct pci_device_id hifier_ids[] __devinitdata = { MODULE_DEVICE_TABLE(pci, hifier_ids); struct hifier_data { - u8 ak4396_ctl2; + u8 ak4396_regs[5]; }; static void ak4396_write(struct oxygen *chip, u8 reg, u8 value) { + struct hifier_data *data = chip->model_data; + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | OXYGEN_SPI_DATA_LENGTH_2 | OXYGEN_SPI_CLOCK_160 | (0 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, AK4396_WRITE | (reg << 8) | value); + data->ak4396_regs[reg] = value; } -static void update_ak4396_volume(struct oxygen *chip) +static void ak4396_write_cached(struct oxygen *chip, u8 reg, u8 value) { - ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); - ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); + struct hifier_data *data = chip->model_data; + + if (value != data->ak4396_regs[reg]) + ak4396_write(chip, reg, value); } static void hifier_registers_init(struct oxygen *chip) @@ -81,16 +86,19 @@ static void hifier_registers_init(struct oxygen *chip) struct hifier_data *data = chip->model_data; ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); - ak4396_write(chip, AK4396_CONTROL_2, data->ak4396_ctl2); + ak4396_write(chip, AK4396_CONTROL_2, + data->ak4396_regs[AK4396_CONTROL_2]); ak4396_write(chip, AK4396_CONTROL_3, AK4396_PCM); - update_ak4396_volume(chip); + ak4396_write(chip, AK4396_LCH_ATT, chip->dac_volume[0]); + ak4396_write(chip, AK4396_RCH_ATT, chip->dac_volume[1]); } static void hifier_init(struct oxygen *chip) { struct hifier_data *data = chip->model_data; - data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; + data->ak4396_regs[AK4396_CONTROL_2] = + AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; hifier_registers_init(chip); snd_component_add(chip->card, "AK4396"); @@ -112,20 +120,29 @@ static void set_ak4396_params(struct oxygen *chip, struct hifier_data *data = chip->model_data; u8 value; - value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; + value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_DFS_MASK; if (params_rate(params) <= 54000) value |= AK4396_DFS_NORMAL; else if (params_rate(params) <= 108000) value |= AK4396_DFS_DOUBLE; else value |= AK4396_DFS_QUAD; - data->ak4396_ctl2 = value; msleep(1); /* wait for the new MCLK to become stable */ - ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB); - ak4396_write(chip, AK4396_CONTROL_2, value); - ak4396_write(chip, AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); + if (value != data->ak4396_regs[AK4396_CONTROL_2]) { + ak4396_write(chip, AK4396_CONTROL_1, + AK4396_DIF_24_MSB); + ak4396_write(chip, AK4396_CONTROL_2, value); + ak4396_write(chip, AK4396_CONTROL_1, + AK4396_DIF_24_MSB | AK4396_RSTN); + } +} + +static void update_ak4396_volume(struct oxygen *chip) +{ + ak4396_write_cached(chip, AK4396_LCH_ATT, chip->dac_volume[0]); + ak4396_write_cached(chip, AK4396_RCH_ATT, chip->dac_volume[1]); } static void update_ak4396_mute(struct oxygen *chip) @@ -133,11 +150,10 @@ static void update_ak4396_mute(struct oxygen *chip) struct hifier_data *data = chip->model_data; u8 value; - value = data->ak4396_ctl2 & ~AK4396_SMUTE; + value = data->ak4396_regs[AK4396_CONTROL_2] & ~AK4396_SMUTE; if (chip->dac_mute) value |= AK4396_SMUTE; - data->ak4396_ctl2 = value; - ak4396_write(chip, AK4396_CONTROL_2, value); + ak4396_write_cached(chip, AK4396_CONTROL_2, value); } static void set_cs5340_params(struct oxygen *chip, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 53dff7193f31..c986c5ebf65b 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -97,8 +97,8 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); #define GPIO_CLARO_HP 0x0100 struct generic_data { - u8 ak4396_ctl2; - u16 saved_wm8785_registers[2]; + u8 ak4396_regs[4][5]; + u16 wm8785_regs[1]; }; static void ak4396_write(struct oxygen *chip, unsigned int codec, @@ -108,12 +108,24 @@ static void ak4396_write(struct oxygen *chip, unsigned int codec, static const u8 codec_spi_map[4] = { 0, 1, 2, 4 }; + struct generic_data *data = chip->model_data; + oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | OXYGEN_SPI_DATA_LENGTH_2 | OXYGEN_SPI_CLOCK_160 | (codec_spi_map[codec] << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_HI, AK4396_WRITE | (reg << 8) | value); + data->ak4396_regs[codec][reg] = value; +} + +static void ak4396_write_cached(struct oxygen *chip, unsigned int codec, + u8 reg, u8 value) +{ + struct generic_data *data = chip->model_data; + + if (value != data->ak4396_regs[codec][reg]) + ak4396_write(chip, codec, reg, value); } static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) @@ -126,20 +138,8 @@ static void wm8785_write(struct oxygen *chip, u8 reg, unsigned int value) (3 << OXYGEN_SPI_CODEC_SHIFT) | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); - if (reg < ARRAY_SIZE(data->saved_wm8785_registers)) - data->saved_wm8785_registers[reg] = value; -} - -static void update_ak4396_volume(struct oxygen *chip) -{ - unsigned int i; - - for (i = 0; i < 4; ++i) { - ak4396_write(chip, i, - AK4396_LCH_ATT, chip->dac_volume[i * 2]); - ak4396_write(chip, i, - AK4396_RCH_ATT, chip->dac_volume[i * 2 + 1]); - } + if (reg < ARRAY_SIZE(data->wm8785_regs)) + data->wm8785_regs[reg] = value; } static void ak4396_registers_init(struct oxygen *chip) @@ -148,21 +148,25 @@ static void ak4396_registers_init(struct oxygen *chip) unsigned int i; for (i = 0; i < 4; ++i) { - ak4396_write(chip, i, - AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); - ak4396_write(chip, i, - AK4396_CONTROL_2, data->ak4396_ctl2); - ak4396_write(chip, i, - AK4396_CONTROL_3, AK4396_PCM); + ak4396_write(chip, i, AK4396_CONTROL_1, + AK4396_DIF_24_MSB | AK4396_RSTN); + ak4396_write(chip, i, AK4396_CONTROL_2, + data->ak4396_regs[0][AK4396_CONTROL_2]); + ak4396_write(chip, i, AK4396_CONTROL_3, + AK4396_PCM); + ak4396_write(chip, i, AK4396_LCH_ATT, + chip->dac_volume[i * 2]); + ak4396_write(chip, i, AK4396_RCH_ATT, + chip->dac_volume[i * 2 + 1]); } - update_ak4396_volume(chip); } static void ak4396_init(struct oxygen *chip) { struct generic_data *data = chip->model_data; - data->ak4396_ctl2 = AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; + data->ak4396_regs[0][AK4396_CONTROL_2] = + AK4396_SMUTE | AK4396_DEM_OFF | AK4396_DFS_NORMAL; ak4396_registers_init(chip); snd_component_add(chip->card, "AK4396"); } @@ -179,17 +183,15 @@ static void wm8785_registers_init(struct oxygen *chip) struct generic_data *data = chip->model_data; wm8785_write(chip, WM8785_R7, 0); - wm8785_write(chip, WM8785_R0, data->saved_wm8785_registers[0]); - wm8785_write(chip, WM8785_R1, data->saved_wm8785_registers[1]); + wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]); } static void wm8785_init(struct oxygen *chip) { struct generic_data *data = chip->model_data; - data->saved_wm8785_registers[0] = WM8785_MCR_SLAVE | - WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; - data->saved_wm8785_registers[1] = WM8785_WL_24; + data->wm8785_regs[0] = + WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; wm8785_registers_init(chip); snd_component_add(chip->card, "WM8785"); } @@ -270,24 +272,36 @@ static void set_ak4396_params(struct oxygen *chip, unsigned int i; u8 value; - value = data->ak4396_ctl2 & ~AK4396_DFS_MASK; + value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_DFS_MASK; if (params_rate(params) <= 54000) value |= AK4396_DFS_NORMAL; else if (params_rate(params) <= 108000) value |= AK4396_DFS_DOUBLE; else value |= AK4396_DFS_QUAD; - data->ak4396_ctl2 = value; msleep(1); /* wait for the new MCLK to become stable */ + if (value != data->ak4396_regs[0][AK4396_CONTROL_2]) { + for (i = 0; i < 4; ++i) { + ak4396_write(chip, i, AK4396_CONTROL_1, + AK4396_DIF_24_MSB); + ak4396_write(chip, i, AK4396_CONTROL_2, value); + ak4396_write(chip, i, AK4396_CONTROL_1, + AK4396_DIF_24_MSB | AK4396_RSTN); + } + } +} + +static void update_ak4396_volume(struct oxygen *chip) +{ + unsigned int i; + for (i = 0; i < 4; ++i) { - ak4396_write(chip, i, - AK4396_CONTROL_1, AK4396_DIF_24_MSB); - ak4396_write(chip, i, - AK4396_CONTROL_2, value); - ak4396_write(chip, i, - AK4396_CONTROL_1, AK4396_DIF_24_MSB | AK4396_RSTN); + ak4396_write_cached(chip, i, AK4396_LCH_ATT, + chip->dac_volume[i * 2]); + ak4396_write_cached(chip, i, AK4396_RCH_ATT, + chip->dac_volume[i * 2 + 1]); } } @@ -297,21 +311,19 @@ static void update_ak4396_mute(struct oxygen *chip) unsigned int i; u8 value; - value = data->ak4396_ctl2 & ~AK4396_SMUTE; + value = data->ak4396_regs[0][AK4396_CONTROL_2] & ~AK4396_SMUTE; if (chip->dac_mute) value |= AK4396_SMUTE; - data->ak4396_ctl2 = value; for (i = 0; i < 4; ++i) - ak4396_write(chip, i, AK4396_CONTROL_2, value); + ak4396_write_cached(chip, i, AK4396_CONTROL_2, value); } static void set_wm8785_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { + struct generic_data *data = chip->model_data; unsigned int value; - wm8785_write(chip, WM8785_R7, 0); - value = WM8785_MCR_SLAVE | WM8785_FORMAT_LJUST; if (params_rate(params) <= 48000) value |= WM8785_OSR_SINGLE; @@ -319,13 +331,10 @@ static void set_wm8785_params(struct oxygen *chip, value |= WM8785_OSR_DOUBLE; else value |= WM8785_OSR_QUAD; - wm8785_write(chip, WM8785_R0, value); - - if (snd_pcm_format_width(params_format(params)) <= 16) - value = WM8785_WL_16; - else - value = WM8785_WL_24; - wm8785_write(chip, WM8785_R1, value); + if (value != data->wm8785_regs[0]) { + wm8785_write(chip, WM8785_R7, 0); + wm8785_write(chip, WM8785_R0, value); + } } static void set_ak5385_params(struct oxygen *chip, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index a8ec4e8271a4..330c5e755917 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -69,62 +69,58 @@ struct xonar_cs43xx { struct xonar_generic generic; - u8 cs4398_fm; - u8 cs4362a_fm; - u8 cs4362a_fm_c; + u8 cs4398_regs[7]; + u8 cs4362a_regs[15]; }; static void cs4398_write(struct oxygen *chip, u8 reg, u8 value) { - oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); -} + struct xonar_cs43xx *data = chip->model_data; -static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) -{ - oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); + oxygen_write_i2c(chip, I2C_DEVICE_CS4398, reg, value); + if (reg < ARRAY_SIZE(data->cs4398_regs)) + data->cs4398_regs[reg] = value; } -static void update_cs4362a_volumes(struct oxygen *chip) +static void cs4398_write_cached(struct oxygen *chip, u8 reg, u8 value) { - u8 mute; + struct xonar_cs43xx *data = chip->model_data; - mute = chip->dac_mute ? CS4362A_MUTE : 0; - cs4362a_write(chip, 7, (127 - chip->dac_volume[2]) | mute); - cs4362a_write(chip, 8, (127 - chip->dac_volume[3]) | mute); - cs4362a_write(chip, 10, (127 - chip->dac_volume[4]) | mute); - cs4362a_write(chip, 11, (127 - chip->dac_volume[5]) | mute); - cs4362a_write(chip, 13, (127 - chip->dac_volume[6]) | mute); - cs4362a_write(chip, 14, (127 - chip->dac_volume[7]) | mute); + if (value != data->cs4398_regs[reg]) + cs4398_write(chip, reg, value); } -static void update_cs43xx_volume(struct oxygen *chip) +static void cs4362a_write(struct oxygen *chip, u8 reg, u8 value) { - cs4398_write(chip, 5, (127 - chip->dac_volume[0]) * 2); - cs4398_write(chip, 6, (127 - chip->dac_volume[1]) * 2); - update_cs4362a_volumes(chip); + struct xonar_cs43xx *data = chip->model_data; + + oxygen_write_i2c(chip, I2C_DEVICE_CS4362A, reg, value); + if (reg < ARRAY_SIZE(data->cs4362a_regs)) + data->cs4362a_regs[reg] = value; } -static void update_cs43xx_mute(struct oxygen *chip) +static void cs4362a_write_cached(struct oxygen *chip, u8 reg, u8 value) { - u8 reg; + struct xonar_cs43xx *data = chip->model_data; - reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; - if (chip->dac_mute) - reg |= CS4398_MUTE_B | CS4398_MUTE_A; - cs4398_write(chip, 4, reg); - update_cs4362a_volumes(chip); + if (value != data->cs4362a_regs[reg]) + cs4362a_write(chip, reg, value); } -static void cs43xx_init(struct oxygen *chip) +static void cs43xx_registers_init(struct oxygen *chip) { struct xonar_cs43xx *data = chip->model_data; + unsigned int i; /* set CPEN (control port mode) and power down */ cs4398_write(chip, 8, CS4398_CPEN | CS4398_PDN); cs4362a_write(chip, 0x01, CS4362A_PDN | CS4362A_CPEN); /* configure */ - cs4398_write(chip, 2, data->cs4398_fm); + cs4398_write(chip, 2, data->cs4398_regs[2]); cs4398_write(chip, 3, CS4398_ATAPI_B_R | CS4398_ATAPI_A_L); + cs4398_write(chip, 4, data->cs4398_regs[4]); + cs4398_write(chip, 5, data->cs4398_regs[5]); + cs4398_write(chip, 6, data->cs4398_regs[6]); cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); @@ -132,11 +128,8 @@ static void cs43xx_init(struct oxygen *chip) CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); cs4362a_write(chip, 0x05, 0); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm_c); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); - update_cs43xx_volume(chip); - update_cs43xx_mute(chip); + for (i = 6; i <= 14; ++i) + cs4362a_write(chip, i, data->cs4362a_regs[i]); /* clear power down */ cs4398_write(chip, 8, CS4398_CPEN); cs4362a_write(chip, 0x01, CS4362A_CPEN); @@ -148,17 +141,29 @@ static void xonar_d1_init(struct oxygen *chip) data->generic.anti_pop_delay = 800; data->generic.output_enable_bit = GPIO_D1_OUTPUT_ENABLE; - data->cs4398_fm = CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; - data->cs4362a_fm = CS4362A_FM_SINGLE | + data->cs4398_regs[2] = + CS4398_FM_SINGLE | CS4398_DEM_NONE | CS4398_DIF_LJUST; + data->cs4398_regs[4] = CS4398_MUTEP_LOW | + CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; + data->cs4398_regs[5] = 60 * 2; + data->cs4398_regs[6] = 60 * 2; + data->cs4362a_regs[6] = CS4362A_FM_SINGLE | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - data->cs4362a_fm_c = data->cs4362a_fm; + data->cs4362a_regs[7] = 60 | CS4362A_MUTE; + data->cs4362a_regs[8] = 60 | CS4362A_MUTE; + data->cs4362a_regs[9] = data->cs4362a_regs[6]; + data->cs4362a_regs[10] = 60 | CS4362A_MUTE; + data->cs4362a_regs[11] = 60 | CS4362A_MUTE; + data->cs4362a_regs[12] = data->cs4362a_regs[6]; + data->cs4362a_regs[13] = 60 | CS4362A_MUTE; + data->cs4362a_regs[14] = 60 | CS4362A_MUTE; oxygen_write16(chip, OXYGEN_2WIRE_BUS_STATUS, OXYGEN_2WIRE_LENGTH_8 | OXYGEN_2WIRE_INTERRUPT_MASK | OXYGEN_2WIRE_SPEED_FAST); - cs43xx_init(chip); + cs43xx_registers_init(chip); oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_D1_FRONT_PANEL | GPIO_D1_INPUT_ROUTE); @@ -200,7 +205,7 @@ static void xonar_d1_resume(struct oxygen *chip) { oxygen_set_bits8(chip, OXYGEN_FUNCTION, OXYGEN_FUNCTION_RESET_CODEC); msleep(1); - cs43xx_init(chip); + cs43xx_registers_init(chip); xonar_enable_output(chip); } @@ -220,27 +225,56 @@ static void set_cs43xx_params(struct oxygen *chip, cs4398_fm = CS4398_FM_QUAD; cs4362a_fm = CS4362A_FM_QUAD; } - data->cs4398_fm = CS4398_DEM_NONE | CS4398_DIF_LJUST | cs4398_fm; - data->cs4362a_fm = - (data->cs4362a_fm & ~CS4362A_FM_MASK) | cs4362a_fm; - data->cs4362a_fm_c = - (data->cs4362a_fm_c & ~CS4362A_FM_MASK) | cs4362a_fm; - cs4398_write(chip, 2, data->cs4398_fm); - cs4362a_write(chip, 0x06, data->cs4362a_fm); - cs4362a_write(chip, 0x09, data->cs4362a_fm_c); - cs4362a_write(chip, 0x0c, data->cs4362a_fm); + cs4398_fm |= CS4398_DEM_NONE | CS4398_DIF_LJUST; + cs4398_write_cached(chip, 2, cs4398_fm); + cs4362a_fm |= data->cs4362a_regs[6] & ~CS4362A_FM_MASK; + cs4362a_write_cached(chip, 6, cs4362a_fm); + cs4362a_write_cached(chip, 12, cs4362a_fm); + cs4362a_fm &= CS4362A_FM_MASK; + cs4362a_fm |= data->cs4362a_regs[9] & ~CS4362A_FM_MASK; + cs4362a_write_cached(chip, 9, cs4362a_fm); +} + +static void update_cs4362a_volumes(struct oxygen *chip) +{ + unsigned int i; + u8 mute; + + mute = chip->dac_mute ? CS4362A_MUTE : 0; + for (i = 0; i < 6; ++i) + cs4362a_write_cached(chip, 7 + i + i / 2, + (127 - chip->dac_volume[2 + i]) | mute); +} + +static void update_cs43xx_volume(struct oxygen *chip) +{ + cs4398_write_cached(chip, 5, (127 - chip->dac_volume[0]) * 2); + cs4398_write_cached(chip, 6, (127 - chip->dac_volume[1]) * 2); + update_cs4362a_volumes(chip); +} + +static void update_cs43xx_mute(struct oxygen *chip) +{ + u8 reg; + + reg = CS4398_MUTEP_LOW | CS4398_PAMUTE; + if (chip->dac_mute) + reg |= CS4398_MUTE_B | CS4398_MUTE_A; + cs4398_write_cached(chip, 4, reg); + update_cs4362a_volumes(chip); } static void update_cs43xx_center_lfe_mix(struct oxygen *chip, bool mixed) { struct xonar_cs43xx *data = chip->model_data; + u8 reg; - data->cs4362a_fm_c &= ~CS4362A_ATAPI_MASK; + reg = data->cs4362a_regs[9] & ~CS4362A_ATAPI_MASK; if (mixed) - data->cs4362a_fm_c |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; + reg |= CS4362A_ATAPI_B_LR | CS4362A_ATAPI_A_LR; else - data->cs4362a_fm_c |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; - cs4362a_write(chip, 0x09, data->cs4362a_fm_c); + reg |= CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; + cs4362a_write_cached(chip, 9, reg); } static const struct snd_kcontrol_new front_panel_switch = { diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 97574dbec2b6..e17ee5e8e510 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -166,11 +166,13 @@ #define I2C_DEVICE_PCM1796(i) (0x98 + ((i) << 1)) /* 10011, ii, /W=0 */ #define I2C_DEVICE_CS2000 0x9c /* 100111, 0, /W=0 */ +#define PCM1796_REG_BASE 16 + struct xonar_pcm179x { struct xonar_generic generic; unsigned int dacs; - u8 oversampling; + u8 pcm1796_regs[4][5]; u8 cs2000_fun_cfg_1; }; @@ -204,54 +206,71 @@ static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec, static void pcm1796_write(struct oxygen *chip, unsigned int codec, u8 reg, u8 value) { + struct xonar_pcm179x *data = chip->model_data; + if ((chip->model.function_flags & OXYGEN_FUNCTION_2WIRE_SPI_MASK) == OXYGEN_FUNCTION_SPI) pcm1796_write_spi(chip, codec, reg, value); else pcm1796_write_i2c(chip, codec, reg, value); + if ((unsigned int)(reg - PCM1796_REG_BASE) + < ARRAY_SIZE(data->pcm1796_regs[codec])) + data->pcm1796_regs[codec][reg - PCM1796_REG_BASE] = value; } -static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) +static void pcm1796_write_cached(struct oxygen *chip, unsigned int codec, + u8 reg, u8 value) { - oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); + struct xonar_pcm179x *data = chip->model_data; + + if (value != data->pcm1796_regs[codec][reg - PCM1796_REG_BASE]) + pcm1796_write(chip, codec, reg, value); } -static void update_pcm1796_volume(struct oxygen *chip) +static void cs2000_write(struct oxygen *chip, u8 reg, u8 value) { struct xonar_pcm179x *data = chip->model_data; - unsigned int i; - for (i = 0; i < data->dacs; ++i) { - pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); - pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); - } + oxygen_write_i2c(chip, I2C_DEVICE_CS2000, reg, value); + if (reg == CS2000_FUN_CFG_1) + data->cs2000_fun_cfg_1 = value; } -static void update_pcm1796_mute(struct oxygen *chip) +static void cs2000_write_cached(struct oxygen *chip, u8 reg, u8 value) { struct xonar_pcm179x *data = chip->model_data; - unsigned int i; - u8 value; - value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; - if (chip->dac_mute) - value |= PCM1796_MUTE; - for (i = 0; i < data->dacs; ++i) - pcm1796_write(chip, i, 18, value); + if (reg != CS2000_FUN_CFG_1 || + value != data->cs2000_fun_cfg_1) + cs2000_write(chip, reg, value); } -static void pcm1796_init(struct oxygen *chip) +static void pcm1796_registers_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; unsigned int i; for (i = 0; i < data->dacs; ++i) { + /* set ATLD before ATL/ATR */ + pcm1796_write(chip, i, 18, + data->pcm1796_regs[0][18 - PCM1796_REG_BASE]); + pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); + pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); - pcm1796_write(chip, i, 20, data->oversampling); + pcm1796_write(chip, i, 20, + data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); pcm1796_write(chip, i, 21, 0); } - update_pcm1796_mute(chip); /* set ATLD before ATL/ATR */ - update_pcm1796_volume(chip); +} + +static void pcm1796_init(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | + PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; + data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; + pcm1796_registers_init(chip); } static void xonar_d2_init(struct oxygen *chip) @@ -261,7 +280,6 @@ static void xonar_d2_init(struct oxygen *chip) data->generic.anti_pop_delay = 300; data->generic.output_enable_bit = GPIO_D2_OUTPUT_ENABLE; data->dacs = 4; - data->oversampling = PCM1796_OS_64; pcm1796_init(chip); @@ -304,7 +322,6 @@ static void xonar_hdav_init(struct oxygen *chip) data->pcm179x.generic.ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; data->pcm179x.generic.ext_power_bit = GPI_EXT_POWER; data->pcm179x.dacs = chip->model.private_data ? 4 : 1; - data->pcm179x.oversampling = PCM1796_OS_64; pcm1796_init(chip); @@ -335,7 +352,6 @@ static void xonar_st_init_common(struct oxygen *chip) data->generic.anti_pop_delay = 100; data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; data->dacs = chip->model.private_data ? 4 : 1; - data->oversampling = PCM1796_OS_64; pcm1796_init(chip); @@ -438,7 +454,7 @@ static void xonar_st_suspend(struct oxygen *chip) static void xonar_d2_resume(struct oxygen *chip) { - pcm1796_init(chip); + pcm1796_registers_init(chip); xonar_enable_output(chip); } @@ -446,14 +462,14 @@ static void xonar_hdav_resume(struct oxygen *chip) { struct xonar_hdav *data = chip->model_data; - pcm1796_init(chip); + pcm1796_registers_init(chip); xonar_hdmi_resume(chip, &data->hdmi); xonar_enable_output(chip); } static void xonar_stx_resume(struct oxygen *chip) { - pcm1796_init(chip); + pcm1796_registers_init(chip); xonar_enable_output(chip); } @@ -468,11 +484,35 @@ static void set_pcm1796_params(struct oxygen *chip, { struct xonar_pcm179x *data = chip->model_data; unsigned int i; + u8 reg; + + reg = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + for (i = 0; i < data->dacs; ++i) + pcm1796_write_cached(chip, i, 20, reg); +} + +static void update_pcm1796_volume(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + + for (i = 0; i < data->dacs; ++i) { + pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]); + pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]); + } +} + +static void update_pcm1796_mute(struct oxygen *chip) +{ + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + u8 value; - data->oversampling = - params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + value = PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; + if (chip->dac_mute) + value |= PCM1796_MUTE; for (i = 0; i < data->dacs; ++i) - pcm1796_write(chip, i, 20, data->oversampling); + pcm1796_write_cached(chip, i, 18, value); } static void set_cs2000_params(struct oxygen *chip, @@ -489,9 +529,8 @@ static void set_cs2000_params(struct oxygen *chip, [OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, [OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, }; - struct xonar_pcm179x *data = chip->model_data; unsigned int rate_index; - u8 rate_mclk; + u8 rate_mclk, reg; rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) & OXYGEN_I2S_RATE_MASK; @@ -499,10 +538,10 @@ static void set_cs2000_params(struct oxygen *chip, oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) - data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; + reg = CS2000_REF_CLK_DIV_1; else - data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_2; - cs2000_write(chip, CS2000_FUN_CFG_1, data->cs2000_fun_cfg_1); + reg = CS2000_REF_CLK_DIV_2; + cs2000_write_cached(chip, CS2000_FUN_CFG_1, reg); } static void set_st_params(struct oxygen *chip, -- cgit v1.2.3 From a361e247b4e36c567b44fef354ab595458422d44 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:19:19 +0200 Subject: sound: virtuoso: add headphone impedance control Add a mixer control to adjust the headphone amplifier output for headphones with different impedances. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_pcm179x.c | 110 +++++++++++++++++++++++++++++++++++---- 1 file changed, 99 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index e17ee5e8e510..cf94e4432a3f 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -173,6 +173,8 @@ struct xonar_pcm179x { struct xonar_generic generic; unsigned int dacs; u8 pcm1796_regs[4][5]; + bool hp_active; + s8 hp_gain_offset; u8 cs2000_fun_cfg_1; }; @@ -249,13 +251,17 @@ static void pcm1796_registers_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; unsigned int i; + s8 gain_offset; + gain_offset = data->hp_active ? data->hp_gain_offset : 0; for (i = 0; i < data->dacs; ++i) { /* set ATLD before ATL/ATR */ pcm1796_write(chip, i, 18, data->pcm1796_regs[0][18 - PCM1796_REG_BASE]); - pcm1796_write(chip, i, 16, chip->dac_volume[i * 2]); - pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1]); + pcm1796_write(chip, i, 16, chip->dac_volume[i * 2] + + gain_offset); + pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] + + gain_offset); pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); pcm1796_write(chip, i, 20, data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); @@ -352,6 +358,7 @@ static void xonar_st_init_common(struct oxygen *chip) data->generic.anti_pop_delay = 100; data->generic.output_enable_bit = GPIO_ST_OUTPUT_ENABLE; data->dacs = chip->model.private_data ? 4 : 1; + data->hp_gain_offset = 2*-18; pcm1796_init(chip); @@ -495,10 +502,14 @@ static void update_pcm1796_volume(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; unsigned int i; + s8 gain_offset; + gain_offset = data->hp_active ? data->hp_gain_offset : 0; for (i = 0; i < data->dacs; ++i) { - pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2]); - pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1]); + pcm1796_write_cached(chip, i, 16, chip->dac_volume[i * 2] + + gain_offset); + pcm1796_write_cached(chip, i, 17, chip->dac_volume[i * 2 + 1] + + gain_offset); } } @@ -606,6 +617,7 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) { struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; u16 gpio_old, gpio; mutex_lock(&chip->mutex); @@ -623,16 +635,83 @@ static int st_output_switch_put(struct snd_kcontrol *ctl, break; } oxygen_write16(chip, OXYGEN_GPIO_DATA, gpio); + data->hp_active = gpio & GPIO_ST_HP; + update_pcm1796_volume(chip); mutex_unlock(&chip->mutex); return gpio != gpio_old; } -static const struct snd_kcontrol_new st_output_switch = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Output", - .info = st_output_switch_info, - .get = st_output_switch_get, - .put = st_output_switch_put, +static int st_hp_volume_offset_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[3] = { + "< 64 ohms", "64-300 ohms", "300-600 ohms" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 3; + if (info->value.enumerated.item > 2) + info->value.enumerated.item = 2; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int st_hp_volume_offset_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + + mutex_lock(&chip->mutex); + if (data->hp_gain_offset < 2*-6) + value->value.enumerated.item[0] = 0; + else if (data->hp_gain_offset < 0) + value->value.enumerated.item[0] = 1; + else + value->value.enumerated.item[0] = 2; + mutex_unlock(&chip->mutex); + return 0; +} + + +static int st_hp_volume_offset_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + static const s8 offsets[] = { 2*-18, 2*-6, 0 }; + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + s8 offset; + int changed; + + if (value->value.enumerated.item[0] > 2) + return -EINVAL; + offset = offsets[value->value.enumerated.item[0]]; + mutex_lock(&chip->mutex); + changed = offset != data->hp_gain_offset; + if (changed) { + data->hp_gain_offset = offset; + update_pcm1796_volume(chip); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new st_controls[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Analog Output", + .info = st_output_switch_info, + .get = st_output_switch_get, + .put = st_output_switch_put, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Headphones Impedance Playback Enum", + .info = st_hp_volume_offset_info, + .get = st_hp_volume_offset_get, + .put = st_hp_volume_offset_put, + }, }; static void xonar_line_mic_ac97_switch(struct oxygen *chip, @@ -671,7 +750,16 @@ static int xonar_d2_mixer_init(struct oxygen *chip) static int xonar_st_mixer_init(struct oxygen *chip) { - return snd_ctl_add(chip->card, snd_ctl_new1(&st_output_switch, chip)); + unsigned int i; + int err; + + for (i = 0; i < ARRAY_SIZE(st_controls); ++i) { + err = snd_ctl_add(chip->card, + snd_ctl_new1(&st_controls[i], chip)); + if (err < 0) + return err; + } + return 0; } static const struct oxygen_model model_xonar_d2 = { -- cgit v1.2.3 From 76ffe1e3fb2f65e98d7ed001c5a2b6f334655364 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:20:11 +0200 Subject: sound: oxygen: allow custom MCLK rates Add a callback that allows model drivers to modify the default I2S MCLK rate. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/hifier.c | 1 + sound/pci/oxygen/oxygen.c | 1 + sound/pci/oxygen/oxygen.h | 4 ++++ sound/pci/oxygen/oxygen_pcm.c | 13 +++++++++---- sound/pci/oxygen/xonar_cs43xx.c | 1 + sound/pci/oxygen/xonar_pcm179x.c | 3 +++ 6 files changed, 19 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index 2079c100aabc..e3c229b63311 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c @@ -170,6 +170,7 @@ static const struct oxygen_model model_hifier = { .init = hifier_init, .cleanup = hifier_cleanup, .resume = hifier_resume, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_ak4396_params, .set_adc_params = set_cs5340_params, .update_dac_volume = update_ak4396_volume, diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index c986c5ebf65b..d12fd9efe94e 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -361,6 +361,7 @@ static const struct oxygen_model model_generic = { .init = generic_init, .cleanup = generic_cleanup, .resume = generic_resume, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_ak4396_params, .set_adc_params = set_wm8785_params, .update_dac_volume = update_ak4396_volume, diff --git a/sound/pci/oxygen/oxygen.h b/sound/pci/oxygen/oxygen.h index 2ac3b3c8253f..6147216af744 100644 --- a/sound/pci/oxygen/oxygen.h +++ b/sound/pci/oxygen/oxygen.h @@ -78,6 +78,8 @@ struct oxygen_model { void (*resume)(struct oxygen *chip); void (*pcm_hardware_filter)(unsigned int channel, struct snd_pcm_hardware *hardware); + unsigned int (*get_i2s_mclk)(struct oxygen *chip, unsigned int channel, + struct snd_pcm_hw_params *hw_params); void (*set_dac_params)(struct oxygen *chip, struct snd_pcm_hw_params *params); void (*set_adc_params)(struct oxygen *chip, @@ -163,6 +165,8 @@ void oxygen_update_spdif_source(struct oxygen *chip); /* oxygen_pcm.c */ int oxygen_pcm_init(struct oxygen *chip); +unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, unsigned int channel, + struct snd_pcm_hw_params *hw_params); /* oxygen_io.c */ diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index 1e98333366df..9dff6954c397 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c @@ -271,13 +271,16 @@ static unsigned int oxygen_rate(struct snd_pcm_hw_params *hw_params) } } -static unsigned int oxygen_i2s_mclk(struct snd_pcm_hw_params *hw_params) +unsigned int oxygen_default_i2s_mclk(struct oxygen *chip, + unsigned int channel, + struct snd_pcm_hw_params *hw_params) { if (params_rate(hw_params) <= 96000) return OXYGEN_I2S_MCLK_256; else return OXYGEN_I2S_MCLK_128; } +EXPORT_SYMBOL(oxygen_default_i2s_mclk); static unsigned int oxygen_i2s_bits(struct snd_pcm_hw_params *hw_params) { @@ -354,7 +357,7 @@ static int oxygen_rec_a_hw_params(struct snd_pcm_substream *substream, OXYGEN_REC_FORMAT_A_MASK); oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, oxygen_rate(hw_params) | - oxygen_i2s_mclk(hw_params) | + chip->model.get_i2s_mclk(chip, PCM_A, hw_params) | chip->model.adc_i2s_format | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | @@ -390,7 +393,8 @@ static int oxygen_rec_b_hw_params(struct snd_pcm_substream *substream, if (!is_ac97) oxygen_write16_masked(chip, OXYGEN_I2S_B_FORMAT, oxygen_rate(hw_params) | - oxygen_i2s_mclk(hw_params) | + chip->model.get_i2s_mclk(chip, PCM_B, + hw_params) | chip->model.adc_i2s_format | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | @@ -472,7 +476,8 @@ static int oxygen_multich_hw_params(struct snd_pcm_substream *substream, oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, oxygen_rate(hw_params) | chip->model.dac_i2s_format | - oxygen_i2s_mclk(hw_params) | + chip->model.get_i2s_mclk(chip, PCM_MULTICH, + hw_params) | oxygen_i2s_bits(hw_params), OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_FORMAT_MASK | diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index 330c5e755917..a83f827feb34 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -321,6 +321,7 @@ static const struct oxygen_model model_xonar_d1 = { .cleanup = xonar_d1_cleanup, .suspend = xonar_d1_suspend, .resume = xonar_d1_resume, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_cs43xx_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_cs43xx_volume, diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index cf94e4432a3f..35b3fb4071fb 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -771,6 +771,7 @@ static const struct oxygen_model model_xonar_d2 = { .cleanup = xonar_d2_cleanup, .suspend = xonar_d2_suspend, .resume = xonar_d2_resume, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_pcm1796_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -801,6 +802,7 @@ static const struct oxygen_model model_xonar_hdav = { .suspend = xonar_hdav_suspend, .resume = xonar_hdav_resume, .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_hdav_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -831,6 +833,7 @@ static const struct oxygen_model model_xonar_st = { .cleanup = xonar_st_cleanup, .suspend = xonar_st_suspend, .resume = xonar_st_resume, + .get_i2s_mclk = oxygen_default_i2s_mclk, .set_dac_params = set_st_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, -- cgit v1.2.3 From 973dca93a3d46cca7e4743300f8a510b779906af Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:20:47 +0200 Subject: sound: virtuoso: add PCM1796 oversampling control Add a control to increase the oversampling factor to 128x on cards with PCM1796 or PCM1792A DACs. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/xonar_pcm179x.c | 182 +++++++++++++++++++++++++++++++++------ 1 file changed, 157 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 35b3fb4071fb..7f153fb1848d 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -173,8 +173,11 @@ struct xonar_pcm179x { struct xonar_generic generic; unsigned int dacs; u8 pcm1796_regs[4][5]; + unsigned int current_rate; + bool os_128; bool hp_active; s8 hp_gain_offset; + bool has_cs2000; u8 cs2000_fun_cfg_1; }; @@ -277,6 +280,7 @@ static void pcm1796_init(struct oxygen *chip) PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; pcm1796_registers_init(chip); + data->current_rate = 48000; } static void xonar_d2_init(struct oxygen *chip) @@ -401,6 +405,7 @@ static void xonar_st_init(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; + data->has_cs2000 = 1; data->cs2000_fun_cfg_1 = CS2000_REF_CLK_DIV_1; oxygen_write16(chip, OXYGEN_I2S_A_FORMAT, @@ -486,18 +491,57 @@ static void xonar_st_resume(struct oxygen *chip) xonar_stx_resume(chip); } -static void set_pcm1796_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) +static unsigned int mclk_from_rate(struct oxygen *chip, unsigned int rate) +{ + struct xonar_pcm179x *data = chip->model_data; + + if (rate <= 32000) + return OXYGEN_I2S_MCLK_512; + else if (rate <= 48000 && data->os_128) + return OXYGEN_I2S_MCLK_512; + else if (rate <= 96000) + return OXYGEN_I2S_MCLK_256; + else + return OXYGEN_I2S_MCLK_128; +} + +static unsigned int get_pcm1796_i2s_mclk(struct oxygen *chip, + unsigned int channel, + struct snd_pcm_hw_params *params) +{ + if (channel == PCM_MULTICH) + return mclk_from_rate(chip, params_rate(params)); + else + return oxygen_default_i2s_mclk(chip, channel, params); +} + +static void update_pcm1796_oversampling(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; unsigned int i; u8 reg; - reg = params_rate(params) >= 96000 ? PCM1796_OS_32 : PCM1796_OS_64; + if (data->current_rate <= 32000) + reg = PCM1796_OS_128; + else if (data->current_rate <= 48000 && data->os_128) + reg = PCM1796_OS_128; + else if (data->current_rate <= 96000 || data->os_128) + reg = PCM1796_OS_64; + else + reg = PCM1796_OS_32; for (i = 0; i < data->dacs; ++i) pcm1796_write_cached(chip, i, 20, reg); } +static void set_pcm1796_params(struct oxygen *chip, + struct snd_pcm_hw_params *params) +{ + struct xonar_pcm179x *data = chip->model_data; + + data->current_rate = params_rate(params); + update_pcm1796_oversampling(chip); +} + static void update_pcm1796_volume(struct oxygen *chip) { struct xonar_pcm179x *data = chip->model_data; @@ -526,26 +570,44 @@ static void update_pcm1796_mute(struct oxygen *chip) pcm1796_write_cached(chip, i, 18, value); } -static void set_cs2000_params(struct oxygen *chip, - struct snd_pcm_hw_params *params) +static void update_cs2000_rate(struct oxygen *chip, unsigned int rate) { - /* XXX Why is the I2S A MCLK half the actual I2S multich MCLK? */ - static const u8 rate_mclks[] = { - [OXYGEN_RATE_32000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_128, - [OXYGEN_RATE_44100] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128, - [OXYGEN_RATE_48000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128, - [OXYGEN_RATE_64000] = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256, - [OXYGEN_RATE_88200] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, - [OXYGEN_RATE_96000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, - [OXYGEN_RATE_176400] = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256, - [OXYGEN_RATE_192000] = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256, - }; - unsigned int rate_index; + struct xonar_pcm179x *data = chip->model_data; u8 rate_mclk, reg; - rate_index = oxygen_read16(chip, OXYGEN_I2S_MULTICH_FORMAT) - & OXYGEN_I2S_RATE_MASK; - rate_mclk = rate_mclks[rate_index]; + switch (rate) { + /* XXX Why is the I2S A MCLK half the actual I2S MCLK? */ + case 32000: + rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; + break; + case 44100: + if (data->os_128) + rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; + else + rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_128; + break; + default: /* 48000 */ + if (data->os_128) + rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; + else + rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_128; + break; + case 64000: + rate_mclk = OXYGEN_RATE_32000 | OXYGEN_I2S_MCLK_256; + break; + case 88200: + rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; + break; + case 96000: + rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; + break; + case 176400: + rate_mclk = OXYGEN_RATE_44100 | OXYGEN_I2S_MCLK_256; + break; + case 192000: + rate_mclk = OXYGEN_RATE_48000 | OXYGEN_I2S_MCLK_256; + break; + } oxygen_write16_masked(chip, OXYGEN_I2S_A_FORMAT, rate_mclk, OXYGEN_I2S_RATE_MASK | OXYGEN_I2S_MCLK_MASK); if ((rate_mclk & OXYGEN_I2S_MCLK_MASK) <= OXYGEN_I2S_MCLK_128) @@ -558,7 +620,7 @@ static void set_cs2000_params(struct oxygen *chip, static void set_st_params(struct oxygen *chip, struct snd_pcm_hw_params *params) { - set_cs2000_params(chip, params); + update_cs2000_rate(chip, params_rate(params)); set_pcm1796_params(chip, params); } @@ -580,6 +642,59 @@ static const struct snd_kcontrol_new alt_switch = { .private_value = GPIO_D2_ALT, }; +static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { "64x", "128x" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int os_128_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + + value->value.enumerated.item[0] = data->os_128; + return 0; +} + +static int os_128_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + int changed; + + mutex_lock(&chip->mutex); + changed = value->value.enumerated.item[0] != data->os_128; + if (changed) { + data->os_128 = value->value.enumerated.item[0]; + if (data->has_cs2000) + update_cs2000_rate(chip, data->current_rate); + oxygen_write16_masked(chip, OXYGEN_I2S_MULTICH_FORMAT, + mclk_from_rate(chip, data->current_rate), + OXYGEN_I2S_MCLK_MASK); + update_pcm1796_oversampling(chip); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new os_128_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Oversampling Playback Enum", + .info = os_128_info, + .get = os_128_get, + .put = os_128_put, +}; + static int st_output_switch_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { @@ -745,7 +860,20 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) static int xonar_d2_mixer_init(struct oxygen *chip) { - return snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); + int err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + if (err < 0) + return err; + return 0; +} + +static int xonar_hdav_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); } static int xonar_st_mixer_init(struct oxygen *chip) @@ -759,6 +887,9 @@ static int xonar_st_mixer_init(struct oxygen *chip) if (err < 0) return err; } + err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + if (err < 0) + return err; return 0; } @@ -771,7 +902,7 @@ static const struct oxygen_model model_xonar_d2 = { .cleanup = xonar_d2_cleanup, .suspend = xonar_d2_suspend, .resume = xonar_d2_resume, - .get_i2s_mclk = oxygen_default_i2s_mclk, + .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_pcm1796_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -798,11 +929,12 @@ static const struct oxygen_model model_xonar_hdav = { .longname = "Asus Virtuoso 200", .chip = "AV200", .init = xonar_hdav_init, + .mixer_init = xonar_hdav_mixer_init, .cleanup = xonar_hdav_cleanup, .suspend = xonar_hdav_suspend, .resume = xonar_hdav_resume, .pcm_hardware_filter = xonar_hdmi_pcm_hardware_filter, - .get_i2s_mclk = oxygen_default_i2s_mclk, + .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_hdav_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, @@ -833,7 +965,7 @@ static const struct oxygen_model model_xonar_st = { .cleanup = xonar_st_cleanup, .suspend = xonar_st_suspend, .resume = xonar_st_resume, - .get_i2s_mclk = oxygen_default_i2s_mclk, + .get_i2s_mclk = get_pcm1796_i2s_mclk, .set_dac_params = set_st_params, .set_adc_params = xonar_set_cs53x1_params, .update_dac_volume = update_pcm1796_volume, -- cgit v1.2.3 From 4852ad02476ab2bbc874f6f8fda9e677e0f09c87 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:21:21 +0200 Subject: sound: oxygen: add digital filter control Add a control to select between sharp and slow roll-of filter responses of the DACs. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 65 ++++++++++++++++++++++++++++++ sound/pci/oxygen/xonar_cs43xx.c | 82 +++++++++++++++++++++++++++++++++++--- sound/pci/oxygen/xonar_pcm179x.c | 85 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 223 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index d12fd9efe94e..3ad9eb00aebd 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -352,6 +352,70 @@ static void set_ak5385_params(struct oxygen *chip, value, GPIO_AK5385_DFS_MASK); } +static int rolloff_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { + "Sharp Roll-off", "Slow Roll-off" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int rolloff_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct generic_data *data = chip->model_data; + + value->value.enumerated.item[0] = + (data->ak4396_regs[0][AK4396_CONTROL_2] & AK4396_SLOW) != 0; + return 0; +} + +static int rolloff_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct generic_data *data = chip->model_data; + unsigned int i; + int changed; + u8 reg; + + mutex_lock(&chip->mutex); + reg = data->ak4396_regs[0][AK4396_CONTROL_2]; + if (value->value.enumerated.item[0]) + reg |= AK4396_SLOW; + else + reg &= ~AK4396_SLOW; + changed = reg != data->ak4396_regs[0][AK4396_CONTROL_2]; + if (changed) { + for (i = 0; i < 4; ++i) + ak4396_write(chip, i, AK4396_CONTROL_2, reg); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new rolloff_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Filter Playback Enum", + .info = rolloff_info, + .get = rolloff_get, + .put = rolloff_put, +}; + +static int generic_mixer_init(struct oxygen *chip) +{ + return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); +} + static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); static const struct oxygen_model model_generic = { @@ -359,6 +423,7 @@ static const struct oxygen_model model_generic = { .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", .init = generic_init, + .mixer_init = generic_mixer_init, .cleanup = generic_cleanup, .resume = generic_resume, .get_i2s_mclk = oxygen_default_i2s_mclk, diff --git a/sound/pci/oxygen/xonar_cs43xx.c b/sound/pci/oxygen/xonar_cs43xx.c index a83f827feb34..16c226bfcd2b 100644 --- a/sound/pci/oxygen/xonar_cs43xx.c +++ b/sound/pci/oxygen/xonar_cs43xx.c @@ -69,7 +69,7 @@ struct xonar_cs43xx { struct xonar_generic generic; - u8 cs4398_regs[7]; + u8 cs4398_regs[8]; u8 cs4362a_regs[15]; }; @@ -121,12 +121,11 @@ static void cs43xx_registers_init(struct oxygen *chip) cs4398_write(chip, 4, data->cs4398_regs[4]); cs4398_write(chip, 5, data->cs4398_regs[5]); cs4398_write(chip, 6, data->cs4398_regs[6]); - cs4398_write(chip, 7, CS4398_RMP_DN | CS4398_RMP_UP | - CS4398_ZERO_CROSS | CS4398_SOFT_RAMP); + cs4398_write(chip, 7, data->cs4398_regs[7]); cs4362a_write(chip, 0x02, CS4362A_DIF_LJUST); cs4362a_write(chip, 0x03, CS4362A_MUTEC_6 | CS4362A_AMUTE | CS4362A_RMP_UP | CS4362A_ZERO_CROSS | CS4362A_SOFT_RAMP); - cs4362a_write(chip, 0x04, CS4362A_RMP_DN | CS4362A_DEM_NONE); + cs4362a_write(chip, 0x04, data->cs4362a_regs[0x04]); cs4362a_write(chip, 0x05, 0); for (i = 6; i <= 14; ++i) cs4362a_write(chip, i, data->cs4362a_regs[i]); @@ -147,6 +146,9 @@ static void xonar_d1_init(struct oxygen *chip) CS4398_MUTE_B | CS4398_MUTE_A | CS4398_PAMUTE; data->cs4398_regs[5] = 60 * 2; data->cs4398_regs[6] = 60 * 2; + data->cs4398_regs[7] = CS4398_RMP_DN | CS4398_RMP_UP | + CS4398_ZERO_CROSS | CS4398_SOFT_RAMP; + data->cs4362a_regs[4] = CS4362A_RMP_DN | CS4362A_DEM_NONE; data->cs4362a_regs[6] = CS4362A_FM_SINGLE | CS4362A_ATAPI_B_R | CS4362A_ATAPI_A_L; data->cs4362a_regs[7] = 60 | CS4362A_MUTE; @@ -286,6 +288,68 @@ static const struct snd_kcontrol_new front_panel_switch = { .private_value = GPIO_D1_FRONT_PANEL, }; +static int rolloff_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { + "Fast Roll-off", "Slow Roll-off" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int rolloff_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_cs43xx *data = chip->model_data; + + value->value.enumerated.item[0] = + (data->cs4398_regs[7] & CS4398_FILT_SEL) != 0; + return 0; +} + +static int rolloff_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_cs43xx *data = chip->model_data; + int changed; + u8 reg; + + mutex_lock(&chip->mutex); + reg = data->cs4398_regs[7]; + if (value->value.enumerated.item[0]) + reg |= CS4398_FILT_SEL; + else + reg &= ~CS4398_FILT_SEL; + changed = reg != data->cs4398_regs[7]; + if (changed) { + cs4398_write(chip, 7, reg); + if (reg & CS4398_FILT_SEL) + reg = data->cs4362a_regs[0x04] | CS4362A_FILT_SEL; + else + reg = data->cs4362a_regs[0x04] & ~CS4362A_FILT_SEL; + cs4362a_write(chip, 0x04, reg); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new rolloff_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Filter Playback Enum", + .info = rolloff_info, + .get = rolloff_get, + .put = rolloff_put, +}; + static void xonar_d1_line_mic_ac97_switch(struct oxygen *chip, unsigned int reg, unsigned int mute) { @@ -309,7 +373,15 @@ static int xonar_d1_control_filter(struct snd_kcontrol_new *template) static int xonar_d1_mixer_init(struct oxygen *chip) { - return snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); + int err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&front_panel_switch, chip)); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); + if (err < 0) + return err; + return 0; } static const struct oxygen_model model_xonar_d1 = { diff --git a/sound/pci/oxygen/xonar_pcm179x.c b/sound/pci/oxygen/xonar_pcm179x.c index 7f153fb1848d..ba18fb546b4f 100644 --- a/sound/pci/oxygen/xonar_pcm179x.c +++ b/sound/pci/oxygen/xonar_pcm179x.c @@ -265,7 +265,8 @@ static void pcm1796_registers_init(struct oxygen *chip) + gain_offset); pcm1796_write(chip, i, 17, chip->dac_volume[i * 2 + 1] + gain_offset); - pcm1796_write(chip, i, 19, PCM1796_FLT_SHARP | PCM1796_ATS_1); + pcm1796_write(chip, i, 19, + data->pcm1796_regs[0][19 - PCM1796_REG_BASE]); pcm1796_write(chip, i, 20, data->pcm1796_regs[0][20 - PCM1796_REG_BASE]); pcm1796_write(chip, i, 21, 0); @@ -278,6 +279,8 @@ static void pcm1796_init(struct oxygen *chip) data->pcm1796_regs[0][18 - PCM1796_REG_BASE] = PCM1796_MUTE | PCM1796_DMF_DISABLED | PCM1796_FMT_24_LJUST | PCM1796_ATLD; + data->pcm1796_regs[0][19 - PCM1796_REG_BASE] = + PCM1796_FLT_SHARP | PCM1796_ATS_1; data->pcm1796_regs[0][20 - PCM1796_REG_BASE] = PCM1796_OS_64; pcm1796_registers_init(chip); data->current_rate = 48000; @@ -642,6 +645,67 @@ static const struct snd_kcontrol_new alt_switch = { .private_value = GPIO_D2_ALT, }; +static int rolloff_info(struct snd_kcontrol *ctl, + struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { + "Sharp Roll-off", "Slow Roll-off" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int rolloff_get(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + + value->value.enumerated.item[0] = + (data->pcm1796_regs[0][19 - PCM1796_REG_BASE] & + PCM1796_FLT_MASK) != PCM1796_FLT_SHARP; + return 0; +} + +static int rolloff_put(struct snd_kcontrol *ctl, + struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct xonar_pcm179x *data = chip->model_data; + unsigned int i; + int changed; + u8 reg; + + mutex_lock(&chip->mutex); + reg = data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; + reg &= ~PCM1796_FLT_MASK; + if (!value->value.enumerated.item[0]) + reg |= PCM1796_FLT_SHARP; + else + reg |= PCM1796_FLT_SLOW; + changed = reg != data->pcm1796_regs[0][19 - PCM1796_REG_BASE]; + if (changed) { + for (i = 0; i < data->dacs; ++i) + pcm1796_write(chip, i, 19, reg); + } + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new rolloff_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "DAC Filter Playback Enum", + .info = rolloff_info, + .get = rolloff_get, + .put = rolloff_put, +}; + static int os_128_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) { static const char *const names[2] = { "64x", "128x" }; @@ -858,6 +922,19 @@ static int xonar_st_control_filter(struct snd_kcontrol_new *template) return 0; } +static int add_pcm1796_controls(struct oxygen *chip) +{ + int err; + + err = snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + if (err < 0) + return err; + return 0; +} + static int xonar_d2_mixer_init(struct oxygen *chip) { int err; @@ -865,7 +942,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) err = snd_ctl_add(chip->card, snd_ctl_new1(&alt_switch, chip)); if (err < 0) return err; - err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + err = add_pcm1796_controls(chip); if (err < 0) return err; return 0; @@ -873,7 +950,7 @@ static int xonar_d2_mixer_init(struct oxygen *chip) static int xonar_hdav_mixer_init(struct oxygen *chip) { - return snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + return add_pcm1796_controls(chip); } static int xonar_st_mixer_init(struct oxygen *chip) @@ -887,7 +964,7 @@ static int xonar_st_mixer_init(struct oxygen *chip) if (err < 0) return err; } - err = snd_ctl_add(chip->card, snd_ctl_new1(&os_128_control, chip)); + err = add_pcm1796_controls(chip); if (err < 0) return err; return 0; -- cgit v1.2.3 From 1ff048869eb8e8408856e23b3dc6af094491f837 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:21:51 +0200 Subject: sound: oxygen: add high-pass filter control Add a control that allows disabling the high-pass filter of the WM8785 ADC. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen.c | 73 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index 3ad9eb00aebd..acbedebcffd9 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c @@ -98,7 +98,7 @@ MODULE_DEVICE_TABLE(pci, oxygen_ids); struct generic_data { u8 ak4396_regs[4][5]; - u16 wm8785_regs[1]; + u16 wm8785_regs[3]; }; static void ak4396_write(struct oxygen *chip, unsigned int codec, @@ -184,6 +184,7 @@ static void wm8785_registers_init(struct oxygen *chip) wm8785_write(chip, WM8785_R7, 0); wm8785_write(chip, WM8785_R0, data->wm8785_regs[0]); + wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]); } static void wm8785_init(struct oxygen *chip) @@ -192,6 +193,7 @@ static void wm8785_init(struct oxygen *chip) data->wm8785_regs[0] = WM8785_MCR_SLAVE | WM8785_OSR_SINGLE | WM8785_FORMAT_LJUST; + data->wm8785_regs[2] = WM8785_HPFR | WM8785_HPFL; wm8785_registers_init(chip); snd_component_add(chip->card, "WM8785"); } @@ -334,6 +336,7 @@ static void set_wm8785_params(struct oxygen *chip, if (value != data->wm8785_regs[0]) { wm8785_write(chip, WM8785_R7, 0); wm8785_write(chip, WM8785_R0, value); + wm8785_write(chip, WM8785_R2, data->wm8785_regs[2]); } } @@ -411,11 +414,75 @@ static const struct snd_kcontrol_new rolloff_control = { .put = rolloff_put, }; +static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) +{ + static const char *const names[2] = { + "None", "High-pass Filter" + }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item >= 2) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct generic_data *data = chip->model_data; + + value->value.enumerated.item[0] = + (data->wm8785_regs[WM8785_R2] & WM8785_HPFR) != 0; + return 0; +} + +static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) +{ + struct oxygen *chip = ctl->private_data; + struct generic_data *data = chip->model_data; + unsigned int reg; + int changed; + + mutex_lock(&chip->mutex); + reg = data->wm8785_regs[WM8785_R2] & ~(WM8785_HPFR | WM8785_HPFL); + if (value->value.enumerated.item[0]) + reg |= WM8785_HPFR | WM8785_HPFL; + changed = reg != data->wm8785_regs[WM8785_R2]; + if (changed) + wm8785_write(chip, WM8785_R2, reg); + mutex_unlock(&chip->mutex); + return changed; +} + +static const struct snd_kcontrol_new hpf_control = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "ADC Filter Capture Enum", + .info = hpf_info, + .get = hpf_get, + .put = hpf_put, +}; + static int generic_mixer_init(struct oxygen *chip) { return snd_ctl_add(chip->card, snd_ctl_new1(&rolloff_control, chip)); } +static int generic_wm8785_mixer_init(struct oxygen *chip) +{ + int err; + + err = generic_mixer_init(chip); + if (err < 0) + return err; + err = snd_ctl_add(chip->card, snd_ctl_new1(&hpf_control, chip)); + if (err < 0) + return err; + return 0; +} + static const DECLARE_TLV_DB_LINEAR(ak4396_db_scale, TLV_DB_GAIN_MUTE, 0); static const struct oxygen_model model_generic = { @@ -423,7 +490,7 @@ static const struct oxygen_model model_generic = { .longname = "C-Media Oxygen HD Audio", .chip = "CMI8788", .init = generic_init, - .mixer_init = generic_mixer_init, + .mixer_init = generic_wm8785_mixer_init, .cleanup = generic_cleanup, .resume = generic_resume, .get_i2s_mclk = oxygen_default_i2s_mclk, @@ -455,6 +522,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, switch (id->driver_data) { case MODEL_MERIDIAN: chip->model.init = meridian_init; + chip->model.mixer_init = generic_mixer_init; chip->model.resume = meridian_resume; chip->model.set_adc_params = set_ak5385_params; chip->model.device_config = PLAYBACK_0_TO_I2S | @@ -470,6 +538,7 @@ static int __devinit get_oxygen_model(struct oxygen *chip, break; case MODEL_CLARO_HALO: chip->model.init = claro_halo_init; + chip->model.mixer_init = generic_mixer_init; chip->model.cleanup = claro_cleanup; chip->model.suspend = claro_suspend; chip->model.resume = claro_resume; -- cgit v1.2.3 From 62428f7b8c873d43be8201e66392c3aad82fec93 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 28 Sep 2009 11:22:18 +0200 Subject: sound: oxygen: fix input monitor control names Insert "Playback" into the input monitor control names to prevent alsa-lib from treating these controls as global controls. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/pci/oxygen/oxygen_mixer.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 5dfb5fb73381..f375b8a27862 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c @@ -805,7 +805,7 @@ static const struct { .controls = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Switch", + .name = "Analog Input Monitor Playback Switch", .info = snd_ctl_boolean_mono_info, .get = monitor_get, .put = monitor_put, @@ -813,7 +813,7 @@ static const struct { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Volume", + .name = "Analog Input Monitor Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = monitor_volume_info, @@ -830,7 +830,7 @@ static const struct { .controls = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Switch", + .name = "Analog Input Monitor Playback Switch", .info = snd_ctl_boolean_mono_info, .get = monitor_get, .put = monitor_put, @@ -838,7 +838,7 @@ static const struct { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Volume", + .name = "Analog Input Monitor Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = monitor_volume_info, @@ -855,7 +855,7 @@ static const struct { .controls = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Switch", + .name = "Analog Input Monitor Playback Switch", .index = 1, .info = snd_ctl_boolean_mono_info, .get = monitor_get, @@ -864,7 +864,7 @@ static const struct { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Input Monitor Volume", + .name = "Analog Input Monitor Playback Volume", .index = 1, .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, @@ -882,7 +882,7 @@ static const struct { .controls = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Monitor Switch", + .name = "Digital Input Monitor Playback Switch", .info = snd_ctl_boolean_mono_info, .get = monitor_get, .put = monitor_put, @@ -890,7 +890,7 @@ static const struct { }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Digital Input Monitor Volume", + .name = "Digital Input Monitor Playback Volume", .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, .info = monitor_volume_info, -- cgit v1.2.3 From 71623855e20c3febebb5fa60528cde2592678bd5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 28 Sep 2009 13:14:04 +0200 Subject: ALSA: hda - Enable MSI as default Since the recent kernel can handle MSI properly on non-Intel platforms, let's enable MSI as default. If any borken device is found, we can add the quirk entry to the list, which is currently empty. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index c9ad182e1b4b..d0effa3563e2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -60,7 +60,7 @@ 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 single_cmd; -static int enable_msi; +static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER static char *patch[SNDRV_CARDS]; #endif @@ -2300,11 +2300,9 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) } /* - * white-list for enable_msi + * white/black-list for enable_msi */ -static struct snd_pci_quirk msi_white_list[] __devinitdata = { - SND_PCI_QUIRK(0x103c, 0x30f7, "HP Pavilion dv4t-1300", 1), - SND_PCI_QUIRK(0x103c, 0x3607, "HP Compa CQ40", 1), +static struct snd_pci_quirk msi_black_list[] __devinitdata = { {} }; @@ -2312,10 +2310,12 @@ static void __devinit check_msi(struct azx *chip) { const struct snd_pci_quirk *q; - chip->msi = enable_msi; - if (chip->msi) + if (enable_msi >= 0) { + chip->msi = !!enable_msi; return; - q = snd_pci_quirk_lookup(chip->pci, msi_white_list); + } + 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", -- cgit v1.2.3 From acd47100914b2896d0699febefd077f85c4dd272 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 1 Oct 2009 00:10:34 +0200 Subject: ALSA: sscape: convert to firmware loader framework The conversion solves the problem that firmware size was set to 64KB while non PnP cards have 128KB firmware files. An additional firmware initialization code has been moved from the OSS driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/Kconfig | 8 +- sound/isa/sscape.c | 328 +++++++++++++++++------------------------------------ 2 files changed, 112 insertions(+), 224 deletions(-) (limited to 'sound') diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index b90fc164a79c..02fe81ca88fd 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig @@ -372,9 +372,9 @@ config SND_SGALAXY config SND_SSCAPE tristate "Ensoniq SoundScape driver" - select SND_HWDEP select SND_MPU401_UART select SND_WSS_LIB + select FW_LOADER help Say Y here to include support for Ensoniq SoundScape and Ensoniq OEM soundcards. @@ -382,7 +382,11 @@ config SND_SSCAPE The PCM audio is supported on SoundScape Classic, Elite, PnP and VIVO cards. The supported OEM cards are SPEA Media FX and Reveal SC-600. - The MIDI support is very experimental. + The MIDI support is very experimental and requires binary + firmware files called "scope.cod" and "sndscape.co?" where the + ? is digit 0, 1, 2, 3 or 4. The firmware files can be found + in DOS or Windows driver packages. One has to put the firmware + files into the /lib/firmware directory. To compile this driver as a module, choose M here: the module will be called snd-sscape. diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index b11c35f6aefe..1ce465cc66a8 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -1,5 +1,5 @@ /* - * Low-level ALSA driver for the ENSONIQ SoundScape PnP + * Low-level ALSA driver for the ENSONIQ SoundScape * Copyright (c) by Chris Rankin * * This driver was written in part using information obtained from @@ -25,22 +25,26 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include -#include - MODULE_AUTHOR("Chris Rankin"); -MODULE_DESCRIPTION("ENSONIQ SoundScape PnP driver"); +MODULE_DESCRIPTION("ENSONIQ SoundScape driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE("sndscape.co0"); +MODULE_FIRMWARE("sndscape.co1"); +MODULE_FIRMWARE("sndscape.co2"); +MODULE_FIRMWARE("sndscape.co3"); +MODULE_FIRMWARE("sndscape.co4"); +MODULE_FIRMWARE("scope.cod"); static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; @@ -142,14 +146,12 @@ struct soundscape { struct resource *wss_res; struct snd_wss *chip; struct snd_mpu401 *mpu; - struct snd_hwdep *hw; /* * The MIDI device won't work until we've loaded * its firmware via a hardware-dependent device IOCTL */ spinlock_t fwlock; - int hw_in_use; unsigned long midi_usage; unsigned char midi_vol; }; @@ -167,12 +169,6 @@ static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu) return (struct soundscape *) (mpu->private_data); } -static inline struct soundscape *get_hwdep_soundscape(struct snd_hwdep * hw) -{ - return (struct soundscape *) (hw->private_data); -} - - /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to @@ -393,12 +389,12 @@ static int obp_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); - if ((x & 0xfe) == 0xfe) + if (x == 0xfe || x == 0xff) return 1; msleep(10); @@ -420,10 +416,10 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) do { unsigned long flags; - unsigned char x; + int x; spin_lock_irqsave(&s->lock, flags); - x = inb(HOST_DATA_IO(s->io_base)); + x = host_read_unsafe(s->io_base); spin_unlock_irqrestore(&s->lock, flags); if (x == 0xfe) return 1; @@ -438,14 +434,14 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) * Upload a byte-stream into the SoundScape using DMA channel A. */ static int upload_dma_data(struct soundscape *s, - const unsigned char __user *data, + const unsigned char *data, size_t size) { unsigned long flags; struct snd_dma_buffer dma; int ret; - if (!get_dmabuf(&dma, PAGE_ALIGN(size))) + if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; spin_lock_irqsave(&s->lock, flags); @@ -458,7 +454,6 @@ static int upload_dma_data(struct soundscape *s, /* * Enable the DMA channels and configure them ... */ - sscape_write_unsafe(s->io_base, GA_DMACFG_REG, 0x50); sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT); sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); @@ -468,35 +463,17 @@ static int upload_dma_data(struct soundscape *s, sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80); /* - * Upload the user's data (firmware?) to the SoundScape + * Upload the firmware to the SoundScape * board through the DMA channel ... */ while (size != 0) { unsigned long len; - /* - * Apparently, copying to/from userspace can sleep. - * We are therefore forbidden from holding any - * spinlocks while we copy ... - */ - spin_unlock_irqrestore(&s->lock, flags); - - /* - * Remember that the data that we want to DMA - * comes from USERSPACE. We have already verified - * the userspace pointer ... - */ len = min(size, dma.bytes); - len -= __copy_from_user(dma.area, data, len); + memcpy(dma.area, data, len); data += len; size -= len; - /* - * Grab that spinlock again, now that we've - * finished copying! - */ - spin_lock_irqsave(&s->lock, flags); - snd_dma_program(s->chip->dma1, dma.addr, len, DMA_MODE_WRITE); sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { @@ -512,6 +489,7 @@ static int upload_dma_data(struct soundscape *s, } /* while */ set_host_mode_unsafe(s->io_base); + outb(0x0, s->io_base); /* * Boot the board ... (I think) @@ -537,7 +515,7 @@ _release_dma: /* * NOTE!!! We are NOT holding any spinlocks at this point !!! */ - sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_ODIE ? 0x70 : 0x40)); + sscape_write(s, GA_DMAA_REG, (s->ic_type == IC_OPUS ? 0x40 : 0x70)); free_dmabuf(&dma); return ret; @@ -547,162 +525,69 @@ _release_dma: * Upload the bootblock(?) into the SoundScape. The only * purpose of this block of code seems to be to tell * us which version of the microcode we should be using. - * - * NOTE: The boot-block data resides in USER-SPACE!!! - * However, we have already verified its memory - * addresses by the time we get here. */ -static int sscape_upload_bootblock(struct soundscape *sscape, struct sscape_bootblock __user *bb) +static int sscape_upload_bootblock(struct snd_card *card) { + struct soundscape *sscape = get_card_soundscape(card); unsigned long flags; + const struct firmware *init_fw = NULL; int data = 0; int ret; - ret = upload_dma_data(sscape, bb->code, sizeof(bb->code)); - - spin_lock_irqsave(&sscape->lock, flags); - if (ret == 0) { - data = host_read_ctrl_unsafe(sscape->io_base, 100); - } - set_midi_mode_unsafe(sscape->io_base); - spin_unlock_irqrestore(&sscape->lock, flags); - - if (ret == 0) { - if (data < 0) { - snd_printk(KERN_ERR "sscape: timeout reading firmware version\n"); - ret = -EAGAIN; - } - else if (__copy_to_user(&bb->version, &data, sizeof(bb->version))) { - ret = -EFAULT; - } + ret = request_firmware(&init_fw, "scope.cod", card->dev); + if (ret < 0) { + snd_printk(KERN_ERR "Error loading scope.cod"); + return ret; } + ret = upload_dma_data(sscape, init_fw->data, init_fw->size); - return ret; -} + release_firmware(init_fw); -/* - * Upload the microcode into the SoundScape. The - * microcode is 64K of data, and if we try to copy - * it into a local variable then we will SMASH THE - * KERNEL'S STACK! We therefore leave it in USER - * SPACE, and save ourselves from copying it at all. - */ -static int sscape_upload_microcode(struct soundscape *sscape, - const struct sscape_microcode __user *mc) -{ - unsigned long flags; - char __user *code; - int err; - - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now. - * - * NOTE: This buffer is 64K long! That's WAY too big to - * copy into a stack-temporary anyway. - */ - if ( get_user(code, &mc->code) || - !access_ok(VERIFY_READ, code, SSCAPE_MICROCODE_SIZE) ) - return -EFAULT; + spin_lock_irqsave(&sscape->lock, flags); + if (ret == 0) + data = host_read_ctrl_unsafe(sscape->io_base, 100); - if ((err = upload_dma_data(sscape, code, SSCAPE_MICROCODE_SIZE)) == 0) { - snd_printk(KERN_INFO "sscape: MIDI firmware loaded\n"); - } + if (data & 0x10) + sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2f); - spin_lock_irqsave(&sscape->lock, flags); - set_midi_mode_unsafe(sscape->io_base); spin_unlock_irqrestore(&sscape->lock, flags); - initialise_mpu401(sscape->mpu); + data &= 0xf; + if (ret == 0 && data > 7) { + snd_printk(KERN_ERR "timeout reading firmware version\n"); + ret = -EAGAIN; + } - return err; + return (ret == 0) ? data : ret; } /* - * Hardware-specific device functions, to implement special - * IOCTLs for the SoundScape card. This is how we upload - * the microcode into the card, for example, and so we - * must ensure that no two processes can open this device - * simultaneously, and that we can't open it at all if - * someone is using the MIDI device. + * Upload the microcode into the SoundScape. */ -static int sscape_hw_open(struct snd_hwdep * hw, struct file *file) +static int sscape_upload_microcode(struct snd_card *card, int version) { - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; + struct soundscape *sscape = get_card_soundscape(card); + const struct firmware *init_fw = NULL; + char name[14]; int err; - spin_lock_irqsave(&sscape->fwlock, flags); + snprintf(name, sizeof(name), "sndscape.co%d", version); - if ((sscape->midi_usage != 0) || sscape->hw_in_use) { - err = -EBUSY; - } else { - sscape->hw_in_use = 1; - err = 0; + err = request_firmware(&init_fw, name, card->dev); + if (err < 0) { + snd_printk(KERN_ERR "Error loading sndscape.co%d", version); + return err; } + err = upload_dma_data(sscape, init_fw->data, init_fw->size); + if (err == 0) + snd_printk(KERN_INFO "MIDI firmware loaded %d KBs\n", + init_fw->size >> 10); - spin_unlock_irqrestore(&sscape->fwlock, flags); - return err; -} - -static int sscape_hw_release(struct snd_hwdep * hw, struct file *file) -{ - register struct soundscape *sscape = get_hwdep_soundscape(hw); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - sscape->hw_in_use = 0; - spin_unlock_irqrestore(&sscape->fwlock, flags); - return 0; -} - -static int sscape_hw_ioctl(struct snd_hwdep * hw, struct file *file, - unsigned int cmd, unsigned long arg) -{ - struct soundscape *sscape = get_hwdep_soundscape(hw); - int err = -EBUSY; - - switch (cmd) { - case SND_SSCAPE_LOAD_BOOTB: - { - register struct sscape_bootblock __user *bb = (struct sscape_bootblock __user *) arg; - - /* - * We are going to have to copy this data into a special - * DMA-able buffer before we can upload it. We shall therefore - * just check that the data pointer is valid for now ... - */ - if ( !access_ok(VERIFY_READ, bb->code, sizeof(bb->code)) ) - return -EFAULT; - - /* - * Now check that we can write the firmware version number too... - */ - if ( !access_ok(VERIFY_WRITE, &bb->version, sizeof(bb->version)) ) - return -EFAULT; - - err = sscape_upload_bootblock(sscape, bb); - } - break; - - case SND_SSCAPE_LOAD_MCODE: - { - register const struct sscape_microcode __user *mc = (const struct sscape_microcode __user *) arg; - - err = sscape_upload_microcode(sscape, mc); - } - break; - - default: - err = -EINVAL; - break; - } /* switch */ + release_firmware(init_fw); return err; } - /* * Mixer control for the SoundScape's MIDI device. */ @@ -920,7 +805,7 @@ static int mpu401_open(struct snd_mpu401 * mpu) spin_lock_irqsave(&sscape->fwlock, flags); - if (sscape->hw_in_use || (sscape->midi_usage == ULONG_MAX)) { + if (sscape->midi_usage == ULONG_MAX) { err = -EBUSY; } else { ++(sscape->midi_usage); @@ -1053,13 +938,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, } } - strcpy(card->driver, "SoundScape"); - strcpy(card->shortname, pcm->name); - snprintf(card->longname, sizeof(card->longname), - "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", - pcm->name, chip->port, chip->irq, - chip->dma1, chip->dma2); - sscape->chip = chip; } @@ -1162,29 +1040,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) return -ENXIO; } - if (sscape->type != SSCAPE_VIVO) { - /* - * Now create the hardware-specific device so that we can - * load the microcode into the on-board processor. - * We cannot use the MPU-401 MIDI system until this firmware - * has been loaded into the card. - */ - err = snd_hwdep_new(card, "MC68EC000", 0, &(sscape->hw)); - if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " - "firmware device\n"); - goto _release_dma; - } - strlcpy(sscape->hw->name, "SoundScape M68K", - sizeof(sscape->hw->name)); - sscape->hw->name[sizeof(sscape->hw->name) - 1] = '\0'; - sscape->hw->iface = SNDRV_HWDEP_IFACE_SSCAPE; - sscape->hw->ops.open = sscape_hw_open; - sscape->hw->ops.release = sscape_hw_release; - sscape->hw->ops.ioctl = sscape_hw_ioctl; - sscape->hw->private_data = sscape; - } - /* * Tell the on-board devices where their resources are (I think - * I can't be sure without a datasheet ... So many magic values!) @@ -1222,28 +1077,56 @@ static int __devinit create_sscape(int dev, struct snd_card *card) wss_port[dev], irq[dev]); goto _release_dma; } + strcpy(card->driver, "SoundScape"); + strcpy(card->shortname, name); + snprintf(card->longname, sizeof(card->longname), + "%s at 0x%lx, IRQ %d, DMA1 %d, DMA2 %d\n", + name, sscape->chip->port, sscape->chip->irq, + sscape->chip->dma1, sscape->chip->dma2); + #define MIDI_DEVNUM 0 if (sscape->type != SSCAPE_VIVO) { - err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]); - if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " - "MPU-401 device at 0x%lx\n", - port[dev]); - goto _release_dma; - } + err = sscape_upload_bootblock(card); + if (err >= 0) + err = sscape_upload_microcode(card, err); - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); - - /* - * Initialize mixer - */ - sscape->midi_vol = 0; - host_write_ctrl_unsafe(sscape->io_base, CMD_SET_MIDI_VOL, 100); - host_write_ctrl_unsafe(sscape->io_base, 0, 100); - host_write_ctrl_unsafe(sscape->io_base, CMD_XXX_MIDI_VOL, 100); + if (err == 0) { + err = create_mpu401(card, MIDI_DEVNUM, port[dev], + mpu_irq[dev]); + if (err < 0) { + printk(KERN_ERR "sscape: Failed to create " + "MPU-401 device at 0x%lx\n", + port[dev]); + goto _release_dma; + } + + /* + * Enable the master IRQ ... + */ + sscape_write(sscape, GA_INTENA_REG, 0x80); + + /* + * Initialize mixer + */ + spin_lock_irqsave(&sscape->lock, flags); + sscape->midi_vol = 0; + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_XXX_MIDI_VOL, 100); + host_write_ctrl_unsafe(sscape->io_base, + sscape->midi_vol, 100); + host_write_ctrl_unsafe(sscape->io_base, + CMD_SET_EXTMIDI, 100); + host_write_ctrl_unsafe(sscape->io_base, + 0, 100); + host_write_ctrl_unsafe(sscape->io_base, CMD_ACK, 100); + + set_midi_mode_unsafe(sscape->io_base); + spin_unlock_irqrestore(&sscape->lock, flags); + } } /* @@ -1301,11 +1184,12 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) sscape->type = SSCAPE; dma[dev] &= 0x03; + snd_card_set_dev(card, pdev); + ret = create_sscape(dev, card); if (ret < 0) goto _release_card; - snd_card_set_dev(card, pdev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; @@ -1426,12 +1310,12 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, wss_port[idx] = pnp_port_start(dev, 1); dma2[idx] = pnp_dma(dev, 1); } + snd_card_set_dev(card, &pcard->card->dev); ret = create_sscape(idx, card); if (ret < 0) goto _release_card; - snd_card_set_dev(card, &pcard->card->dev); if ((ret = snd_card_register(card)) < 0) { printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; -- cgit v1.2.3 From 0afe5f891501609f31146798fb41784f4adad27c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 2 Oct 2009 09:20:00 +0200 Subject: ALSA: hda - Clean up name string creation in patch_realtek.c Use a common helper to create playback controls. This gives less chance of typos. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 137 ++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 80 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7810d3dcad83..a751858811e1 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4309,6 +4309,20 @@ static int add_control(struct alc_spec *spec, int type, const char *name, return 0; } +static int add_control_with_pfx(struct alc_spec *spec, int type, + const char *pfx, const char *dir, + const char *sfx, unsigned long val) +{ + char name[32]; + snprintf(name, sizeof(name), "%s %s %s", pfx, dir, sfx); + return add_control(spec, type, name, val); +} + +#define add_pb_vol_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Volume", val) +#define add_pb_sw_ctrl(spec, type, pfx, val) \ + add_control_with_pfx(spec, type, pfx, "Playback", "Switch", val) + #define alc880_is_fixed_pin(nid) ((nid) >= 0x14 && (nid) <= 0x17) #define alc880_fixed_pin_idx(nid) ((nid) - 0x14) #define alc880_is_multi_pin(nid) ((nid) >= 0x18) @@ -4362,7 +4376,6 @@ static int alc880_auto_fill_dac_nids(struct alc_spec *spec, static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - char name[32]; static const char *chname[4] = { "Front", "Surround", NULL /*CLFE*/, "Side" }; @@ -4375,26 +4388,26 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, nid = alc880_idx_to_mixer(alc880_dac_to_idx(spec->multiout.dac_nids[i])); if (i == 2) { /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", HDA_COMPOSE_AMP_VAL(nid, 1, 2, HDA_INPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", HDA_COMPOSE_AMP_VAL(nid, 2, 2, HDA_INPUT)); if (err < 0) @@ -4406,14 +4419,12 @@ static int alc880_auto_create_multi_out_ctls(struct alc_spec *spec, pfx = "Speaker"; else pfx = chname[i]; - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); if (err < 0) @@ -4429,7 +4440,6 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, { hda_nid_t nid; int err; - char name[32]; if (!pin) return 0; @@ -4443,21 +4453,18 @@ static int alc880_auto_create_extra_out(struct alc_spec *spec, hda_nid_t pin, spec->multiout.extra_out_nid[0] = nid; /* control HP volume/switch on the output mixer amp */ nid = alc880_idx_to_mixer(alc880_fixed_pin_idx(pin)); - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid, 3, 2, HDA_INPUT)); if (err < 0) return err; } else if (alc880_is_multi_pin(pin)) { /* set manual connection */ /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -4470,16 +4477,13 @@ static int new_analog_input(struct alc_spec *spec, hda_nid_t pin, const char *ctlname, int idx, hda_nid_t mix_nid) { - char name[32]; int err; - sprintf(name, "%s Playback Volume", ctlname); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", ctlname); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; @@ -5972,7 +5976,6 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, { hda_nid_t nid_vol; unsigned long vol_val, sw_val; - char name[32]; int err; if (nid >= 0x0f && nid < 0x11) { @@ -5992,14 +5995,12 @@ static int alc260_add_playback_controls(struct alc_spec *spec, hda_nid_t nid, if (!(*vol_bits & (1 << nid_vol))) { /* first control for the volume widget */ - snprintf(name, sizeof(name), "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, vol_val); + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, vol_val); if (err < 0) return err; *vol_bits |= (1 << nid_vol); } - snprintf(name, sizeof(name), "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, sw_val); + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, sw_val); if (err < 0) return err; return 1; @@ -10936,7 +10937,6 @@ static int alc262_check_volbit(hda_nid_t nid) static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, const char *pfx, int *vbits) { - char name[32]; unsigned long val; int vbit; @@ -10946,28 +10946,25 @@ static int alc262_add_out_vol_ctl(struct alc_spec *spec, hda_nid_t nid, if (*vbits & vbit) /* a volume control for this mixer already there */ return 0; *vbits |= vbit; - snprintf(name, sizeof(name), "%s Playback Volume", pfx); if (vbit == 2) val = HDA_COMPOSE_AMP_VAL(0x0e, 2, 0, HDA_OUTPUT); else val = HDA_COMPOSE_AMP_VAL(0x0c, 3, 0, HDA_OUTPUT); - return add_control(spec, ALC_CTL_WIDGET_VOL, name, val); + return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, val); } static int alc262_add_out_sw_ctl(struct alc_spec *spec, hda_nid_t nid, const char *pfx) { - char name[32]; unsigned long val; if (!nid) return 0; - snprintf(name, sizeof(name), "%s Playback Switch", pfx); if (nid == 0x16) val = HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT); else val = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_OUTPUT); - return add_control(spec, ALC_CTL_WIDGET_MUTE, name, val); + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, val); } /* add playback controls from the parsed DAC table */ @@ -12305,11 +12302,9 @@ static struct snd_kcontrol_new alc268_test_mixer[] = { static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, const char *ctlname, int idx) { - char name[32]; hda_nid_t dac; int err; - sprintf(name, "%s Playback Volume", ctlname); switch (nid) { case 0x14: case 0x16: @@ -12323,7 +12318,7 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, } if (spec->multiout.dac_nids[0] != dac && spec->multiout.dac_nids[1] != dac) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, ctlname, HDA_COMPOSE_AMP_VAL(dac, 3, idx, HDA_OUTPUT)); if (err < 0) @@ -12331,12 +12326,11 @@ static int alc268_new_analog_output(struct alc_spec *spec, hda_nid_t nid, spec->multiout.dac_nids[spec->multiout.num_dacs++] = dac; } - sprintf(name, "%s Playback Switch", ctlname); if (nid != 0x16) - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, HDA_COMPOSE_AMP_VAL(nid, 3, idx, HDA_OUTPUT)); else /* mono */ - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, ctlname, HDA_COMPOSE_AMP_VAL(nid, 2, idx, HDA_OUTPUT)); if (err < 0) return err; @@ -12366,8 +12360,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, nid = cfg->speaker_pins[0]; if (nid == 0x1d) { - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Speaker Playback Volume", + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, "Speaker", HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT)); if (err < 0) return err; @@ -12385,8 +12378,7 @@ static int alc268_auto_create_multi_out_ctls(struct alc_spec *spec, nid = cfg->line_out_pins[1] | cfg->line_out_pins[2]; if (nid == 0x16) { - err = add_control(spec, ALC_CTL_WIDGET_MUTE, - "Mono Playback Switch", + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, "Mono", HDA_COMPOSE_AMP_VAL(nid, 2, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -14235,9 +14227,7 @@ static int alc861_auto_fill_dac_nids(struct hda_codec *codec, static int alc861_create_out_sw(struct hda_codec *codec, const char *pfx, hda_nid_t nid, unsigned int chs) { - char name[32]; - snprintf(name, sizeof(name), "%s Playback Switch", pfx); - return add_control(codec->spec, ALC_CTL_WIDGET_MUTE, name, + return add_pb_sw_ctrl(codec->spec, ALC_CTL_WIDGET_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } @@ -15360,7 +15350,6 @@ static void alc861vd_auto_init_analog_input(struct hda_codec *codec) static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, const struct auto_pin_cfg *cfg) { - char name[32]; static const char *chname[4] = {"Front", "Surround", "CLFE", "Side"}; hda_nid_t nid_v, nid_s; int i, err; @@ -15377,26 +15366,26 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, if (i == 2) { /* Center/LFE */ - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "Center Playback Volume", + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "Center", HDA_COMPOSE_AMP_VAL(nid_v, 1, 0, HDA_OUTPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_WIDGET_VOL, - "LFE Playback Volume", + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, + "LFE", HDA_COMPOSE_AMP_VAL(nid_v, 2, 0, HDA_OUTPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "Center Playback Switch", + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "Center", HDA_COMPOSE_AMP_VAL(nid_s, 1, 2, HDA_INPUT)); if (err < 0) return err; - err = add_control(spec, ALC_CTL_BIND_MUTE, - "LFE Playback Switch", + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, + "LFE", HDA_COMPOSE_AMP_VAL(nid_s, 2, 2, HDA_INPUT)); if (err < 0) @@ -15411,8 +15400,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, pfx = "PCM"; } else pfx = chname[i]; - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); if (err < 0) @@ -15420,8 +15408,7 @@ static int alc861vd_auto_create_multi_out_ctls(struct alc_spec *spec, if (cfg->line_outs == 1 && cfg->line_out_type == AUTO_PIN_SPEAKER_OUT) pfx = "Speaker"; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); if (err < 0) @@ -15439,7 +15426,6 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec, { hda_nid_t nid_v, nid_s; int err; - char name[32]; if (!pin) return 0; @@ -15457,21 +15443,18 @@ static int alc861vd_auto_create_extra_out(struct alc_spec *spec, nid_s = alc861vd_idx_to_mixer_switch( alc880_fixed_pin_idx(pin)); - sprintf(name, "%s Playback Volume", pfx); - err = add_control(spec, ALC_CTL_WIDGET_VOL, name, + err = add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, HDA_COMPOSE_AMP_VAL(nid_v, 3, 0, HDA_OUTPUT)); if (err < 0) return err; - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_BIND_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_BIND_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid_s, 3, 2, HDA_INPUT)); if (err < 0) return err; } else if (alc880_is_multi_pin(pin)) { /* set manual connection */ /* we have only a switch on HP-out PIN */ - sprintf(name, "%s Playback Switch", pfx); - err = add_control(spec, ALC_CTL_WIDGET_MUTE, name, + err = add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -17213,21 +17196,17 @@ static int alc662_auto_fill_dac_nids(struct hda_codec *codec, return 0; } -static int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, +static inline int alc662_add_vol_ctl(struct alc_spec *spec, const char *pfx, hda_nid_t nid, unsigned int chs) { - char name[32]; - sprintf(name, "%s Playback Volume", pfx); - return add_control(spec, ALC_CTL_WIDGET_VOL, name, + return add_pb_vol_ctrl(spec, ALC_CTL_WIDGET_VOL, pfx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT)); } -static int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, +static inline int alc662_add_sw_ctl(struct alc_spec *spec, const char *pfx, hda_nid_t nid, unsigned int chs) { - char name[32]; - sprintf(name, "%s Playback Switch", pfx); - return add_control(spec, ALC_CTL_WIDGET_MUTE, name, + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT)); } @@ -17305,13 +17284,11 @@ static int alc662_auto_create_extra_out(struct hda_codec *codec, hda_nid_t pin, return 0; nid = alc662_look_for_dac(codec, pin); if (!nid) { - char name[32]; /* the corresponding DAC is already occupied */ if (!(get_wcaps(codec, pin) & AC_WCAP_OUT_AMP)) return 0; /* no way */ /* create a switch only */ - sprintf(name, "%s Playback Switch", pfx); - return add_control(spec, ALC_CTL_WIDGET_MUTE, name, + return add_pb_sw_ctrl(spec, ALC_CTL_WIDGET_MUTE, pfx, HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); } -- cgit v1.2.3 From bcde1f8a80d1bdfd43fb498996dfa89666fd7fe3 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 2 Oct 2009 18:41:29 +0200 Subject: ALSA: sscape: remove MIDI instances counting with limit ULONG_MAX There is no sense to limit open MIDI connections with limit as high as ULONG_MAX. Also, convert more messages to use the snd_printk. Correct few old and misleading comments as well. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/sscape.c | 101 +++++++++++++++-------------------------------------- 1 file changed, 29 insertions(+), 72 deletions(-) (limited to 'sound') diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 1ce465cc66a8..c739374af20e 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -147,12 +147,6 @@ struct soundscape { struct snd_wss *chip; struct snd_mpu401 *mpu; - /* - * The MIDI device won't work until we've loaded - * its firmware via a hardware-dependent device IOCTL - */ - spinlock_t fwlock; - unsigned long midi_usage; unsigned char midi_vol; }; @@ -164,11 +158,6 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) return (struct soundscape *) (c->private_data); } -static inline struct soundscape *get_mpu401_soundscape(struct snd_mpu401 * mpu) -{ - return (struct soundscape *) (mpu->private_data); -} - /* * Allocates some kernel memory that we can use for DMA. * I think this means that the memory has to map to @@ -179,7 +168,9 @@ static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned lo if (buf) { if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), size, buf) < 0) { - snd_printk(KERN_ERR "sscape: Failed to allocate %lu bytes for DMA\n", size); + snd_printk(KERN_ERR "sscape: Failed to allocate " + "%lu bytes for DMA\n", + size); return NULL; } } @@ -482,7 +473,8 @@ static int upload_dma_data(struct soundscape *s, */ spin_unlock_irqrestore(&s->lock, flags); - snd_printk(KERN_ERR "sscape: DMA upload has timed out\n"); + snd_printk(KERN_ERR + "sscape: DMA upload has timed out\n"); ret = -EAGAIN; goto _release_dma; } @@ -504,10 +496,12 @@ static int upload_dma_data(struct soundscape *s, */ ret = 0; if (!obp_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: No response from on-board processor after upload\n"); + snd_printk(KERN_ERR "sscape: No response " + "from on-board processor after upload\n"); ret = -EAGAIN; } else if (!host_startup_ack(s, 5000)) { - snd_printk(KERN_ERR "sscape: SoundScape failed to initialise\n"); + snd_printk(KERN_ERR + "sscape: SoundScape failed to initialise\n"); ret = -EAGAIN; } @@ -536,7 +530,7 @@ static int sscape_upload_bootblock(struct snd_card *card) ret = request_firmware(&init_fw, "scope.cod", card->dev); if (ret < 0) { - snd_printk(KERN_ERR "Error loading scope.cod"); + snd_printk(KERN_ERR "sscape: Error loading scope.cod"); return ret; } ret = upload_dma_data(sscape, init_fw->data, init_fw->size); @@ -554,7 +548,8 @@ static int sscape_upload_bootblock(struct snd_card *card) data &= 0xf; if (ret == 0 && data > 7) { - snd_printk(KERN_ERR "timeout reading firmware version\n"); + snd_printk(KERN_ERR + "sscape: timeout reading firmware version\n"); ret = -EAGAIN; } @@ -575,12 +570,13 @@ static int sscape_upload_microcode(struct snd_card *card, int version) err = request_firmware(&init_fw, name, card->dev); if (err < 0) { - snd_printk(KERN_ERR "Error loading sndscape.co%d", version); + snd_printk(KERN_ERR "sscape: Error loading sndscape.co%d", + version); return err; } err = upload_dma_data(sscape, init_fw->data, init_fw->size); if (err == 0) - snd_printk(KERN_INFO "MIDI firmware loaded %d KBs\n", + snd_printk(KERN_INFO "sscape: MIDI firmware loaded %d KBs\n", init_fw->size >> 10); release_firmware(init_fw); @@ -750,7 +746,6 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) msleep(1); spin_lock_irqsave(&s->lock, flags); } - snd_printd(KERN_INFO "init delay = %d ms\n", d); if ((inb(wss_io) & 0x80) != 0) goto _done; @@ -774,7 +769,6 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) msleep(1); spin_lock_irqsave(&s->lock, flags); } - snd_printd(KERN_INFO "init delay = %d ms\n", d); /* * SoundScape successfully detected! @@ -794,38 +788,13 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) */ static int mpu401_open(struct snd_mpu401 * mpu) { - int err; - if (!verify_mpu401(mpu)) { - snd_printk(KERN_ERR "sscape: MIDI disabled, please load firmware\n"); - err = -ENODEV; - } else { - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - - if (sscape->midi_usage == ULONG_MAX) { - err = -EBUSY; - } else { - ++(sscape->midi_usage); - err = 0; - } - - spin_unlock_irqrestore(&sscape->fwlock, flags); + snd_printk(KERN_ERR "sscape: MIDI disabled, " + "please load firmware\n"); + return -ENODEV; } - return err; -} - -static void mpu401_close(struct snd_mpu401 * mpu) -{ - register struct soundscape *sscape = get_mpu401_soundscape(mpu); - unsigned long flags; - - spin_lock_irqsave(&sscape->fwlock, flags); - --(sscape->midi_usage); - spin_unlock_irqrestore(&sscape->fwlock, flags); + return 0; } /* @@ -845,8 +814,6 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; - mpu->close_input = mpu401_close; - mpu->close_output = mpu401_close; mpu->private_data = sscape; sscape->mpu = mpu; @@ -993,13 +960,13 @@ static int __devinit create_sscape(int dev, struct snd_card *card) } spin_lock_init(&sscape->lock); - spin_lock_init(&sscape->fwlock); sscape->io_res = io_res; sscape->wss_res = wss_res; sscape->io_base = port[dev]; if (!detect_sscape(sscape, wss_port[dev])) { - printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", sscape->io_base); + printk(KERN_ERR "sscape: hardware not detected at 0x%x\n", + sscape->io_base); err = -ENODEV; goto _release_dma; } @@ -1036,7 +1003,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card) mpu_irq_cfg = get_irq_config(sscape->type, mpu_irq[dev]); if (mpu_irq_cfg == INVALID_IRQ) { - printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); + snd_printk(KERN_ERR "sscape: Invalid IRQ %d\n", mpu_irq[dev]); return -ENXIO; } @@ -1073,8 +1040,9 @@ static int __devinit create_sscape(int dev, struct snd_card *card) err = create_ad1845(card, wss_port[dev], irq[dev], dma[dev], dma2[dev]); if (err < 0) { - printk(KERN_ERR "sscape: No AD1845 device at 0x%lx, IRQ %d\n", - wss_port[dev], irq[dev]); + snd_printk(KERN_ERR + "sscape: No AD1845 device at 0x%lx, IRQ %d\n", + wss_port[dev], irq[dev]); goto _release_dma; } strcpy(card->driver, "SoundScape"); @@ -1094,7 +1062,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card) err = create_mpu401(card, MIDI_DEVNUM, port[dev], mpu_irq[dev]); if (err < 0) { - printk(KERN_ERR "sscape: Failed to create " + snd_printk(KERN_ERR "sscape: Failed to create " "MPU-401 device at 0x%lx\n", port[dev]); goto _release_dma; @@ -1191,7 +1159,7 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) goto _release_card; if ((ret = snd_card_register(card)) < 0) { - printk(KERN_ERR "sscape: Failed to register sound card\n"); + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } dev_set_drvdata(pdev, card); @@ -1250,18 +1218,7 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, * We have found a candidate ISA PnP card. Now we * have to check that it has the devices that we * expect it to have. - * - * We will NOT try and autoconfigure all of the resources - * needed and then activate the card as we are assuming that - * has already been done at boot-time using /proc/isapnp. - * We shall simply try to give each active card the resources - * that it wants. This is a sensible strategy for a modular - * system where unused modules are unloaded regularly. - * - * This strategy is utterly useless if we compile the driver - * into the kernel, of course. */ - // printk(KERN_INFO "sscape: %s\n", card->name); /* * Check that we still have room for another sound card ... @@ -1272,7 +1229,7 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, if (!pnp_is_active(dev)) { if (pnp_activate_dev(dev) < 0) { - printk(KERN_INFO "sscape: device is inactive\n"); + snd_printk(KERN_INFO "sscape: device is inactive\n"); return -EBUSY; } } @@ -1317,7 +1274,7 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, goto _release_card; if ((ret = snd_card_register(card)) < 0) { - printk(KERN_ERR "sscape: Failed to register sound card\n"); + snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } -- cgit v1.2.3 From 1cb0fdebae08f6daaac81197d8dde1746e0a1d96 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 5 Oct 2009 18:18:57 +0200 Subject: ALSA: sscape: force AD1848 codec mode on old Soundscape Old Soundscape cards (pre PnP) work only with AD1848 codecs. If the CS4231 codec is installed it must be used in AD1848 compatible mode. Also, add gameport support and remove an unused mpu field. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/sscape.c | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index c739374af20e..279be505b72e 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -54,6 +54,7 @@ static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; +static bool joystick[SNDRV_CARDS] __devinitdata; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); @@ -79,6 +80,9 @@ MODULE_PARM_DESC(dma, "DMA # for SoundScape driver."); module_param_array(dma2, int, NULL, 0444); MODULE_PARM_DESC(dma2, "DMA2 # for SoundScape driver."); +module_param_array(joystick, bool, NULL, 0444); +MODULE_PARM_DESC(joystick, "Enable gameport."); + #ifdef CONFIG_PNP static int isa_registered; static int pnp_registered; @@ -145,7 +149,6 @@ struct soundscape { struct resource *io_res; struct resource *wss_res; struct snd_wss *chip; - struct snd_mpu401 *mpu; unsigned char midi_vol; }; @@ -815,7 +818,6 @@ static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned l mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; mpu->private_data = sscape; - sscape->mpu = mpu; initialise_mpu401(mpu); } @@ -836,12 +838,30 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, register struct soundscape *sscape = get_card_soundscape(card); struct snd_wss *chip; int err; + int codec_type = WSS_HW_DETECT; + + switch (sscape->type) { + case MEDIA_FX: + case SSCAPE: + /* + * There are some freak examples of early Soundscape cards + * with CS4231 instead of AD1848/CS4248. Unfortunately, the + * CS4231 works only in CS4248 compatibility mode on + * these cards so force it. + */ + if (sscape->ic_type != IC_OPUS) + codec_type = WSS_HW_AD1848; + break; - if (sscape->type == SSCAPE_VIVO) + case SSCAPE_VIVO: port += 4; + break; + default: + break; + } err = snd_wss_create(card, port, -1, irq, dma1, dma2, - WSS_HW_DETECT, WSS_HWSHARE_DMA1, &chip); + codec_type, WSS_HWSHARE_DMA1, &chip); if (!err) { unsigned long flags; struct snd_pcm *pcm; @@ -927,6 +947,7 @@ static int __devinit create_sscape(int dev, struct snd_card *card) struct resource *wss_res; unsigned long flags; int err; + int val; const char *name; /* @@ -1026,6 +1047,10 @@ static int __devinit create_sscape(int dev, struct snd_card *card) sscape_write_unsafe(sscape->io_base, GA_DMAB_REG, 0x20); mpu_irq_cfg |= mpu_irq_cfg << 2; + val = sscape_read_unsafe(sscape->io_base, GA_HMCTL_REG) & 0xF7; + if (joystick[dev]) + val |= 8; + sscape_write_unsafe(sscape->io_base, GA_HMCTL_REG, val | 0x10); sscape_write_unsafe(sscape->io_base, GA_INTCFG_REG, 0xf0 | mpu_irq_cfg); sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, 0x09 | DMA_8BIT -- cgit v1.2.3 From ed76f652d5329d9dff0ea7f3953b1357ed7f8e6e Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 5 Oct 2009 18:27:28 +0200 Subject: ALSA: sscape - Remove invalid __devinitdata to module parameters Module parameters shouldn't be marked as __devinitdata since they can be referred via sysfs even after probing. Signed-off-by: Takashi Iwai --- sound/isa/sscape.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 279be505b72e..579a59b9e470 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -46,15 +46,15 @@ MODULE_FIRMWARE("sndscape.co3"); MODULE_FIRMWARE("sndscape.co4"); MODULE_FIRMWARE("scope.cod"); -static int index[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IDX; -static char* id[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_STR; -static long port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; -static long wss_port[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_PORT; -static int irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; -static int mpu_irq[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_IRQ; -static int dma[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; -static int dma2[SNDRV_CARDS] __devinitdata = SNDRV_DEFAULT_DMA; -static bool joystick[SNDRV_CARDS] __devinitdata; +static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; +static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; +static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; +static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; +static int dma[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; +static bool joystick[SNDRV_CARDS]; module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index number for SoundScape soundcard"); -- cgit v1.2.3 From 6fcfa3959a5f5ecb7c333f54f401575d94eb8172 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 10 Oct 2009 10:27:58 +0200 Subject: ALSA: sscape: coding style fixes Fix coding style errors in the driver. Also, add missing argument for CMD_XXX_MIDI_VOL command. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/sscape.c | 169 ++++++++++++++++++++++++++--------------------------- 1 file changed, 83 insertions(+), 86 deletions(-) (limited to 'sound') diff --git a/sound/isa/sscape.c b/sound/isa/sscape.c index 579a59b9e470..e2d5d2d3ed96 100644 --- a/sound/isa/sscape.c +++ b/sound/isa/sscape.c @@ -109,14 +109,14 @@ MODULE_DEVICE_TABLE(pnp_card, sscape_pnpids); #define RX_READY 0x01 #define TX_READY 0x02 -#define CMD_ACK 0x80 -#define CMD_SET_MIDI_VOL 0x84 -#define CMD_GET_MIDI_VOL 0x85 -#define CMD_XXX_MIDI_VOL 0x86 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d +#define CMD_ACK 0x80 +#define CMD_SET_MIDI_VOL 0x84 +#define CMD_GET_MIDI_VOL 0x85 +#define CMD_XXX_MIDI_VOL 0x86 +#define CMD_SET_EXTMIDI 0x8a +#define CMD_GET_EXTMIDI 0x8b +#define CMD_SET_MT32 0x8c +#define CMD_GET_MT32 0x8d enum GA_REG { GA_INTSTAT_REG = 0, @@ -166,10 +166,12 @@ static inline struct soundscape *get_card_soundscape(struct snd_card *c) * I think this means that the memory has to map to * contiguous pages of physical memory. */ -static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, unsigned long size) +static struct snd_dma_buffer *get_dmabuf(struct snd_dma_buffer *buf, + unsigned long size) { if (buf) { - if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, snd_dma_isa_data(), + if (snd_dma_alloc_pages_fallback(SNDRV_DMA_TYPE_DEV, + snd_dma_isa_data(), size, buf) < 0) { snd_printk(KERN_ERR "sscape: Failed to allocate " "%lu bytes for DMA\n", @@ -190,13 +192,13 @@ static void free_dmabuf(struct snd_dma_buffer *buf) snd_dma_free_pages(buf); } - /* * This function writes to the SoundScape's control registers, * but doesn't do any locking. It's up to the caller to do that. * This is why this function is "unsafe" ... */ -static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsigned char val) +static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, + unsigned char val) { outb(reg, ODIE_ADDR_IO(io_base)); outb(val, ODIE_DATA_IO(io_base)); @@ -206,7 +208,8 @@ static inline void sscape_write_unsafe(unsigned io_base, enum GA_REG reg, unsign * Write to the SoundScape's control registers, and do the * necessary locking ... */ -static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char val) +static void sscape_write(struct soundscape *s, enum GA_REG reg, + unsigned char val) { unsigned long flags; @@ -219,7 +222,8 @@ static void sscape_write(struct soundscape *s, enum GA_REG reg, unsigned char va * Read from the SoundScape's control registers, but leave any * locking to the caller. This is why the function is "unsafe" ... */ -static inline unsigned char sscape_read_unsafe(unsigned io_base, enum GA_REG reg) +static inline unsigned char sscape_read_unsafe(unsigned io_base, + enum GA_REG reg) { outb(reg, ODIE_ADDR_IO(io_base)); return inb(ODIE_DATA_IO(io_base)); @@ -248,9 +252,8 @@ static inline void set_midi_mode_unsafe(unsigned io_base) static inline int host_read_unsafe(unsigned io_base) { int data = -1; - if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) { + if ((inb(HOST_CTRL_IO(io_base)) & RX_READY) != 0) data = inb(HOST_DATA_IO(io_base)); - } return data; } @@ -292,7 +295,7 @@ static inline int host_write_unsafe(unsigned io_base, unsigned char data) * Also leaves all locking-issues to the caller ... */ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, - unsigned timeout) + unsigned timeout) { int err; @@ -311,7 +314,7 @@ static int host_write_ctrl_unsafe(unsigned io_base, unsigned char data, * * NOTE: This check is based upon observation, not documentation. */ -static inline int verify_mpu401(const struct snd_mpu401 * mpu) +static inline int verify_mpu401(const struct snd_mpu401 *mpu) { return ((inb(MPU401C(mpu)) & 0xc0) == 0x80); } @@ -319,7 +322,7 @@ static inline int verify_mpu401(const struct snd_mpu401 * mpu) /* * This is apparently the standard way to initailise an MPU-401 */ -static inline void initialise_mpu401(const struct snd_mpu401 * mpu) +static inline void initialise_mpu401(const struct snd_mpu401 *mpu) { outb(0, MPU401D(mpu)); } @@ -329,9 +332,10 @@ static inline void initialise_mpu401(const struct snd_mpu401 * mpu) * The AD1845 detection fails if we *don't* do this, so I * think that this is a good idea ... */ -static inline void activate_ad1845_unsafe(unsigned io_base) +static void activate_ad1845_unsafe(unsigned io_base) { - sscape_write_unsafe(io_base, GA_HMCTL_REG, (sscape_read_unsafe(io_base, GA_HMCTL_REG) & 0xcf) | 0x10); + unsigned char val = sscape_read_unsafe(io_base, GA_HMCTL_REG); + sscape_write_unsafe(io_base, GA_HMCTL_REG, (val & 0xcf) | 0x10); sscape_write_unsafe(io_base, GA_CDCFG_REG, 0x80); } @@ -350,24 +354,27 @@ static void soundscape_free(struct snd_card *c) * Tell the SoundScape to begin a DMA tranfer using the given channel. * All locking issues are left to the caller. */ -static inline void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) +static void sscape_start_dma_unsafe(unsigned io_base, enum GA_REG reg) { - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) | 0x01); - sscape_write_unsafe(io_base, reg, sscape_read_unsafe(io_base, reg) & 0xfe); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) | 0x01); + sscape_write_unsafe(io_base, reg, + sscape_read_unsafe(io_base, reg) & 0xfe); } /* * Wait for a DMA transfer to complete. This is a "limited busy-wait", * and all locking issues are left to the caller. */ -static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, unsigned timeout) +static int sscape_wait_dma_unsafe(unsigned io_base, enum GA_REG reg, + unsigned timeout) { while (!(sscape_read_unsafe(io_base, reg) & 0x01) && (timeout != 0)) { udelay(100); --timeout; } /* while */ - return (sscape_read_unsafe(io_base, reg) & 0x01); + return sscape_read_unsafe(io_base, reg) & 0x01; } /* @@ -427,13 +434,13 @@ static int host_startup_ack(struct soundscape *s, unsigned timeout) /* * Upload a byte-stream into the SoundScape using DMA channel A. */ -static int upload_dma_data(struct soundscape *s, - const unsigned char *data, - size_t size) +static int upload_dma_data(struct soundscape *s, const unsigned char *data, + size_t size) { unsigned long flags; struct snd_dma_buffer dma; int ret; + unsigned char val; if (!get_dmabuf(&dma, PAGE_ALIGN(32 * 1024))) return -ENOMEM; @@ -443,18 +450,21 @@ static int upload_dma_data(struct soundscape *s, /* * Reset the board ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val & 0x3f); /* * Enable the DMA channels and configure them ... */ - sscape_write_unsafe(s->io_base, GA_DMAA_REG, (s->chip->dma1 << 4) | DMA_8BIT); + val = (s->chip->dma1 << 4) | DMA_8BIT; + sscape_write_unsafe(s->io_base, GA_DMAA_REG, val); sscape_write_unsafe(s->io_base, GA_DMAB_REG, 0x20); /* * Take the board out of reset ... */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x80); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x80); /* * Upload the firmware to the SoundScape @@ -472,7 +482,7 @@ static int upload_dma_data(struct soundscape *s, sscape_start_dma_unsafe(s->io_base, GA_DMAA_REG); if (!sscape_wait_dma_unsafe(s->io_base, GA_DMAA_REG, 5000)) { /* - * Don't forget to release this spinlock we're holding ... + * Don't forget to release this spinlock we're holding */ spin_unlock_irqrestore(&s->lock, flags); @@ -489,7 +499,8 @@ static int upload_dma_data(struct soundscape *s, /* * Boot the board ... (I think) */ - sscape_write_unsafe(s->io_base, GA_HMCTL_REG, sscape_read_unsafe(s->io_base, GA_HMCTL_REG) | 0x40); + val = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); + sscape_write_unsafe(s->io_base, GA_HMCTL_REG, val | 0x40); spin_unlock_irqrestore(&s->lock, flags); /* @@ -591,7 +602,7 @@ static int sscape_upload_microcode(struct snd_card *card, int version) * Mixer control for the SoundScape's MIDI device. */ static int sscape_midi_info(struct snd_kcontrol *ctl, - struct snd_ctl_elem_info *uinfo) + struct snd_ctl_elem_info *uinfo) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 1; @@ -601,7 +612,7 @@ static int sscape_midi_info(struct snd_kcontrol *ctl, } static int sscape_midi_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; @@ -615,16 +626,18 @@ static int sscape_midi_get(struct snd_kcontrol *kctl, } static int sscape_midi_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *uctl) + struct snd_ctl_elem_value *uctl) { struct snd_wss *chip = snd_kcontrol_chip(kctl); struct snd_card *card = chip->card; - register struct soundscape *s = get_card_soundscape(card); + struct soundscape *s = get_card_soundscape(card); unsigned long flags; int change; + unsigned char new_val; spin_lock_irqsave(&s->lock, flags); + new_val = uctl->value.integer.value[0] & 127; /* * We need to put the board into HOST mode before we * can send any volume-changing HOST commands ... @@ -637,15 +650,16 @@ static int sscape_midi_put(struct snd_kcontrol *kctl, * and then perform another volume-related command. Perhaps the * first command is an "open" and the second command is a "close"? */ - if (s->midi_vol == ((unsigned char) uctl->value.integer. value[0] & 127)) { + if (s->midi_vol == new_val) { change = 0; goto __skip_change; } - change = (host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) - && host_write_ctrl_unsafe(s->io_base, ((unsigned char) uctl->value.integer. value[0]) & 127, 100) - && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100)); - s->midi_vol = (unsigned char) uctl->value.integer.value[0] & 127; - __skip_change: + change = host_write_ctrl_unsafe(s->io_base, CMD_SET_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100) + && host_write_ctrl_unsafe(s->io_base, CMD_XXX_MIDI_VOL, 100) + && host_write_ctrl_unsafe(s->io_base, new_val, 100); + s->midi_vol = new_val; +__skip_change: /* * Take the board out of HOST mode and back into MIDI mode ... @@ -738,7 +752,7 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) if (s->type == SSCAPE_VIVO) wss_io += 4; - d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ @@ -762,7 +776,7 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) if ((inb(wss_io) & 0x80) != 0) s->type = MEDIA_FX; - d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG) & 0x3f; + d = sscape_read_unsafe(s->io_base, GA_HMCTL_REG); sscape_write_unsafe(s->io_base, GA_HMCTL_REG, d | 0xc0); /* wait for WSS codec */ for (d = 0; d < 500; d++) { @@ -778,7 +792,7 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) */ retval = 1; - _done: +_done: spin_unlock_irqrestore(&s->lock, flags); return retval; } @@ -789,7 +803,7 @@ static int __devinit detect_sscape(struct soundscape *s, long wss_io) * to crash the machine. Also check that someone isn't using the hardware * IOCTL device. */ -static int mpu401_open(struct snd_mpu401 * mpu) +static int mpu401_open(struct snd_mpu401 *mpu) { if (!verify_mpu401(mpu)) { snd_printk(KERN_ERR "sscape: MIDI disabled, " @@ -803,18 +817,18 @@ static int mpu401_open(struct snd_mpu401 * mpu) /* * Initialse an MPU-401 subdevice for MIDI support on the SoundScape. */ -static int __devinit create_mpu401(struct snd_card *card, int devnum, unsigned long port, int irq) +static int __devinit create_mpu401(struct snd_card *card, int devnum, + unsigned long port, int irq) { struct soundscape *sscape = get_card_soundscape(card); struct snd_rawmidi *rawmidi; int err; - if ((err = snd_mpu401_uart_new(card, devnum, - MPU401_HW_MPU401, - port, MPU401_INFO_INTEGRATED, - irq, IRQF_DISABLED, - &rawmidi)) == 0) { - struct snd_mpu401 *mpu = (struct snd_mpu401 *) rawmidi->private_data; + err = snd_mpu401_uart_new(card, devnum, MPU401_HW_MPU401, port, + MPU401_INFO_INTEGRATED, irq, IRQF_DISABLED, + &rawmidi); + if (err == 0) { + struct snd_mpu401 *mpu = rawmidi->private_data; mpu->open_input = mpu401_open; mpu->open_output = mpu401_open; mpu->private_data = sscape; @@ -866,19 +880,6 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, unsigned long flags; struct snd_pcm *pcm; -/* - * It turns out that the PLAYBACK_ENABLE bit is set - * by the lowlevel driver ... - * -#define AD1845_IFACE_CONFIG \ - (CS4231_AUTOCALIB | CS4231_RECORD_ENABLE | CS4231_PLAYBACK_ENABLE) - snd_wss_mce_up(chip); - spin_lock_irqsave(&chip->reg_lock, flags); - snd_wss_out(chip, CS4231_IFACE_CTRL, AD1845_IFACE_CONFIG); - spin_unlock_irqrestore(&chip->reg_lock, flags); - snd_wss_mce_down(chip); - */ - if (sscape->type != SSCAPE_VIVO) { /* * The input clock frequency on the SoundScape must @@ -928,7 +929,7 @@ static int __devinit create_ad1845(struct snd_card *card, unsigned port, sscape->chip = chip; } - _error: +_error: return err; } @@ -1034,7 +1035,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) */ spin_lock_irqsave(&sscape->lock, flags); - sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x00); /* disable */ sscape_write_unsafe(sscape->io_base, GA_SMCFGA_REG, 0x2e); sscape_write_unsafe(sscape->io_base, GA_SMCFGB_REG, 0x00); @@ -1055,6 +1055,10 @@ static int __devinit create_sscape(int dev, struct snd_card *card) sscape_write_unsafe(sscape->io_base, GA_CDCFG_REG, 0x09 | DMA_8BIT | (dma[dev] << 4) | (irq_cfg << 1)); + /* + * Enable the master IRQ ... + */ + sscape_write_unsafe(sscape->io_base, GA_INTENA_REG, 0x80); spin_unlock_irqrestore(&sscape->lock, flags); @@ -1093,11 +1097,6 @@ static int __devinit create_sscape(int dev, struct snd_card *card) goto _release_dma; } - /* - * Enable the master IRQ ... - */ - sscape_write(sscape, GA_INTENA_REG, 0x80); - /* * Initialize mixer */ @@ -1155,7 +1154,8 @@ static int __devinit snd_sscape_match(struct device *pdev, unsigned int i) mpu_irq[i] == SNDRV_AUTO_IRQ || dma[i] == SNDRV_AUTO_DMA) { printk(KERN_INFO - "sscape: insufficient parameters, need IO, IRQ, MPU-IRQ and DMA\n"); + "sscape: insufficient parameters, " + "need IO, IRQ, MPU-IRQ and DMA\n"); return 0; } @@ -1183,7 +1183,8 @@ static int __devinit snd_sscape_probe(struct device *pdev, unsigned int dev) if (ret < 0) goto _release_card; - if ((ret = snd_card_register(card)) < 0) { + ret = snd_card_register(card); + if (ret < 0) { snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } @@ -1236,20 +1237,15 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, * Allow this function to fail *quietly* if all the ISA PnP * devices were configured using module parameters instead. */ - if ((idx = get_next_autoindex(idx)) >= SNDRV_CARDS) + idx = get_next_autoindex(idx); + if (idx >= SNDRV_CARDS) return -ENOSPC; - /* - * We have found a candidate ISA PnP card. Now we - * have to check that it has the devices that we - * expect it to have. - */ - /* * Check that we still have room for another sound card ... */ dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL); - if (! dev) + if (!dev) return -ENODEV; if (!pnp_is_active(dev)) { @@ -1298,7 +1294,8 @@ static int __devinit sscape_pnp_detect(struct pnp_card_link *pcard, if (ret < 0) goto _release_card; - if ((ret = snd_card_register(card)) < 0) { + ret = snd_card_register(card); + if (ret < 0) { snd_printk(KERN_ERR "sscape: Failed to register sound card\n"); goto _release_card; } -- cgit v1.2.3 From abd134db940ddccaf6a61d88cf0841a62b917ab3 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 10 Oct 2009 10:25:39 +0200 Subject: ALSA: wss: convert CS4231 mixer to dB scale Convert CS4231 mixer to dB scale after AD1848 mixer. Also, add missing microphone boost control for the AD1848 and correct wrong bits for loopback volume on the AD1848. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/wss/wss_lib.c | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) (limited to 'sound') diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5d2ba1b749ab..754a2089c650 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2198,6 +2198,7 @@ EXPORT_SYMBOL(snd_wss_put_double); static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); static struct snd_kcontrol_new snd_ad1848_controls[] = { WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, @@ -2224,38 +2225,45 @@ WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, .get = snd_wss_get_mux, .put = snd_wss_put_mux, }, +WSS_DOUBLE("Mic Boost", 0, + CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0, +WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, db_scale_6bit), }; static struct snd_kcontrol_new snd_wss_controls[] = { WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), WSS_DOUBLE("Line Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Aux Playback Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_SINGLE("Mono Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, - CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE_TLV("Mono Playback Volume", 0, + CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), WSS_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), WSS_SINGLE("Mono Output Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = "Capture Source", @@ -2267,15 +2275,16 @@ WSS_DOUBLE("Mic Boost", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE("Loopback Capture Volume", 0, - CS4231_LOOPBACK, 2, 63, 1) +WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, + db_scale_6bit), }; static struct snd_kcontrol_new snd_opti93x_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), -WSS_DOUBLE("Master Playback Volume", 0, - OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, + db_scale_6bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE("PCM Playback Volume", 0, -- cgit v1.2.3 From b6153e1175a46db9dde17d12609adba7d72330b9 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:23 +0800 Subject: ALSA: HDA VIA: Remove unused IS_VT17xx_VENDORID macro IS_VT17*_VENDORID macros are used nowhere, so clean them up. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 8 -------- 1 file changed, 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index ee89db90c9b6..9dfe1b55970c 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -76,14 +76,6 @@ #define VT1702_HP_NID 0x17 #define VT1702_DIGOUT_NID 0x11 -#define IS_VT1708_VENDORID(x) ((x) >= 0x11061708 && (x) <= 0x1106170b) -#define IS_VT1709_10CH_VENDORID(x) ((x) >= 0x1106e710 && (x) <= 0x1106e713) -#define IS_VT1709_6CH_VENDORID(x) ((x) >= 0x1106e714 && (x) <= 0x1106e717) -#define IS_VT1708B_8CH_VENDORID(x) ((x) >= 0x1106e720 && (x) <= 0x1106e723) -#define IS_VT1708B_4CH_VENDORID(x) ((x) >= 0x1106e724 && (x) <= 0x1106e727) -#define IS_VT1708S_VENDORID(x) ((x) >= 0x11060397 && (x) <= 0x11067397) -#define IS_VT1702_VENDORID(x) ((x) >= 0x11060398 && (x) <= 0x11067398) - enum VIA_HDA_CODEC { UNKNOWN = -1, VT1708, -- cgit v1.2.3 From 744ff5f487925223beb6e21460c8cec468b54ab4 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:26 +0800 Subject: ALSA: HDA VIA: Change get_codec_type argument to hda_codec type Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 9dfe1b55970c..e7d739f12247 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -88,8 +88,9 @@ enum VIA_HDA_CODEC { CODEC_TYPES, }; -static enum VIA_HDA_CODEC get_codec_type(u32 vendor_id) +static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) { + u32 vendor_id = codec->vendor_id; u16 ven_id = vendor_id >> 16; u16 dev_id = vendor_id & 0xffff; enum VIA_HDA_CODEC codec_type; @@ -141,7 +142,7 @@ static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = get_amp_nid(kcontrol); - if (get_codec_type(codec->vendor_id) == VT1708S + if (get_codec_type(codec) == VT1708S && (nid == 0x1a || nid == 0x1e)) { if (size < 4 * sizeof(unsigned int)) return -ENOMEM; @@ -163,7 +164,7 @@ static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); hda_nid_t nid = get_amp_nid(kcontrol); - if (get_codec_type(codec->vendor_id) == VT1708S + if (get_codec_type(codec) == VT1708S && (nid == 0x1a || nid == 0x1e)) { uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = 2; -- cgit v1.2.3 From 518bf3ba753ad93644e7c6cf95c043c918d9429b Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:29 +0800 Subject: ALSA: HDA VIA: Add VT1708B-CE codec support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e7d739f12247..4d9ffd6f190b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -84,6 +84,7 @@ enum VIA_HDA_CODEC { VT1708B_8CH, VT1708B_4CH, VT1708S, + VT1708BCE, VT1702, CODEC_TYPES, }; @@ -104,9 +105,11 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1709_10CH; else if (dev_id >= 0xe714 && dev_id <= 0xe717) codec_type = VT1709_6CH; - else if (dev_id >= 0xe720 && dev_id <= 0xe723) + else if (dev_id >= 0xe720 && dev_id <= 0xe723) { codec_type = VT1708B_8CH; - else if (dev_id >= 0xe724 && dev_id <= 0xe727) + if (snd_hda_param_read(codec, 0x16, AC_PAR_CONNLIST_LEN) == 0x7) + codec_type = VT1708BCE; + } else if (dev_id >= 0xe724 && dev_id <= 0xe727) codec_type = VT1708B_4CH; else if ((dev_id & 0xfff) == 0x397 && (dev_id >> 12) < 8) @@ -224,6 +227,8 @@ struct via_spec { const struct hda_input_mux *hp_mux; unsigned int hp_independent_mode; + enum VIA_HDA_CODEC codec_type; + #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; #endif @@ -979,6 +984,10 @@ static int via_init(struct hda_codec *codec) for (i = 0; i < spec->num_iverbs; i++) snd_hda_sequence_write(codec, spec->init_verbs[i]); + spec->codec_type = get_codec_type(codec); + if (spec->codec_type == VT1708BCE) + spec->codec_type = VT1708S; /* VT1708BCE & VT1708S are almost + same */ /* Lydia Add for EAPD enable */ if (!spec->dig_in_nid) { /* No Digital In connection */ if (spec->dig_in_pin) { @@ -2369,12 +2378,14 @@ static struct hda_amp_list vt1708B_loopbacks[] = { { } /* end */ }; #endif - +static int patch_vt1708S(struct hda_codec *codec); static int patch_vt1708B_8ch(struct hda_codec *codec) { struct via_spec *spec; int err; + if (get_codec_type(codec) == VT1708BCE) + return patch_vt1708S(codec); /* create a codec specific record */ spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -2906,6 +2917,16 @@ static int patch_vt1708S(struct hda_codec *codec) spec->loopback.amplist = vt1708S_loopbacks; #endif + /* correct names for VT1708BCE */ + if (get_codec_type(codec) == VT1708BCE) { + kfree(codec->chip_name); + codec->chip_name = kstrdup("VT1708BCE", GFP_KERNEL); + snprintf(codec->bus->card->mixername, + sizeof(codec->bus->card->mixername), + "%s %s", codec->vendor_name, codec->chip_name); + spec->stream_name_analog = "VT1708BCE Analog"; + spec->stream_name_digital = "VT1708BCE Digital"; + } return 0; } -- cgit v1.2.3 From c2c02ea326d3683f551120e74a297b354a223357 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:32 +0800 Subject: ALSA: HDA VIA: Limit VT1702 AA-Path max volume according to customer request, VT1702 AA-Path max volume (12 dB) is too high, so limit to 0 dB. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4d9ffd6f190b..e62698984287 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3166,6 +3166,12 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) err = vt1702_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); if (err < 0) return err; + /* limit AA path volume to 0 dB */ + snd_hda_override_amp_caps(codec, 0x1A, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x5 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); err = vt1702_auto_create_analog_input_ctls(spec, &spec->autocfg); if (err < 0) return err; -- cgit v1.2.3 From f5271101faf1655d862849f42518c2a88ef394fb Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:35 +0800 Subject: ALSA HDA VIA: Add VIA_CTL_WIDGET_ANALOG_MUTE control type Enter low power state if AA-Path volume is muted. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 240 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 239 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e62698984287..d6bee620ced6 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -128,6 +128,7 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) enum { VIA_CTL_WIDGET_VOL, VIA_CTL_WIDGET_MUTE, + VIA_CTL_WIDGET_ANALOG_MUTE, }; enum { @@ -177,9 +178,34 @@ static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, return 0; } +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); +static void set_jack_power_state(struct hda_codec *codec); + +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_jack_power_state(codec); + analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); + 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 struct snd_kcontrol_new vt1708_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), + ANALOG_INPUT_MUTE, }; @@ -303,7 +329,7 @@ static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, if (err < 0) return err; sprintf(name, "%s Playback Switch", ctlname); - err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, + err = via_add_control(spec, VIA_CTL_WIDGET_ANALOG_MUTE, name, HDA_COMPOSE_AMP_VAL(mix_nid, 3, idx, HDA_INPUT)); if (err < 0) return err; @@ -362,6 +388,131 @@ static void via_auto_init_analog_input(struct hda_codec *codec) } } + +static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, + unsigned int *affected_parm) +{ + unsigned parm; + unsigned def_conf = snd_hda_codec_get_pincfg(codec, nid); + unsigned no_presence = (def_conf & AC_DEFCFG_MISC) + >> AC_DEFCFG_MISC_SHIFT + & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ + unsigned present = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0) >> 31; + + if ((no_presence || present) && get_defcfg_connect(def_conf) + != AC_JACK_PORT_NONE) { + *affected_parm = AC_PWRST_D0; /* if it's connected */ + parm = AC_PWRST_D0; + } else + parm = AC_PWRST_D3; + + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, parm); +} + +static void set_jack_power_state(struct hda_codec *codec) +{ + struct via_spec *spec = codec->spec; + int imux_is_smixer; + unsigned int parm; + + if (spec->codec_type == VT1702) { + imux_is_smixer = snd_hda_codec_read( + codec, 0x13, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + /* inputs */ + /* PW 1/2/5 (14h/15h/18h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x14, &parm); + set_pin_power_state(codec, 0x15, &parm); + set_pin_power_state(codec, 0x18, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; /* SW0 = stereo mixer (idx 3) */ + /* SW0 (13h), AIW 0/1/2 (12h/1fh/20h) */ + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x12, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* outputs */ + /* PW 3/4 (16h/17h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x16, &parm); + set_pin_power_state(codec, 0x17, &parm); + /* MW0 (1ah), AOW 0/1 (10h/1dh) */ + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x1d, 0, AC_VERB_SET_POWER_STATE, + parm); + } else if (spec->codec_type == VT1708B_8CH + || spec->codec_type == VT1708B_4CH + || spec->codec_type == VT1708S) { + /* SW0 (17h) = stereo mixer */ + int is_8ch = spec->codec_type != VT1708B_4CH; + imux_is_smixer = snd_hda_codec_read( + codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) + == ((spec->codec_type == VT1708S) ? 5 : 0); + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW 0/1 (13h/14h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* PW6 (22h), SW2 (26h), AOW2 (24h) */ + if (is_8ch) { + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x22, &parm); + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x24, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* PW 3/4/7 (1ch/1dh/23h) */ + parm = AC_PWRST_D3; + /* force to D0 for internal Speaker */ + set_pin_power_state(codec, 0x1c, &parm); + set_pin_power_state(codec, 0x1d, &parm); + if (is_8ch) + set_pin_power_state(codec, 0x23, &parm); + /* MW0 (16h), Sw3 (27h), AOW 0/3 (10h/25h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + parm); + if (is_8ch) { + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x27, 0, + AC_VERB_SET_POWER_STATE, parm); + } + } +} + /* * input MUX handling */ @@ -504,6 +655,93 @@ static struct snd_kcontrol_new vt1708_capture_mixer[] = { }, { } /* end */ }; + +/* check AA path's mute statue */ +static int is_aa_path_mute(struct hda_codec *codec) +{ + int mute = 1; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; + int i; + struct via_spec *spec = codec->spec; + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + case VT1702: + nid_mixer = 0x1a; + start_idx = 1; + end_idx = 3; + break; + default: + return 0; + } + /* check AA path's mute status */ + for (i = start_idx; i <= end_idx; i++) { + unsigned int con_list = snd_hda_codec_read( + codec, nid_mixer, 0, AC_VERB_GET_CONNECT_LIST, i/4*4); + int shift = 8 * (i % 4); + hda_nid_t nid_pin = (con_list & (0xff << shift)) >> shift; + unsigned int defconf = snd_hda_codec_get_pincfg(codec, nid_pin); + if (get_defcfg_connect(defconf) == AC_JACK_PORT_COMPLEX) { + /* check mute status while the pin is connected */ + int mute_l = snd_hda_codec_amp_read(codec, nid_mixer, 0, + HDA_INPUT, i) >> 7; + int mute_r = snd_hda_codec_amp_read(codec, nid_mixer, 1, + HDA_INPUT, i) >> 7; + if (!mute_l || !mute_r) { + mute = 0; + break; + } + } + } + return mute; +} + +/* enter/exit analog low-current mode */ +static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) +{ + struct via_spec *spec = codec->spec; + static int saved_stream_idle = 1; /* saved stream idle status */ + int enable = is_aa_path_mute(codec); + unsigned int verb = 0; + unsigned int parm = 0; + + if (stream_idle == -1) /* stream status did not change */ + enable = enable && saved_stream_idle; + else { + enable = enable && stream_idle; + saved_stream_idle = stream_idle; + } + + /* decide low current mode's verb & parameter */ + switch (spec->codec_type) { + case VT1708B_8CH: + case VT1708B_4CH: + verb = 0xf70; + parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */ + break; + case VT1708S: + verb = 0xf73; + parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ + break; + case VT1702: + verb = 0xf73; + parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ + break; + default: + return; /* other codecs are not supported */ + } + /* send verb */ + snd_hda_codec_write(codec, codec->afg, 0, verb, parm); +} + /* * generic initialization of ADC, input mixers and output mixers */ -- cgit v1.2.3 From 173143791068ac9f155c378a591d0b3d6c4a45ca Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:37 +0800 Subject: ALSA: HDA VIA: Add low current mode for power saving. For VT1708B, VT1708S and VT1702, enter low current mode if no analog stream is opened and all aa path mute. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 41 +++++++++++++++++++++++++++++++++++------ 1 file changed, 35 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index d6bee620ced6..7ace0fca933d 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -783,6 +783,10 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + + analog_low_current_mode(codec, idle); return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); } @@ -1089,6 +1093,11 @@ static int via_build_controls(struct hda_codec *codec) if (err < 0) return err; } + + /* init power states */ + set_jack_power_state(codec); + analog_low_current_mode(codec, 1); + via_free_kctls(codec); /* no longer needed */ return 0; } @@ -2312,6 +2321,17 @@ static struct hda_verb vt1708B_uniwill_init_verbs[] = { { } }; +static int via_pcm_open_close(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + int idle = substream->pstr->substream_opened == 1 + && substream->ref_count == 0; + + analog_low_current_mode(codec, idle); + return 0; +} + static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { .substreams = 2, .channels_min = 2, @@ -2320,7 +2340,8 @@ static struct hda_pcm_stream vt1708B_8ch_pcm_analog_playback = { .ops = { .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close }, }; @@ -2342,8 +2363,10 @@ static struct hda_pcm_stream vt1708B_pcm_analog_capture = { .channels_max = 2, .nid = 0x13, /* NID to query formats and rates */ .ops = { + .open = via_pcm_open_close, .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close }, }; @@ -2800,7 +2823,8 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { .ops = { .open = via_playback_pcm_open, .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .cleanup = via_playback_pcm_cleanup, + .close = via_pcm_open_close }, }; @@ -2810,8 +2834,10 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { .channels_max = 2, .nid = 0x13, /* NID to query formats and rates */ .ops = { + .open = via_pcm_open_close, .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close }, }; @@ -3236,7 +3262,8 @@ static struct hda_pcm_stream vt1702_pcm_analog_playback = { .ops = { .open = via_playback_pcm_open, .prepare = via_playback_multi_pcm_prepare, - .cleanup = via_playback_multi_pcm_cleanup + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close }, }; @@ -3246,8 +3273,10 @@ static struct hda_pcm_stream vt1702_pcm_analog_capture = { .channels_max = 2, .nid = 0x12, /* NID to query formats and rates */ .ops = { + .open = via_pcm_open_close, .prepare = via_capture_pcm_prepare, - .cleanup = via_capture_pcm_cleanup + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close }, }; -- cgit v1.2.3 From 9510e8dd9cb4469d146953270364af6dd86a39be Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:39 +0800 Subject: ALSA: HDA VIA: Remove unused argument of via_new_analog_input Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 7ace0fca933d..0da57db3a691 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -317,8 +317,8 @@ static void via_free_kctls(struct hda_codec *codec) } /* create input playback/capture controls for the given pin */ -static int via_new_analog_input(struct via_spec *spec, hda_nid_t pin, - const char *ctlname, int idx, int mix_nid) +static int via_new_analog_input(struct via_spec *spec, const char *ctlname, + int idx, int mix_nid) { char name[32]; int err; @@ -1480,8 +1480,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, idx = 1; break; } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x17); + err = via_new_analog_input(spec, labels[i], idx, 0x17); if (err < 0) return err; imux->items[imux->num_items].label = labels[i]; @@ -2014,8 +2013,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, idx = 1; break; } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x18); + err = via_new_analog_input(spec, labels[i], idx, 0x18); if (err < 0) return err; imux->items[imux->num_items].label = labels[i]; @@ -2576,8 +2574,7 @@ static int vt1708B_auto_create_analog_input_ctls(struct via_spec *spec, idx = 1; break; } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x16); + err = via_new_analog_input(spec, labels[i], idx, 0x16); if (err < 0) return err; imux->items[imux->num_items].label = labels[i]; @@ -3048,8 +3045,7 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, idx = 1; break; } - err = via_new_analog_input(spec, cfg->input_pins[i], labels[i], - idx, 0x16); + err = via_new_analog_input(spec, labels[i], idx, 0x16); if (err < 0) return err; imux->items[imux->num_items].label = labels[i]; @@ -3402,8 +3398,7 @@ static int vt1702_auto_create_analog_input_ctls(struct via_spec *spec, idx = 3; break; } - err = via_new_analog_input(spec, cfg->input_pins[i], - labels[i], idx, 0x1A); + err = via_new_analog_input(spec, labels[i], idx, 0x1A); if (err < 0) return err; imux->items[imux->num_items].label = labels[i]; -- cgit v1.2.3 From 0713efebfa1a1878feeeb17cbadc3d2d2c9e9ed2 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:43 +0800 Subject: ALSA: HDA VIA: Change VT1708S & VT1702 hp mode controls For VT1708S and VT1702, deactivate "Headphone Playback Volume" and "Headphone Playback Mute" control if "Independent HP" mode is OFF. and rename VT1702 "Independent HP" text. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 0da57db3a691..9e8dd57e8d5c 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -572,6 +572,18 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, return 0; } +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; + snd_ctl_notify(codec->bus->card, + SNDRV_CTL_EVENT_MASK_VALUE, &ctl->id); + } +} + static int via_independent_hp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -620,6 +632,14 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, spec->multiout.hp_nid, 0, 0, 0); + /* update HP volume/swtich active state */ + if (spec->codec_type == VT1708S + || spec->codec_type == VT1702) { + activate_ctl(codec, "Headphone Playback Volume", + spec->hp_independent_mode); + activate_ctl(codec, "Headphone Playback Switch", + spec->hp_independent_mode); + } return 0; } @@ -3342,11 +3362,11 @@ static int vt1702_auto_create_line_out_ctls(struct via_spec *spec, static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) { - int err; - + int err, i; + struct hda_input_mux *imux; + static const char *texts[] = { "ON", "OFF", NULL}; if (!pin) return 0; - spec->multiout.hp_nid = 0x1D; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, @@ -3361,8 +3381,18 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) if (err < 0) return err; - create_hp_imux(spec); + imux = &spec->private_imux[1]; + /* for hp mode select */ + i = 0; + while (texts[i] != NULL) { + imux->items[imux->num_items].label = texts[i]; + imux->items[imux->num_items].index = i; + imux->num_items++; + i++; + } + + spec->hp_mux = &spec->private_imux[1]; return 0; } -- cgit v1.2.3 From cdc1784d49258198df600fbc1d37c07d7eee5ed6 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:47 +0800 Subject: ALSA: HDA VIA: Rewrite via_independent_hp_put Use hp_independent_mode_index to store hp index, and simplify function via_independent_hp_put with it. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 85 +++++++++++++++++++++++++---------------------- 1 file changed, 46 insertions(+), 39 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 9e8dd57e8d5c..e3bd5261986e 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -252,6 +252,7 @@ struct via_spec { /* HP mode source */ const struct hda_input_mux *hp_mux; unsigned int hp_independent_mode; + unsigned int hp_independent_mode_index; enum VIA_HDA_CODEC codec_type; @@ -584,6 +585,36 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active) } } +static int update_side_mute_status(struct hda_codec *codec) +{ + /* mute side channel */ + struct via_spec *spec = codec->spec; + unsigned int parm = spec->hp_independent_mode + ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; + hda_nid_t sw3; + + switch (spec->codec_type) { + case VT1708: + sw3 = 0x1b; + break; + case VT1709_10CH: + sw3 = 0x29; + break; + case VT1708B_8CH: + case VT1708S: + sw3 = 0x27; + break; + default: + sw3 = 0; + break; + } + + if (sw3) + snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, + parm); + return 0; +} + static int via_independent_hp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -591,47 +622,18 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, struct via_spec *spec = codec->spec; hda_nid_t nid = spec->autocfg.hp_pins[0]; unsigned int pinsel = ucontrol->value.enumerated.item[0]; - unsigned int con_nid = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_LIST, 0) & 0xff; - - if (con_nid == spec->multiout.hp_nid) { - if (pinsel == 0) { - if (!spec->hp_independent_mode) { - if (spec->multiout.num_dacs > 1) - spec->multiout.num_dacs -= 1; - spec->hp_independent_mode = 1; - } - } else if (pinsel == 1) { - if (spec->hp_independent_mode) { - if (spec->multiout.num_dacs > 1) - spec->multiout.num_dacs += 1; - spec->hp_independent_mode = 0; - } - } - } else { - if (pinsel == 0) { - if (spec->hp_independent_mode) { - if (spec->multiout.num_dacs > 1) - spec->multiout.num_dacs += 1; - spec->hp_independent_mode = 0; - } - } else if (pinsel == 1) { - if (!spec->hp_independent_mode) { - if (spec->multiout.num_dacs > 1) - spec->multiout.num_dacs -= 1; - spec->hp_independent_mode = 1; - } - } - } - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, - pinsel); + /* Get Independent Mode index of headphone pin widget */ + spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel + ? 1 : 0; - if (spec->multiout.hp_nid && - spec->multiout.hp_nid != spec->multiout.dac_nids[HDA_FRONT]) - snd_hda_codec_setup_stream(codec, - spec->multiout.hp_nid, - 0, 0, 0); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); + + if (spec->multiout.hp_nid && spec->multiout.hp_nid + != spec->multiout.dac_nids[HDA_FRONT]) + snd_hda_codec_setup_stream(codec, spec->multiout.hp_nid, + 0, 0, 0); + update_side_mute_status(codec); /* update HP volume/swtich active state */ if (spec->codec_type == VT1708S || spec->codec_type == VT1702) { @@ -1447,6 +1449,7 @@ static int vt1708_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) return 0; spec->multiout.hp_nid = VT1708_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Headphone Playback Volume", @@ -1982,6 +1985,7 @@ static int vt1709_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) spec->multiout.hp_nid = VT1709_HP_DAC_NID; else if (spec->multiout.num_dacs == 3) /* 6 channels */ spec->multiout.hp_nid = 0; + spec->hp_independent_mode_index = 1; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Headphone Playback Volume", @@ -2541,6 +2545,7 @@ static int vt1708B_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) return 0; spec->multiout.hp_nid = VT1708B_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Headphone Playback Volume", @@ -3011,6 +3016,7 @@ static int vt1708S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) return 0; spec->multiout.hp_nid = VT1708S_HP_NID; /* AOW3 */ + spec->hp_independent_mode_index = 1; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Headphone Playback Volume", @@ -3368,6 +3374,7 @@ static int vt1702_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) if (!pin) return 0; spec->multiout.hp_nid = 0x1D; + spec->hp_independent_mode_index = 0; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Headphone Playback Volume", -- cgit v1.2.3 From 1564b2878f5cf160f60af99d4dbca1dd7809ee8a Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:52 +0800 Subject: ALSA: HDA VIA: Add smart5.1 function. Smart 5.1 is for 3-jacks model, to reuse input pins as outputs. While off, they act as "line out" / "line in" / "mic in". While on, they acts as "line out" / "back left/right" / "center/lfe". Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 177 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 173 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index e3bd5261986e..26ee1c3a4d16 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -211,7 +211,7 @@ static struct snd_kcontrol_new vt1708_control_templates[] = { struct via_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[3]; + struct snd_kcontrol_new *mixers[4]; unsigned int num_mixers; struct hda_verb *init_verbs[5]; @@ -253,6 +253,7 @@ struct via_spec { const struct hda_input_mux *hp_mux; unsigned int hp_independent_mode; unsigned int hp_independent_mode_index; + unsigned int smart51_enabled; enum VIA_HDA_CODEC codec_type; @@ -390,6 +391,8 @@ static void via_auto_init_analog_input(struct hda_codec *codec) } } +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin); + static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned int *affected_parm) { @@ -400,9 +403,10 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ unsigned present = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0) >> 31; - - if ((no_presence || present) && get_defcfg_connect(def_conf) - != AC_JACK_PORT_NONE) { + struct via_spec *spec = codec->spec; + if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) + || ((no_presence || present) + && get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE)) { *affected_parm = AC_PWRST_D0; /* if it's connected */ parm = AC_PWRST_D0; } else @@ -657,6 +661,167 @@ static struct snd_kcontrol_new via_hp_mixer[] = { { } /* end */ }; +static void notify_aa_path_ctls(struct hda_codec *codec) +{ + int i; + struct snd_ctl_elem_id id; + const char *labels[] = {"Mic", "Front Mic", "Line"}; + + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + for (i = 0; i < ARRAY_SIZE(labels); i++) { + sprintf(id.name, "%s Playback Volume", labels[i]); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); + } +} + +static void mute_aa_path(struct hda_codec *codec, int mute) +{ + struct via_spec *spec = codec->spec; + hda_nid_t nid_mixer; + int start_idx; + int end_idx; + int i; + /* get nid of MW0 and start & end index */ + switch (spec->codec_type) { + case VT1708: + nid_mixer = 0x17; + start_idx = 2; + end_idx = 4; + break; + case VT1709_10CH: + case VT1709_6CH: + nid_mixer = 0x18; + start_idx = 2; + end_idx = 4; + break; + case VT1708B_8CH: + case VT1708B_4CH: + case VT1708S: + nid_mixer = 0x16; + start_idx = 2; + end_idx = 4; + break; + default: + return; + } + /* check AA path's mute status */ + for (i = start_idx; i <= end_idx; i++) { + int val = mute ? HDA_AMP_MUTE : HDA_AMP_UNMUTE; + snd_hda_codec_amp_stereo(codec, nid_mixer, HDA_INPUT, i, + HDA_AMP_MUTE, val); + } +} +static int is_smart51_pins(struct via_spec *spec, hda_nid_t pin) +{ + int res = 0; + int index; + for (index = AUTO_PIN_MIC; index < AUTO_PIN_FRONT_LINE; index++) { + if (pin == spec->autocfg.input_pins[index]) { + res = 1; + break; + } + } + return res; +} + +static int via_smart51_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +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; + int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; + int on = 1; + int i; + + for (i = 0; i < ARRAY_SIZE(index); i++) { + hda_nid_t nid = spec->autocfg.input_pins[index[i]]; + if (nid) { + int ctl = + snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, + 0); + if (i == AUTO_PIN_FRONT_MIC + && spec->hp_independent_mode) + continue; /* ignore FMic for independent HP */ + if (ctl & AC_PINCTL_IN_EN + && !(ctl & AC_PINCTL_OUT_EN)) + on = 0; + } + } + *ucontrol->value.integer.value = on; + 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 index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; + int i; + + for (i = 0; i < ARRAY_SIZE(index); i++) { + hda_nid_t nid = spec->autocfg.input_pins[index[i]]; + if (i == AUTO_PIN_FRONT_MIC + && spec->hp_independent_mode) + continue; /* don't retask FMic for independent HP */ + if (nid) { + unsigned int 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_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + parm); + if (out_in == AC_PINCTL_OUT_EN) { + mute_aa_path(codec, 1); + notify_aa_path_ctls(codec); + } + } + if (i == AUTO_PIN_FRONT_MIC) { + if (spec->codec_type == VT1708S) { + /* input = index 1 (AOW3) */ + snd_hda_codec_write( + codec, nid, 0, + AC_VERB_SET_CONNECT_SEL, 1); + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, + 0, HDA_AMP_MUTE, HDA_AMP_UNMUTE); + } + } + } + spec->smart51_enabled = *ucontrol->value.integer.value; + set_jack_power_state(codec); + return 1; +} + +static struct snd_kcontrol_new via_smart51_mixer[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Smart 5.1", + .count = 1, + .info = via_smart51_info, + .get = via_smart51_get, + .put = via_smart51_put, + }, + {} /* end */ +}; + /* capture mixer elements */ static struct snd_kcontrol_new vt1708_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), @@ -1587,6 +1752,7 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) if (spec->hp_mux) spec->mixers[spec->num_mixers++] = via_hp_mixer; + spec->mixers[spec->num_mixers++] = via_smart51_mixer; return 1; } @@ -2087,6 +2253,7 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) if (spec->hp_mux) spec->mixers[spec->num_mixers++] = via_hp_mixer; + spec->mixers[spec->num_mixers++] = via_smart51_mixer; return 1; } @@ -2649,6 +2816,7 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) if (spec->hp_mux) spec->mixers[spec->num_mixers++] = via_hp_mixer; + spec->mixers[spec->num_mixers++] = via_smart51_mixer; return 1; } @@ -3142,6 +3310,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) if (spec->hp_mux) spec->mixers[spec->num_mixers++] = via_hp_mixer; + spec->mixers[spec->num_mixers++] = via_smart51_mixer; return 1; } -- cgit v1.2.3 From a80e6e3c8c21ca50837e2e42fa438a4ff4a9788e Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:07:55 +0800 Subject: ALSA: HDA VIA: When changing input source, update power state. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 26ee1c3a4d16..c5e99944990a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -549,6 +549,14 @@ static int via_mux_enum_put(struct snd_kcontrol *kcontrol, if (!spec->mux_nids[adc_idx]) return -EINVAL; + /* switch to D0 beofre change index */ + if (snd_hda_codec_read(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_GET_POWER_STATE, 0x00) != AC_PWRST_D0) + snd_hda_codec_write(codec, spec->mux_nids[adc_idx], 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + /* update jack power state */ + set_jack_power_state(codec); + return snd_hda_input_mux_put(codec, spec->input_mux, ucontrol, spec->mux_nids[adc_idx], &spec->cur_mux[adc_idx]); -- cgit v1.2.3 From a34df19a658170fb7125e8017ee46ba54b1ad495 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:01 +0800 Subject: ALSA: HDA VIA: Add VIA_JACK_EVENT process in via_unsol_event. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 38 +++++++++++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index c5e99944990a..cd62c88b5246 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -124,6 +124,7 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 +#define VIA_JACK_EVENT 0x04 enum { VIA_CTL_WIDGET_VOL, @@ -1413,10 +1414,12 @@ static void via_unsol_event(struct hda_codec *codec, unsigned int res) { res >>= 26; - if (res == VIA_HP_EVENT) + if (res & VIA_HP_EVENT) via_hp_automute(codec); - else if (res == VIA_GPIO_EVENT) + if (res & VIA_GPIO_EVENT) via_gpio_control(codec); + if (res & VIA_JACK_EVENT) + set_jack_power_state(codec); } static int via_init(struct hda_codec *codec) @@ -1878,7 +1881,8 @@ static struct snd_kcontrol_new vt1709_capture_mixer[] = { }; static struct hda_verb vt1709_uniwill_init_verbs[] = { - {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + {0x20, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, { } }; @@ -2514,7 +2518,15 @@ static struct hda_verb vt1708B_4ch_volume_init_verbs[] = { }; static struct hda_verb vt1708B_uniwill_init_verbs[] = { - {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; @@ -3009,7 +3021,15 @@ static struct hda_verb vt1708S_volume_init_verbs[] = { }; static struct hda_verb vt1708S_uniwill_init_verbs[] = { - {0x1D, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x22, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; @@ -3448,8 +3468,12 @@ static struct hda_verb vt1702_volume_init_verbs[] = { }; static struct hda_verb vt1702_uniwill_init_verbs[] = { - {0x01, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_GPIO_EVENT}, - {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_HP_EVENT}, + {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, { } }; -- cgit v1.2.3 From dcf34c8cc685781cebbe1f4c75272a3269eba3a1 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:15 +0800 Subject: ALSA: HDA VIA: Refresh front playback mute in via_hp_automute. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index cd62c88b5246..c1f4307feaae 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1351,14 +1351,25 @@ static void via_free(struct hda_codec *codec) /* mute internal speaker if HP is plugged */ static void via_hp_automute(struct hda_codec *codec) { - unsigned int present; + unsigned int present = 0; struct via_spec *spec = codec->spec; present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - snd_hda_codec_amp_stereo(codec, spec->autocfg.line_out_pins[0], - HDA_OUTPUT, 0, HDA_AMP_MUTE, - present ? HDA_AMP_MUTE : 0); + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + /* auto mute */ + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Front Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); + } } static void via_gpio_control(struct hda_codec *codec) -- cgit v1.2.3 From 1f2e99febd5dd0c91f0d0752674029a4376649e5 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:17 +0800 Subject: ALSA: HDA VIA: Add Jack detect feature for VT1708. VT1708 does not support unsolicited response, but we need hp detect to automute speaker. Implemented in workqueue. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 230 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 173 insertions(+), 57 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index c1f4307feaae..38418a53acd7 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -89,6 +89,64 @@ enum VIA_HDA_CODEC { CODEC_TYPES, }; +struct via_spec { + /* codec parameterization */ + struct snd_kcontrol_new *mixers[4]; + unsigned int num_mixers; + + struct hda_verb *init_verbs[5]; + unsigned int num_iverbs; + + char *stream_name_analog; + struct hda_pcm_stream *stream_analog_playback; + struct hda_pcm_stream *stream_analog_capture; + + char *stream_name_digital; + struct hda_pcm_stream *stream_digital_playback; + struct hda_pcm_stream *stream_digital_capture; + + /* playback */ + struct hda_multi_out multiout; + hda_nid_t slave_dig_outs[2]; + + /* capture */ + unsigned int num_adc_nids; + hda_nid_t *adc_nids; + hda_nid_t mux_nids[3]; + hda_nid_t dig_in_nid; + hda_nid_t dig_in_pin; + + /* capture source */ + const struct hda_input_mux *input_mux; + unsigned int cur_mux[3]; + + /* PCM information */ + struct hda_pcm pcm_rec[3]; + + /* dynamic controls, init_verbs and input_mux */ + struct auto_pin_cfg autocfg; + struct snd_array kctls; + struct hda_input_mux private_imux[2]; + hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; + + /* HP mode source */ + const struct hda_input_mux *hp_mux; + unsigned int hp_independent_mode; + unsigned int hp_independent_mode_index; + unsigned int smart51_enabled; + + enum VIA_HDA_CODEC codec_type; + + /* work to check hp jack state */ + struct hda_codec *codec; + struct delayed_work vt1708_hp_work; + int vt1708_jack_detectect; + int vt1708_hp_present; +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct hda_loopback_check loopback; +#endif +}; + static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) { u32 vendor_id = codec->vendor_id; @@ -181,6 +239,31 @@ static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); static void set_jack_power_state(struct hda_codec *codec); +static int is_aa_path_mute(struct hda_codec *codec); + +static void vt1708_start_hp_work(struct via_spec *spec) +{ + if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + return; + snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, + !spec->vt1708_jack_detectect); + if (!delayed_work_pending(&spec->vt1708_hp_work)) + schedule_delayed_work(&spec->vt1708_hp_work, + msecs_to_jiffies(100)); +} + +static void vt1708_stop_hp_work(struct via_spec *spec) +{ + if (spec->codec_type != VT1708 || spec->autocfg.hp_pins[0] == 0) + return; + if (snd_hda_get_bool_hint(spec->codec, "analog_loopback_hp_detect") == 1 + && !is_aa_path_mute(spec->codec)) + return; + snd_hda_codec_write(spec->codec, 0x1, 0, 0xf81, + !spec->vt1708_jack_detectect); + cancel_delayed_work(&spec->vt1708_hp_work); + flush_scheduled_work(); +} static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) @@ -190,6 +273,12 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, set_jack_power_state(codec); analog_low_current_mode(snd_kcontrol_chip(kcontrol), -1); + if (snd_hda_get_bool_hint(codec, "analog_loopback_hp_detect") == 1) { + if (is_aa_path_mute(codec)) + vt1708_start_hp_work(codec->spec); + else + vt1708_stop_hp_work(codec->spec); + } return change; } @@ -210,59 +299,6 @@ static struct snd_kcontrol_new vt1708_control_templates[] = { }; -struct via_spec { - /* codec parameterization */ - struct snd_kcontrol_new *mixers[4]; - unsigned int num_mixers; - - struct hda_verb *init_verbs[5]; - unsigned int num_iverbs; - - char *stream_name_analog; - struct hda_pcm_stream *stream_analog_playback; - struct hda_pcm_stream *stream_analog_capture; - - char *stream_name_digital; - struct hda_pcm_stream *stream_digital_playback; - struct hda_pcm_stream *stream_digital_capture; - - /* playback */ - struct hda_multi_out multiout; - hda_nid_t slave_dig_outs[2]; - - /* capture */ - unsigned int num_adc_nids; - hda_nid_t *adc_nids; - hda_nid_t mux_nids[3]; - hda_nid_t dig_in_nid; - hda_nid_t dig_in_pin; - - /* capture source */ - const struct hda_input_mux *input_mux; - unsigned int cur_mux[3]; - - /* PCM information */ - struct hda_pcm pcm_rec[3]; - - /* dynamic controls, init_verbs and input_mux */ - struct auto_pin_cfg autocfg; - struct snd_array kctls; - struct hda_input_mux private_imux[2]; - hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; - - /* HP mode source */ - const struct hda_input_mux *hp_mux; - unsigned int hp_independent_mode; - unsigned int hp_independent_mode_index; - unsigned int smart51_enabled; - - enum VIA_HDA_CODEC codec_type; - -#ifdef CONFIG_SND_HDA_POWER_SAVE - struct hda_loopback_check loopback; -#endif -}; - static hda_nid_t vt1708_adc_nids[2] = { /* ADC1-2 */ 0x15, 0x27 @@ -981,7 +1017,6 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, struct via_spec *spec = codec->spec; int idle = substream->pstr->substream_opened == 1 && substream->ref_count == 0; - analog_low_current_mode(codec, idle); return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, hinfo); @@ -994,6 +1029,7 @@ static int via_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + vt1708_start_hp_work(spec); return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, stream_tag, format, substream); } @@ -1003,6 +1039,7 @@ static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct via_spec *spec = codec->spec; + vt1708_stop_hp_work(spec); return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); } @@ -1094,7 +1131,7 @@ static int via_playback_multi_pcm_prepare(struct hda_pcm_stream *hinfo, snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); } - + vt1708_start_hp_work(spec); return 0; } @@ -1134,7 +1171,7 @@ static int via_playback_multi_pcm_cleanup(struct hda_pcm_stream *hinfo, snd_hda_codec_setup_stream(codec, mout->hp_nid, 0, 0, 0); } - + vt1708_stop_hp_work(spec); return 0; } @@ -1345,6 +1382,7 @@ static void via_free(struct hda_codec *codec) return; via_free_kctls(codec); + vt1708_stop_hp_work(spec); kfree(codec->spec); } @@ -1464,6 +1502,15 @@ static int via_init(struct hda_codec *codec) return 0; } +#ifdef SND_HDA_NEEDS_RESUME +static int via_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct via_spec *spec = codec->spec; + vt1708_stop_hp_work(spec); + return 0; +} +#endif + #ifdef CONFIG_SND_HDA_POWER_SAVE static int via_check_power_status(struct hda_codec *codec, hda_nid_t nid) { @@ -1479,6 +1526,9 @@ static struct hda_codec_ops via_patch_ops = { .build_pcms = via_build_pcms, .init = via_init, .free = via_free, +#ifdef SND_HDA_NEEDS_RESUME + .suspend = via_suspend, +#endif #ifdef CONFIG_SND_HDA_POWER_SAVE .check_power_status = via_check_power_status, #endif @@ -1728,6 +1778,51 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) return; } +static int vt1708_jack_detectect_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; + + if (spec->codec_type != VT1708) + return 0; + spec->vt1708_jack_detectect = + !((snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8) & 0x1); + ucontrol->value.integer.value[0] = spec->vt1708_jack_detectect; + return 0; +} + +static int vt1708_jack_detectect_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 change; + + if (spec->codec_type != VT1708) + return 0; + spec->vt1708_jack_detectect = ucontrol->value.integer.value[0]; + change = (0x1 & (snd_hda_codec_read(codec, 0x1, 0, 0xf84, 0) >> 8)) + == !spec->vt1708_jack_detectect; + if (spec->vt1708_jack_detectect) { + mute_aa_path(codec, 1); + notify_aa_path_ctls(codec); + } + return change; +} + +static struct snd_kcontrol_new vt1708_jack_detectect[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Jack Detect", + .count = 1, + .info = snd_ctl_boolean_mono_info, + .get = vt1708_jack_detectect_get, + .put = vt1708_jack_detectect_put, + }, + {} /* end */ +}; + static int vt1708_parse_auto_config(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1753,6 +1848,10 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) if (err < 0) return err; err = vt1708_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + /* add jack detect on/off control */ + err = snd_hda_add_new_ctls(codec, vt1708_jack_detectect); if (err < 0) return err; @@ -1788,6 +1887,22 @@ static int via_auto_init(struct hda_codec *codec) return 0; } +static void vt1708_update_hp_jack_state(struct work_struct *work) +{ + struct via_spec *spec = container_of(work, struct via_spec, + vt1708_hp_work.work); + if (spec->codec_type != VT1708) + return; + /* if jack state toggled */ + if (spec->vt1708_hp_present + != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) >> 31)) { + spec->vt1708_hp_present ^= 1; + via_hp_automute(spec->codec); + } + vt1708_start_hp_work(spec); +} + static int get_mux_nids(struct hda_codec *codec) { struct via_spec *spec = codec->spec; @@ -1864,7 +1979,8 @@ static int patch_vt1708(struct hda_codec *codec) #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1708_loopbacks; #endif - + spec->codec = codec; + INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); return 0; } -- cgit v1.2.3 From 82ef9e45c48634af5e3f6ab9ac75b6642c538020 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:19 +0800 Subject: ALSA: HDA VIA: Modify vt1708_set_pinconfig_connect function. like seqassoc 0xff, seqassoc 0xf0 of vt1708 should override Port Connectivity field into 'AC_JACK_PORT_COMPLEX' Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 38418a53acd7..dc416ec0c6d4 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1768,11 +1768,10 @@ static void vt1708_set_pinconfig_connect(struct hda_codec *codec, hda_nid_t nid) def_conf = snd_hda_codec_get_pincfg(codec, nid); seqassoc = (unsigned char) get_defcfg_association(def_conf); seqassoc = (seqassoc << 4) | get_defcfg_sequence(def_conf); - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) { - if (seqassoc == 0xff) { - def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); - snd_hda_codec_set_pincfg(codec, nid, def_conf); - } + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE + && (seqassoc == 0xf0 || seqassoc == 0xff)) { + def_conf = def_conf & (~(AC_JACK_PORT_BOTH << 30)); + snd_hda_codec_set_pincfg(codec, nid, def_conf); } return; -- cgit v1.2.3 From c873cc25280113d71463ad5075413d283be6b766 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:21 +0800 Subject: ALSA: HDA VIA: Replace via_playback_pcm_prepare/cleanup Replaced with via_playback_multi_pcm_prepare/cleanup to support multi-stream operations Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index dc416ec0c6d4..4d3c447342b0 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1022,28 +1022,6 @@ static int via_playback_pcm_open(struct hda_pcm_stream *hinfo, hinfo); } -static int via_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; - vt1708_start_hp_work(spec); - return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, - stream_tag, format, substream); -} - -static int via_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - struct via_spec *spec = codec->spec; - vt1708_stop_hp_work(spec); - return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); -} - - static void playback_multi_pcm_prep_0(struct hda_codec *codec, unsigned int stream_tag, unsigned int format, @@ -1252,7 +1230,7 @@ static struct hda_pcm_stream vt1708_pcm_analog_playback = { }; static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { - .substreams = 1, + .substreams = 2, .channels_min = 2, .channels_max = 8, .nid = 0x10, /* NID to query formats and rates */ @@ -1263,8 +1241,8 @@ static struct hda_pcm_stream vt1708_pcm_analog_s16_playback = { .formats = SNDRV_PCM_FMTBIT_S16_LE, .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup }, }; @@ -2062,8 +2040,8 @@ static struct hda_pcm_stream vt1709_10ch_pcm_analog_playback = { .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, }, }; @@ -2074,8 +2052,8 @@ static struct hda_pcm_stream vt1709_6ch_pcm_analog_playback = { .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, }, }; @@ -3166,8 +3144,8 @@ static struct hda_pcm_stream vt1708S_pcm_analog_playback = { .nid = 0x10, /* NID to query formats and rates */ .ops = { .open = via_playback_pcm_open, - .prepare = via_playback_pcm_prepare, - .cleanup = via_playback_pcm_cleanup, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, .close = via_pcm_open_close }, }; -- cgit v1.2.3 From 9645c2039d5cfdbdcebe297420e180b6cd262836 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:27 +0800 Subject: ALSA: HDA VIA: Modify vt1708_auto_create_multi_out_ctls. Rewrite nid_vol/mute assignment for clearity, and check line connection before adding control for it. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4d3c447342b0..efadacd60835 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1553,7 +1553,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, { char name[32]; static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid, nid_vol = 0; + hda_nid_t nid, nid_vol, nid_vols[] = {0x17, 0x19, 0x1a, 0x1b}; int i, err; for (i = 0; i <= AUTO_SEQ_SIDE; i++) { @@ -1562,8 +1562,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid) continue; - if (i != AUTO_SEQ_FRONT) - nid_vol = 0x18 + i; + nid_vol = nid_vols[i]; if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ @@ -1595,13 +1594,13 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, /* add control to mixer index 0 */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Master Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_INPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x17, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_INPUT)); if (err < 0) return err; -- cgit v1.2.3 From 4483a2f5907fa824bd6384c36fdcee9777cab1b9 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:29 +0800 Subject: ALSA: HDA VIA: Modify vt1709_auto_create_multi_out_ctls. Rewrite nid_vol/mute assignment for clearity, and check line connection before adding control for it. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index efadacd60835..f9702a17fc16 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -2160,7 +2160,7 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, { char name[32]; static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; - hda_nid_t nid = 0; + hda_nid_t nid, nid_vol, nid_vols[] = {0x18, 0x1a, 0x1b, 0x29}; int i, err; for (i = 0; i <= AUTO_SEQ_SIDE; i++) { @@ -2169,43 +2169,45 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid) continue; + nid_vol = nid_vols[i]; + if (i == AUTO_SEQ_CENLFE) { /* Center/LFE */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Center Playback Volume", - HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "LFE Playback Volume", - HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, "Center Playback Switch", - HDA_COMPOSE_AMP_VAL(0x1b, 1, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, "LFE Playback Switch", - HDA_COMPOSE_AMP_VAL(0x1b, 2, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); if (err < 0) return err; } else if (i == AUTO_SEQ_FRONT){ - /* add control to mixer index 0 */ + /* ADD control to mixer index 0 */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Master Front Playback Volume", - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_INPUT)); if (err < 0) return err; err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, "Master Front Playback Switch", - HDA_COMPOSE_AMP_VAL(0x18, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_INPUT)); if (err < 0) return err; @@ -2226,26 +2228,26 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, } else if (i == AUTO_SEQ_SURROUND) { sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); if (err < 0) return err; sprintf(name, "%s Playback Switch", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x1a, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); if (err < 0) return err; } else if (i == AUTO_SEQ_SIDE) { sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); if (err < 0) return err; sprintf(name, "%s Playback Switch", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, name, - HDA_COMPOSE_AMP_VAL(0x29, 3, 0, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); if (err < 0) return err; -- cgit v1.2.3 From 6369bcfccb57da28ad3e09b25fecd841a415ae95 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:31 +0800 Subject: ALSA: HDA VIA: Replace MIC_BOOST_VOLUME. With snd_hda_override_amp_caps. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 72 ++++++++++------------------------------------- 1 file changed, 15 insertions(+), 57 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index f9702a17fc16..4b7cd5971701 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -197,46 +197,6 @@ enum { AUTO_SEQ_SIDE }; -/* Some VT1708S based boards gets the micboost setting wrong, so we have - * to apply some brute-force and re-write the TLV's by software. */ -static int mic_boost_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *_tlv) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - - if (get_codec_type(codec) == VT1708S - && (nid == 0x1a || nid == 0x1e)) { - if (size < 4 * sizeof(unsigned int)) - return -ENOMEM; - if (put_user(1, _tlv)) /* SNDRV_CTL_TLVT_DB_SCALE */ - return -EFAULT; - if (put_user(2 * sizeof(unsigned int), _tlv + 1)) - return -EFAULT; - if (put_user(0, _tlv + 2)) /* offset = 0 */ - return -EFAULT; - if (put_user(1000, _tlv + 3)) /* step size = 10 dB */ - return -EFAULT; - } - return 0; -} - -static int mic_boost_volume_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - hda_nid_t nid = get_amp_nid(kcontrol); - - if (get_codec_type(codec) == VT1708S - && (nid == 0x1a || nid == 0x1e)) { - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 2; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 3; - } - return 0; -} - static void analog_low_current_mode(struct hda_codec *codec, int stream_idle); static void set_jack_power_state(struct hda_codec *codec); static int is_aa_path_mute(struct hda_codec *codec); @@ -3063,29 +3023,15 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) /* Patch for VT1708S */ -/* VT1708S software backdoor based override for buggy hardware micboost - * setting */ -#define MIC_BOOST_VOLUME(xname, nid) { \ - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ - .name = xname, \ - .index = 0, \ - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ - SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ - .info = mic_boost_volume_info, \ - .get = snd_hda_mixer_amp_volume_get, \ - .put = snd_hda_mixer_amp_volume_put, \ - .tlv = { .c = mic_boost_tlv }, \ - .private_value = HDA_COMPOSE_AMP_VAL(nid, 3, 0, HDA_INPUT) } - /* capture mixer elements */ static struct snd_kcontrol_new vt1708S_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), - MIC_BOOST_VOLUME("Mic Boost Capture Volume", 0x1A), - MIC_BOOST_VOLUME("Front Mic Boost Capture Volume", 0x1E), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, /* The multiple "Capture Source" controls confuse alsamixer @@ -3457,6 +3403,16 @@ static struct hda_amp_list vt1708S_loopbacks[] = { }; #endif +static void override_mic_boost(struct hda_codec *codec, hda_nid_t pin, + int offset, int num_steps, int step_size) +{ + snd_hda_override_amp_caps(codec, pin, HDA_INPUT, + (offset << AC_AMPCAP_OFFSET_SHIFT) | + (num_steps << AC_AMPCAP_NUM_STEPS_SHIFT) | + (step_size << AC_AMPCAP_STEP_SIZE_SHIFT) | + (0 << AC_AMPCAP_MUTE_SHIFT)); +} + static int patch_vt1708S(struct hda_codec *codec) { struct via_spec *spec; @@ -3493,6 +3449,8 @@ static int patch_vt1708S(struct hda_codec *codec) spec->adc_nids = vt1708S_adc_nids; spec->num_adc_nids = ARRAY_SIZE(vt1708S_adc_nids); get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); spec->mixers[spec->num_mixers] = vt1708S_capture_mixer; spec->num_mixers++; } -- cgit v1.2.3 From bc7e7e5ce05047e16633a94d36fa144af1d2b4c7 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:32 +0800 Subject: ALSA: HDA VIA: Move backdoor verbs to vt17xx_volume_init_verb As init verbs, vt17xx_volume_init_verb is a better place to hold them. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4b7cd5971701..1c87231fa7e5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -3068,6 +3068,8 @@ static struct hda_verb vt1708S_volume_init_verbs[] = { {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* Enable Mic Boost Volume backdoor */ {0x1, 0xf98, 0x1}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, { } }; @@ -3527,6 +3529,10 @@ static struct hda_verb vt1702_volume_init_verbs[] = { /* PW6 PW7 Output enable */ {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, {0x1C, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* mixer enable */ + {0x1, 0xF88, 0x3}, + /* GPIO 0~2 */ + {0x1, 0xF82, 0x3F}, { } }; @@ -3768,8 +3774,6 @@ static int patch_vt1702(struct hda_codec *codec) { struct via_spec *spec; int err; - unsigned int response; - unsigned char control; /* create a codec specific record */ spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -3814,18 +3818,6 @@ static int patch_vt1702(struct hda_codec *codec) spec->loopback.amplist = vt1702_loopbacks; #endif - /* Open backdoor */ - response = snd_hda_codec_read(codec, codec->afg, 0, 0xF8C, 0); - control = (unsigned char)(response & 0xff); - control |= 0x3; - snd_hda_codec_write(codec, codec->afg, 0, 0xF88, control); - - /* Enable GPIO 0&1 for volume&mute control */ - /* Enable GPIO 2 for DMIC-DATA */ - response = snd_hda_codec_read(codec, codec->afg, 0, 0xF84, 0); - control = (unsigned char)((response >> 16) & 0x3f); - snd_hda_codec_write(codec, codec->afg, 0, 0xF82, control); - return 0; } -- cgit v1.2.3 From eb7188cafcb7aa1419b8889494cdbd4e6a01da1c Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:34 +0800 Subject: ALSA: HDA VIA: Add VT1718S support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 554 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 545 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 1c87231fa7e5..c78385340694 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -86,6 +86,7 @@ enum VIA_HDA_CODEC { VT1708S, VT1708BCE, VT1702, + VT1718S, CODEC_TYPES, }; @@ -175,6 +176,9 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) else if ((dev_id & 0xfff) == 0x398 && (dev_id >> 12) < 8) codec_type = VT1702; + else if ((dev_id & 0xfff) == 0x428 + && (dev_id >> 12) < 8) + codec_type = VT1718S; else codec_type = UNKNOWN; return codec_type; @@ -284,6 +288,11 @@ static hda_nid_t vt1702_adc_nids[3] = { 0x12, 0x20, 0x1F }; +static hda_nid_t vt1718S_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + /* add dynamic controls */ static int via_add_control(struct via_spec *spec, int type, const char *name, unsigned long val) @@ -512,6 +521,67 @@ static void set_jack_power_state(struct hda_codec *codec) snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, parm); } + } else if (spec->codec_type == VT1718S) { + /* MUX6 (1eh) = stereo mixer */ + imux_is_smixer = snd_hda_codec_read( + codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* 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; + /* MUX6/7 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* outputs */ + /* PW3 (27h), MW2 (1ah), AOW3 (bh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x27, &parm); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0xb, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* PW2 (26h), AOW2 (ah) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + snd_hda_codec_write(codec, 0xa, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* PW0/1 (24h/25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + set_pin_power_state(codec, 0x25, &parm); + if (!spec->hp_independent_mode) /* check for redirected HP */ + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x8, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x9, 0, AC_VERB_SET_POWER_STATE, + parm); + /* MW9 (21h), Mw2 (1ah), AOW0 (8h) */ + snd_hda_codec_write(codec, 0x21, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + if (spec->hp_independent_mode) { + /* PW4 (28h), MW3 (1bh), MUX1(34h), AOW4 (ch) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0xc, 0, + AC_VERB_SET_POWER_STATE, parm); + } } } @@ -572,11 +642,21 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct via_spec *spec = codec->spec; - hda_nid_t nid = spec->autocfg.hp_pins[0]; - unsigned int pinsel = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_CONNECT_SEL, - 0x00); + hda_nid_t nid; + unsigned int pinsel; + switch (spec->codec_type) { + case VT1718S: + nid = 0x34; + break; + default: + nid = spec->autocfg.hp_pins[0]; + break; + } + /* use !! to translate conn sel 2 for VT1718S */ + pinsel = !!snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_CONNECT_SEL, + 0x00); ucontrol->value.enumerated.item[0] = pinsel; return 0; @@ -635,6 +715,16 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel ? 1 : 0; + switch (spec->codec_type) { + case VT1718S: + nid = 0x34; + pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ + spec->multiout.num_dacs = 4; + break; + default: + nid = spec->autocfg.hp_pins[0]; + break; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); if (spec->multiout.hp_nid && spec->multiout.hp_nid @@ -645,7 +735,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, update_side_mute_status(codec); /* update HP volume/swtich active state */ if (spec->codec_type == VT1708S - || spec->codec_type == VT1702) { + || spec->codec_type == VT1702 + || spec->codec_type == VT1718S) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", @@ -758,7 +849,8 @@ static int via_smart51_get(struct snd_kcontrol *kcontrol, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); if (i == AUTO_PIN_FRONT_MIC - && spec->hp_independent_mode) + && spec->hp_independent_mode + && spec->codec_type != VT1718S) continue; /* ignore FMic for independent HP */ if (ctl & AC_PINCTL_IN_EN && !(ctl & AC_PINCTL_OUT_EN)) @@ -782,7 +874,8 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, for (i = 0; i < ARRAY_SIZE(index); i++) { hda_nid_t nid = spec->autocfg.input_pins[index[i]]; if (i == AUTO_PIN_FRONT_MIC - && spec->hp_independent_mode) + && spec->hp_independent_mode + && spec->codec_type != VT1718S) continue; /* don't retask FMic for independent HP */ if (nid) { unsigned int parm = snd_hda_codec_read( @@ -797,6 +890,10 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, mute_aa_path(codec, 1); notify_aa_path_ctls(codec); } + if (spec->codec_type == VT1718S) + snd_hda_codec_amp_stereo( + codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, + HDA_AMP_UNMUTE); } if (i == AUTO_PIN_FRONT_MIC) { if (spec->codec_type == VT1708S) { @@ -871,6 +968,11 @@ static int is_aa_path_mute(struct hda_codec *codec) start_idx = 1; end_idx = 3; break; + case VT1718S: + nid_mixer = 0x21; + start_idx = 1; + end_idx = 3; + break; default: return 0; } @@ -920,6 +1022,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) parm = enable ? 0x02 : 0x00; /* 0x02: 2/3x, 0x00: 1x */ break; case VT1708S: + case VT1718S: verb = 0xf73; parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ break; @@ -1026,8 +1129,8 @@ static void playback_multi_pcm_prep_0(struct hda_codec *codec, snd_hda_codec_setup_stream(codec, nids[HDA_FRONT], stream_tag, 0, format); - if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] && - !spec->hp_independent_mode) + if (mout->hp_nid && mout->hp_nid != nids[HDA_FRONT] + && !spec->hp_independent_mode) /* headphone out will just decode front left/right (stereo) */ snd_hda_codec_setup_stream(codec, mout->hp_nid, stream_tag, 0, format); @@ -3821,6 +3924,435 @@ static int patch_vt1702(struct hda_codec *codec) return 0; } +/* Patch for VT1718S */ + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1718S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct hda_verb vt1718S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x11, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(5)}, + + /* Setup default input of Front HP to MW9 */ + {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* PW9 PW10 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + {0x2e, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + /* PW11 Input enable */ + {0x2f, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_IN_EN}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf88, 0x8}, + /* MW0/1/2/3/4: un-mute index 0 (AOWx), mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* set MUX1 = 2 (AOW4), MUX2 = 1 (AOW3) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0x2}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* Unmute MW4's index 0 */ + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + { } +}; + + +static struct hda_verb vt1718S_uniwill_init_verbs[] = { + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x24, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x27, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static struct hda_pcm_stream vt1718S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 10, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1718S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1718S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + /* 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 struct hda_pcm_stream vt1718S_pcm_digital_capture = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1718S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 4; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->multiout.dac_nids[i] = 0x8; + break; + case AUTO_SEQ_CENLFE: + spec->multiout.dac_nids[i] = 0xa; + break; + case AUTO_SEQ_SURROUND: + spec->multiout.dac_nids[i] = 0x9; + break; + case AUTO_SEQ_SIDE: + spec->multiout.dac_nids[i] = 0xb; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1718S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[4] = { "Front", "Surround", "C/LFE", "Side" }; + hda_nid_t nid_vols[] = {0x8, 0x9, 0xa, 0xb}; + hda_nid_t nid_mutes[] = {0x24, 0x25, 0x26, 0x27}; + hda_nid_t nid, nid_vol, nid_mute = 0; + int i, err; + + for (i = 0; i <= AUTO_SEQ_SIDE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + /* Center/LFE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + /* Front */ + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1718S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0xc; /* AOW4 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0xc, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1718S_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 5; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x2b: /* Mic */ + idx = 1; + break; + + case 0x2a: /* Line In */ + idx = 2; + break; + + case 0x29: /* Front Mic */ + idx = 3; + break; + + case 0x2c: /* CD */ + idx = 0; + break; + } + err = via_new_analog_input(spec, labels[i], idx, 0x21); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } + return 0; +} + +static int vt1718S_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; + err = vt1718S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1718S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1718S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1718S_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->autocfg.dig_in_pin && codec->vendor_id == 0x11060428) + spec->dig_in_nid = 0x13; + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + spec->mixers[spec->num_mixers++] = via_hp_mixer; + + spec->mixers[spec->num_mixers++] = via_smart51_mixer; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1718S_loopbacks[] = { + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { 0x21, HDA_INPUT, 3 }, + { 0x21, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static int patch_vt1718S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1718S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; + + spec->stream_name_analog = "VT1718S Analog"; + spec->stream_analog_playback = &vt1718S_pcm_analog_playback; + spec->stream_analog_capture = &vt1718S_pcm_analog_capture; + + spec->stream_name_digital = "VT1718S Digital"; + spec->stream_digital_playback = &vt1718S_pcm_digital_playback; + if (codec->vendor_id == 0x11060428) + spec->stream_digital_capture = &vt1718S_pcm_digital_capture; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1718S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event, + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1718S_loopbacks; +#endif + + return 0; +} /* * patch entries */ @@ -3893,6 +4425,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1702}, { .id = 0x11067398, .name = "VT1702", .patch = patch_vt1702}, + { .id = 0x11060428, .name = "VT1718S", + .patch = patch_vt1718S}, + { .id = 0x11064428, .name = "VT1718S", + .patch = patch_vt1718S}, {} /* terminator */ }; -- cgit v1.2.3 From bb3c6bfc3f7a5416d85c5dbc312e2d47fc672eef Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:39 +0800 Subject: ALSA: HDA VIA: Add VT1828S and VT2020 support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index c78385340694..2e7e72c83a52 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -179,6 +179,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) else if ((dev_id & 0xfff) == 0x428 && (dev_id >> 12) < 8) codec_type = VT1718S; + else if (dev_id == 0x0441 || dev_id == 0x4441) + codec_type = VT1718S; else codec_type = UNKNOWN; return codec_type; @@ -4323,21 +4325,31 @@ static int patch_vt1718S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1718S_volume_init_verbs; spec->init_verbs[spec->num_iverbs++] = vt1718S_uniwill_init_verbs; - spec->stream_name_analog = "VT1718S Analog"; + if (codec->vendor_id == 0x11060441) + spec->stream_name_analog = "VT2020 Analog"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_analog = "VT1828S Analog"; + else + spec->stream_name_analog = "VT1718S Analog"; spec->stream_analog_playback = &vt1718S_pcm_analog_playback; spec->stream_analog_capture = &vt1718S_pcm_analog_capture; - spec->stream_name_digital = "VT1718S Digital"; + if (codec->vendor_id == 0x11060441) + spec->stream_name_digital = "VT2020 Digital"; + else if (codec->vendor_id == 0x11064441) + spec->stream_name_digital = "VT1828S Digital"; + else + spec->stream_name_digital = "VT1718S Digital"; spec->stream_digital_playback = &vt1718S_pcm_digital_playback; - if (codec->vendor_id == 0x11060428) + if (codec->vendor_id == 0x11060428 || codec->vendor_id == 0x11060441) spec->stream_digital_capture = &vt1718S_pcm_digital_capture; if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1718S_adc_nids; spec->num_adc_nids = ARRAY_SIZE(vt1718S_adc_nids); get_mux_nids(codec); - override_mic_boost(codec, 0x1a, 0, 3, 40); - override_mic_boost(codec, 0x1e, 0, 3, 40); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); spec->mixers[spec->num_mixers] = vt1718S_capture_mixer; spec->num_mixers++; } @@ -4429,6 +4441,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1718S}, { .id = 0x11064428, .name = "VT1718S", .patch = patch_vt1718S}, + { .id = 0x11060441, .name = "VT2020", + .patch = patch_vt1718S}, + { .id = 0x11064441, .name = "VT1828S", + .patch = patch_vt1718S}, {} /* terminator */ }; -- cgit v1.2.3 From f3db423df84570c9950754a5771ad26f0111235f Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:41 +0800 Subject: ALSA: HDA VIA: Add VT1716S support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 648 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 644 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2e7e72c83a52..2977004677ec 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -87,12 +87,13 @@ enum VIA_HDA_CODEC { VT1708BCE, VT1702, VT1718S, + VT1716S, CODEC_TYPES, }; struct via_spec { /* codec parameterization */ - struct snd_kcontrol_new *mixers[4]; + struct snd_kcontrol_new *mixers[6]; unsigned int num_mixers; struct hda_verb *init_verbs[5]; @@ -135,7 +136,7 @@ struct via_spec { unsigned int hp_independent_mode; unsigned int hp_independent_mode_index; unsigned int smart51_enabled; - + unsigned int dmic_enabled; enum VIA_HDA_CODEC codec_type; /* work to check hp jack state */ @@ -179,6 +180,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) else if ((dev_id & 0xfff) == 0x428 && (dev_id >> 12) < 8) codec_type = VT1718S; + else if (dev_id == 0x0433 || dev_id == 0xa721) + codec_type = VT1716S; else if (dev_id == 0x0441 || dev_id == 0x4441) codec_type = VT1718S; else @@ -189,6 +192,7 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_HP_EVENT 0x01 #define VIA_GPIO_EVENT 0x02 #define VIA_JACK_EVENT 0x04 +#define VIA_MONO_EVENT 0x08 enum { VIA_CTL_WIDGET_VOL, @@ -295,6 +299,11 @@ static hda_nid_t vt1718S_adc_nids[2] = { 0x10, 0x11 }; +static hda_nid_t vt1716S_adc_nids[2] = { + /* ADC1-2 */ + 0x13, 0x14 +}; + /* add dynamic controls */ static int via_add_control(struct via_spec *spec, int type, const char *name, unsigned long val) @@ -584,6 +593,106 @@ static void set_jack_power_state(struct hda_codec *codec) snd_hda_codec_write(codec, 0xc, 0, AC_VERB_SET_POWER_STATE, parm); } + } else if (spec->codec_type == VT1716S) { + unsigned int mono_out, present; + /* SW0 (17h) = stereo mixer */ + imux_is_smixer = snd_hda_codec_read( + codec, 0x17, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* inputs */ + /* PW 1/2/5 (1ah/1bh/1eh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1a, &parm); + set_pin_power_state(codec, 0x1b, &parm); + set_pin_power_state(codec, 0x1e, &parm); + if (imux_is_smixer) + parm = AC_PWRST_D0; + /* SW0 (17h), AIW0(13h) */ + snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x13, 0, AC_VERB_SET_POWER_STATE, + parm); + + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x1e, &parm); + /* PW11 (22h) */ + if (spec->dmic_enabled) + set_pin_power_state(codec, 0x22, &parm); + else + snd_hda_codec_write( + codec, 0x22, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + + /* SW2(26h), AIW1(14h) */ + snd_hda_codec_write(codec, 0x26, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* outputs */ + /* PW0 (19h), SW1 (18h), AOW1 (11h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x19, &parm); + /* Smart 5.1 PW2(1bh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1b, &parm); + snd_hda_codec_write(codec, 0x18, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* PW7 (23h), SW3 (27h), AOW3 (25h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x23, &parm); + /* Smart 5.1 PW1(1ah) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1a, &parm); + snd_hda_codec_write(codec, 0x27, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* Smart 5.1 PW5(1eh) */ + if (spec->smart51_enabled) + set_pin_power_state(codec, 0x1e, &parm); + snd_hda_codec_write(codec, 0x25, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* Mono out */ + /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ + present = snd_hda_codec_read( + codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + if (present) + mono_out = 0; + else { + present = snd_hda_codec_read( + codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0) + & 0x80000000; + if (!spec->hp_independent_mode && present) + mono_out = 0; + else + mono_out = 1; + } + parm = mono_out ? AC_PWRST_D0 : AC_PWRST_D3; + snd_hda_codec_write(codec, 0x28, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x29, 0, AC_VERB_SET_POWER_STATE, + parm); + snd_hda_codec_write(codec, 0x2a, 0, AC_VERB_SET_POWER_STATE, + parm); + + /* PW 3/4 (1ch/1dh) */ + parm = AC_PWRST_D3; + 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) + snd_hda_codec_write(codec, 0x25, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* force to D0 for internal Speaker */ + /* MW0 (16h), AOW0 (10h) */ + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_POWER_STATE, + imux_is_smixer ? AC_PWRST_D0 : parm); + snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, + mono_out ? AC_PWRST_D0 : parm); } } @@ -738,7 +847,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, /* update HP volume/swtich active state */ if (spec->codec_type == VT1708S || spec->codec_type == VT1702 - || spec->codec_type == VT1718S) { + || spec->codec_type == VT1718S + || spec->codec_type == VT1716S) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", @@ -797,6 +907,7 @@ static void mute_aa_path(struct hda_codec *codec, int mute) case VT1708B_8CH: case VT1708B_4CH: case VT1708S: + case VT1716S: nid_mixer = 0x16; start_idx = 2; end_idx = 4; @@ -898,7 +1009,8 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, HDA_AMP_UNMUTE); } if (i == AUTO_PIN_FRONT_MIC) { - if (spec->codec_type == VT1708S) { + if (spec->codec_type == VT1708S + || spec->codec_type == VT1716S) { /* input = index 1 (AOW3) */ snd_hda_codec_write( codec, nid, 0, @@ -961,6 +1073,7 @@ static int is_aa_path_mute(struct hda_codec *codec) case VT1708B_8CH: case VT1708B_4CH: case VT1708S: + case VT1716S: nid_mixer = 0x16; start_idx = 2; end_idx = 4; @@ -1025,6 +1138,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) break; case VT1708S: case VT1718S: + case VT1716S: verb = 0xf73; parm = enable ? 0x51 : 0xe1; /* 0x51: 4/28x, 0xe1: 1x */ break; @@ -1453,6 +1567,36 @@ static void via_hp_automute(struct hda_codec *codec) } } +/* mute mono out if HP or Line out is plugged */ +static void via_mono_automute(struct hda_codec *codec) +{ + unsigned int hp_present, lineout_present; + struct via_spec *spec = codec->spec; + + if (spec->codec_type != VT1716S) + return; + + lineout_present = snd_hda_codec_read( + codec, spec->autocfg.line_out_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + /* Mute Mono Out if Line Out is plugged */ + if (lineout_present) { + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); + return; + } + + hp_present = snd_hda_codec_read( + codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + if (!spec->hp_independent_mode) + snd_hda_codec_amp_stereo( + codec, 0x2A, HDA_OUTPUT, 0, HDA_AMP_MUTE, + hp_present ? HDA_AMP_MUTE : 0); +} + static void via_gpio_control(struct hda_codec *codec) { unsigned int gpio_data; @@ -1512,6 +1656,8 @@ static void via_unsol_event(struct hda_codec *codec, via_gpio_control(codec); if (res & VIA_JACK_EVENT) set_jack_power_state(codec); + if (res & VIA_MONO_EVENT) + via_mono_automute(codec); } static int via_init(struct hda_codec *codec) @@ -4365,6 +4511,496 @@ static int patch_vt1718S(struct hda_codec *codec) return 0; } + +/* Patch for VT1716S */ + +static int vt1716s_dmic_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; + uinfo->count = 1; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 1; + return 0; +} + +static int vt1716s_dmic_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + int index = 0; + + index = snd_hda_codec_read(codec, 0x26, 0, + AC_VERB_GET_CONNECT_SEL, 0); + if (index != -1) + *ucontrol->value.integer.value = index; + + return 0; +} + +static int vt1716s_dmic_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 index = *ucontrol->value.integer.value; + + snd_hda_codec_write(codec, 0x26, 0, + AC_VERB_SET_CONNECT_SEL, index); + spec->dmic_enabled = index; + set_jack_power_state(codec); + + return 1; +} + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1716S_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x13, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x14, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x1A, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x1E, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Input Source", + .count = 1, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { + HDA_CODEC_VOLUME("Digital Mic Capture Volume", 0x22, 0x0, HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Digital Mic Capture Switch", + .count = 1, + .info = vt1716s_dmic_info, + .get = vt1716s_dmic_get, + .put = vt1716s_dmic_put, + }, + {} /* end */ +}; + + +/* mono-out mixer elements */ +static struct snd_kcontrol_new vt1716S_mono_out_mixer[] = { + HDA_CODEC_MUTE("Mono Playback Switch", 0x2a, 0x0, HDA_OUTPUT), + { } /* end */ +}; + +static struct hda_verb vt1716S_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x13, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {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)}, + {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Stereo Mixer = 5 */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0x5}, + + /* Setup default input of PW4 to MW0 */ + {0x1d, AC_VERB_SET_CONNECT_SEL, 0x0}, + + /* Setup default input of SW1 as MW0 */ + {0x18, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* Setup default input of SW4 as AOW0 */ + {0x28, AC_VERB_SET_CONNECT_SEL, 0x1}, + + /* PW9 PW10 Output enable */ + {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + + /* Unmute SW1, PW12 */ + {0x29, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x2a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + /* PW12 Output enable */ + {0x2a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, + /* Enable Boost Volume backdoor */ + {0x1, 0xf8a, 0x80}, + /* don't bybass mixer */ + {0x1, 0xf88, 0xc0}, + /* Enable mono output */ + {0x1, 0xf90, 0x08}, + { } +}; + + +static struct hda_verb vt1716S_uniwill_init_verbs[] = { + {0x1d, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_HP_EVENT | VIA_JACK_EVENT}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x1c, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_MONO_EVENT | VIA_JACK_EVENT}, + {0x1e, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x23, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static struct hda_pcm_stream vt1716S_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 6, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1716S_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x13, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1716S_pcm_digital_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + /* 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 + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1716S_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ int i; + hda_nid_t nid; + + spec->multiout.num_dacs = cfg->line_outs; + + spec->multiout.dac_nids = spec->private_dac_nids; + + for (i = 0; i < 3; i++) { + nid = cfg->line_out_pins[i]; + if (nid) { + /* config dac list */ + switch (i) { + case AUTO_SEQ_FRONT: + spec->multiout.dac_nids[i] = 0x10; + break; + case AUTO_SEQ_CENLFE: + spec->multiout.dac_nids[i] = 0x25; + break; + case AUTO_SEQ_SURROUND: + spec->multiout.dac_nids[i] = 0x11; + break; + } + } + } + + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt1716S_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + char name[32]; + static const char *chname[3] = { "Front", "Surround", "C/LFE" }; + hda_nid_t nid_vols[] = {0x10, 0x11, 0x25}; + hda_nid_t nid_mutes[] = {0x1C, 0x18, 0x27}; + hda_nid_t nid, nid_vol, nid_mute; + int i, err; + + for (i = 0; i <= AUTO_SEQ_CENLFE; i++) { + nid = cfg->line_out_pins[i]; + + if (!nid) + continue; + + nid_vol = nid_vols[i]; + nid_mute = nid_mutes[i]; + + if (i == AUTO_SEQ_CENLFE) { + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Center Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 1, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "LFE Playback Volume", + HDA_COMPOSE_AMP_VAL(nid_vol, 2, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Center Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 1, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "LFE Playback Switch", + HDA_COMPOSE_AMP_VAL(nid_mute, 2, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else if (i == AUTO_SEQ_FRONT) { + + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x16, 3, 0, HDA_INPUT)); + if (err < 0) + return err; + + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } else { + sprintf(name, "%s Playback Volume", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_VOL, name, + HDA_COMPOSE_AMP_VAL(nid_vol, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + sprintf(name, "%s Playback Switch", chname[i]); + err = via_add_control( + spec, VIA_CTL_WIDGET_MUTE, name, + HDA_COMPOSE_AMP_VAL(nid_mute, 3, 0, + HDA_OUTPUT)); + if (err < 0) + return err; + } + } + return 0; +} + +static int vt1716S_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x25; /* AOW3 */ + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1716S_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 5; + imux->num_items++; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x1a: /* Mic */ + idx = 2; + break; + + case 0x1b: /* Line In */ + idx = 3; + break; + + case 0x1e: /* Front Mic */ + idx = 4; + break; + + case 0x1f: /* CD */ + idx = 1; + break; + } + err = via_new_analog_input(spec, labels[i], idx, 0x16); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx-1; + imux->num_items++; + } + return 0; +} + +static int vt1716S_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; + err = vt1716S_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt1716S_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1716S_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1716S_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + spec->mixers[spec->num_mixers++] = via_hp_mixer; + + spec->mixers[spec->num_mixers++] = via_smart51_mixer; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1716S_loopbacks[] = { + { 0x16, HDA_INPUT, 1 }, + { 0x16, HDA_INPUT, 2 }, + { 0x16, HDA_INPUT, 3 }, + { 0x16, HDA_INPUT, 4 }, + { } /* end */ +}; +#endif + +static int patch_vt1716S(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1716S_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt1716S_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1716S_uniwill_init_verbs; + + spec->stream_name_analog = "VT1716S Analog"; + spec->stream_analog_playback = &vt1716S_pcm_analog_playback; + spec->stream_analog_capture = &vt1716S_pcm_analog_capture; + + spec->stream_name_digital = "VT1716S Digital"; + spec->stream_digital_playback = &vt1716S_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1716S_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1716S_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x1a, 0, 3, 40); + override_mic_boost(codec, 0x1e, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1716S_capture_mixer; + spec->num_mixers++; + } + + spec->mixers[spec->num_mixers] = vt1716s_dmic_mixer; + spec->num_mixers++; + + spec->mixers[spec->num_mixers++] = vt1716S_mono_out_mixer; + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event, + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1716S_loopbacks; +#endif + + return 0; +} /* * patch entries */ @@ -4445,6 +5081,10 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1718S}, { .id = 0x11064441, .name = "VT1828S", .patch = patch_vt1718S}, + { .id = 0x11060433, .name = "VT1716S", + .patch = patch_vt1716S}, + { .id = 0x1106a721, .name = "VT1716S", + .patch = patch_vt1716S}, {} /* terminator */ }; -- cgit v1.2.3 From 25eaba2f8a6877ba6f58197c4723c2433a316e09 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:43 +0800 Subject: ALSA: HDA VIA: Add VT2002P support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 665 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 660 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 2977004677ec..a94cc91c18ff 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -88,6 +88,7 @@ enum VIA_HDA_CODEC { VT1702, VT1718S, VT1716S, + VT2002P, CODEC_TYPES, }; @@ -184,6 +185,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1716S; else if (dev_id == 0x0441 || dev_id == 0x4441) codec_type = VT1718S; + else if (dev_id == 0x0438 || dev_id == 0x4438) + codec_type = VT2002P; else codec_type = UNKNOWN; return codec_type; @@ -193,11 +196,14 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) #define VIA_GPIO_EVENT 0x02 #define VIA_JACK_EVENT 0x04 #define VIA_MONO_EVENT 0x08 +#define VIA_SPEAKER_EVENT 0x10 +#define VIA_BIND_HP_EVENT 0x20 enum { VIA_CTL_WIDGET_VOL, VIA_CTL_WIDGET_MUTE, VIA_CTL_WIDGET_ANALOG_MUTE, + VIA_CTL_WIDGET_BIND_PIN_MUTE, }; enum { @@ -235,6 +241,7 @@ static void vt1708_stop_hp_work(struct via_spec *spec) flush_scheduled_work(); } + static int analog_input_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -262,13 +269,108 @@ static int analog_input_switch_put(struct snd_kcontrol *kcontrol, .put = analog_input_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } +static void via_hp_bind_automute(struct hda_codec *codec); + +static int bind_pin_switch_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 i; + int change = 0; + + long *valp = ucontrol->value.integer.value; + int lmute, rmute; + if (strstr(kcontrol->id.name, "Switch") == NULL) { + snd_printd("Invalid control!\n"); + return change; + } + change = snd_hda_mixer_amp_switch_put(kcontrol, + ucontrol); + /* Get mute value */ + lmute = *valp ? 0 : HDA_AMP_MUTE; + valp++; + rmute = *valp ? 0 : HDA_AMP_MUTE; + + /* Set hp pins */ + if (!spec->hp_independent_mode) { + for (i = 0; i < spec->autocfg.hp_outs; i++) { + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + snd_hda_codec_amp_update( + codec, spec->autocfg.hp_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + + if (!lmute && !rmute) { + /* Line Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], + HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); + /* unmute */ + via_hp_bind_automute(codec); + + } else { + if (lmute) { + /* Mute all left channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 0, HDA_OUTPUT, 0, HDA_AMP_MUTE, + lmute); + } + if (rmute) { + /* mute all right channels */ + for (i = 1; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.line_out_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_update( + codec, + spec->autocfg.speaker_pins[i], + 1, HDA_OUTPUT, 0, HDA_AMP_MUTE, + rmute); + } + } + return change; +} + +#define BIND_PIN_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 = bind_pin_switch_put, \ + .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } + static struct snd_kcontrol_new vt1708_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, + BIND_PIN_MUTE, }; - static hda_nid_t vt1708_adc_nids[2] = { /* ADC1-2 */ 0x15, 0x27 @@ -304,6 +406,11 @@ static hda_nid_t vt1716S_adc_nids[2] = { 0x13, 0x14 }; +static hda_nid_t vt2002P_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + /* add dynamic controls */ static int via_add_control(struct via_spec *spec, int type, const char *name, unsigned long val) @@ -386,10 +493,13 @@ static void via_auto_init_hp_out(struct hda_codec *codec) { struct via_spec *spec = codec->spec; hda_nid_t pin; + int i; - pin = spec->autocfg.hp_pins[0]; - if (pin) /* connect to front */ - via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + for (i = 0; i < spec->autocfg.hp_outs; i++) { + pin = spec->autocfg.hp_pins[i]; + if (pin) /* connect to front */ + via_auto_set_output_and_unmute(codec, pin, PIN_HP, 0); + } } static void via_auto_init_analog_input(struct hda_codec *codec) @@ -693,6 +803,107 @@ static void set_jack_power_state(struct hda_codec *codec) imux_is_smixer ? AC_PWRST_D0 : parm); snd_hda_codec_write(codec, 0x10, 0, AC_VERB_SET_POWER_STATE, mono_out ? AC_PWRST_D0 : parm); + } else if (spec->codec_type == VT2002P) { + unsigned int present; + /* MUX9 (1eh) = stereo mixer */ + imux_is_smixer = snd_hda_codec_read( + codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 3; + /* 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; + /* MUX9/10 (1eh/1fh), AIW 0/1 (10h/11h) */ + snd_hda_codec_write(codec, 0x1e, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* PW4 (26h), MW4 (1ch), MUX4(37h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x26, &parm); + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x37, + 0, AC_VERB_SET_POWER_STATE, parm); + + /* PW1 (25h), MW1 (19h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x19, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + if (spec->hp_independent_mode) { + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* Class-D */ + /* PW0 (24h), MW0(18h), MUX0(34h) */ + present = snd_hda_codec_read( + codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (present) { + snd_hda_codec_write( + codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write( + codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write( + codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write( + codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + /* Mono Out */ + /* PW15 (31h), MW8(17h), MUX8(3bh) */ + present = snd_hda_codec_read( + codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x31, &parm); + if (present) { + snd_hda_codec_write( + codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + snd_hda_codec_write( + codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else { + snd_hda_codec_write( + codec, 0x17, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + snd_hda_codec_write( + codec, 0x3b, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + } + + /* MW9 (21h) */ + if (imux_is_smixer || !is_aa_path_mute(codec)) + snd_hda_codec_write( + codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + else + snd_hda_codec_write( + codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); } } @@ -760,6 +971,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, case VT1718S: nid = 0x34; break; + case VT2002P: + nid = 0x35; + break; default: nid = spec->autocfg.hp_pins[0]; break; @@ -832,6 +1046,9 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ spec->multiout.num_dacs = 4; break; + case VT2002P: + nid = 0x35; + break; default: nid = spec->autocfg.hp_pins[0]; break; @@ -848,7 +1065,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, if (spec->codec_type == VT1708S || spec->codec_type == VT1702 || spec->codec_type == VT1718S - || spec->codec_type == VT1716S) { + || spec->codec_type == VT1716S + || spec->codec_type == VT2002P) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", @@ -1088,6 +1306,11 @@ static int is_aa_path_mute(struct hda_codec *codec) start_idx = 1; end_idx = 3; break; + case VT2002P: + nid_mixer = 0x21; + start_idx = 0; + end_idx = 2; + break; default: return 0; } @@ -1146,6 +1369,10 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) verb = 0xf73; parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ break; + case VT2002P: + verb = 0xf93; + parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ + break; default: return; /* other codecs are not supported */ } @@ -1645,6 +1872,66 @@ static void via_gpio_control(struct hda_codec *codec) } } +/* mute Internal-Speaker if HP is plugged */ +static void via_speaker_automute(struct hda_codec *codec) +{ + unsigned int hp_present; + struct via_spec *spec = codec->spec; + + if (spec->codec_type != VT2002P) + return; + + hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + if (!spec->hp_independent_mode) { + struct snd_ctl_elem_id id; + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[0], HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + /* notify change */ + memset(&id, 0, sizeof(id)); + id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; + strcpy(id.name, "Speaker Playback Switch"); + snd_ctl_notify(codec->bus->card, SNDRV_CTL_EVENT_MASK_VALUE, + &id); + } +} + +/* mute line-out and internal speaker if HP is plugged */ +static void via_hp_bind_automute(struct hda_codec *codec) +{ + unsigned int hp_present, present = 0; + struct via_spec *spec = codec->spec; + int i; + + if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0]) + return; + + hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + + if (!spec->hp_independent_mode) { + /* Mute Line-Outs */ + for (i = 0; i < spec->autocfg.line_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.line_out_pins[i], + HDA_OUTPUT, 0, + HDA_AMP_MUTE, hp_present ? HDA_AMP_MUTE : 0); + if (hp_present) + present = hp_present; + } + /* Speakers */ + for (i = 0; i < spec->autocfg.speaker_outs; i++) + snd_hda_codec_amp_stereo( + codec, spec->autocfg.speaker_pins[i], HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); +} + + /* unsolicited event for jack sensing */ static void via_unsol_event(struct hda_codec *codec, unsigned int res) @@ -1658,6 +1945,10 @@ static void via_unsol_event(struct hda_codec *codec, set_jack_power_state(codec); if (res & VIA_MONO_EVENT) via_mono_automute(codec); + if (res & VIA_SPEAKER_EVENT) + via_speaker_automute(codec); + if (res & VIA_BIND_HP_EVENT) + via_hp_bind_automute(codec); } static int via_init(struct hda_codec *codec) @@ -2067,10 +2358,19 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) /* init callback for auto-configuration model -- overriding the default init */ static int via_auto_init(struct hda_codec *codec) { + struct via_spec *spec = codec->spec; + via_init(codec); via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); + if (spec->codec_type == VT2002P) { + via_hp_bind_automute(codec); + } else { + via_hp_automute(codec); + via_speaker_automute(codec); + } + return 0; } @@ -5001,6 +5301,359 @@ static int patch_vt1716S(struct hda_codec *codec) return 0; } + +/* for vt2002P */ + +/* capture mixer elements */ +static struct snd_kcontrol_new vt2002P_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .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 = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct hda_verb vt2002P_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/8: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/8 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x37, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3b, AC_VERB_SET_CONNECT_SEL, 0}, + + /* set PW0 index=0 (MW0) */ + {0x24, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0x88}, + { } +}; + + +static struct hda_verb vt2002P_uniwill_init_verbs[] = { + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x26, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static struct hda_pcm_stream vt2002P_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt2002P_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt2002P_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + /* 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 + }, +}; + +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt2002P_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->multiout.dac_nids[0] = 0x8; + return 0; +} + +/* add playback controls from the parsed DAC table */ +static int vt2002P_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + if (!cfg->line_out_pins[0]) + return -1; + + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x26, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt2002P_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(0x25, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt2002P_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x2b: /* Mic */ + idx = 0; + break; + + case 0x2a: /* Line In */ + idx = 1; + break; + + case 0x29: /* Front Mic */ + idx = 2; + break; + } + err = via_new_analog_input(spec, labels[i], idx, 0x21); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } + + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 3, 0x21); + if (err < 0) + return err; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 3; + imux->num_items++; + + /* for digital mic select */ + imux->items[imux->num_items].label = "Digital Mic"; + imux->items[imux->num_items].index = 4; + imux->num_items++; + + return 0; +} + +static int vt2002P_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; + + err = vt2002P_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs && !spec->autocfg.hp_pins[0]) + return 0; /* can't find valid BIOS pin config */ + + err = vt2002P_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt2002P_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt2002P_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + spec->mixers[spec->num_mixers++] = via_hp_mixer; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt2002P_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ +}; +#endif + + +/* patch for vt2002P */ +static int patch_vt2002P(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt2002P_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + spec->init_verbs[spec->num_iverbs++] = vt2002P_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt2002P_uniwill_init_verbs; + + spec->stream_name_analog = "VT2002P Analog"; + spec->stream_analog_playback = &vt2002P_pcm_analog_playback; + spec->stream_analog_capture = &vt2002P_pcm_analog_capture; + + spec->stream_name_digital = "VT2002P Digital"; + spec->stream_digital_playback = &vt2002P_pcm_digital_playback; + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt2002P_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt2002P_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt2002P_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event, + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt2002P_loopbacks; +#endif + + return 0; +} /* * patch entries */ @@ -5085,6 +5738,8 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1716S}, { .id = 0x1106a721, .name = "VT1716S", .patch = patch_vt1716S}, + { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, + { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, {} /* terminator */ }; -- cgit v1.2.3 From ab6734e7ea32e9f9cbe0f55eeddf4aa629ed1c3d Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:46 +0800 Subject: ALSA: HDA VIA: Add VT1812 support. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 494 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 491 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index a94cc91c18ff..b3c5e8a78154 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -89,6 +89,7 @@ enum VIA_HDA_CODEC { VT1718S, VT1716S, VT2002P, + VT1812, CODEC_TYPES, }; @@ -187,6 +188,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT1718S; else if (dev_id == 0x0438 || dev_id == 0x4438) codec_type = VT2002P; + else if (dev_id == 0x0448) + codec_type = VT1812; else codec_type = UNKNOWN; return codec_type; @@ -411,6 +414,12 @@ static hda_nid_t vt2002P_adc_nids[2] = { 0x10, 0x11 }; +static hda_nid_t vt1812_adc_nids[2] = { + /* ADC1-2 */ + 0x10, 0x11 +}; + + /* add dynamic controls */ static int via_add_control(struct via_spec *spec, int type, const char *name, unsigned long val) @@ -895,6 +904,120 @@ static void set_jack_power_state(struct hda_codec *codec) AC_VERB_SET_POWER_STATE, AC_PWRST_D0); } + /* MW9 (21h) */ + if (imux_is_smixer || !is_aa_path_mute(codec)) + snd_hda_codec_write( + codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + else + snd_hda_codec_write( + codec, 0x21, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D3); + } else if (spec->codec_type == VT1812) { + unsigned int present; + /* MUX10 (1eh) = stereo mixer */ + imux_is_smixer = snd_hda_codec_read( + codec, 0x1e, 0, AC_VERB_GET_CONNECT_SEL, 0x00) == 5; + /* 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) */ + snd_hda_codec_write(codec, 0x1e, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x1f, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x10, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x11, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* outputs */ + /* AOW0 (8h)*/ + snd_hda_codec_write(codec, 0x8, 0, + AC_VERB_SET_POWER_STATE, AC_PWRST_D0); + + /* PW4 (28h), MW4 (18h), MUX4(38h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x28, &parm); + snd_hda_codec_write(codec, 0x18, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x38, 0, + AC_VERB_SET_POWER_STATE, parm); + + /* PW1 (25h), MW1 (15h), MUX1(35h), AOW1 (9h) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x25, &parm); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x35, 0, + AC_VERB_SET_POWER_STATE, parm); + if (spec->hp_independent_mode) { + snd_hda_codec_write(codec, 0x9, 0, + AC_VERB_SET_POWER_STATE, parm); + } + + /* Internal Speaker */ + /* PW0 (24h), MW0(14h), MUX0(34h) */ + present = snd_hda_codec_read( + codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x24, &parm); + if (present) { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + snd_hda_codec_write(codec, 0x34, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + } + /* Mono Out */ + /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ + present = snd_hda_codec_read( + codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x31, &parm); + if (present) { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D3); + } else { + snd_hda_codec_write(codec, 0x1c, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3c, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + snd_hda_codec_write(codec, 0x3e, 0, + AC_VERB_SET_POWER_STATE, + AC_PWRST_D0); + } + + /* PW15 (33h), MW15 (1dh), MUX15(3dh) */ + parm = AC_PWRST_D3; + set_pin_power_state(codec, 0x33, &parm); + snd_hda_codec_write(codec, 0x1d, 0, + AC_VERB_SET_POWER_STATE, parm); + snd_hda_codec_write(codec, 0x3d, 0, + AC_VERB_SET_POWER_STATE, parm); + /* MW9 (21h) */ if (imux_is_smixer || !is_aa_path_mute(codec)) snd_hda_codec_write( @@ -974,6 +1097,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, case VT2002P: nid = 0x35; break; + case VT1812: + nid = 0x3d; + break; default: nid = spec->autocfg.hp_pins[0]; break; @@ -1049,6 +1175,9 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, case VT2002P: nid = 0x35; break; + case VT1812: + nid = 0x3d; + break; default: nid = spec->autocfg.hp_pins[0]; break; @@ -1066,7 +1195,8 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, || spec->codec_type == VT1702 || spec->codec_type == VT1718S || spec->codec_type == VT1716S - || spec->codec_type == VT2002P) { + || spec->codec_type == VT2002P + || spec->codec_type == VT1812) { activate_ctl(codec, "Headphone Playback Volume", spec->hp_independent_mode); activate_ctl(codec, "Headphone Playback Switch", @@ -1307,6 +1437,7 @@ static int is_aa_path_mute(struct hda_codec *codec) end_idx = 3; break; case VT2002P: + case VT1812: nid_mixer = 0x21; start_idx = 0; end_idx = 2; @@ -1370,6 +1501,7 @@ static void analog_low_current_mode(struct hda_codec *codec, int stream_idle) parm = enable ? 0x01 : 0x1d; /* 0x01: 4/40x, 0x1d: 1x */ break; case VT2002P: + case VT1812: verb = 0xf93; parm = enable ? 0x00 : 0xe0; /* 0x00: 4/40x, 0xe0: 1x */ break; @@ -1878,7 +2010,7 @@ static void via_speaker_automute(struct hda_codec *codec) unsigned int hp_present; struct via_spec *spec = codec->spec; - if (spec->codec_type != VT2002P) + if (spec->codec_type != VT2002P && spec->codec_type != VT1812) return; hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, @@ -2364,7 +2496,7 @@ static int via_auto_init(struct hda_codec *codec) via_auto_init_multi_out(codec); via_auto_init_hp_out(codec); via_auto_init_analog_input(codec); - if (spec->codec_type == VT2002P) { + if (spec->codec_type == VT2002P || spec->codec_type == VT1812) { via_hp_bind_automute(codec); } else { via_hp_automute(codec); @@ -5654,6 +5786,361 @@ static int patch_vt2002P(struct hda_codec *codec) return 0; } + +/* for vt1812 */ + +/* capture mixer elements */ +static struct snd_kcontrol_new vt1812_capture_mixer[] = { + HDA_CODEC_VOLUME("Capture Volume", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Capture Switch", 0x10, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x11, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Boost Capture Volume", 0x2b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Front Mic Boost Capture Volume", 0x29, 0x0, + HDA_INPUT), + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + /* The multiple "Capture Source" controls confuse alsamixer + * So call somewhat different.. + */ + .name = "Input Source", + .count = 2, + .info = via_mux_enum_info, + .get = via_mux_enum_get, + .put = via_mux_enum_put, + }, + { } /* end */ +}; + +static struct hda_verb vt1812_volume_init_verbs[] = { + /* + * Unmute ADC0-1 and set the default input to mic-in + */ + {0x8, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x9, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + + + /* Mute input amps (CD, Line In, Mic 1 & Mic 2) of the analog-loopback + * mixer widget + */ + /* Amp Indices: CD = 1, Mic1 = 2, Line = 3, Mic2 = 4 */ + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + + /* MUX Indices: Mic = 0 */ + {0x1e, AC_VERB_SET_CONNECT_SEL, 0}, + {0x1f, AC_VERB_SET_CONNECT_SEL, 0}, + + /* PW9 Output enable */ + {0x2d, AC_VERB_SET_PIN_WIDGET_CONTROL, AC_PINCTL_OUT_EN}, + + /* Enable Boost Volume backdoor */ + {0x1, 0xfb9, 0x24}, + + /* MW0/1/4/13/15: un-mute index 0 (MUXx), un-mute index 1 (MW9) */ + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, + + /* set MUX0/1/4/13/15 = 0 (AOW0) */ + {0x34, AC_VERB_SET_CONNECT_SEL, 0}, + {0x35, AC_VERB_SET_CONNECT_SEL, 0}, + {0x38, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3c, AC_VERB_SET_CONNECT_SEL, 0}, + {0x3d, AC_VERB_SET_CONNECT_SEL, 0}, + + /* Enable AOW0 to MW9 */ + {0x1, 0xfb8, 0xa8}, + { } +}; + + +static struct hda_verb vt1812_uniwill_init_verbs[] = { + {0x33, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x25, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT }, + {0x28, AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | VIA_JACK_EVENT | VIA_BIND_HP_EVENT}, + {0x29, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2a, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + {0x2b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | VIA_JACK_EVENT}, + { } +}; + +static struct hda_pcm_stream vt1812_pcm_analog_playback = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x8, /* NID to query formats and rates */ + .ops = { + .open = via_playback_pcm_open, + .prepare = via_playback_multi_pcm_prepare, + .cleanup = via_playback_multi_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1812_pcm_analog_capture = { + .substreams = 2, + .channels_min = 2, + .channels_max = 2, + .nid = 0x10, /* NID to query formats and rates */ + .ops = { + .open = via_pcm_open_close, + .prepare = via_capture_pcm_prepare, + .cleanup = via_capture_pcm_cleanup, + .close = via_pcm_open_close, + }, +}; + +static struct hda_pcm_stream vt1812_pcm_digital_playback = { + .substreams = 1, + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_48000, + /* 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 + }, +}; +/* fill in the dac_nids table from the parsed pin configuration */ +static int vt1812_auto_fill_dac_nids(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + spec->multiout.num_dacs = 1; + spec->multiout.dac_nids = spec->private_dac_nids; + if (cfg->line_out_pins[0]) + spec->multiout.dac_nids[0] = 0x8; + return 0; +} + + +/* add playback controls from the parsed DAC table */ +static int vt1812_auto_create_multi_out_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + int err; + + if (!cfg->line_out_pins[0]) + return -1; + + /* Line-Out: PortE */ + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Master Front Playback Volume", + HDA_COMPOSE_AMP_VAL(0x8, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + err = via_add_control(spec, VIA_CTL_WIDGET_BIND_PIN_MUTE, + "Master Front Playback Switch", + HDA_COMPOSE_AMP_VAL(0x28, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + return 0; +} + +static int vt1812_auto_create_hp_ctls(struct via_spec *spec, hda_nid_t pin) +{ + int err; + + if (!pin) + return 0; + + spec->multiout.hp_nid = 0x9; + spec->hp_independent_mode_index = 1; + + + err = via_add_control(spec, VIA_CTL_WIDGET_VOL, + "Headphone Playback Volume", + HDA_COMPOSE_AMP_VAL( + spec->multiout.hp_nid, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + err = via_add_control(spec, VIA_CTL_WIDGET_MUTE, + "Headphone Playback Switch", + HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_OUTPUT)); + if (err < 0) + return err; + + create_hp_imux(spec); + return 0; +} + +/* create playback/capture controls for input pins */ +static int vt1812_auto_create_analog_input_ctls(struct via_spec *spec, + const struct auto_pin_cfg *cfg) +{ + static char *labels[] = { + "Mic", "Front Mic", "Line", "Front Line", "CD", "Aux", NULL + }; + struct hda_input_mux *imux = &spec->private_imux[0]; + int i, err, idx = 0; + + for (i = 0; i < AUTO_PIN_LAST; i++) { + if (!cfg->input_pins[i]) + continue; + + switch (cfg->input_pins[i]) { + case 0x2b: /* Mic */ + idx = 0; + break; + + case 0x2a: /* Line In */ + idx = 1; + break; + + case 0x29: /* Front Mic */ + idx = 2; + break; + } + err = via_new_analog_input(spec, labels[i], idx, 0x21); + if (err < 0) + return err; + imux->items[imux->num_items].label = labels[i]; + imux->items[imux->num_items].index = idx; + imux->num_items++; + } + /* build volume/mute control of loopback */ + err = via_new_analog_input(spec, "Stereo Mixer", 5, 0x21); + if (err < 0) + return err; + + /* for internal loopback recording select */ + imux->items[imux->num_items].label = "Stereo Mixer"; + imux->items[imux->num_items].index = 5; + imux->num_items++; + + /* for digital mic select */ + imux->items[imux->num_items].label = "Digital Mic"; + imux->items[imux->num_items].index = 6; + imux->num_items++; + + return 0; +} + +static int vt1812_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; + fill_dig_outs(codec); + err = vt1812_auto_fill_dac_nids(spec, &spec->autocfg); + if (err < 0) + return err; + + if (!spec->autocfg.line_outs && !spec->autocfg.hp_outs) + return 0; /* can't find valid BIOS pin config */ + + err = vt1812_auto_create_multi_out_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + err = vt1812_auto_create_hp_ctls(spec, spec->autocfg.hp_pins[0]); + if (err < 0) + return err; + err = vt1812_auto_create_analog_input_ctls(spec, &spec->autocfg); + if (err < 0) + return err; + + spec->multiout.max_channels = spec->multiout.num_dacs * 2; + + fill_dig_outs(codec); + + if (spec->kctls.list) + spec->mixers[spec->num_mixers++] = spec->kctls.list; + + spec->input_mux = &spec->private_imux[0]; + + if (spec->hp_mux) + spec->mixers[spec->num_mixers++] = via_hp_mixer; + + return 1; +} + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static struct hda_amp_list vt1812_loopbacks[] = { + { 0x21, HDA_INPUT, 0 }, + { 0x21, HDA_INPUT, 1 }, + { 0x21, HDA_INPUT, 2 }, + { } /* end */ +}; +#endif + + +/* patch for vt1812 */ +static int patch_vt1812(struct hda_codec *codec) +{ + struct via_spec *spec; + int err; + + /* create a codec specific record */ + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + /* automatic parse from the BIOS config */ + err = vt1812_parse_auto_config(codec); + if (err < 0) { + via_free(codec); + return err; + } else if (!err) { + printk(KERN_INFO "hda_codec: Cannot set up configuration " + "from BIOS. Using genenic mode...\n"); + } + + + spec->init_verbs[spec->num_iverbs++] = vt1812_volume_init_verbs; + spec->init_verbs[spec->num_iverbs++] = vt1812_uniwill_init_verbs; + + spec->stream_name_analog = "VT1812 Analog"; + spec->stream_analog_playback = &vt1812_pcm_analog_playback; + spec->stream_analog_capture = &vt1812_pcm_analog_capture; + + spec->stream_name_digital = "VT1812 Digital"; + spec->stream_digital_playback = &vt1812_pcm_digital_playback; + + + if (!spec->adc_nids && spec->input_mux) { + spec->adc_nids = vt1812_adc_nids; + spec->num_adc_nids = ARRAY_SIZE(vt1812_adc_nids); + get_mux_nids(codec); + override_mic_boost(codec, 0x2b, 0, 3, 40); + override_mic_boost(codec, 0x29, 0, 3, 40); + spec->mixers[spec->num_mixers] = vt1812_capture_mixer; + spec->num_mixers++; + } + + codec->patch_ops = via_patch_ops; + + codec->patch_ops.init = via_auto_init; + codec->patch_ops.unsol_event = via_unsol_event, + +#ifdef CONFIG_SND_HDA_POWER_SAVE + spec->loopback.amplist = vt1812_loopbacks; +#endif + + return 0; +} + /* * patch entries */ @@ -5740,6 +6227,7 @@ static struct hda_codec_preset snd_hda_preset_via[] = { .patch = patch_vt1716S}, { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, + { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, {} /* terminator */ }; -- cgit v1.2.3 From 71eb7dccb7d2d22236dbe46db07f8000d09fba01 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:49 +0800 Subject: ALSA: HDA VIA: rename vt1708_control_templates[]. To via_control_templates[]. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b3c5e8a78154..257b51c61422 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -367,7 +367,7 @@ static int bind_pin_switch_put(struct snd_kcontrol *kcontrol, .put = bind_pin_switch_put, \ .private_value = HDA_COMPOSE_AMP_VAL(0, 3, 0, 0) } -static struct snd_kcontrol_new vt1708_control_templates[] = { +static struct snd_kcontrol_new via_control_templates[] = { HDA_CODEC_VOLUME(NULL, 0, 0, 0), HDA_CODEC_MUTE(NULL, 0, 0, 0), ANALOG_INPUT_MUTE, @@ -430,7 +430,7 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, knew = snd_array_new(&spec->kctls); if (!knew) return -ENOMEM; - *knew = vt1708_control_templates[type]; + *knew = via_control_templates[type]; knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; -- cgit v1.2.3 From bfdc675a73f7697ead12c07dbf11e2b2632676f4 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:50 +0800 Subject: ALSA: HDA VIA: Change PW4 connect select default to to MW0. According to customer request, hp should be default to redirected mode, i.e. PW4 connect select default to to MW0. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 257b51c61422..4ea18a759a05 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1541,8 +1541,8 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Setup default input to PW4 */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* Setup default input MW0 to PW4 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x25, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, { } @@ -2668,8 +2668,8 @@ static struct hda_verb vt1709_10ch_volume_init_verbs[] = { {0x1f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x20, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - /* Set input of PW4 as AOW4 */ - {0x20, AC_VERB_SET_CONNECT_SEL, 0x1}, + /* Set input of PW4 as MW0 */ + {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x24, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, { } @@ -3222,7 +3222,7 @@ static struct hda_verb vt1708B_8ch_volume_init_verbs[] = { {0x27, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, /* Setup default input to PW4 */ - {0x1d, AC_VERB_SET_CONNECT_SEL, 0x1}, + {0x1d, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ {0x20, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40}, /* PW10 Input enable */ -- cgit v1.2.3 From 8e86597f3cbd0a58808560116abe1bc0023256b0 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:52 +0800 Subject: ALSA: HDA VIA: comments: update copyright, changeset, etc. Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 4ea18a759a05..fab875a21726 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -1,10 +1,10 @@ /* * Universal Interface for Intel High Definition Audio Codec * - * HD audio interface patch for VIA VT1702/VT1708/VT1709 codec + * HD audio interface patch for VIA VT17xx/VT18xx/VT20xx codec * - * Copyright (c) 2006-2008 Lydia Wang - * Takashi Iwai + * (C) 2006-2009 VIA Technology, Inc. + * (C) 2006-2008 Takashi Iwai * * 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 @@ -36,6 +36,11 @@ /* 2008-04-09 Lydia Wang Add Independent HP feature */ /* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ /* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ +/* 2009-02-16 Logan Li Add support for VT1718S */ +/* 2009-03-13 Logan Li Add support for VT1716S */ +/* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */ +/* 2009-07-08 Lydia Wang Add support for VT2002P */ +/* 2009-07-21 Lydia Wang Add support for VT1812 */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -- cgit v1.2.3 From 377ff31ae06f0d2644839246cd18c3e17fe62a48 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Sat, 10 Oct 2009 19:08:55 +0800 Subject: ALSA: HDA VIA: Only cosmetic changes Signed-off-by: Lydia Wang Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 64 ++++++++++++++++++++++++----------------------- 1 file changed, 33 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index fab875a21726..30260e259181 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -22,26 +22,26 @@ */ /* * * * * * * * * * * * * * Release History * * * * * * * * * * * * * * * * */ -/* */ +/* */ /* 2006-03-03 Lydia Wang Create the basic patch to support VT1708 codec */ -/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ -/* 2006-08-02 Lydia Wang Add support to VT1709 codec */ +/* 2006-03-14 Lydia Wang Modify hard code for some pin widget nid */ +/* 2006-08-02 Lydia Wang Add support to VT1709 codec */ /* 2006-09-08 Lydia Wang Fix internal loopback recording source select bug */ -/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ -/* 2007-09-17 Lydia Wang Add VT1708B codec support */ +/* 2007-09-12 Lydia Wang Add EAPD enable during driver initialization */ +/* 2007-09-17 Lydia Wang Add VT1708B codec support */ /* 2007-11-14 Lydia Wang Add VT1708A codec HP and CD pin connect config */ /* 2008-02-03 Lydia Wang Fix Rear channels and Back channels inverse issue */ -/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ -/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ -/* 2008-04-09 Lydia Wang Add Independent HP feature */ +/* 2008-03-06 Lydia Wang Add VT1702 codec and VT1708S codec support */ +/* 2008-04-09 Lydia Wang Add mute front speaker when HP plugin */ +/* 2008-04-09 Lydia Wang Add Independent HP feature */ /* 2008-05-28 Lydia Wang Add second S/PDIF Out support for VT1702 */ -/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ +/* 2008-09-15 Logan Li Add VT1708S Mic Boost workaround/backdoor */ /* 2009-02-16 Logan Li Add support for VT1718S */ /* 2009-03-13 Logan Li Add support for VT1716S */ /* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */ /* 2009-07-08 Lydia Wang Add support for VT2002P */ /* 2009-07-21 Lydia Wang Add support for VT1812 */ -/* */ +/* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -486,7 +486,7 @@ static void via_auto_set_output_and_unmute(struct hda_codec *codec, snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); if (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD) - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x02); } @@ -1545,7 +1545,7 @@ static struct hda_verb vt1708_volume_init_verbs[] = { {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, - + /* Setup default input MW0 to PW4 */ {0x20, AC_VERB_SET_CONNECT_SEL, 0}, /* PW9 Output enable */ @@ -1865,8 +1865,10 @@ static int via_build_pcms(struct hda_codec *codec) codec->pcm_info = info; info->name = spec->stream_name_analog; - 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] = + *(spec->stream_analog_playback); + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = + spec->multiout.dac_nids[0]; info->stream[SNDRV_PCM_STREAM_CAPTURE] = *(spec->stream_analog_capture); info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adc_nids[0]; @@ -2116,7 +2118,7 @@ static int via_init(struct hda_codec *codec) if (spec->slave_dig_outs[0]) codec->slave_dig_outs = spec->slave_dig_outs; - return 0; + return 0; } #ifdef SND_HDA_NEEDS_RESUME @@ -2161,8 +2163,8 @@ static int vt1708_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.num_dacs = cfg->line_outs; spec->multiout.dac_nids = spec->private_dac_nids; - - for(i = 0; i < 4; i++) { + + for (i = 0; i < 4; i++) { nid = cfg->line_out_pins[i]; if (nid) { /* config dac list */ @@ -2200,7 +2202,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, if (!nid) continue; - + nid_vol = nid_vols[i]; if (i == AUTO_SEQ_CENLFE) { @@ -2229,7 +2231,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, HDA_OUTPUT)); if (err < 0) return err; - } else if (i == AUTO_SEQ_FRONT){ + } else if (i == AUTO_SEQ_FRONT) { /* add control to mixer index 0 */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Master Front Playback Volume", @@ -2243,7 +2245,7 @@ static int vt1708_auto_create_multi_out_ctls(struct via_spec *spec, HDA_INPUT)); if (err < 0) return err; - + /* add control to PW3 */ sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, @@ -2343,7 +2345,7 @@ static int vt1708_auto_create_analog_input_ctls(struct via_spec *spec, case 0x1d: /* Mic */ idx = 2; break; - + case 0x1e: /* Line In */ idx = 3; break; @@ -2576,7 +2578,7 @@ static int patch_vt1708(struct hda_codec *codec) "from BIOS. Using genenic mode...\n"); } - + spec->stream_name_analog = "VT1708 Analog"; spec->stream_analog_playback = &vt1708_pcm_analog_playback; /* disable 32bit format on VT1708 */ @@ -2588,7 +2590,7 @@ static int patch_vt1708(struct hda_codec *codec) spec->stream_digital_playback = &vt1708_pcm_digital_playback; spec->stream_digital_capture = &vt1708_pcm_digital_capture; - + if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1708_adc_nids; spec->num_adc_nids = ARRAY_SIZE(vt1708_adc_nids); @@ -2775,11 +2777,11 @@ static int vt1709_auto_fill_dac_nids(struct via_spec *spec, spec->multiout.dac_nids[cfg->line_outs] = 0x28; /* AOW4 */ } else if (cfg->line_outs == 3) { /* 6 channels */ - for(i = 0; i < cfg->line_outs; i++) { + for (i = 0; i < cfg->line_outs; i++) { nid = cfg->line_out_pins[i]; if (nid) { /* config dac list */ - switch(i) { + switch (i) { case AUTO_SEQ_FRONT: /* AOW0 */ spec->multiout.dac_nids[i] = 0x10; @@ -2814,7 +2816,7 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, for (i = 0; i <= AUTO_SEQ_SIDE; i++) { nid = cfg->line_out_pins[i]; - if (!nid) + if (!nid) continue; nid_vol = nid_vols[i]; @@ -2845,7 +2847,7 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, HDA_OUTPUT)); if (err < 0) return err; - } else if (i == AUTO_SEQ_FRONT){ + } else if (i == AUTO_SEQ_FRONT) { /* ADD control to mixer index 0 */ err = via_add_control(spec, VIA_CTL_WIDGET_VOL, "Master Front Playback Volume", @@ -2859,7 +2861,7 @@ static int vt1709_auto_create_multi_out_ctls(struct via_spec *spec, HDA_INPUT)); if (err < 0) return err; - + /* add control to PW3 */ sprintf(name, "%s Playback Volume", chname[i]); err = via_add_control(spec, VIA_CTL_WIDGET_VOL, name, @@ -2955,7 +2957,7 @@ static int vt1709_auto_create_analog_input_ctls(struct via_spec *spec, case 0x1d: /* Mic */ idx = 2; break; - + case 0x1e: /* Line In */ idx = 3; break; @@ -3064,7 +3066,7 @@ static int patch_vt1709_10ch(struct hda_codec *codec) spec->stream_digital_playback = &vt1709_pcm_digital_playback; spec->stream_digital_capture = &vt1709_pcm_digital_capture; - + if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1709_adc_nids; spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); @@ -3158,7 +3160,7 @@ static int patch_vt1709_6ch(struct hda_codec *codec) spec->stream_digital_playback = &vt1709_pcm_digital_playback; spec->stream_digital_capture = &vt1709_pcm_digital_capture; - + if (!spec->adc_nids && spec->input_mux) { spec->adc_nids = vt1709_adc_nids; spec->num_adc_nids = ARRAY_SIZE(vt1709_adc_nids); -- cgit v1.2.3 From 633c7e92bdd54ba939f2bd3b78c72e1e1a1dd077 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 11 Oct 2009 12:38:49 +0200 Subject: ALSA: wss: reuse CS4231 controls for AD1848 The C4231 control set is a superset of the AD1848 control set so reuse the CS4231 controls definitions for the AD1848. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/wss/wss_lib.c | 79 ++++++++++++++----------------------------------- 1 file changed, 23 insertions(+), 56 deletions(-) (limited to 'sound') diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 754a2089c650..2ba18978b419 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2200,49 +2200,12 @@ static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); -static struct snd_kcontrol_new snd_ad1848_controls[] = { -WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, - 7, 7, 1, 1), -WSS_DOUBLE_TLV("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, - db_scale_6bit), -WSS_DOUBLE("Aux Playback Switch", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE_TLV("Aux Playback Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), -WSS_DOUBLE("Aux Playback Switch", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE_TLV("Aux Playback Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, - db_scale_5bit_12db_max), -WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, - 0, 0, 15, 0, db_scale_rec_gain), -{ - .name = "Capture Source", - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .info = snd_wss_info_mux, - .get = snd_wss_get_mux, - .put = snd_wss_put_mux, -}, -WSS_DOUBLE("Mic Boost", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), -WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, - db_scale_6bit), -}; - static struct snd_kcontrol_new snd_wss_controls[] = { WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("PCM Playback Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, db_scale_6bit), -WSS_DOUBLE("Line Playback Switch", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE_TLV("Line Playback Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, - db_scale_5bit_12db_max), WSS_DOUBLE("Aux Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE_TLV("Aux Playback Volume", 0, @@ -2253,15 +2216,6 @@ WSS_DOUBLE("Aux Playback Switch", 1, WSS_DOUBLE_TLV("Aux Playback Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, db_scale_5bit_12db_max), -WSS_SINGLE("Mono Playback Switch", 0, - CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE_TLV("Mono Playback Volume", 0, - CS4231_MONO_CTRL, 0, 15, 1, - db_scale_4bit), -WSS_SINGLE("Mono Output Playback Switch", 0, - CS4231_MONO_CTRL, 6, 1, 1), -WSS_SINGLE("Mono Output Playback Bypass", 0, - CS4231_MONO_CTRL, 5, 1, 0), WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0, db_scale_rec_gain), { @@ -2277,6 +2231,20 @@ WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 2, 63, 1, db_scale_6bit), +WSS_DOUBLE("Line Playback Switch", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), +WSS_DOUBLE_TLV("Line Playback Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), +WSS_SINGLE("Mono Playback Switch", 0, + CS4231_MONO_CTRL, 7, 1, 1), +WSS_SINGLE_TLV("Mono Playback Volume", 0, + CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), +WSS_SINGLE("Mono Output Playback Switch", 0, + CS4231_MONO_CTRL, 6, 1, 1), +WSS_SINGLE("Mono Output Playback Bypass", 0, + CS4231_MONO_CTRL, 5, 1, 0), }; static struct snd_kcontrol_new snd_opti93x_controls[] = { @@ -2343,22 +2311,21 @@ int snd_wss_mixer(struct snd_wss *chip) if (err < 0) return err; } - else if (chip->hardware & WSS_HW_AD1848_MASK) - for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) { - err = snd_ctl_add(card, - snd_ctl_new1(&snd_ad1848_controls[idx], - chip)); - if (err < 0) - return err; - } - else - for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) { + else { + int count = ARRAY_SIZE(snd_wss_controls); + + /* Use only the first 11 entries on AD1848 */ + if (chip->hardware & WSS_HW_AD1848_MASK) + count = 11; + + for (idx = 0; idx < count; idx++) { err = snd_ctl_add(card, snd_ctl_new1(&snd_wss_controls[idx], chip)); if (err < 0) return err; } + } return 0; } EXPORT_SYMBOL(snd_wss_mixer); -- cgit v1.2.3 From 8066e51ae7329220f459470a38387f8533e99141 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 11 Oct 2009 12:48:00 +0200 Subject: ALSA: snd_dma_pointer workaround for chipsets with buggy DMA The chipsets with the isa_dma_bridge_buggy set do not stop DMA during DMA counter reads. The DMA counter is read in two 8-bit read steps on x86 platform. Sometimes, such reads happen during higher byte change so the lower byte is already decremented (rolled over) but the higher byte is not. It introduces an error that position is moved 256 bytes ahead of the true position. Thus, the next DMA position read can return a lower value then the previous read. If the DMA position is decreased (reversed) the ALSA subsystem is tricked into the playback underrun error and resets the playback. It results in a "pop" during a playback. Work around the issue by reading the counter twice and choosing a higher value. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/core/isadma.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/isadma.c b/sound/core/isadma.c index 79f0f16af339..950e19ba91fc 100644 --- a/sound/core/isadma.c +++ b/sound/core/isadma.c @@ -85,16 +85,24 @@ EXPORT_SYMBOL(snd_dma_disable); unsigned int snd_dma_pointer(unsigned long dma, unsigned int size) { unsigned long flags; - unsigned int result; + unsigned int result, result1; flags = claim_dma_lock(); clear_dma_ff(dma); if (!isa_dma_bridge_buggy) disable_dma(dma); result = get_dma_residue(dma); + /* + * HACK - read the counter again and choose higher value in order to + * avoid reading during counter lower byte roll over if the + * isa_dma_bridge_buggy is set. + */ + result1 = get_dma_residue(dma); if (!isa_dma_bridge_buggy) enable_dma(dma); release_dma_lock(flags); + if (unlikely(result < result1)) + result = result1; #ifdef CONFIG_SND_DEBUG if (result > size) snd_printk(KERN_ERR "pointer (0x%x) for DMA #%ld is greater than transfer size (0x%x)\n", result, dma, size); -- cgit v1.2.3 From 0f48327eac5f65ad029d7112cac97577766730ba Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Mon, 12 Oct 2009 15:56:17 +1100 Subject: sound: use semicolons to end statements Fixes: sound/pci/hda/patch_via.c: In function 'patch_vt1718S': sound/pci/hda/patch_via.c:4951: error: expected expression before 'return' sound/pci/hda/patch_via.c: In function 'patch_vt1716S': sound/pci/hda/patch_via.c:5441: error: expected expression before 'return' sound/pci/hda/patch_via.c: In function 'patch_vt2002P': sound/pci/hda/patch_via.c:5794: error: expected expression before 'return' sound/pci/hda/patch_via.c: In function 'patch_vt1812': sound/pci/hda/patch_via.c:6148: error: expected expression before 'return' Signed-off-by: Stephen Rothwell Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 30260e259181..a294060ed684 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -4942,7 +4942,7 @@ static int patch_vt1718S(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; - codec->patch_ops.unsol_event = via_unsol_event, + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1718S_loopbacks; @@ -5432,7 +5432,7 @@ static int patch_vt1716S(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; - codec->patch_ops.unsol_event = via_unsol_event, + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1716S_loopbacks; @@ -5785,7 +5785,7 @@ static int patch_vt2002P(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; - codec->patch_ops.unsol_event = via_unsol_event, + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt2002P_loopbacks; @@ -6139,7 +6139,7 @@ static int patch_vt1812(struct hda_codec *codec) codec->patch_ops = via_patch_ops; codec->patch_ops.init = via_auto_init; - codec->patch_ops.unsol_event = via_unsol_event, + codec->patch_ops.unsol_event = via_unsol_event; #ifdef CONFIG_SND_HDA_POWER_SAVE spec->loopback.amplist = vt1812_loopbacks; -- cgit v1.2.3 From 68f139204c1a2b10cc292d9cca036ebdbb6730a8 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Sat, 10 Oct 2009 23:53:49 +0800 Subject: ALSA: SND_CS5535AUDIO: Remove the X86 platform dependency SND_CS5535AUDIO is available on Loongson(MIPS compatible) family machines, and checked it with ARCH=x86_64, no relative compiling warnings & errors, so, remove the platform dependency directly. Reported-by: rixed@happyleptic.org Acked-by: Andres Salomon Signed-off-by: Wu Zhangjin Signed-off-by: Takashi Iwai --- sound/pci/Kconfig | 1 - 1 file changed, 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index fb5ee3cc3968..75c602b5b132 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -259,7 +259,6 @@ config SND_CS5530 config SND_CS5535AUDIO tristate "CS5535/CS5536 Audio" - depends on X86 && !X86_64 select SND_PCM select SND_AC97_CODEC help -- cgit v1.2.3 From a688e4885c1aa6b88ab5ffa64655bacc01749c9e Mon Sep 17 00:00:00 2001 From: Tobias Hansen Date: Mon, 12 Oct 2009 16:24:15 +0200 Subject: ALSA: snd-usb-us122l: corrent error number for not probing US-144 on ehci-hcd snd-usb-us122l: corrent error number for not probing US-144 on ehci-hcd This is the correct error number for telling the USB system that this driver is not for the device. Signed-off-by: Tobias Hansen Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 6c7b64a23c13..b54e8ca360d1 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -601,7 +601,7 @@ static int snd_us122l_probe(struct usb_interface *intf, if (device->descriptor.idProduct == USB_ID_US144 && device->speed == USB_SPEED_HIGH) { snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); - return -ENOENT; + return -ENODEV; } snd_printdd(KERN_DEBUG"%p:%i\n", -- cgit v1.2.3 From d2ed82a3e7d1f63b2da3f1aa5763667dd17919ac Mon Sep 17 00:00:00 2001 From: Logan Li Date: Wed, 14 Oct 2009 10:10:38 +0800 Subject: ALSA: HDA VIA: Remove 48k sample rate limit for S/PDIF 48 kHz limit is for slightly better stability, and sample rates other than 48k (like 96k/192k) are for better sound quality. We choose better quality, so remove the 48k limit. Signed-off-by: Logan Li Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index a294060ed684..89e084d45369 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -4626,7 +4626,6 @@ static struct hda_pcm_stream vt1718S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, @@ -5124,7 +5123,6 @@ static struct hda_pcm_stream vt1716S_pcm_digital_playback = { .substreams = 2, .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, @@ -5561,7 +5559,6 @@ static struct hda_pcm_stream vt2002P_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, @@ -5914,7 +5911,6 @@ static struct hda_pcm_stream vt1812_pcm_digital_playback = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .rates = SNDRV_PCM_RATE_48000, /* NID is set in via_build_pcms */ .ops = { .open = via_dig_playback_pcm_open, -- cgit v1.2.3 From ce491cf85466c3377228c5a852ea627ec5136956 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Tue, 20 Oct 2009 09:40:47 -0700 Subject: omap: headers: Move remaining headers from include/mach to include/plat Move the remaining headers under plat-omap/include/mach to plat-omap/include/plat. Also search and replace the files using these headers to include using the right path. This was done with: #!/bin/bash mach_dir_old="arch/arm/plat-omap/include/mach" plat_dir_new="arch/arm/plat-omap/include/plat" headers=$(cd $mach_dir_old && ls *.h) omap_dirs="arch/arm/*omap*/ \ drivers/video/omap \ sound/soc/omap" other_files="drivers/leds/leds-ams-delta.c \ drivers/mfd/menelaus.c \ drivers/mfd/twl4030-core.c \ drivers/mtd/nand/ams-delta.c" for header in $headers; do old="#include --- sound/soc/omap/ams-delta.c | 4 ++-- sound/soc/omap/n810.c | 2 +- sound/soc/omap/omap-mcbsp.c | 6 +++--- sound/soc/omap/omap-pcm.c | 2 +- sound/soc/omap/omap2evm.c | 2 +- sound/soc/omap/omap3beagle.c | 2 +- sound/soc/omap/omap3evm.c | 2 +- sound/soc/omap/osk5912.c | 2 +- sound/soc/omap/overo.c | 2 +- sound/soc/omap/sdp3430.c | 2 +- sound/soc/omap/zoom2.c | 2 +- 11 files changed, 14 insertions(+), 14 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/ams-delta.c b/sound/soc/omap/ams-delta.c index 5a5166ac7279..3f1a6c1a0355 100644 --- a/sound/soc/omap/ams-delta.c +++ b/sound/soc/omap/ams-delta.c @@ -31,8 +31,8 @@ #include -#include -#include +#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/n810.c b/sound/soc/omap/n810.c index 0a505938e42b..08e09d72790f 100644 --- a/sound/soc/omap/n810.c +++ b/sound/soc/omap/n810.c @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index 3341f49402ca..e8e63ba40877 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -31,9 +31,9 @@ #include #include -#include -#include -#include +#include +#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c index 5735945788bf..1169d2ec2e24 100644 --- a/sound/soc/omap/omap-pcm.c +++ b/sound/soc/omap/omap-pcm.c @@ -28,7 +28,7 @@ #include #include -#include +#include #include "omap-pcm.h" static const struct snd_pcm_hardware omap_pcm_hardware = { diff --git a/sound/soc/omap/omap2evm.c b/sound/soc/omap/omap2evm.c index 027e1a40f8a1..c7adea38274c 100644 --- a/sound/soc/omap/omap2evm.c +++ b/sound/soc/omap/omap2evm.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap3beagle.c b/sound/soc/omap/omap3beagle.c index b0cff9f33b7e..d88ad5ca526c 100644 --- a/sound/soc/omap/omap3beagle.c +++ b/sound/soc/omap/omap3beagle.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/omap3evm.c b/sound/soc/omap/omap3evm.c index 9114c263077b..41a91b5cf12b 100644 --- a/sound/soc/omap/omap3evm.c +++ b/sound/soc/omap/omap3evm.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/osk5912.c b/sound/soc/omap/osk5912.c index a4e149b7f0eb..498ca2e03519 100644 --- a/sound/soc/omap/osk5912.c +++ b/sound/soc/omap/osk5912.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/overo.c b/sound/soc/omap/overo.c index ec4f8fd8b3a2..624f40ecc472 100644 --- a/sound/soc/omap/overo.c +++ b/sound/soc/omap/overo.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index 4a3f62d1f295..c071f9603a38 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -34,7 +34,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c index f90b45f56220..f90a2ac888cf 100644 --- a/sound/soc/omap/zoom2.c +++ b/sound/soc/omap/zoom2.c @@ -29,7 +29,7 @@ #include #include #include -#include +#include #include "omap-mcbsp.h" #include "omap-pcm.h" -- cgit v1.2.3 From 739b47f1e5aa3b36eadd7906cc6b41f0175c6ed1 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:34:19 +0100 Subject: ALSA: hda - select IbexPeak handler for Calpella An earlier patch merely adds id for 0x80862804. It has 2/3 cvt/pin nodes and shall be tied to the IbexPeak handler. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 01a18ed475ac..7c23016fe8fa 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -684,7 +684,7 @@ static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, - { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, + { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ -- cgit v1.2.3 From f5d6def5c642587434c42722c57fb65642f61038 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:38:26 +0100 Subject: ALSA: hda - vectorize get_empty_pcm_device() This unifies the code and data structure, and makes it easy to add more HDMI devices. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 49 ++++++++++++++++------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index af989f660cca..49289cd50697 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2885,43 +2885,26 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) static const char *dev_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; - /* starting device index for each PCM type */ - static int dev_idx[HDA_PCM_NTYPES] = { - [HDA_PCM_TYPE_AUDIO] = 0, - [HDA_PCM_TYPE_SPDIF] = 1, - [HDA_PCM_TYPE_HDMI] = 3, - [HDA_PCM_TYPE_MODEM] = 6 + /* audio device indices; not linear to keep compatibility */ + static int audio_idx[HDA_PCM_NTYPES][5] = { + [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, + [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, + [HDA_PCM_TYPE_HDMI] = { 3, -1 }, + [HDA_PCM_TYPE_MODEM] = { 6, -1 }, }; - /* normal audio device indices; not linear to keep compatibility */ - static int audio_idx[4] = { 0, 2, 4, 5 }; - int i, dev; - - switch (type) { - case HDA_PCM_TYPE_AUDIO: - for (i = 0; i < ARRAY_SIZE(audio_idx); i++) { - dev = audio_idx[i]; - if (!test_bit(dev, bus->pcm_dev_bits)) - goto ok; - } - snd_printk(KERN_WARNING "Too many audio devices\n"); - return -EAGAIN; - case HDA_PCM_TYPE_SPDIF: - case HDA_PCM_TYPE_HDMI: - case HDA_PCM_TYPE_MODEM: - dev = dev_idx[type]; - if (test_bit(dev, bus->pcm_dev_bits)) { - snd_printk(KERN_WARNING "%s already defined\n", - dev_name[type]); - return -EAGAIN; - } - break; - default: + int i; + + if (type >= HDA_PCM_NTYPES) { snd_printk(KERN_WARNING "Invalid PCM type %d\n", type); return -EINVAL; } - ok: - set_bit(dev, bus->pcm_dev_bits); - return dev; + + for (i = 0; audio_idx[type][i] >= 0 ; i++) + if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) + return audio_idx[type][i]; + + snd_printk(KERN_WARNING "Too many %s devices\n", dev_name[type]); + return -EAGAIN; } /* -- cgit v1.2.3 From 92608badc519a8c1f65d93743396517aaa582b53 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:40:03 +0100 Subject: ALSA: hda - allow up to 4 HDMI devices The new Intel HDMI codec supports 2 independant HDMI/DisplayPort pipes. We'll be exporting them as 2 pcm devices. So bump up the allowed number of HDMI devices. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 49289cd50697..2c1366343335 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2889,7 +2889,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) static int audio_idx[HDA_PCM_NTYPES][5] = { [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, [HDA_PCM_TYPE_SPDIF] = { 1, -1 }, - [HDA_PCM_TYPE_HDMI] = { 3, -1 }, + [HDA_PCM_TYPE_HDMI] = { 3, 7, 8, 9, -1 }, [HDA_PCM_TYPE_MODEM] = { 6, -1 }, }; int i; -- cgit v1.2.3 From 6797cf2bfcbf2fa1fd05c0b785dc1402f73e2ce5 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:40:40 +0100 Subject: ALSA: hda - convert intelhdmi global references to local parameters No behavior change. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 80 ++++++++++++++++++++++------------------- 1 file changed, 43 insertions(+), 37 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 7c23016fe8fa..2dfb1efc2d08 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -189,35 +189,36 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { */ #ifdef BE_PARANOID -static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t nid, +static void hdmi_get_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, int *packet_index, int *byte_index) { int val; - val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_INDEX, 0); + val = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_INDEX, 0); *packet_index = val >> 5; *byte_index = val & 0x1f; } #endif -static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t nid, +static void hdmi_set_dip_index(struct hda_codec *codec, hda_nid_t pin_nid, int packet_index, int byte_index) { int val; val = (packet_index << 5) | (byte_index & 0x1f); - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_INDEX, val); } -static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t nid, +static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid, unsigned char val) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_DATA, val); } -static void hdmi_enable_output(struct hda_codec *codec) +static void hdmi_enable_output(struct hda_codec *codec, hda_nid_t pin_nid) { /* Unmute */ if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) @@ -231,7 +232,8 @@ static void hdmi_enable_output(struct hda_codec *codec) /* * Enable Audio InfoFrame Transmission */ -static void hdmi_start_infoframe_trans(struct hda_codec *codec) +static void hdmi_start_infoframe_trans(struct hda_codec *codec, + hda_nid_t pin_nid) { hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, @@ -241,37 +243,40 @@ static void hdmi_start_infoframe_trans(struct hda_codec *codec) /* * Disable Audio InfoFrame Transmission */ -static void hdmi_stop_infoframe_trans(struct hda_codec *codec) +static void hdmi_stop_infoframe_trans(struct hda_codec *codec, + hda_nid_t pin_nid) { hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_DIP_XMIT, AC_DIPXMIT_DISABLE); } -static int hdmi_get_channel_count(struct hda_codec *codec) +static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) { - return 1 + snd_hda_codec_read(codec, cvt_nid, 0, + return 1 + snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } -static void hdmi_set_channel_count(struct hda_codec *codec, int chs) +static void hdmi_set_channel_count(struct hda_codec *codec, + hda_nid_t nid, int chs) { - snd_hda_codec_write(codec, cvt_nid, 0, - AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); - if (chs != hdmi_get_channel_count(codec)) +#ifdef CONFIG_SND_DEBUG_VERBOSE + if (chs != hdmi_get_channel_count(codec, nid)) snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", - chs, hdmi_get_channel_count(codec)); + chs, hdmi_get_channel_count(codec, nid)); +#endif } -static void hdmi_debug_channel_mapping(struct hda_codec *codec) +static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) { #ifdef CONFIG_SND_DEBUG_VERBOSE int i; int slot; for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, cvt_nid, 0, + slot = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", slot >> 4, slot & 0x7); @@ -293,7 +298,7 @@ static void hdmi_parse_eld(struct hda_codec *codec) * Audio InfoFrame routines */ -static void hdmi_debug_dip_size(struct hda_codec *codec) +static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) { #ifdef CONFIG_SND_DEBUG_VERBOSE int i; @@ -310,7 +315,7 @@ static void hdmi_debug_dip_size(struct hda_codec *codec) #endif } -static void hdmi_clear_dip_buffers(struct hda_codec *codec) +static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) { #ifdef BE_PARANOID int i, j; @@ -340,14 +345,15 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec) } static void hdmi_fill_audio_infoframe(struct hda_codec *codec, - struct hdmi_audio_infoframe *ai) + hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) { u8 *params = (u8 *)ai; u8 sum = 0; int i; - hdmi_debug_dip_size(codec); - hdmi_clear_dip_buffers(codec); /* be paranoid */ + hdmi_debug_dip_size(codec, pin_nid); + hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ for (i = 0; i < sizeof(ai); i++) sum += params[i]; @@ -386,7 +392,7 @@ static void init_channel_allocations(void) * * TODO: it could select the wrong CA from multiple candidates. */ -static int hdmi_setup_channel_allocation(struct hda_codec *codec, +static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, struct hdmi_audio_infoframe *ai) { struct intel_hdmi_spec *spec = codec->spec; @@ -439,8 +445,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, return ai->CA; } -static void hdmi_setup_channel_mapping(struct hda_codec *codec, - struct hdmi_audio_infoframe *ai) +static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, + struct hdmi_audio_infoframe *ai) { int i; @@ -453,15 +459,15 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, */ for (i = 0; i < 8; i++) - snd_hda_codec_write(codec, cvt_nid, 0, + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_HDMI_CHAN_SLOT, (i << 4) | i); - hdmi_debug_channel_mapping(codec); + hdmi_debug_channel_mapping(codec, nid); } -static void hdmi_setup_audio_infoframe(struct hda_codec *codec, +static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, struct snd_pcm_substream *substream) { struct hdmi_audio_infoframe ai = { @@ -471,11 +477,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, .CC02_CT47 = substream->runtime->channels - 1, }; - hdmi_setup_channel_allocation(codec, &ai); - hdmi_setup_channel_mapping(codec, &ai); + hdmi_setup_channel_allocation(codec, nid, &ai); + hdmi_setup_channel_mapping(codec, nid, &ai); - hdmi_fill_audio_infoframe(codec, &ai); - hdmi_start_infoframe_trans(codec); + hdmi_fill_audio_infoframe(codec, pin_nid, &ai); + hdmi_start_infoframe_trans(codec, pin_nid); } @@ -553,7 +559,7 @@ static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, { struct intel_hdmi_spec *spec = codec->spec; - hdmi_stop_infoframe_trans(codec); + hdmi_stop_infoframe_trans(codec, pin_nid); return snd_hda_multi_out_dig_close(codec, &spec->multiout); } @@ -569,9 +575,9 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, format, substream); - hdmi_set_channel_count(codec, substream->runtime->channels); + hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); - hdmi_setup_audio_infoframe(codec, substream); + hdmi_setup_audio_infoframe(codec, cvt_nid, substream); return 0; } @@ -619,7 +625,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) static int intel_hdmi_init(struct hda_codec *codec) { - hdmi_enable_output(codec); + hdmi_enable_output(codec, pin_nid); snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, -- cgit v1.2.3 From 7bedb011ef4db93b15049ece8d50b29d6fe6af9d Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:41:44 +0100 Subject: ALSA: hda - remove intelhdmi dependency on multiout We'll be managing multiple HDMI audio sources/sinks on our own. So remove multiout dependency from intelhdmi. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 2dfb1efc2d08..02be428be667 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -39,7 +39,6 @@ static hda_nid_t pin_nid; /* HDMI output pin */ #define INTEL_HDMI_EVENT_TAG 0x08 struct intel_hdmi_spec { - struct hda_multi_out multiout; struct hda_pcm pcm_rec; struct hdmi_eld sink_eld; }; @@ -548,9 +547,7 @@ static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct intel_hdmi_spec *spec = codec->spec; - - return snd_hda_multi_out_dig_open(codec, &spec->multiout); + return 0; } static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, @@ -561,7 +558,8 @@ static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, hdmi_stop_infoframe_trans(codec, pin_nid); - return snd_hda_multi_out_dig_close(codec, &spec->multiout); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); + return 0; } static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, @@ -570,15 +568,12 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - struct intel_hdmi_spec *spec = codec->spec; - - snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, - format, substream); - - hdmi_set_channel_count(codec, cvt_nid, substream->runtime->channels); + hdmi_set_channel_count(codec, cvt_nid, + substream->runtime->channels); hdmi_setup_audio_infoframe(codec, cvt_nid, substream); + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); return 0; } @@ -616,7 +611,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) struct intel_hdmi_spec *spec = codec->spec; int err; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); + err = snd_hda_create_spdif_out_ctls(codec, cvt_nid); if (err < 0) return err; @@ -657,10 +652,6 @@ static int do_patch_intel_hdmi(struct hda_codec *codec) if (spec == NULL) return -ENOMEM; - spec->multiout.num_dacs = 0; /* no analog */ - spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = cvt_nid; - codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; -- cgit v1.2.3 From 70ca35fb42680fc4315d4a01f6c77c9a9962199c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:42:18 +0100 Subject: ALSA: hda - use pcm prepare/cleanup callbacks for intelhdmi Remove pcm callbacks open/close in favor of the prepare/cleanup. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 02be428be667..c17feacab754 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -543,16 +543,9 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) * Callbacks */ -static int intel_hdmi_playback_pcm_open(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) -{ - return 0; -} - -static int intel_hdmi_playback_pcm_close(struct hda_pcm_stream *hinfo, - struct hda_codec *codec, - struct snd_pcm_substream *substream) +static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; @@ -582,9 +575,8 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { .channels_min = 2, .channels_max = 8, .ops = { - .open = intel_hdmi_playback_pcm_open, - .close = intel_hdmi_playback_pcm_close, - .prepare = intel_hdmi_playback_pcm_prepare + .prepare = intel_hdmi_playback_pcm_prepare, + .cleanup = intel_hdmi_playback_pcm_cleanup, }, }; -- cgit v1.2.3 From ddb8152b054e357907f57fb5ae65d494a3c79065 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:43:03 +0100 Subject: ALSA: hda - reorder intelhdmi prepare/cleanup callbacks No behavior change. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index c17feacab754..6be5ca44a83b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -543,30 +543,30 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) * Callbacks */ -static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, +static int intel_hdmi_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 intel_hdmi_spec *spec = codec->spec; + hdmi_set_channel_count(codec, cvt_nid, + substream->runtime->channels); - hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_setup_audio_infoframe(codec, cvt_nid, substream); - snd_hda_codec_cleanup_stream(codec, hinfo->nid); + snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); return 0; } -static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, +static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, - unsigned int stream_tag, - unsigned int format, struct snd_pcm_substream *substream) { - hdmi_set_channel_count(codec, cvt_nid, - substream->runtime->channels); + struct intel_hdmi_spec *spec = codec->spec; - hdmi_setup_audio_infoframe(codec, cvt_nid, substream); + hdmi_stop_infoframe_trans(codec, pin_nid); - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; } -- cgit v1.2.3 From 54a25f87e943fc77f57e86849897ad6602519286 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:44:26 +0100 Subject: ALSA: hda - vectorize intelhdmi The Intel IbexPeak HDMI codec supports 2 converters and 3 pins, which requires converting the cvt_nid/pin_nid to arrays. The active pin number (the one connected with a live HDMI monitor/sink) will be dynamically identified on hotplug events. It exports two HDMI devices, so that user space can choose the A/V pipe for sending the audio samples. It's still undefined behavior when there are two active monitors connected and routed to the same audio converter. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 5 +- sound/pci/hda/hda_local.h | 6 +- sound/pci/hda/patch_intelhdmi.c | 191 +++++++++++++++++++++++++++++++--------- 3 files changed, 155 insertions(+), 47 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 9446a5abea13..20fa6aee29c0 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -560,13 +560,14 @@ 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 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", codec->addr); + 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; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5f1dcc59002b..461e0c15c77a 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -541,11 +541,13 @@ int snd_hdmi_get_eld(struct hdmi_eld *, struct hda_codec *, hda_nid_t); void snd_hdmi_show_eld(struct hdmi_eld *eld); #ifdef CONFIG_PROC_FS -int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld); +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) + struct hdmi_eld *eld, + int index) { return 0; } diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 6be5ca44a83b..08ea88deba6f 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -33,14 +33,43 @@ #include "hda_codec.h" #include "hda_local.h" -static hda_nid_t cvt_nid; /* audio converter */ -static hda_nid_t pin_nid; /* HDMI output pin */ +/* + * The HDMI/DisplayPort configuration can be highly dynamic. A graphics device + * could support two 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 INTEL_HDMI_CVTS 2 +#define INTEL_HDMI_PINS 3 -#define INTEL_HDMI_EVENT_TAG 0x08 +static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { + "INTEL HDMI 0", + "INTEL HDMI 1", +}; struct intel_hdmi_spec { - struct hda_pcm pcm_rec; - struct hdmi_eld sink_eld; + int num_cvts; + int num_pins; + hda_nid_t cvt[INTEL_HDMI_CVTS+1]; /* audio sources */ + hda_nid_t pin[INTEL_HDMI_PINS+1]; /* audio sinks */ + + /* + * source connection for each pin + */ + hda_nid_t pin_cvt[INTEL_HDMI_PINS+1]; + + /* + * HDMI sink attached to each pin + */ + bool sink_present[INTEL_HDMI_PINS]; + bool sink_eldv[INTEL_HDMI_PINS]; + struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; + + /* + * export one pcm per pipe + */ + struct hda_pcm pcm_rec[INTEL_HDMI_CVTS]; }; struct hdmi_audio_infoframe { @@ -183,6 +212,19 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, }; + +static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) +{ + int i; + + for (i = 0; nids[i]; i++) + if (nids[i] == nid) + return i; + + snd_printk(KERN_WARNING "HDMI: nid %d not registered\n", nid); + return -EINVAL; +} + /* * HDMI routines */ @@ -283,12 +325,12 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) #endif } -static void hdmi_parse_eld(struct hda_codec *codec) +static void hdmi_parse_eld(struct hda_codec *codec, int index) { struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld = &spec->sink_eld; + struct hdmi_eld *eld = &spec->sink_eld[index]; - if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + if (!snd_hdmi_get_eld(eld, codec, spec->pin[index])) snd_hdmi_show_eld(eld); } @@ -395,7 +437,7 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, struct hdmi_audio_infoframe *ai) { struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld = &spec->sink_eld; + struct hdmi_eld *eld; int i; int spk_mask = 0; int channels = 1 + (ai->CC02_CT47 & 0x7); @@ -407,6 +449,11 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, if (channels <= 2) return 0; + i = hda_node_index(spec->pin_cvt, nid); + if (i < 0) + return 0; + eld = &spec->sink_eld[i]; + /* * HDMI sink's ELD info cannot always be retrieved for now, e.g. * in console or for audio devices. Assume the highest speakers @@ -469,6 +516,9 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, struct snd_pcm_substream *substream) { + struct intel_hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid; + int i; struct hdmi_audio_infoframe ai = { .type = 0x84, .ver = 0x01, @@ -479,8 +529,16 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, hdmi_setup_channel_allocation(codec, nid, &ai); hdmi_setup_channel_mapping(codec, nid, &ai); - hdmi_fill_audio_infoframe(codec, pin_nid, &ai); - hdmi_start_infoframe_trans(codec, pin_nid); + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (spec->sink_present[i] != true) + continue; + + pin_nid = spec->pin[i]; + hdmi_fill_audio_infoframe(codec, pin_nid, &ai); + hdmi_start_infoframe_trans(codec, pin_nid); + } } @@ -490,27 +548,39 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) { + struct intel_hdmi_spec *spec = codec->spec; + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int pind = !!(res & AC_UNSOL_RES_PD); int eldv = !!(res & AC_UNSOL_RES_ELDV); + int index; printk(KERN_INFO - "HDMI hot plug event: Presence_Detect=%d ELD_Valid=%d\n", - pind, eldv); + "HDMI hot plug event: Pin=%d Presence_Detect=%d ELD_Valid=%d\n", + tag, pind, eldv); + + index = hda_node_index(spec->pin, tag); + if (index < 0) + return; + + spec->sink_present[index] = pind; + spec->sink_eldv[index] = eldv; if (pind && eldv) { - hdmi_parse_eld(codec); + hdmi_parse_eld(codec, index); /* TODO: do real things about ELD */ } } static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) { + int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; int cp_state = !!(res & AC_UNSOL_RES_CP_STATE); int cp_ready = !!(res & AC_UNSOL_RES_CP_READY); printk(KERN_INFO - "HDMI content protection event: SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + "HDMI CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + tag, subtag, cp_state, cp_ready); @@ -525,10 +595,11 @@ static void hdmi_non_intrinsic_event(struct hda_codec *codec, unsigned int res) static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) { + struct intel_hdmi_spec *spec = codec->spec; int tag = res >> AC_UNSOL_RES_TAG_SHIFT; int subtag = (res & AC_UNSOL_RES_SUBTAG) >> AC_UNSOL_RES_SUBTAG_SHIFT; - if (tag != INTEL_HDMI_EVENT_TAG) { + if (hda_node_index(spec->pin, tag) < 0) { snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); return; } @@ -549,10 +620,10 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int format, struct snd_pcm_substream *substream) { - hdmi_set_channel_count(codec, cvt_nid, + hdmi_set_channel_count(codec, hinfo->nid, substream->runtime->channels); - hdmi_setup_audio_infoframe(codec, cvt_nid, substream); + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); return 0; @@ -563,8 +634,14 @@ static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct snd_pcm_substream *substream) { struct intel_hdmi_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != hinfo->nid) + continue; - hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_stop_infoframe_trans(codec, spec->pin[i]); + } snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; @@ -583,17 +660,19 @@ static struct hda_pcm_stream intel_hdmi_pcm_playback = { static int intel_hdmi_build_pcms(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hda_pcm *info = spec->pcm_rec; + int i; - codec->num_pcms = 1; + codec->num_pcms = spec->num_cvts; codec->pcm_info = info; - /* NID to query formats and rates and setup streams */ - intel_hdmi_pcm_playback.nid = cvt_nid; - - info->name = "INTEL HDMI"; - info->pcm_type = HDA_PCM_TYPE_HDMI; - info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; + for (i = 0; i < codec->num_pcms; i++, info++) { + info->name = intel_hdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] = + intel_hdmi_pcm_playback; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; + } return 0; } @@ -602,29 +681,39 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; int err; + int i; - err = snd_hda_create_spdif_out_ctls(codec, cvt_nid); - if (err < 0) - return err; + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, spec->cvt[i]); + if (err < 0) + return err; + } return 0; } static int intel_hdmi_init(struct hda_codec *codec) { - hdmi_enable_output(codec, pin_nid); + struct intel_hdmi_spec *spec = codec->spec; + int i; - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | INTEL_HDMI_EVENT_TAG); + for (i = 0; spec->pin[i]; i++) { + hdmi_enable_output(codec, spec->pin[i]); + snd_hda_codec_write(codec, spec->pin[i], 0, + AC_VERB_SET_UNSOLICITED_ENABLE, + AC_USRSP_EN | spec->pin[i]); + } return 0; } static void intel_hdmi_free(struct hda_codec *codec) { struct intel_hdmi_spec *spec = codec->spec; + int i; + + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); - snd_hda_eld_proc_free(codec, &spec->sink_eld); kfree(spec); } @@ -636,18 +725,38 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .unsol_event = intel_hdmi_unsol_event, }; -static int do_patch_intel_hdmi(struct hda_codec *codec) +static struct intel_hdmi_spec static_specs[] = { + { + .num_cvts = 1, + .num_pins = 1, + .cvt = { 0x2 }, + .pin = { 0x3 }, + .pin_cvt = { 0x2 }, + }, + { + .num_cvts = 2, + .num_pins = 3, + .cvt = { 0x2, 0x3 }, + .pin = { 0x4, 0x5, 0x6 }, + .pin_cvt = { 0x2, 0x2, 0x2 }, + }, +}; + +static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) { struct intel_hdmi_spec *spec; + int i; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; + *spec = static_specs[spec_id]; codec->spec = spec; codec->patch_ops = intel_hdmi_patch_ops; - snd_hda_eld_proc_new(codec, &spec->sink_eld); + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); init_channel_allocations(); @@ -656,16 +765,12 @@ static int do_patch_intel_hdmi(struct hda_codec *codec) static int patch_intel_hdmi(struct hda_codec *codec) { - cvt_nid = 0x02; - pin_nid = 0x03; - return do_patch_intel_hdmi(codec); + return do_patch_intel_hdmi(codec, 0); } static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) { - cvt_nid = 0x02; - pin_nid = 0x04; - return do_patch_intel_hdmi(codec); + return do_patch_intel_hdmi(codec, 1); } static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { -- cgit v1.2.3 From 69fb346896b4265c0cbcbd2fdd1a97ae09fe198d Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:45:04 +0100 Subject: ALSA: hda - get intelhdmi max channels from widget caps Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 08ea88deba6f..3c68aa9742d7 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -650,7 +650,6 @@ static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, static struct hda_pcm_stream intel_hdmi_pcm_playback = { .substreams = 1, .channels_min = 2, - .channels_max = 8, .ops = { .prepare = intel_hdmi_playback_pcm_prepare, .cleanup = intel_hdmi_playback_pcm_cleanup, @@ -667,11 +666,17 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) codec->pcm_info = info; for (i = 0; i < codec->num_pcms; i++, info++) { + unsigned int chans; + + chans = get_wcaps(codec, spec->cvt[i]); + chans = get_wcaps_channels(chans); + info->name = intel_hdmi_pcm_names[i]; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] = intel_hdmi_pcm_playback; info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; } return 0; -- cgit v1.2.3 From f424367c3a393ca8b9669ceaa5b7f959d83bb14c Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:45:35 +0100 Subject: ALSA: hda - auto parse intelhdmi cvt/pin configurations Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 120 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 3c68aa9742d7..1c374f11ed07 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -213,6 +213,10 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { }; +/* + * HDA/HDMI auto parsing + */ + static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) { int i; @@ -225,6 +229,113 @@ static int hda_node_index(hda_nid_t *nids, hda_nid_t nid) return -EINVAL; } +static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct intel_hdmi_spec *spec = codec->spec; + hda_nid_t conn_list[HDA_MAX_CONNECTIONS]; + int conn_len, curr; + int index; + + 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", + pin_nid, get_wcaps(codec, pin_nid)); + return -EINVAL; + } + + conn_len = snd_hda_get_connections(codec, pin_nid, conn_list, + HDA_MAX_CONNECTIONS); + if (conn_len > 1) + curr = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_CONNECT_SEL, 0); + else + curr = 0; + + index = hda_node_index(spec->pin, pin_nid); + if (index < 0) + return -EINVAL; + + spec->pin_cvt[index] = conn_list[curr]; + + return 0; +} + +static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct intel_hdmi_spec *spec = codec->spec; + + if (spec->num_pins >= INTEL_HDMI_PINS) { + snd_printk(KERN_WARNING + "HDMI: no space for pin %d \n", pin_nid); + return -EINVAL; + } + + spec->pin[spec->num_pins] = pin_nid; + spec->num_pins++; + + /* + * It is assumed that converter nodes come first in the node list and + * hence have been registered and usable now. + */ + return intel_hdmi_read_pin_conn(codec, pin_nid); +} + +static int intel_hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) +{ + struct intel_hdmi_spec *spec = codec->spec; + + if (spec->num_cvts >= INTEL_HDMI_CVTS) { + snd_printk(KERN_WARNING + "HDMI: no space for converter %d \n", nid); + return -EINVAL; + } + + spec->cvt[spec->num_cvts] = nid; + spec->num_cvts++; + + return 0; +} + +static int intel_hdmi_parse_codec(struct hda_codec *codec) +{ + hda_nid_t nid; + int i, nodes; + + 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"); + return -EINVAL; + } + + for (i = 0; i < nodes; i++, nid++) { + unsigned int caps; + unsigned int type; + + caps = snd_hda_param_read(codec, nid, AC_PAR_AUDIO_WIDGET_CAP); + type = get_wcaps_type(caps); + + if (!(caps & AC_WCAP_DIGITAL)) + continue; + + switch (type) { + case AC_WID_AUD_OUT: + if (intel_hdmi_add_cvt(codec, nid) < 0) + return -EINVAL; + break; + case AC_WID_PIN: + caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); + if (!(caps & AC_PINCAP_HDMI)) + continue; + if (intel_hdmi_add_pin(codec, nid) < 0) + return -EINVAL; + break; + } + } + + return 0; +} + /* * HDMI routines */ @@ -756,8 +867,15 @@ static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) if (spec == NULL) return -ENOMEM; - *spec = static_specs[spec_id]; codec->spec = spec; + if (intel_hdmi_parse_codec(codec) < 0) { + codec->spec = NULL; + kfree(spec); + return -EINVAL; + } + if (memcmp(spec, static_specs + spec_id, sizeof(*spec))) + snd_printk(KERN_WARNING + "HDMI: auto parse disagree with known config\n"); codec->patch_ops = intel_hdmi_patch_ops; for (i = 0; i < spec->num_pins; i++) -- cgit v1.2.3 From fd080b2d8a6a13992b4b1b6300e1befdb9e089f2 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 30 Oct 2009 11:46:22 +0100 Subject: ALSA: hda - remove static intelhdmi configurations Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 36 +++--------------------------------- 1 file changed, 3 insertions(+), 33 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 1c374f11ed07..650de1b4ea8d 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -841,24 +841,7 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .unsol_event = intel_hdmi_unsol_event, }; -static struct intel_hdmi_spec static_specs[] = { - { - .num_cvts = 1, - .num_pins = 1, - .cvt = { 0x2 }, - .pin = { 0x3 }, - .pin_cvt = { 0x2 }, - }, - { - .num_cvts = 2, - .num_pins = 3, - .cvt = { 0x2, 0x3 }, - .pin = { 0x4, 0x5, 0x6 }, - .pin_cvt = { 0x2, 0x2, 0x2 }, - }, -}; - -static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) +static int patch_intel_hdmi(struct hda_codec *codec) { struct intel_hdmi_spec *spec; int i; @@ -873,9 +856,6 @@ static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) kfree(spec); return -EINVAL; } - if (memcmp(spec, static_specs + spec_id, sizeof(*spec))) - snd_printk(KERN_WARNING - "HDMI: auto parse disagree with known config\n"); codec->patch_ops = intel_hdmi_patch_ops; for (i = 0; i < spec->num_pins; i++) @@ -886,23 +866,13 @@ static int do_patch_intel_hdmi(struct hda_codec *codec, int spec_id) return 0; } -static int patch_intel_hdmi(struct hda_codec *codec) -{ - return do_patch_intel_hdmi(codec, 0); -} - -static int patch_intel_hdmi_ibexpeak(struct hda_codec *codec) -{ - return do_patch_intel_hdmi(codec, 1); -} - static struct hda_codec_preset snd_hda_preset_intelhdmi[] = { { .id = 0x808629fb, .name = "G45 DEVCL", .patch = patch_intel_hdmi }, { .id = 0x80862801, .name = "G45 DEVBLC", .patch = patch_intel_hdmi }, { .id = 0x80862802, .name = "G45 DEVCTG", .patch = patch_intel_hdmi }, { .id = 0x80862803, .name = "G45 DEVELK", .patch = patch_intel_hdmi }, - { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, - { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi_ibexpeak }, + { .id = 0x80862804, .name = "G45 DEVIBX", .patch = patch_intel_hdmi }, + { .id = 0x80860054, .name = "Q57 DEVIBX", .patch = patch_intel_hdmi }, { .id = 0x10951392, .name = "SiI1392 HDMI", .patch = patch_intel_hdmi }, {} /* terminator */ }; -- cgit v1.2.3 From 36dd5c4afff825fca1b6ccde678f51d6933a6850 Mon Sep 17 00:00:00 2001 From: Lydia Wang Date: Tue, 20 Oct 2009 13:18:04 +0800 Subject: ALSA: VIA HDA: Add support for VT1818S. Add support for VT1818S codec, which is similiar with VT1708S. Signed-off-by: Lydia Wang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 89e084d45369..5ec0e39593b5 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -41,6 +41,7 @@ /* 2009-04-14 Lydai Wang Add support for VT1828S and VT2020 */ /* 2009-07-08 Lydia Wang Add support for VT2002P */ /* 2009-07-21 Lydia Wang Add support for VT1812 */ +/* 2009-09-19 Lydia Wang Add support for VT1818S */ /* */ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ @@ -195,6 +196,8 @@ static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) codec_type = VT2002P; else if (dev_id == 0x0448) codec_type = VT1812; + else if (dev_id == 0x0440) + codec_type = VT1708S; else codec_type = UNKNOWN; return codec_type; @@ -4130,11 +4133,17 @@ static int patch_vt1708S(struct hda_codec *codec) spec->init_verbs[spec->num_iverbs++] = vt1708S_volume_init_verbs; spec->init_verbs[spec->num_iverbs++] = vt1708S_uniwill_init_verbs; - spec->stream_name_analog = "VT1708S Analog"; + if (codec->vendor_id == 0x11060440) + spec->stream_name_analog = "VT1818S Analog"; + else + spec->stream_name_analog = "VT1708S Analog"; spec->stream_analog_playback = &vt1708S_pcm_analog_playback; spec->stream_analog_capture = &vt1708S_pcm_analog_capture; - spec->stream_name_digital = "VT1708S Digital"; + if (codec->vendor_id == 0x11060440) + spec->stream_name_digital = "VT1818S Digital"; + else + spec->stream_name_digital = "VT1708S Digital"; spec->stream_digital_playback = &vt1708S_pcm_digital_playback; if (!spec->adc_nids && spec->input_mux) { @@ -6231,6 +6240,8 @@ static struct hda_codec_preset snd_hda_preset_via[] = { { .id = 0x11060438, .name = "VT2002P", .patch = patch_vt2002P}, { .id = 0x11064438, .name = "VT2002P", .patch = patch_vt2002P}, { .id = 0x11060448, .name = "VT1812", .patch = patch_vt1812}, + { .id = 0x11060440, .name = "VT1818S", + .patch = patch_vt1708S}, {} /* terminator */ }; -- cgit v1.2.3 From 84ed1a1942e8c28fb4c23a6235ec48672fc43e49 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 23 Oct 2009 16:03:08 +0200 Subject: ALSA: Cleanup redundant tests on unsigned The variables are unsigned so the test `>= 0' is always true, the `< 0' test always fails. In these cases the other part of the test catches wrapped values. In dac_audio_write() there does not occur a test for wrapped values, but the test appears redundant. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/sh_dac_audio.c | 3 --- sound/pci/ca0106/ca0106_proc.c | 4 ++-- sound/pci/ctxfi/ctatc.c | 2 +- sound/pci/emu10k1/emu10k1x.c | 3 +-- sound/pci/emu10k1/emuproc.c | 4 ++-- sound/pci/emu10k1/io.c | 2 +- sound/soc/codecs/tlv320aic23.c | 2 +- 7 files changed, 8 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index b2ed8757542a..4153752507e3 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c @@ -164,9 +164,6 @@ static ssize_t dac_audio_write(struct file *file, const char *buf, size_t count, int free; int nbytes; - if (count < 0) - return -EINVAL; - if (!count) { dac_audio_sync(); return 0; diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c62b7d10ec61..15523e60351c 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -304,7 +304,7 @@ static void snd_ca0106_proc_reg_write32(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >=0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -405,7 +405,7 @@ static void snd_ca0106_proc_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x80) && (reg >=0) && (val <= 0xffffffff) && (channel_id >=0) && (channel_id <= 3) ) + if (reg < 0x80 && val <= 0xffffffff && channel_id <= 3) snd_ca0106_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index b1b3a644f738..6bfce99b42a2 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -240,7 +240,7 @@ static int select_rom(unsigned int pitch) } else if (pitch == 0x02000000) { /* pitch == 2 */ return 3; - } else if (pitch >= 0x0 && pitch <= 0x08000000) { + } else if (pitch <= 0x08000000) { /* 0 <= pitch <= 8 */ return 0; } else { diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 36e08bd2b3cc..6b8ae7b5cd54 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -1040,8 +1040,7 @@ static void snd_emu10k1x_proc_reg_write(struct snd_info_entry *entry, if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0x49) && (reg >= 0) && (val <= 0xffffffff) - && (channel_id >= 0) && (channel_id <= 2) ) + if (reg < 0x49 && val <= 0xffffffff && channel_id <= 2) snd_emu10k1x_ptr_write(emu, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index 216f9748aff5..baa7cd508cd8 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c @@ -451,7 +451,7 @@ static void snd_emu_proc_io_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x", ®, &val) != 2) continue; - if ((reg < 0x40) && (reg >= 0) && (val <= 0xffffffff) ) { + if (reg < 0x40 && val <= 0xffffffff) { spin_lock_irqsave(&emu->emu_lock, flags); outl(val, emu->port + (reg & 0xfffffffc)); spin_unlock_irqrestore(&emu->emu_lock, flags); @@ -527,7 +527,7 @@ static void snd_emu_proc_ptr_reg_write(struct snd_info_entry *entry, while (!snd_info_get_line(buffer, line, sizeof(line))) { if (sscanf(line, "%x %x %x", ®, &channel_id, &val) != 3) continue; - if ((reg < 0xa0) && (reg >= 0) && (val <= 0xffffffff) && (channel_id >= 0) && (channel_id <= 3) ) + if (reg < 0xa0 && val <= 0xffffffff && channel_id <= 3) snd_ptr_write(emu, iobase, reg, channel_id, val); } } diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index c1a5aa15af8f..5ef7080e14d0 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c @@ -256,7 +256,7 @@ int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, u32 reg, u32 value) if (reg > 0x3f) return 1; reg += 0x40; /* 0x40 upwards are registers. */ - if (value < 0 || value > 0x3f) /* 0 to 0x3f are values */ + if (value > 0x3f) /* 0 to 0x3f are values */ return 1; spin_lock_irqsave(&emu->emu_lock, flags); outl(reg, emu->port + A_IOCFG); diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c index 0b8dcb5cd729..35606ae60868 100644 --- a/sound/soc/codecs/tlv320aic23.c +++ b/sound/soc/codecs/tlv320aic23.c @@ -85,7 +85,7 @@ static int tlv320aic23_write(struct snd_soc_codec *codec, unsigned int reg, * of data into val */ - if ((reg < 0 || reg > 9) && (reg != 15)) { + if (reg > 9 && reg != 15) { printk(KERN_WARNING "%s Invalid register R%u\n", __func__, reg); return -1; } -- cgit v1.2.3 From 6a5f96ce72b9e1a4bf06422df53fa819947d2293 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Oct 2009 12:31:39 +0100 Subject: ALSA: hda - Add a proper ifdef to a debug code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added a proper ifdef CONFIG_SND_DEBUG_VERBOSE to avoid a compile warning: sound/pci/hda/patch_intelhdmi.c:406: warning: ‘hdmi_get_channel_count’ defined but not used Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 650de1b4ea8d..4f25f08d332b 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -403,11 +403,13 @@ static void hdmi_stop_infoframe_trans(struct hda_codec *codec, AC_DIPXMIT_DISABLE); } +#ifdef CONFIG_SND_DEBUG_VERBOSE static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) { return 1 + snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } +#endif static void hdmi_set_channel_count(struct hda_codec *codec, hda_nid_t nid, int chs) -- cgit v1.2.3 From b7d5d946e50116f4150542f881ac90ac74c28165 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 24 Oct 2009 17:47:33 +0200 Subject: sound: remove OSS Ensoniq SoundScape driver The OSS driver for Ensoniq SoundScape cards is broken after conversion to mutexes and a new ALSA snd-sscape driver handles all devices handled by the OSS one. The ALSA driver was tested with these cards: Spea V7 MediaFX Ensoniq Soundscape Elite Ensoniq Soundscape VIVO (this card is not handled by the OSS driver) Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/oss/Kconfig | 12 - sound/oss/Makefile | 1 - sound/oss/sscape.c | 1480 ---------------------------------------------------- 3 files changed, 1493 deletions(-) delete mode 100644 sound/oss/sscape.c (limited to 'sound') diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index bcf2a0698d54..135a2b77cc4a 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -287,18 +287,6 @@ config SOUND_DMAP Say Y unless you have 16MB or more RAM or a PCI sound card. -config SOUND_SSCAPE - tristate "Ensoniq SoundScape support" - help - Answer Y if you have a sound card based on the Ensoniq SoundScape - chipset. Such cards are being manufactured at least by Ensoniq, Spea - and Reveal (Reveal makes also other cards). - - If you compile the driver into the kernel, you have to add - "sscape=,,,," to the kernel command - line. - - config SOUND_VMIDI tristate "Loopback MIDI device support" help diff --git a/sound/oss/Makefile b/sound/oss/Makefile index e0ae4d4d6a5c..567b8a74178a 100644 --- a/sound/oss/Makefile +++ b/sound/oss/Makefile @@ -13,7 +13,6 @@ obj-$(CONFIG_SOUND_SH_DAC_AUDIO) += sh_dac_audio.o obj-$(CONFIG_SOUND_AEDSP16) += aedsp16.o obj-$(CONFIG_SOUND_PSS) += pss.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_TRIX) += trix.o ad1848.o sb_lib.o uart401.o -obj-$(CONFIG_SOUND_SSCAPE) += sscape.o ad1848.o mpu401.o obj-$(CONFIG_SOUND_MSS) += ad1848.o obj-$(CONFIG_SOUND_PAS) += pas2.o sb.o sb_lib.o uart401.o obj-$(CONFIG_SOUND_SB) += sb.o sb_lib.o uart401.o diff --git a/sound/oss/sscape.c b/sound/oss/sscape.c deleted file mode 100644 index 30c36d1f35d7..000000000000 --- a/sound/oss/sscape.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * sound/oss/sscape.c - * - * Low level driver for Ensoniq SoundScape - * - * - * Copyright (C) by Hannu Savolainen 1993-1997 - * - * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL) - * Version 2 (June 1991). See the "COPYING" file distributed with this software - * for more info. - * - * - * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed) - * Sergey Smitienko : ensoniq p'n'p support - * Christoph Hellwig : adapted to module_init/module_exit - * Bartlomiej Zolnierkiewicz : added __init to attach_sscape() - * Chris Rankin : Specify that this module owns the coprocessor - * Arnaldo C. de Melo : added missing restore_flags in sscape_pnp_upload_file - */ - -#include -#include - -#include "sound_config.h" -#include "sound_firmware.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "coproc.h" - -#include "ad1848.h" -#include "mpu401.h" - -/* - * I/O ports - */ -#define MIDI_DATA 0 -#define MIDI_CTRL 1 -#define HOST_CTRL 2 -#define TX_READY 0x02 -#define RX_READY 0x01 -#define HOST_DATA 3 -#define ODIE_ADDR 4 -#define ODIE_DATA 5 - -/* - * Indirect registers - */ - -#define GA_INTSTAT_REG 0 -#define GA_INTENA_REG 1 -#define GA_DMAA_REG 2 -#define GA_DMAB_REG 3 -#define GA_INTCFG_REG 4 -#define GA_DMACFG_REG 5 -#define GA_CDCFG_REG 6 -#define GA_SMCFGA_REG 7 -#define GA_SMCFGB_REG 8 -#define GA_HMCTL_REG 9 - -/* - * DMA channel identifiers (A and B) - */ - -#define SSCAPE_DMA_A 0 -#define SSCAPE_DMA_B 1 - -#define PORT(name) (devc->base+name) - -/* - * Host commands recognized by the OBP microcode - */ - -#define CMD_GEN_HOST_ACK 0x80 -#define CMD_GEN_MPU_ACK 0x81 -#define CMD_GET_BOARD_TYPE 0x82 -#define CMD_SET_CONTROL 0x88 /* Old firmware only */ -#define CMD_GET_CONTROL 0x89 /* Old firmware only */ -#define CTL_MASTER_VOL 0 -#define CTL_MIC_MODE 2 -#define CTL_SYNTH_VOL 4 -#define CTL_WAVE_VOL 7 -#define CMD_SET_EXTMIDI 0x8a -#define CMD_GET_EXTMIDI 0x8b -#define CMD_SET_MT32 0x8c -#define CMD_GET_MT32 0x8d - -#define CMD_ACK 0x80 - -#define IC_ODIE 1 -#define IC_OPUS 2 - -typedef struct sscape_info -{ - int base, irq, dma; - - int codec, codec_irq; /* required to setup pnp cards*/ - int codec_type; - int ic_type; - char* raw_buf; - unsigned long raw_buf_phys; - int buffsize; /* -------------------------- */ - spinlock_t lock; - int ok; /* Properly detected */ - int failed; - int dma_allocated; - int codec_audiodev; - int opened; - int *osp; - int my_audiodev; -} sscape_info; - -static struct sscape_info adev_info = { - 0 -}; - -static struct sscape_info *devc = &adev_info; -static int sscape_mididev = -1; - -/* Some older cards have assigned interrupt bits differently than new ones */ -static char valid_interrupts_old[] = { - 9, 7, 5, 15 -}; - -static char valid_interrupts_new[] = { - 9, 5, 7, 10 -}; - -static char *valid_interrupts = valid_interrupts_new; - -/* - * See the bottom of the driver. This can be set by spea =0/1. - */ - -#ifdef REVEAL_SPEA -static char old_hardware = 1; -#else -static char old_hardware; -#endif - -static void sleep(unsigned howlong) -{ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(howlong); -} - -static unsigned char sscape_read(struct sscape_info *devc, int reg) -{ - unsigned long flags; - unsigned char val; - - spin_lock_irqsave(&devc->lock,flags); - outb(reg, PORT(ODIE_ADDR)); - val = inb(PORT(ODIE_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return val; -} - -static void __sscape_write(int reg, int data) -{ - outb(reg, PORT(ODIE_ADDR)); - outb(data, PORT(ODIE_DATA)); -} - -static void sscape_write(struct sscape_info *devc, int reg, int data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - __sscape_write(reg, data); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static unsigned char sscape_pnp_read_codec(sscape_info* devc, unsigned char reg) -{ - unsigned char res; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - res = inb (devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); - return res; - -} - -static void sscape_pnp_write_codec(sscape_info* devc, unsigned char reg, unsigned char data) -{ - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - outb( reg, devc -> codec); - outb( data, devc -> codec + 1); - spin_unlock_irqrestore(&devc->lock,flags); -} - -static void host_open(struct sscape_info *devc) -{ - outb((0x00), PORT(HOST_CTRL)); /* Put the board to the host mode */ -} - -static void host_close(struct sscape_info *devc) -{ - outb((0x03), PORT(HOST_CTRL)); /* Put the board to the MIDI mode */ -} - -static int host_write(struct sscape_info *devc, unsigned char *data, int count) -{ - unsigned long flags; - int i, timeout_val; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Send the command and data bytes - */ - - for (i = 0; i < count; i++) - { - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & TX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - outb(data[i], PORT(HOST_DATA)); - } - spin_unlock_irqrestore(&devc->lock,flags); - return 1; -} - -static int host_read(struct sscape_info *devc) -{ - unsigned long flags; - int timeout_val; - unsigned char data; - - spin_lock_irqsave(&devc->lock,flags); - /* - * Read a byte - */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - if (inb(PORT(HOST_CTRL)) & RX_READY) - break; - - if (timeout_val <= 0) - { - spin_unlock_irqrestore(&devc->lock,flags); - return -1; - } - data = inb(PORT(HOST_DATA)); - spin_unlock_irqrestore(&devc->lock,flags); - return data; -} - -#if 0 /* unused */ -static int host_command1(struct sscape_info *devc, int cmd) -{ - unsigned char buf[10]; - buf[0] = (unsigned char) (cmd & 0xff); - return host_write(devc, buf, 1); -} -#endif /* unused */ - - -static int host_command2(struct sscape_info *devc, int cmd, int parm1) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - - return host_write(devc, buf, 2); -} - -static int host_command3(struct sscape_info *devc, int cmd, int parm1, int parm2) -{ - unsigned char buf[10]; - - buf[0] = (unsigned char) (cmd & 0xff); - buf[1] = (unsigned char) (parm1 & 0xff); - buf[2] = (unsigned char) (parm2 & 0xff); - return host_write(devc, buf, 3); -} - -static void set_mt32(struct sscape_info *devc, int value) -{ - host_open(devc); - host_command2(devc, CMD_SET_MT32, value ? 1 : 0); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting MT32 mode failed\n"); */ - } - host_close(devc); -} - -static void set_control(struct sscape_info *devc, int ctrl, int value) -{ - host_open(devc); - host_command3(devc, CMD_SET_CONTROL, ctrl, value); - if (host_read(devc) != CMD_ACK) - { - /* printk( "SNDSCAPE: Setting control (%d) failed\n", ctrl); */ - } - host_close(devc); -} - -static void do_dma(struct sscape_info *devc, int dma_chan, unsigned long buf, int blk_size, int mode) -{ - unsigned char temp; - - if (dma_chan != SSCAPE_DMA_A) - { - printk(KERN_WARNING "soundscape: Tried to use DMA channel != A. Why?\n"); - return; - } - audio_devs[devc->codec_audiodev]->flags &= ~DMA_AUTOMODE; - DMAbuf_start_dma(devc->codec_audiodev, buf, blk_size, mode); - audio_devs[devc->codec_audiodev]->flags |= DMA_AUTOMODE; - - temp = devc->dma << 4; /* Setup DMA channel select bits */ - if (devc->dma <= 3) - temp |= 0x80; /* 8 bit DMA channel */ - - temp |= 1; /* Trigger DMA */ - sscape_write(devc, GA_DMAA_REG, temp); - temp &= 0xfe; /* Clear DMA trigger */ - sscape_write(devc, GA_DMAA_REG, temp); -} - -static int verify_mpu(struct sscape_info *devc) -{ - /* - * The SoundScape board could be in three modes (MPU, 8250 and host). - * If the card is not in the MPU mode, enabling the MPU driver will - * cause infinite loop (the driver believes that there is always some - * received data in the buffer. - * - * Detect this by looking if there are more than 10 received MIDI bytes - * (0x00) in the buffer. - */ - - int i; - - for (i = 0; i < 10; i++) - { - if (inb(devc->base + HOST_CTRL) & 0x80) - return 1; - - if (inb(devc->base) != 0x00) - return 1; - } - printk(KERN_WARNING "SoundScape: The device is not in the MPU-401 mode\n"); - return 0; -} - -static int sscape_coproc_open(void *dev_info, int sub_device) -{ - if (sub_device == COPR_MIDI) - { - set_mt32(devc, 0); - if (!verify_mpu(devc)) - return -EIO; - } - return 0; -} - -static void sscape_coproc_close(void *dev_info, int sub_device) -{ - struct sscape_info *devc = dev_info; - unsigned long flags; - - spin_lock_irqsave(&devc->lock,flags); - if (devc->dma_allocated) - { - __sscape_write(GA_DMAA_REG, 0x20); /* DMA channel disabled */ - devc->dma_allocated = 0; - } - spin_unlock_irqrestore(&devc->lock,flags); - return; -} - -static void sscape_coproc_reset(void *dev_info) -{ -} - -static int sscape_download_boot(struct sscape_info *devc, unsigned char *block, int size, int flag) -{ - unsigned long flags; - unsigned char temp; - volatile int done, timeout_val; - static unsigned char codec_dma_bits; - - if (flag & CPF_FIRST) - { - /* - * First block. Have to allocate DMA and to reset the board - * before continuing. - */ - - spin_lock_irqsave(&devc->lock,flags); - codec_dma_bits = sscape_read(devc, GA_CDCFG_REG); - - if (devc->dma_allocated == 0) - devc->dma_allocated = 1; - - spin_unlock_irqrestore(&devc->lock,flags); - - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) & 0x3f); /*Reset */ - - for (timeout_val = 10000; timeout_val > 0; timeout_val--) - sscape_read(devc, GA_HMCTL_REG); /* Delay */ - - /* Take board out of reset */ - sscape_write(devc, GA_HMCTL_REG, - (temp = sscape_read(devc, GA_HMCTL_REG)) | 0x80); - } - /* - * Transfer one code block using DMA - */ - if (audio_devs[devc->codec_audiodev]->dmap_out->raw_buf == NULL) - { - printk(KERN_WARNING "soundscape: DMA buffer not available\n"); - return 0; - } - memcpy(audio_devs[devc->codec_audiodev]->dmap_out->raw_buf, block, size); - - spin_lock_irqsave(&devc->lock,flags); - - /******** INTERRUPTS DISABLED NOW ********/ - - do_dma(devc, SSCAPE_DMA_A, - audio_devs[devc->codec_audiodev]->dmap_out->raw_buf_phys, - size, DMA_MODE_WRITE); - - /* - * Wait until transfer completes. - */ - - done = 0; - timeout_val = 30; - while (!done && timeout_val-- > 0) - { - int resid; - - if (HZ / 50) - sleep(HZ / 50); - clear_dma_ff(devc->dma); - if ((resid = get_dma_residue(devc->dma)) == 0) - done = 1; - } - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - return 0; - - if (flag & CPF_LAST) - { - /* - * Take the board out of reset - */ - outb((0x00), PORT(HOST_CTRL)); - outb((0x00), PORT(MIDI_CTRL)); - - temp = sscape_read(devc, GA_HMCTL_REG); - temp |= 0x40; - sscape_write(devc, GA_HMCTL_REG, temp); /* Kickstart the board */ - - /* - * Wait until the ODB wakes up - */ - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - - sleep(1); - x = inb(PORT(HOST_DATA)); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - DDB(printk("Soundscape: Acknowledge = %x\n", x)); - done = 1; - } - } - sscape_write(devc, GA_CDCFG_REG, codec_dma_bits); - - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: The OBP didn't respond after code download\n"); - return 0; - } - spin_lock_irqsave(&devc->lock,flags); - done = 0; - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - sleep(1); - if (inb(PORT(HOST_DATA)) == 0xfe) /* Host startup acknowledge */ - done = 1; - } - spin_unlock_irqrestore(&devc->lock,flags); - if (!done) - { - printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - return 0; - } - printk(KERN_INFO "SoundScape board initialized OK\n"); - set_control(devc, CTL_MASTER_VOL, 100); - set_control(devc, CTL_SYNTH_VOL, 100); - -#ifdef SSCAPE_DEBUG3 - /* - * Temporary debugging aid. Print contents of the registers after - * downloading the code. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - } - return 1; -} - -static int download_boot_block(void *dev_info, copr_buffer * buf) -{ - if (buf->len <= 0 || buf->len > sizeof(buf->data)) - return -EINVAL; - - if (!sscape_download_boot(devc, buf->data, buf->len, buf->flags)) - { - printk(KERN_ERR "soundscape: Unable to load microcode block to the OBP.\n"); - return -EIO; - } - return 0; -} - -static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) -{ - copr_buffer *buf; - int err; - - switch (cmd) - { - case SNDCTL_COPR_RESET: - sscape_coproc_reset(dev_info); - return 0; - - case SNDCTL_COPR_LOAD: - buf = (copr_buffer *) vmalloc(sizeof(copr_buffer)); - if (buf == NULL) - return -ENOSPC; - if (copy_from_user(buf, arg, sizeof(copr_buffer))) - { - vfree(buf); - return -EFAULT; - } - err = download_boot_block(dev_info, buf); - vfree(buf); - return err; - - default: - return -EINVAL; - } -} - -static coproc_operations sscape_coproc_operations = -{ - "SoundScape M68K", - THIS_MODULE, - sscape_coproc_open, - sscape_coproc_close, - sscape_coproc_ioctl, - sscape_coproc_reset, - &adev_info -}; - -static struct resource *sscape_ports; -static int sscape_is_pnp; - -static void __init attach_sscape(struct address_info *hw_config) -{ -#ifndef SSCAPE_REGS - /* - * Config register values for Spea/V7 Media FX and Ensoniq S-2000. - * These values are card - * dependent. If you have another SoundScape based card, you have to - * find the correct values. Do the following: - * - Compile this driver with SSCAPE_DEBUG1 defined. - * - Shut down and power off your machine. - * - Boot with DOS so that the SSINIT.EXE program is run. - * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed - * when detecting the SoundScape. - * - Modify the following list to use the values printed during boot. - * Undefine the SSCAPE_DEBUG1 - */ -#define SSCAPE_REGS { \ -/* I0 */ 0x00, \ -/* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ -/* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ -/* I4 */ 0xf5, /* Ignored */ \ -/* I5 */ 0x10, \ -/* I6 */ 0x00, \ -/* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ -/* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \ -/* I9 */ 0x40 /* Ignored */ \ - } -#endif - - unsigned long flags; - static unsigned char regs[10] = SSCAPE_REGS; - - int i, irq_bits = 0xff; - - if (old_hardware) - { - valid_interrupts = valid_interrupts_old; - conf_printf("Ensoniq SoundScape (old)", hw_config); - } - else - conf_printf("Ensoniq SoundScape", hw_config); - - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) - { - printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - if (sscape_is_pnp) - release_region(devc->codec, 2); - return; - } - - if (!sscape_is_pnp) { - - spin_lock_irqsave(&devc->lock,flags); - /* Host interrupt enable */ - sscape_write(devc, 1, 0xf0); /* All interrupts enabled */ - /* DMA A status/trigger register */ - sscape_write(devc, 2, 0x20); /* DMA channel disabled */ - /* DMA B status/trigger register */ - sscape_write(devc, 3, 0x20); /* DMA channel disabled */ - /* Host interrupt config reg */ - sscape_write(devc, 4, 0xf0 | (irq_bits << 2) | irq_bits); - /* Don't destroy CD-ROM DMA config bits (0xc0) */ - sscape_write(devc, 5, (regs[5] & 0x3f) | (sscape_read(devc, 5) & 0xc0)); - /* CD-ROM config (WSS codec actually) */ - sscape_write(devc, 6, regs[6]); - sscape_write(devc, 7, regs[7]); - sscape_write(devc, 8, regs[8]); - /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ - sscape_write(devc, 9, (sscape_read(devc, 9) & 0xf0) | 0x08); - spin_unlock_irqrestore(&devc->lock,flags); - } -#ifdef SSCAPE_DEBUG2 - /* - * Temporary debugging aid. Print contents of the registers after - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); - } -#endif - - if (probe_mpu401(hw_config, sscape_ports)) - hw_config->always_detect = 1; - hw_config->name = "SoundScape"; - - hw_config->irq *= -1; /* Negative value signals IRQ sharing */ - attach_mpu401(hw_config, THIS_MODULE); - hw_config->irq *= -1; /* Restore it */ - - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - { - sscape_mididev = hw_config->slots[1]; - midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; - } - sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ - devc->ok = 1; - devc->failed = 0; -} - -static int detect_ga(sscape_info * devc) -{ - unsigned char save; - - DDB(printk("Entered Soundscape detect_ga(%x)\n", devc->base)); - - /* - * First check that the address register of "ODIE" is - * there and that it has exactly 4 writable bits. - * First 4 bits - */ - - if ((save = inb(PORT(ODIE_ADDR))) & 0xf0) - { - DDB(printk("soundscape: Detect error A\n")); - return 0; - } - outb((0x00), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x00) - { - DDB(printk("soundscape: Detect error B\n")); - return 0; - } - outb((0xff), PORT(ODIE_ADDR)); - if (inb(PORT(ODIE_ADDR)) != 0x0f) - { - DDB(printk("soundscape: Detect error C\n")); - return 0; - } - outb((save), PORT(ODIE_ADDR)); - - /* - * Now verify that some indirect registers return zero on some bits. - * This may break the driver with some future revisions of "ODIE" but... - */ - - if (sscape_read(devc, 0) & 0x0c) - { - DDB(printk("soundscape: Detect error D (%x)\n", sscape_read(devc, 0))); - return 0; - } - if (sscape_read(devc, 1) & 0x0f) - { - DDB(printk("soundscape: Detect error E\n")); - return 0; - } - if (sscape_read(devc, 5) & 0x0f) - { - DDB(printk("soundscape: Detect error F\n")); - return 0; - } - return 1; -} - -static int sscape_read_host_ctrl(sscape_info* devc) -{ - return host_read(devc); -} - -static void sscape_write_host_ctrl2(sscape_info *devc, int a, int b) -{ - host_command2(devc, a, b); -} - -static int sscape_alloc_dma(sscape_info *devc) -{ - char *start_addr, *end_addr; - int dma_pagesize; - int sz, size; - struct page *page; - - if (devc->raw_buf != NULL) return 0; /* Already done */ - dma_pagesize = (devc->dma < 4) ? (64 * 1024) : (128 * 1024); - devc->raw_buf = NULL; - devc->buffsize = 8192*4; - if (devc->buffsize > dma_pagesize) devc->buffsize = dma_pagesize; - start_addr = NULL; - /* - * Now loop until we get a free buffer. Try to get smaller buffer if - * it fails. Don't accept smaller than 8k buffer for performance - * reasons. - */ - while (start_addr == NULL && devc->buffsize > PAGE_SIZE) { - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - devc->buffsize = PAGE_SIZE * (1 << sz); - start_addr = (char *) __get_free_pages(GFP_ATOMIC|GFP_DMA, sz); - if (start_addr == NULL) devc->buffsize /= 2; - } - - if (start_addr == NULL) { - printk(KERN_ERR "sscape pnp init error: Couldn't allocate DMA buffer\n"); - return 0; - } else { - /* make some checks */ - end_addr = start_addr + devc->buffsize - 1; - /* now check if it fits into the same dma-pagesize */ - - if (((long) start_addr & ~(dma_pagesize - 1)) != ((long) end_addr & ~(dma_pagesize - 1)) - || end_addr >= (char *) (MAX_DMA_ADDRESS)) { - printk(KERN_ERR "sscape pnp: Got invalid address 0x%lx for %db DMA-buffer\n", (long) start_addr, devc->buffsize); - return 0; - } - } - devc->raw_buf = start_addr; - devc->raw_buf_phys = virt_to_bus(start_addr); - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - SetPageReserved(page); - return 1; -} - -static void sscape_free_dma(sscape_info *devc) -{ - int sz, size; - unsigned long start_addr, end_addr; - struct page *page; - - if (devc->raw_buf == NULL) return; - for (sz = 0, size = PAGE_SIZE; size < devc->buffsize; sz++, size <<= 1); - start_addr = (unsigned long) devc->raw_buf; - end_addr = start_addr + devc->buffsize; - - for (page = virt_to_page(start_addr); page <= virt_to_page(end_addr); page++) - ClearPageReserved(page); - - free_pages((unsigned long) devc->raw_buf, sz); - devc->raw_buf = NULL; -} - -/* Intel version !!!!!!!!! */ - -static int sscape_start_dma(int chan, unsigned long physaddr, int count, int dma_mode) -{ - unsigned long flags; - - flags = claim_dma_lock(); - disable_dma(chan); - clear_dma_ff(chan); - set_dma_mode(chan, dma_mode); - set_dma_addr(chan, physaddr); - set_dma_count(chan, count); - enable_dma(chan); - release_dma_lock(flags); - return 0; -} - -static void sscape_pnp_start_dma(sscape_info* devc, int arg ) -{ - int reg; - if (arg == 0) reg = 2; - else reg = 3; - - sscape_write(devc, reg, sscape_read( devc, reg) | 0x01); - sscape_write(devc, reg, sscape_read( devc, reg) & 0xFE); -} - -static int sscape_pnp_wait_dma (sscape_info* devc, int arg ) -{ - int reg; - unsigned long i; - unsigned char d; - - if (arg == 0) reg = 2; - else reg = 3; - - sleep ( 1 ); - i = 0; - do { - d = sscape_read(devc, reg) & 1; - if ( d == 1) break; - i++; - } while (i < 500000); - d = sscape_read(devc, reg) & 1; - return d; -} - -static int sscape_pnp_alloc_dma(sscape_info* devc) -{ - /* printk(KERN_INFO "sscape: requesting dma\n"); */ - if (request_dma(devc -> dma, "sscape")) return 0; - /* printk(KERN_INFO "sscape: dma channel allocated\n"); */ - if (!sscape_alloc_dma(devc)) { - free_dma(devc -> dma); - return 0; - }; - return 1; -} - -static void sscape_pnp_free_dma(sscape_info* devc) -{ - sscape_free_dma( devc); - free_dma(devc -> dma ); - /* printk(KERN_INFO "sscape: dma released\n"); */ -} - -static int sscape_pnp_upload_file(sscape_info* devc, char* fn) -{ - int done = 0; - int timeout_val; - char* data,*dt; - int len,l; - unsigned long flags; - - sscape_write( devc, 9, sscape_read(devc, 9 ) & 0x3F ); - sscape_write( devc, 2, (devc -> dma << 4) | 0x80 ); - sscape_write( devc, 3, 0x20 ); - sscape_write( devc, 9, sscape_read( devc, 9 ) | 0x80 ); - - len = mod_firmware_load(fn, &data); - if (len == 0) { - printk(KERN_ERR "sscape: file not found: %s\n", fn); - return 0; - } - dt = data; - spin_lock_irqsave(&devc->lock,flags); - while ( len > 0 ) { - if (len > devc -> buffsize) l = devc->buffsize; - else l = len; - len -= l; - memcpy(devc->raw_buf, dt, l); dt += l; - sscape_start_dma(devc->dma, devc->raw_buf_phys, l, 0x48); - sscape_pnp_start_dma ( devc, 0 ); - if (sscape_pnp_wait_dma ( devc, 0 ) == 0) { - spin_unlock_irqrestore(&devc->lock,flags); - return 0; - } - } - - spin_unlock_irqrestore(&devc->lock,flags); - vfree(data); - - outb(0, devc -> base + 2); - outb(0, devc -> base); - - sscape_write ( devc, 9, sscape_read( devc, 9 ) | 0x40); - - timeout_val = 5 * HZ; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xff || x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - timeout_val = 5 * HZ; - done = 0; - while (!done && timeout_val-- > 0) - { - unsigned char x; - sleep(1); - x = inb( devc -> base + 3); - if (x == 0xfe) /* OBP startup acknowledge */ - { - //printk(KERN_ERR "Soundscape: Acknowledge = %x\n", x); - done = 1; - } - } - - if ( !done ) printk(KERN_ERR "soundscape: OBP Initialization failed.\n"); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, (devc -> dma << 4) + 0x80); - return 1; -} - -static void __init sscape_pnp_init_hw(sscape_info* devc) -{ - unsigned char midi_irq = 0, sb_irq = 0; - unsigned i; - static char code_file_name[23] = "/sndscape/sndscape.cox"; - - int sscape_joystic_enable = 0x7f; - int sscape_mic_enable = 0; - int sscape_ext_midi = 0; - - if ( !sscape_pnp_alloc_dma(devc) ) { - printk(KERN_ERR "sscape: faild to allocate dma\n"); - return; - } - - for (i = 0; i < 4; i++) { - if ( devc -> irq == valid_interrupts[i] ) - midi_irq = i; - if ( devc -> codec_irq == valid_interrupts[i] ) - sb_irq = i; - } - - sscape_write( devc, 5, 0x50); - sscape_write( devc, 7, 0x2e); - sscape_write( devc, 8, 0x00); - - sscape_write( devc, 2, devc->ic_type == IC_ODIE ? 0x70 : 0x40); - sscape_write( devc, 3, ( devc -> dma << 4) | 0x80); - - sscape_write (devc, 4, 0xF0 | (midi_irq<<2) | midi_irq); - - i = 0x10; //sscape_read(devc, 9) & (devc->ic_type == IC_ODIE ? 0xf0 : 0xc0); - if (sscape_joystic_enable) i |= 8; - - sscape_write (devc, 9, i); - sscape_write (devc, 6, 0x80); - sscape_write (devc, 1, 0x80); - - if (devc -> codec_type == 2) { - sscape_pnp_write_codec( devc, 0x0C, 0x50); - sscape_pnp_write_codec( devc, 0x10, sscape_pnp_read_codec( devc, 0x10) & 0x3F); - sscape_pnp_write_codec( devc, 0x11, sscape_pnp_read_codec( devc, 0x11) | 0xC0); - sscape_pnp_write_codec( devc, 29, 0x20); - } - - if (sscape_pnp_upload_file(devc, "/sndscape/scope.cod") == 0 ) { - printk(KERN_ERR "sscape: faild to upload file /sndscape/scope.cod\n"); - sscape_pnp_free_dma(devc); - return; - } - - i = sscape_read_host_ctrl( devc ); - - if ( (i & 0x0F) > 7 ) { - printk(KERN_ERR "sscape: scope.cod faild\n"); - sscape_pnp_free_dma(devc); - return; - } - if ( i & 0x10 ) sscape_write( devc, 7, 0x2F); - code_file_name[21] = (char) ( i & 0x0F) + 0x30; - if (sscape_pnp_upload_file( devc, code_file_name) == 0) { - printk(KERN_ERR "sscape: faild to upload file %s\n", code_file_name); - sscape_pnp_free_dma(devc); - return; - } - - if (devc->ic_type != IC_ODIE) { - sscape_pnp_write_codec( devc, 10, (sscape_pnp_read_codec(devc, 10) & 0x7f) | - ( sscape_mic_enable == 0 ? 0x00 : 0x80) ); - } - sscape_write_host_ctrl2( devc, 0x84, 0x64 ); /* MIDI volume */ - sscape_write_host_ctrl2( devc, 0x86, 0x64 ); /* MIDI volume?? */ - sscape_write_host_ctrl2( devc, 0x8A, sscape_ext_midi); - - sscape_pnp_write_codec ( devc, 6, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 7, 0x3f ); //WAV_VOL - sscape_pnp_write_codec ( devc, 2, 0x1F ); //WD_CDXVOLL - sscape_pnp_write_codec ( devc, 3, 0x1F ); //WD_CDXVOLR - - if (devc -> codec_type == 1) { - sscape_pnp_write_codec ( devc, 4, 0x1F ); - sscape_pnp_write_codec ( devc, 5, 0x1F ); - sscape_write_host_ctrl2( devc, 0x88, sscape_mic_enable); - } else { - int t; - sscape_pnp_write_codec ( devc, 0x10, 0x1F << 1); - sscape_pnp_write_codec ( devc, 0x11, 0xC0 | (0x1F << 1)); - - t = sscape_pnp_read_codec( devc, 0x00) & 0xDF; - if ( (sscape_mic_enable == 0)) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x00, t); - t = sscape_pnp_read_codec( devc, 0x01) & 0xDF; - if ( (sscape_mic_enable == 0) ) t |= 0; - else t |= 0x20; - sscape_pnp_write_codec ( devc, 0x01, t); - sscape_pnp_write_codec ( devc, 0x40 | 29 , 0x20); - outb(0, devc -> codec); - } - if (devc -> ic_type == IC_OPUS ) { - int i = sscape_read( devc, 9 ); - sscape_write( devc, 9, i | 3 ); - sscape_write( devc, 3, 0x40); - - if (request_region(0x228, 1, "sscape setup junk")) { - outb(0, 0x228); - release_region(0x228,1); - } - sscape_write( devc, 3, (devc -> dma << 4) | 0x80); - sscape_write( devc, 9, i ); - } - - host_close ( devc ); - sscape_pnp_free_dma(devc); -} - -static int __init detect_sscape_pnp(sscape_info* devc) -{ - long i, irq_bits = 0xff; - unsigned int d; - - DDB(printk("Entered detect_sscape_pnp(%x)\n", devc->base)); - - if (!request_region(devc->codec, 2, "sscape codec")) { - printk(KERN_ERR "detect_sscape_pnp: port %x is not free\n", devc->codec); - return 0; - } - - if ((inb(devc->base + 2) & 0x78) != 0) - goto fail; - - d = inb ( devc -> base + 4) & 0xF0; - if (d & 0x80) - goto fail; - - if (d == 0) { - devc->codec_type = 1; - devc->ic_type = IC_ODIE; - } else if ( (d & 0x60) != 0) { - devc->codec_type = 2; - devc->ic_type = IC_OPUS; - } else if ( (d & 0x40) != 0) { /* WTF? */ - devc->codec_type = 2; - devc->ic_type = IC_ODIE; - } else - goto fail; - - sscape_is_pnp = 1; - - outb(0xFA, devc -> base+4); - if ((inb( devc -> base+4) & 0x9F) != 0x0A) - goto fail; - outb(0xFE, devc -> base+4); - if ( (inb(devc -> base+4) & 0x9F) != 0x0E) - goto fail; - if ( (inb(devc -> base+5) & 0x9F) != 0x0E) - goto fail; - - if (devc->codec_type == 2) { - if (devc->codec != devc->base + 8) { - printk("soundscape warning: incorrect codec port specified\n"); - goto fail; - } - d = 0x10 | (sscape_read(devc, 9) & 0xCF); - sscape_write(devc, 9, d); - sscape_write(devc, 6, 0x80); - } else { - //todo: check codec is not base + 8 - } - - d = (sscape_read(devc, 9) & 0x3F) | 0xC0; - sscape_write(devc, 9, d); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80) ) break; - - d = inb(devc -> codec); - if (d & 0x80) - goto fail; - if ( inb(devc -> codec + 2) == 0xFF) - goto fail; - - sscape_write(devc, 9, sscape_read(devc, 9) & 0x3F ); - - d = inb(devc -> codec) & 0x80; - if ( d == 0) { - printk(KERN_INFO "soundscape: hardware detected\n"); - valid_interrupts = valid_interrupts_new; - } else { - printk(KERN_INFO "soundscape: board looks like media fx\n"); - valid_interrupts = valid_interrupts_old; - old_hardware = 1; - } - - sscape_write( devc, 9, 0xC0 | (sscape_read(devc, 9) & 0x3F) ); - - for (i = 0; i < 550000; i++) - if ( !(inb(devc -> codec) & 0x80)) - break; - - sscape_pnp_init_hw(devc); - - for (i = 0; i < 4; i++) - { - if (devc->codec_irq == valid_interrupts[i]) { - irq_bits = i; - break; - } - } - sscape_write(devc, GA_INTENA_REG, 0x00); - sscape_write(devc, GA_DMACFG_REG, 0x50); - sscape_write(devc, GA_DMAA_REG, 0x70); - sscape_write(devc, GA_DMAB_REG, 0x20); - sscape_write(devc, GA_INTCFG_REG, 0xf0); - sscape_write(devc, GA_CDCFG_REG, 0x89 | (devc->dma << 4) | (irq_bits << 1)); - - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 0) | 0x20); - sscape_pnp_write_codec( devc, 0, sscape_pnp_read_codec( devc, 1) | 0x20); - - return 1; -fail: - release_region(devc->codec, 2); - return 0; -} - -static int __init probe_sscape(struct address_info *hw_config) -{ - devc->base = hw_config->io_base; - devc->irq = hw_config->irq; - devc->dma = hw_config->dma; - devc->osp = hw_config->osp; - -#ifdef SSCAPE_DEBUG1 - /* - * Temporary debugging aid. Print contents of the registers before - * changing them. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x (old value)\n", i, sscape_read(devc, i)); - } -#endif - devc->failed = 1; - - sscape_ports = request_region(devc->base, 2, "mpu401"); - if (!sscape_ports) - return 0; - - if (!request_region(devc->base + 2, 6, "SoundScape")) { - release_region(devc->base, 2); - return 0; - } - - if (!detect_ga(devc)) { - if (detect_sscape_pnp(devc)) - return 1; - release_region(devc->base, 2); - release_region(devc->base + 2, 6); - return 0; - } - - if (old_hardware) /* Check that it's really an old Spea/Reveal card. */ - { - unsigned char tmp; - int cc; - - if (!((tmp = sscape_read(devc, GA_HMCTL_REG)) & 0xc0)) - { - sscape_write(devc, GA_HMCTL_REG, tmp | 0x80); - for (cc = 0; cc < 200000; ++cc) - inb(devc->base + ODIE_ADDR); - } - } - return 1; -} - -static int __init init_ss_ms_sound(struct address_info *hw_config) -{ - int i, irq_bits = 0xff; - int ad_flags = 0; - struct resource *ports; - - if (devc->failed) - { - printk(KERN_ERR "soundscape: Card not detected\n"); - return 0; - } - if (devc->ok == 0) - { - printk(KERN_ERR "soundscape: Invalid initialization order.\n"); - return 0; - } - for (i = 0; i < 4; i++) - { - if (hw_config->irq == valid_interrupts[i]) - { - irq_bits = i; - break; - } - } - if (irq_bits == 0xff) { - printk(KERN_ERR "soundscape: Invalid MSS IRQ%d\n", hw_config->irq); - return 0; - } - - if (old_hardware) - ad_flags = 0x12345677; /* Tell that we may have a CS4248 chip (Spea-V7 Media FX) */ - else if (sscape_is_pnp) - ad_flags = 0x87654321; /* Tell that we have a soundscape pnp with 1845 chip */ - - ports = request_region(hw_config->io_base, 4, "ad1848"); - if (!ports) { - printk(KERN_ERR "soundscape: ports busy\n"); - return 0; - } - - if (!ad1848_detect(ports, &ad_flags, hw_config->osp)) { - release_region(hw_config->io_base, 4); - return 0; - } - - if (!sscape_is_pnp) /*pnp is already setup*/ - { - /* - * Setup the DMA polarity. - */ - sscape_write(devc, GA_DMACFG_REG, 0x50); - - /* - * Take the gate-array off of the DMA channel. - */ - sscape_write(devc, GA_DMAB_REG, 0x20); - - /* - * Init the AD1848 (CD-ROM) config reg. - */ - sscape_write(devc, GA_CDCFG_REG, 0x89 | (hw_config->dma << 4) | (irq_bits << 1)); - } - - if (hw_config->irq == devc->irq) - printk(KERN_WARNING "soundscape: Warning! The WSS mode can't share IRQ with MIDI\n"); - - hw_config->slots[0] = ad1848_init( - sscape_is_pnp ? "SoundScape" : "SoundScape PNP", - ports, - hw_config->irq, - hw_config->dma, - hw_config->dma, - 0, - devc->osp, - THIS_MODULE); - - - if (hw_config->slots[0] != -1) /* The AD1848 driver installed itself */ - { - audio_devs[hw_config->slots[0]]->coproc = &sscape_coproc_operations; - devc->codec_audiodev = hw_config->slots[0]; - devc->my_audiodev = hw_config->slots[0]; - - /* Set proper routings here (what are they) */ - AD1848_REROUTE(SOUND_MIXER_LINE1, SOUND_MIXER_LINE); - } - -#ifdef SSCAPE_DEBUG5 - /* - * Temporary debugging aid. Print contents of the registers - * after the AD1848 device has been initialized. - */ - { - int i; - - for (i = 0; i < 13; i++) - printk("I%d = %02x\n", i, sscape_read(devc, i)); - } -#endif - return 1; -} - -static void __exit unload_sscape(struct address_info *hw_config) -{ - release_region(devc->base + 2, 6); - unload_mpu401(hw_config); - if (sscape_is_pnp) - release_region(devc->codec, 2); -} - -static void __exit unload_ss_ms_sound(struct address_info *hw_config) -{ - ad1848_unload(hw_config->io_base, - hw_config->irq, - devc->dma, - devc->dma, - 0); - sound_unload_audiodev(hw_config->slots[0]); -} - -static struct address_info cfg; -static struct address_info cfg_mpu; - -static int __initdata spea = -1; -static int mss = 0; -static int __initdata dma = -1; -static int __initdata irq = -1; -static int __initdata io = -1; -static int __initdata mpu_irq = -1; -static int __initdata mpu_io = -1; - -module_param(dma, int, 0); -module_param(irq, int, 0); -module_param(io, int, 0); -module_param(spea, int, 0); /* spea=0/1 set the old_hardware */ -module_param(mpu_irq, int, 0); -module_param(mpu_io, int, 0); -module_param(mss, int, 0); - -static int __init init_sscape(void) -{ - printk(KERN_INFO "Soundscape driver Copyright (C) by Hannu Savolainen 1993-1996\n"); - - cfg.irq = irq; - cfg.dma = dma; - cfg.io_base = io; - - cfg_mpu.irq = mpu_irq; - cfg_mpu.io_base = mpu_io; - /* WEH - Try to get right dma channel */ - cfg_mpu.dma = dma; - - devc->codec = cfg.io_base; - devc->codec_irq = cfg.irq; - devc->codec_type = 0; - devc->ic_type = 0; - devc->raw_buf = NULL; - spin_lock_init(&devc->lock); - - if (cfg.dma == -1 || cfg.irq == -1 || cfg.io_base == -1) { - printk(KERN_ERR "DMA, IRQ, and IO port must be specified.\n"); - return -EINVAL; - } - - if (cfg_mpu.irq == -1 && cfg_mpu.io_base != -1) { - printk(KERN_ERR "MPU_IRQ must be specified if MPU_IO is set.\n"); - return -EINVAL; - } - - if(spea != -1) { - old_hardware = spea; - printk(KERN_INFO "Forcing %s hardware support.\n", - spea?"new":"old"); - } - if (probe_sscape(&cfg_mpu) == 0) - return -ENODEV; - - attach_sscape(&cfg_mpu); - - mss = init_ss_ms_sound(&cfg); - - return 0; -} - -static void __exit cleanup_sscape(void) -{ - if (mss) - unload_ss_ms_sound(&cfg); - unload_sscape(&cfg_mpu); -} - -module_init(init_sscape); -module_exit(cleanup_sscape); - -#ifndef MODULE -static int __init setup_sscape(char *str) -{ - /* io, irq, dma, mpu_io, mpu_irq */ - int ints[6]; - - str = get_options(str, ARRAY_SIZE(ints), ints); - - io = ints[1]; - irq = ints[2]; - dma = ints[3]; - mpu_io = ints[4]; - mpu_irq = ints[5]; - - return 1; -} - -__setup("sscape=", setup_sscape); -#endif -MODULE_LICENSE("GPL"); -- cgit v1.2.3 From 3c76b4d69bedde5b9e7e42612a7d2ede4ab7fd8d Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 25 Oct 2009 11:05:19 +0100 Subject: ALSA: es18xx: remove snd_card pointer from snd_es18xx structure The snd_card pointer is redundant and code can be easily changed to work without it. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 75 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 8cfbff73a835..160752bc2e8e 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -121,7 +121,6 @@ struct snd_es18xx { unsigned int dma1_shift; unsigned int dma2_shift; - struct snd_card *card; struct snd_pcm *pcm; struct snd_pcm_substream *playback_a_substream; struct snd_pcm_substream *capture_a_substream; @@ -755,7 +754,9 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream, static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) { - struct snd_es18xx *chip = dev_id; + struct snd_card *card = dev_id; + struct snd_audiodrive *acard = card->private_data; + struct snd_es18xx *chip = acard->chip; unsigned char status; if (chip->caps & ES18XX_CONTROL) { @@ -805,12 +806,16 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) int split = 0; if (chip->caps & ES18XX_HWV) { split = snd_es18xx_mixer_read(chip, 0x64) & 0x80; - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->hw_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->hw_volume->id); } if (!split) { - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_switch->id); - snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_VALUE, &chip->master_volume->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_switch->id); + snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, + &chip->master_volume->id); } /* ack interrupt */ snd_es18xx_mixer_write(chip, 0x66, 0x00); @@ -1691,8 +1696,11 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { .pointer = snd_es18xx_capture_pointer, }; -static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct snd_pcm ** rpcm) +static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, + struct snd_pcm **rpcm) { + struct snd_audiodrive *acard = card->private_data; + struct snd_es18xx *chip = acard->chip; struct snd_pcm *pcm; char str[16]; int err; @@ -1701,9 +1709,9 @@ static int __devinit snd_es18xx_pcm(struct snd_es18xx *chip, int device, struct *rpcm = NULL; sprintf(str, "ES%x", chip->version); if (chip->caps & ES18XX_PCM2) - err = snd_pcm_new(chip->card, str, device, 2, 1, &pcm); + err = snd_pcm_new(card, str, device, 2, 1, &pcm); else - err = snd_pcm_new(chip->card, str, device, 1, 1, &pcm); + err = snd_pcm_new(card, str, device, 1, 1, &pcm); if (err < 0) return err; @@ -1737,7 +1745,7 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) struct snd_audiodrive *acard = card->private_data; struct snd_es18xx *chip = acard->chip; - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); + snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); @@ -1758,18 +1766,21 @@ static int snd_es18xx_resume(struct snd_card *card) /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); - snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); + snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* CONFIG_PM */ -static int snd_es18xx_free(struct snd_es18xx *chip) +static int snd_es18xx_free(struct snd_card *card) { + struct snd_audiodrive *acard = card->private_data; + struct snd_es18xx *chip = acard->chip; + release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_ctrl_port); release_and_free_resource(chip->res_mpu_port); if (chip->irq >= 0) - free_irq(chip->irq, (void *) chip); + free_irq(chip->irq, (void *) card); if (chip->dma1 >= 0) { disable_dma(chip->dma1); free_dma(chip->dma1); @@ -1784,8 +1795,7 @@ static int snd_es18xx_free(struct snd_es18xx *chip) static int snd_es18xx_dev_free(struct snd_device *device) { - struct snd_es18xx *chip = device->device_data; - return snd_es18xx_free(chip); + return snd_es18xx_free(device->card); } static int __devinit snd_es18xx_new_device(struct snd_card *card, @@ -1808,7 +1818,6 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); spin_lock_init(&chip->ctrl_lock); - chip->card = card; chip->port = port; chip->mpu_port = mpu_port; chip->fm_port = fm_port; @@ -1818,53 +1827,55 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, chip->audio2_vol = 0x00; chip->active = 0; - if ((chip->res_port = request_region(port, 16, "ES18xx")) == NULL) { - snd_es18xx_free(chip); + chip->res_port = request_region(port, 16, "ES18xx"); + if (chip->res_port == NULL) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap ports 0x%lx-0x%lx\n", port, port + 16 - 1); return -EBUSY; } - if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", (void *) chip)) { - snd_es18xx_free(chip); + if (request_irq(irq, snd_es18xx_interrupt, IRQF_DISABLED, "ES18xx", + (void *) card)) { + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap IRQ %d\n", irq); return -EBUSY; } chip->irq = irq; if (request_dma(dma1, "ES18xx DMA 1")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA1 %d\n", dma1); return -EBUSY; } chip->dma1 = dma1; if (dma2 != dma1 && request_dma(dma2, "ES18xx DMA 2")) { - snd_es18xx_free(chip); + snd_es18xx_free(card); snd_printk(KERN_ERR PFX "unable to grap DMA2 %d\n", dma2); return -EBUSY; } chip->dma2 = dma2; if (snd_es18xx_probe(chip) < 0) { - snd_es18xx_free(chip); + snd_es18xx_free(card); return -ENODEV; } - if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { - snd_es18xx_free(chip); + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, NULL, &ops); + if (err < 0) { + snd_es18xx_free(card); return err; } *rchip = chip; return 0; } -static int __devinit snd_es18xx_mixer(struct snd_es18xx *chip) +static int __devinit snd_es18xx_mixer(struct snd_card *card) { - struct snd_card *card; + struct snd_audiodrive *acard = card->private_data; + struct snd_es18xx *chip = acard->chip; int err; unsigned int idx; - card = chip->card; - strcpy(card->mixername, chip->pcm->name); for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_base_controls); idx++) { @@ -2161,10 +2172,12 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) chip->port, irq[dev], dma1[dev]); - if ((err = snd_es18xx_pcm(chip, 0, NULL)) < 0) + err = snd_es18xx_pcm(card, 0, NULL); + if (err < 0) return err; - if ((err = snd_es18xx_mixer(chip)) < 0) + err = snd_es18xx_mixer(card); + if (err < 0) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { -- cgit v1.2.3 From b14f5de731ae657d498d18d713c6431bfbeefb4b Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 25 Oct 2009 11:10:01 +0100 Subject: ALSA: es18xx: remove snd_audiodrive structure Remove intermediate snd_audiodrive structure between snd_card structure and snd_es18xx. This reduces size of source code and binary driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 71 +++++++++++++++++++----------------------------------- 1 file changed, 25 insertions(+), 46 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 160752bc2e8e..5cf42b4d65fd 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -139,10 +139,6 @@ struct snd_es18xx { #ifdef CONFIG_PM unsigned char pm_reg; #endif -}; - -struct snd_audiodrive { - struct snd_es18xx *chip; #ifdef CONFIG_PNP struct pnp_dev *dev; struct pnp_dev *devc; @@ -755,8 +751,7 @@ static int snd_es18xx_playback_trigger(struct snd_pcm_substream *substream, static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) { struct snd_card *card = dev_id; - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; unsigned char status; if (chip->caps & ES18XX_CONTROL) { @@ -1699,8 +1694,7 @@ static struct snd_pcm_ops snd_es18xx_capture_ops = { static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, struct snd_pcm **rpcm) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; struct snd_pcm *pcm; char str[16]; int err; @@ -1742,8 +1736,7 @@ static int __devinit snd_es18xx_pcm(struct snd_card *card, int device, #ifdef CONFIG_PM static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -1760,8 +1753,7 @@ static int snd_es18xx_suspend(struct snd_card *card, pm_message_t state) static int snd_es18xx_resume(struct snd_card *card) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; /* restore PM register, we won't wake till (not 0x07) i/o activity though */ snd_es18xx_write(chip, ES18XX_PM, chip->pm_reg ^= ES18XX_PM_FM); @@ -1773,8 +1765,7 @@ static int snd_es18xx_resume(struct snd_card *card) static int snd_es18xx_free(struct snd_card *card) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_ctrl_port); @@ -1789,7 +1780,6 @@ static int snd_es18xx_free(struct snd_card *card) disable_dma(chip->dma2); free_dma(chip->dma2); } - kfree(chip); return 0; } @@ -1802,19 +1792,14 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, unsigned long port, unsigned long mpu_port, unsigned long fm_port, - int irq, int dma1, int dma2, - struct snd_es18xx ** rchip) + int irq, int dma1, int dma2) { - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; static struct snd_device_ops ops = { .dev_free = snd_es18xx_dev_free, }; int err; - *rchip = NULL; - chip = kzalloc(sizeof(*chip), GFP_KERNEL); - if (chip == NULL) - return -ENOMEM; spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); spin_lock_init(&chip->ctrl_lock); @@ -1865,14 +1850,12 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, snd_es18xx_free(card); return err; } - *rchip = chip; return 0; } static int __devinit snd_es18xx_mixer(struct snd_card *card) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip = acard->chip; + struct snd_es18xx *chip = card->private_data; int err; unsigned int idx; @@ -2074,11 +2057,11 @@ static int __devinit snd_audiodrive_pnp_init_main(int dev, struct pnp_dev *pdev) return 0; } -static int __devinit snd_audiodrive_pnp(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnp(int dev, struct snd_es18xx *chip, struct pnp_dev *pdev) { - acard->dev = pdev; - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + chip->dev = pdev; + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; } @@ -2104,26 +2087,26 @@ static struct pnp_card_device_id snd_audiodrive_pnpids[] = { MODULE_DEVICE_TABLE(pnp_card, snd_audiodrive_pnpids); -static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, +static int __devinit snd_audiodrive_pnpc(int dev, struct snd_es18xx *chip, struct pnp_card_link *card, const struct pnp_card_device_id *id) { - acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL); - if (acard->dev == NULL) + chip->dev = pnp_request_card_device(card, id->devs[0].id, NULL); + if (chip->dev == NULL) return -EBUSY; - acard->devc = pnp_request_card_device(card, id->devs[1].id, NULL); - if (acard->devc == NULL) + chip->devc = pnp_request_card_device(card, id->devs[1].id, NULL); + if (chip->devc == NULL) return -EBUSY; /* Control port initialization */ - if (pnp_activate_dev(acard->devc) < 0) { + if (pnp_activate_dev(chip->devc) < 0) { snd_printk(KERN_ERR PFX "PnP control configure failure (out of resources?)\n"); return -EAGAIN; } snd_printdd("pnp: port=0x%llx\n", - (unsigned long long)pnp_port_start(acard->devc, 0)); - if (snd_audiodrive_pnp_init_main(dev, acard->dev) < 0) + (unsigned long long)pnp_port_start(chip->devc, 0)); + if (snd_audiodrive_pnp_init_main(dev, chip->dev) < 0) return -EBUSY; return 0; @@ -2139,24 +2122,20 @@ static int __devinit snd_audiodrive_pnpc(int dev, struct snd_audiodrive *acard, static int snd_es18xx_card_new(int dev, struct snd_card **cardp) { return snd_card_create(index[dev], id[dev], THIS_MODULE, - sizeof(struct snd_audiodrive), cardp); + sizeof(struct snd_es18xx), cardp); } static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) { - struct snd_audiodrive *acard = card->private_data; - struct snd_es18xx *chip; + struct snd_es18xx *chip = card->private_data; struct snd_opl3 *opl3; int err; - if ((err = snd_es18xx_new_device(card, - port[dev], - mpu_port[dev], - fm_port[dev], - irq[dev], dma1[dev], dma2[dev], - &chip)) < 0) + err = snd_es18xx_new_device(card, + port[dev], mpu_port[dev], fm_port[dev], + irq[dev], dma1[dev], dma2[dev]); + if (err < 0) return err; - acard->chip = chip; sprintf(card->driver, "ES%x", chip->version); -- cgit v1.2.3 From 23c4a8812a17f0af2b573a63fc991baa7d3570ed Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 30 Oct 2009 13:21:49 +0100 Subject: ALSA: hda - Switch to polling mode before disabling MSI When any codec communication error happens, try to switch to the polling mode first before turning off MSI. MSI gets more stable nowadays, thus we should keep it on as much as possible. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d0effa3563e2..a0eface6e99a 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -677,6 +677,14 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, } } + 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", @@ -692,14 +700,6 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, 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->probing) { /* If this critical timeout happens during the codec probing * phase, this is likely an access to a non-existing codec -- cgit v1.2.3 From bcc2c6b7cb320d10c7fcccd87dce87f4384b4332 Mon Sep 17 00:00:00 2001 From: Stas Sergeev Date: Sun, 1 Nov 2009 11:13:19 +0100 Subject: ALSA: snd-pcsp: add nopcm mode Currently, if the high-res timers are unavailable, snd-pcsp does not initialize. People who choose it over pcspkr, loose their console beeps in that case and get annoyed. With this patch, the console beeps remain regardless of the high-res timers. Additionally, the "nopcm" modparam is added to forcibly disable the PCM capabilities of the driver. Signed-off-by: Stas Sergeev Signed-off-by: Takashi Iwai --- sound/drivers/pcsp/pcsp.c | 32 ++++++++++++++++++++------------ sound/drivers/pcsp/pcsp.h | 2 +- sound/drivers/pcsp/pcsp_mixer.c | 33 ++++++++++++++++++++++++++------- 3 files changed, 47 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/drivers/pcsp/pcsp.c b/sound/drivers/pcsp/pcsp.c index b60cef257b58..f165c77d6273 100644 --- a/sound/drivers/pcsp/pcsp.c +++ b/sound/drivers/pcsp/pcsp.c @@ -26,6 +26,7 @@ MODULE_ALIAS("platform:pcspkr"); static int index = SNDRV_DEFAULT_IDX1; /* Index 0-MAX */ static char *id = SNDRV_DEFAULT_STR1; /* ID for this card */ static int enable = SNDRV_DEFAULT_ENABLE1; /* Enable this card */ +static int nopcm; /* Disable PCM capability of the driver */ module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for pcsp soundcard."); @@ -33,6 +34,8 @@ module_param(id, charp, 0444); MODULE_PARM_DESC(id, "ID string for pcsp soundcard."); module_param(enable, bool, 0444); MODULE_PARM_DESC(enable, "Enable PC-Speaker sound."); +module_param(nopcm, bool, 0444); +MODULE_PARM_DESC(nopcm, "Disable PC-Speaker PCM sound. Only beeps remain."); struct snd_pcsp pcsp_chip; @@ -43,13 +46,16 @@ static int __devinit snd_pcsp_create(struct snd_card *card) int err; int div, min_div, order; - hrtimer_get_res(CLOCK_MONOTONIC, &tp); - if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { - printk(KERN_ERR "PCSP: Timer resolution is not sufficient " - "(%linS)\n", tp.tv_nsec); - printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " - "enabled.\n"); - return -EIO; + if (!nopcm) { + hrtimer_get_res(CLOCK_MONOTONIC, &tp); + if (tp.tv_sec || tp.tv_nsec > PCSP_MAX_PERIOD_NS) { + printk(KERN_ERR "PCSP: Timer resolution is not sufficient " + "(%linS)\n", tp.tv_nsec); + printk(KERN_ERR "PCSP: Make sure you have HPET and ACPI " + "enabled.\n"); + printk(KERN_ERR "PCSP: Turned into nopcm mode.\n"); + nopcm = 1; + } } if (loops_per_jiffy >= PCSP_MIN_LPJ && tp.tv_nsec <= PCSP_MIN_PERIOD_NS) @@ -107,12 +113,14 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev) snd_card_free(card); return err; } - err = snd_pcsp_new_pcm(&pcsp_chip); - if (err < 0) { - snd_card_free(card); - return err; + if (!nopcm) { + err = snd_pcsp_new_pcm(&pcsp_chip); + if (err < 0) { + snd_card_free(card); + return err; + } } - err = snd_pcsp_new_mixer(&pcsp_chip); + err = snd_pcsp_new_mixer(&pcsp_chip, nopcm); if (err < 0) { snd_card_free(card); return err; diff --git a/sound/drivers/pcsp/pcsp.h b/sound/drivers/pcsp/pcsp.h index 174dd2ff0f22..1e123077923d 100644 --- a/sound/drivers/pcsp/pcsp.h +++ b/sound/drivers/pcsp/pcsp.h @@ -83,6 +83,6 @@ extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle); extern void pcsp_sync_stop(struct snd_pcsp *chip); extern int snd_pcsp_new_pcm(struct snd_pcsp *chip); -extern int snd_pcsp_new_mixer(struct snd_pcsp *chip); +extern int snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm); #endif diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 903bc846763f..02e05552632b 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -119,24 +119,43 @@ static int pcsp_pcspkr_put(struct snd_kcontrol *kcontrol, .put = pcsp_##ctl_type##_put, \ } -static struct snd_kcontrol_new __devinitdata snd_pcsp_controls[] = { +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { PCSP_MIXER_CONTROL(enable, "Master Playback Switch"), PCSP_MIXER_CONTROL(treble, "BaseFRQ Playback Volume"), +}; + +static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"), }; -int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip) +static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, + struct snd_kcontrol_new *ctls, int num) { - struct snd_card *card = chip->card; int i, err; + struct snd_card *card = chip->card; + for (i = 0; i < num; i++) { + err = snd_ctl_add(card, snd_ctl_new1(ctls + i, chip)); + if (err < 0) + return err; + } + return 0; +} + +int __devinit snd_pcsp_new_mixer(struct snd_pcsp *chip, int nopcm) +{ + int err; + struct snd_card *card = chip->card; - for (i = 0; i < ARRAY_SIZE(snd_pcsp_controls); i++) { - err = snd_ctl_add(card, - snd_ctl_new1(snd_pcsp_controls + i, - chip)); + if (!nopcm) { + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_pcm, + ARRAY_SIZE(snd_pcsp_controls_pcm)); if (err < 0) return err; } + err = snd_pcsp_ctls_add(chip, snd_pcsp_controls_spkr, + ARRAY_SIZE(snd_pcsp_controls_spkr)); + if (err < 0) + return err; strcpy(card->mixername, "PC-Speaker"); -- cgit v1.2.3 From 5bdaaada16363d64e10ae081755d1a8d392429f2 Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Wed, 4 Nov 2009 07:57:45 +0100 Subject: ALSA: hda - Enable GPIO control for mute LED on HP systems This patch enables GPIO to control mute LED indicator on the HP systems with the special string in BIOS and applies it with the correct polarity on HP B-series systems. It also restores configuration of the pin intended as the second Headphone on HP B-series systems but configured as something else in the BIOS to pass MS DTM. Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 68 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 66c0876bf734..b513eba2d2f7 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1693,6 +1694,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "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, "HP", STAC_HP_DV5), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, @@ -4730,6 +4733,26 @@ static int stac92xx_resume(struct hda_codec *codec) return 0; } +static int hp_bseries_system(u32 subsystem_id) +{ + switch (subsystem_id) { + case 0x103c307e: + case 0x103c307f: + case 0x103c3080: + case 0x103c3081: + case 0x103c1722: + case 0x103c1723: + case 0x103c1724: + case 0x103c1725: + case 0x103c1726: + case 0x103c1727: + case 0x103c1728: + case 0x103c1729: + return 1; + } + return 0; +} + /* * using power check for controlling mute led of HP notebooks * check for mute state only on Speakers (nid = 0x10) @@ -4754,6 +4777,11 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, else spec->gpio_data |= spec->gpio_led; /* white */ + if (hp_bseries_system(codec->subsystem_id)) { + /* LED state is inverted on these systems */ + spec->gpio_data ^= spec->gpio_led; + } + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); @@ -5243,6 +5271,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) { struct sigmatel_spec *spec; struct hda_verb *unmute_init = stac92hd71bxx_unmute_core_init; + unsigned int pin_cfg; int err = 0; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -5426,6 +5455,45 @@ again: break; } + if (hp_bseries_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 ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { + const struct dmi_device *dev = NULL; + while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, + NULL, dev))) { + if (strcmp(dev->name, "HP_Mute_LED_1")) { + switch (codec->vendor_id) { + case 0x111d7608: + spec->gpio_led = 0x01; + break; + case 0x111d7600: + case 0x111d7601: + case 0x111d7602: + case 0x111d7603: + spec->gpio_led = 0x08; + break; + } + break; + } + } + } + #ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { spec->gpio_mask |= spec->gpio_led; -- cgit v1.2.3 From 9dcaa7b25f2c8f6a0485854cd3641f585a154072 Mon Sep 17 00:00:00 2001 From: Rafael Ignacio Zurita Date: Tue, 3 Nov 2009 17:16:27 -0300 Subject: ALSA: sh: add SuperH DAC audio driver for ALSA V4 This is a port of the sound/oss/sh_dac_audio.c driver. The driver uses an on-chip 8-bit D/A converter, which has a speaker connected to one of its channels, found in several ancient HP machines. For interrupts it uses a high-resolution timer (hrtimer). Tested on SH7709 based hp6xx (HP Jornada 680/690 and HP Palmtop 620lx/660lx). Also, since OSS Emulation works, the old OSS sound/oss/sh_dac_audio.c driver would be obsolete soon, and it could be removed. Signed-off-by: Rafael Ignacio Zurita Acked-by: Paul Mundt Signed-off-by: Takashi Iwai --- sound/sh/Kconfig | 8 + sound/sh/Makefile | 2 + sound/sh/sh_dac_audio.c | 453 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 463 insertions(+) create mode 100644 sound/sh/sh_dac_audio.c (limited to 'sound') diff --git a/sound/sh/Kconfig b/sound/sh/Kconfig index aed0f90c3919..61139f3c1614 100644 --- a/sound/sh/Kconfig +++ b/sound/sh/Kconfig @@ -19,5 +19,13 @@ config SND_AICA help ALSA Sound driver for the SEGA Dreamcast console. +config SND_SH_DAC_AUDIO + tristate "SuperH DAC audio support" + depends on SND + depends on CPU_SH3 && HIGH_RES_TIMERS + select SND_PCM + help + Say Y here to include support for the on-chip DAC. + endif # SND_SUPERH diff --git a/sound/sh/Makefile b/sound/sh/Makefile index 8fdcb6e26f00..7d09b5188cf7 100644 --- a/sound/sh/Makefile +++ b/sound/sh/Makefile @@ -3,6 +3,8 @@ # snd-aica-objs := aica.o +snd-sh_dac_audio-objs := sh_dac_audio.o # Toplevel Module Dependency obj-$(CONFIG_SND_AICA) += snd-aica.o +obj-$(CONFIG_SND_SH_DAC_AUDIO) += snd-sh_dac_audio.o diff --git a/sound/sh/sh_dac_audio.c b/sound/sh/sh_dac_audio.c new file mode 100644 index 000000000000..76d9ad27d91c --- /dev/null +++ b/sound/sh/sh_dac_audio.c @@ -0,0 +1,453 @@ +/* + * sh_dac_audio.c - SuperH DAC audio driver for ALSA + * + * Copyright (c) 2009 by Rafael Ignacio Zurita + * + * + * Based on sh_dac_audio.c (Copyright (C) 2004, 2005 by Andriy Skulysh) + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Rafael Ignacio Zurita "); +MODULE_DESCRIPTION("SuperH DAC audio driver"); +MODULE_LICENSE("GPL"); +MODULE_SUPPORTED_DEVICE("{{SuperH DAC audio support}}"); + +/* Module Parameters */ +static int index = SNDRV_DEFAULT_IDX1; +static char *id = SNDRV_DEFAULT_STR1; +module_param(index, int, 0444); +MODULE_PARM_DESC(index, "Index value for SuperH DAC audio."); +module_param(id, charp, 0444); +MODULE_PARM_DESC(id, "ID string for SuperH DAC audio."); + +/* main struct */ +struct snd_sh_dac { + struct snd_card *card; + struct snd_pcm_substream *substream; + struct hrtimer hrtimer; + ktime_t wakeups_per_second; + + int rate; + int empty; + char *data_buffer, *buffer_begin, *buffer_end; + int processed; /* bytes proccesed, to compare with period_size */ + int buffer_size; + struct dac_audio_pdata *pdata; +}; + + +static void dac_audio_start_timer(struct snd_sh_dac *chip) +{ + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); +} + +static void dac_audio_stop_timer(struct snd_sh_dac *chip) +{ + hrtimer_cancel(&chip->hrtimer); +} + +static void dac_audio_reset(struct snd_sh_dac *chip) +{ + dac_audio_stop_timer(chip); + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; +} + +static void dac_audio_set_rate(struct snd_sh_dac *chip) +{ + chip->wakeups_per_second = ktime_set(0, 1000000000 / chip->rate); +} + + +/* PCM INTERFACE */ + +static struct snd_pcm_hardware snd_sh_dac_pcm_hw = { + .info = (SNDRV_PCM_INFO_MMAP | + SNDRV_PCM_INFO_MMAP_VALID | + SNDRV_PCM_INFO_INTERLEAVED | + SNDRV_PCM_INFO_HALF_DUPLEX), + .formats = SNDRV_PCM_FMTBIT_U8, + .rates = SNDRV_PCM_RATE_8000, + .rate_min = 8000, + .rate_max = 8000, + .channels_min = 1, + .channels_max = 1, + .buffer_bytes_max = (48*1024), + .period_bytes_min = 1, + .period_bytes_max = (48*1024), + .periods_min = 1, + .periods_max = 1024, +}; + +static int snd_sh_dac_pcm_open(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + + runtime->hw = snd_sh_dac_pcm_hw; + + chip->substream = substream; + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + + chip->pdata->start(chip->pdata); + + return 0; +} + +static int snd_sh_dac_pcm_close(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + chip->substream = NULL; + + dac_audio_stop_timer(chip); + chip->pdata->stop(chip->pdata); + + return 0; +} + +static int snd_sh_dac_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *hw_params) +{ + return snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(hw_params)); +} + +static int snd_sh_dac_pcm_hw_free(struct snd_pcm_substream *substream) +{ + return snd_pcm_lib_free_pages(substream); +} + +static int snd_sh_dac_pcm_prepare(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + + chip->buffer_size = runtime->buffer_size; + memset(chip->data_buffer, 0, chip->pdata->buffer_size); + + return 0; +} + +static int snd_sh_dac_pcm_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + dac_audio_start_timer(chip); + break; + case SNDRV_PCM_TRIGGER_STOP: + chip->buffer_begin = chip->buffer_end = chip->data_buffer; + chip->processed = 0; + chip->empty = 1; + dac_audio_stop_timer(chip); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int snd_sh_dac_pcm_copy(struct snd_pcm_substream *substream, int channel, + snd_pcm_uframes_t pos, void __user *src, snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memcpy_toio(chip->data_buffer + b_pos, src, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static int snd_sh_dac_pcm_silence(struct snd_pcm_substream *substream, + int channel, snd_pcm_uframes_t pos, + snd_pcm_uframes_t count) +{ + /* channel is not used (interleaved data) */ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + struct snd_pcm_runtime *runtime = substream->runtime; + ssize_t b_count = frames_to_bytes(runtime , count); + ssize_t b_pos = frames_to_bytes(runtime , pos); + + if (count < 0) + return -EINVAL; + + if (!count) + return 0; + + memset_io(chip->data_buffer + b_pos, 0, b_count); + chip->buffer_end = chip->data_buffer + b_pos + b_count; + + if (chip->empty) { + chip->empty = 0; + dac_audio_start_timer(chip); + } + + return 0; +} + +static +snd_pcm_uframes_t snd_sh_dac_pcm_pointer(struct snd_pcm_substream *substream) +{ + struct snd_sh_dac *chip = snd_pcm_substream_chip(substream); + int pointer = chip->buffer_begin - chip->data_buffer; + + return pointer; +} + +/* pcm ops */ +static struct snd_pcm_ops snd_sh_dac_pcm_ops = { + .open = snd_sh_dac_pcm_open, + .close = snd_sh_dac_pcm_close, + .ioctl = snd_pcm_lib_ioctl, + .hw_params = snd_sh_dac_pcm_hw_params, + .hw_free = snd_sh_dac_pcm_hw_free, + .prepare = snd_sh_dac_pcm_prepare, + .trigger = snd_sh_dac_pcm_trigger, + .pointer = snd_sh_dac_pcm_pointer, + .copy = snd_sh_dac_pcm_copy, + .silence = snd_sh_dac_pcm_silence, + .mmap = snd_pcm_lib_mmap_iomem, +}; + +static int __devinit snd_sh_dac_pcm(struct snd_sh_dac *chip, int device) +{ + int err; + struct snd_pcm *pcm; + + /* device should be always 0 for us */ + err = snd_pcm_new(chip->card, "SH_DAC PCM", device, 1, 0, &pcm); + if (err < 0) + return err; + + pcm->private_data = chip; + strcpy(pcm->name, "SH_DAC PCM"); + snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sh_dac_pcm_ops); + + /* buffer size=48K */ + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, + snd_dma_continuous_data(GFP_KERNEL), + 48 * 1024, + 48 * 1024); + + return 0; +} +/* END OF PCM INTERFACE */ + + +/* driver .remove -- destructor */ +static int snd_sh_dac_remove(struct platform_device *devptr) +{ + snd_card_free(platform_get_drvdata(devptr)); + platform_set_drvdata(devptr, NULL); + + return 0; +} + +/* free -- it has been defined by create */ +static int snd_sh_dac_free(struct snd_sh_dac *chip) +{ + /* release the data */ + kfree(chip->data_buffer); + kfree(chip); + + return 0; +} + +static int snd_sh_dac_dev_free(struct snd_device *device) +{ + struct snd_sh_dac *chip = device->device_data; + + return snd_sh_dac_free(chip); +} + +static enum hrtimer_restart sh_dac_audio_timer(struct hrtimer *handle) +{ + struct snd_sh_dac *chip = container_of(handle, struct snd_sh_dac, + hrtimer); + struct snd_pcm_runtime *runtime = chip->substream->runtime; + ssize_t b_ps = frames_to_bytes(runtime, runtime->period_size); + + if (!chip->empty) { + sh_dac_output(*chip->buffer_begin, chip->pdata->channel); + chip->buffer_begin++; + + chip->processed++; + if (chip->processed >= b_ps) { + chip->processed -= b_ps; + snd_pcm_period_elapsed(chip->substream); + } + + if (chip->buffer_begin == (chip->data_buffer + + chip->buffer_size - 1)) + chip->buffer_begin = chip->data_buffer; + + if (chip->buffer_begin == chip->buffer_end) + chip->empty = 1; + + } + + if (!chip->empty) + hrtimer_start(&chip->hrtimer, chip->wakeups_per_second, + HRTIMER_MODE_REL); + + return HRTIMER_NORESTART; +} + +/* create -- chip-specific constructor for the cards components */ +static int __devinit snd_sh_dac_create(struct snd_card *card, + struct platform_device *devptr, + struct snd_sh_dac **rchip) +{ + struct snd_sh_dac *chip; + int err; + + static struct snd_device_ops ops = { + .dev_free = snd_sh_dac_dev_free, + }; + + *rchip = NULL; + + chip = kzalloc(sizeof(*chip), GFP_KERNEL); + if (chip == NULL) + return -ENOMEM; + + chip->card = card; + + hrtimer_init(&chip->hrtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + chip->hrtimer.function = sh_dac_audio_timer; + + dac_audio_reset(chip); + chip->rate = 8000; + dac_audio_set_rate(chip); + + chip->pdata = devptr->dev.platform_data; + + chip->data_buffer = kmalloc(chip->pdata->buffer_size, GFP_KERNEL); + if (chip->data_buffer == NULL) { + kfree(chip); + return -ENOMEM; + } + + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); + if (err < 0) { + snd_sh_dac_free(chip); + return err; + } + + *rchip = chip; + + return 0; +} + +/* driver .probe -- constructor */ +static int __devinit snd_sh_dac_probe(struct platform_device *devptr) +{ + struct snd_sh_dac *chip; + struct snd_card *card; + int err; + + err = snd_card_create(index, id, THIS_MODULE, 0, &card); + if (err < 0) { + snd_printk(KERN_ERR "cannot allocate the card\n"); + return err; + } + + err = snd_sh_dac_create(card, devptr, &chip); + if (err < 0) + goto probe_error; + + err = snd_sh_dac_pcm(chip, 0); + if (err < 0) + goto probe_error; + + strcpy(card->driver, "snd_sh_dac"); + strcpy(card->shortname, "SuperH DAC audio driver"); + printk(KERN_INFO "%s %s", card->longname, card->shortname); + + err = snd_card_register(card); + if (err < 0) + goto probe_error; + + snd_printk("ALSA driver for SuperH DAC audio"); + + platform_set_drvdata(devptr, card); + return 0; + +probe_error: + snd_card_free(card); + return err; +} + +/* + * "driver" definition + */ +static struct platform_driver driver = { + .probe = snd_sh_dac_probe, + .remove = snd_sh_dac_remove, + .driver = { + .name = "dac_audio", + }, +}; + +static int __init sh_dac_init(void) +{ + return platform_driver_register(&driver); +} + +static void __exit sh_dac_exit(void) +{ + platform_driver_unregister(&driver); +} + +module_init(sh_dac_init); +module_exit(sh_dac_exit); -- cgit v1.2.3 From 798a8a15011e88cc63dbbb15728b42572c152093 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Wed, 4 Nov 2009 10:11:07 +0000 Subject: ALSA: hda - Add OLPC XO-1.5 PCI ID The XO-1.5 laptop now has a unique subvendor/subproduct ID, which can be used to automatically select the correct CXT5066 configuration. Signed-off-by: Daniel Drake Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 3fbbc8c01e70..6479e65858d3 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2325,6 +2325,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { CXT5066_LAPTOP), SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), + SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), {} }; -- cgit v1.2.3 From 7e6c3989af5baee999ef9a4424e85938cba8d34a Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 4 Nov 2009 21:03:46 -0500 Subject: ALSA: intel8x0: Mute External Amplifier by default for another Sony model BugLink: https://bugs.launchpad.net/bugs/474972 This Sony model needs External Amplifier muted for audible playback, so make sure we set the inv_eapd quirk. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 754867ed4785..aac20fb4aad2 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -1948,6 +1948,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "HP xw4200", /* AD1981B*/ .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x104d, + .subdevice = 0x8144, + .name = "Sony", + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x104d, .subdevice = 0x8197, -- cgit v1.2.3 From d355c82a0191d5a3e971bd5af96cc81fe3ed25b9 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 3 Nov 2009 15:47:25 +0100 Subject: ALSA: rename "PC Speaker" and "PC Beep" controls to "Beep" To avoid confusion in control names for the standard analog PC Beep generator using a small Internal PC Speaker, rename all related "PC Speaker" and "PC Beep" controls to "Beep" only. This name is more universal and can be also used on more platforms without confusion. Introduce also "Internal Speaker" in ControlNames.txt for systems with full-featured build-in internal speaker. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/oss/mixer_oss.c | 3 ++- sound/drivers/pcsp/pcsp_mixer.c | 2 +- sound/isa/cmi8330.c | 4 ++-- sound/isa/es1688/es1688_lib.c | 2 +- sound/isa/es18xx.c | 2 +- sound/isa/sb/sb_mixer.c | 4 ++-- sound/pci/ac97/ac97_codec.c | 6 +++--- sound/pci/ac97/ac97_patch.c | 12 ++++++------ sound/pci/azt3328.c | 4 ++-- sound/pci/ca0106/ca0106_mixer.c | 4 ++-- sound/pci/cmipci.c | 4 ++-- sound/pci/emu10k1/emumixer.c | 4 ++-- sound/pci/es1938.c | 2 +- sound/pci/hda/patch_cmedia.c | 4 ++-- sound/pci/hda/patch_realtek.c | 4 ++-- sound/pci/hda/patch_sigmatel.c | 6 +++--- sound/soc/codecs/wm9713.c | 22 +++++++++++----------- 17 files changed, 45 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 772423889eb3..b935ac9dce8d 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1251,7 +1251,8 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) { SOUND_MIXER_SYNTH, "FM", 0 }, /* fallback */ { SOUND_MIXER_SYNTH, "Music", 0 }, /* fallback */ { SOUND_MIXER_PCM, "PCM", 0 }, - { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, + { SOUND_MIXER_SPEAKER, "Beep", 0 }, + { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */ { SOUND_MIXER_LINE, "Line", 0 }, { SOUND_MIXER_MIC, "Mic", 0 }, { SOUND_MIXER_CD, "CD", 0 }, diff --git a/sound/drivers/pcsp/pcsp_mixer.c b/sound/drivers/pcsp/pcsp_mixer.c index 02e05552632b..6f633f4f3b96 100644 --- a/sound/drivers/pcsp/pcsp_mixer.c +++ b/sound/drivers/pcsp/pcsp_mixer.c @@ -125,7 +125,7 @@ static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_pcm[] = { }; static struct snd_kcontrol_new __devinitdata snd_pcsp_controls_spkr[] = { - PCSP_MIXER_CONTROL(pcspkr, "PC Speaker Playback Switch"), + PCSP_MIXER_CONTROL(pcspkr, "Beep Playback Switch"), }; static int __devinit snd_pcsp_ctls_add(struct snd_pcsp *chip, diff --git a/sound/isa/cmi8330.c b/sound/isa/cmi8330.c index 02f79d252718..8246aae32ab4 100644 --- a/sound/isa/cmi8330.c +++ b/sound/isa/cmi8330.c @@ -237,7 +237,7 @@ WSS_DOUBLE("Wavetable Capture Volume", 0, CMI8330_WAVGAIN, CMI8330_WAVGAIN, 4, 0, 15, 0), WSS_SINGLE("3D Control - Switch", 0, CMI8330_RMUX3D, 5, 1, 1), -WSS_SINGLE("PC Speaker Playback Volume", 0, +WSS_SINGLE("Beep Playback Volume", 0, CMI8330_OUTPUTVOL, 3, 3, 0), WSS_DOUBLE("FM Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), @@ -262,7 +262,7 @@ SB_DOUBLE("SB Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, SB_DOUBLE("SB Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), SB_SINGLE("SB Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), SB_SINGLE("SB Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), -SB_SINGLE("SB PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3), +SB_SINGLE("SB Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), SB_DOUBLE("SB Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), SB_DOUBLE("SB Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), SB_SINGLE("SB Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c index 4c6e14f87f2d..c76bb00c9d15 100644 --- a/sound/isa/es1688/es1688_lib.c +++ b/sound/isa/es1688/es1688_lib.c @@ -982,7 +982,7 @@ ES1688_DOUBLE("CD Playback Volume", 0, ES1688_CD_DEV, ES1688_CD_DEV, 4, 0, 15, 0 ES1688_DOUBLE("FM Playback Volume", 0, ES1688_FM_DEV, ES1688_FM_DEV, 4, 0, 15, 0), ES1688_DOUBLE("Mic Playback Volume", 0, ES1688_MIC_DEV, ES1688_MIC_DEV, 4, 0, 15, 0), ES1688_DOUBLE("Aux Playback Volume", 0, ES1688_AUX_DEV, ES1688_AUX_DEV, 4, 0, 15, 0), -ES1688_SINGLE("PC Speaker Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0), +ES1688_SINGLE("Beep Playback Volume", 0, ES1688_SPEAKER_DEV, 0, 7, 0), ES1688_DOUBLE("Capture Volume", 0, ES1688_RECLEV_DEV, ES1688_RECLEV_DEV, 4, 0, 15, 0), ES1688_SINGLE("Capture Switch", 0, ES1688_REC_DEV, 4, 1, 1), { diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 5cf42b4d65fd..e5bf3355d2ca 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -1313,7 +1313,7 @@ ES18XX_DOUBLE("Aux Capture Volume", 0, 0x6c, 0x6c, 4, 0, 15, 0) * The chipset specific mixer controls */ static struct snd_kcontrol_new snd_es18xx_opt_speaker = - ES18XX_SINGLE("PC Speaker Playback Volume", 0, 0x3c, 0, 7, 0); + ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0); static struct snd_kcontrol_new snd_es18xx_opt_1869[] = { ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 475220bbcc96..318ff0c823e7 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c @@ -631,7 +631,7 @@ static struct sbmix_elem snd_sb16_ctl_mic_play_switch = static struct sbmix_elem snd_sb16_ctl_mic_play_vol = SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = - SB_SINGLE("PC Speaker Volume", SB_DSP4_SPEAKER_DEV, 6, 3); + SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); static struct sbmix_elem snd_sb16_ctl_capture_vol = SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); static struct sbmix_elem snd_sb16_ctl_play_vol = @@ -689,7 +689,7 @@ static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = - SB_SINGLE("PC Speaker Volume", SB_DT019X_SPKR_DEV, 0, 7); + SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); static struct sbmix_elem snd_dt019x_ctl_line_play_vol = SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 78288dbfc17a..20cb60afb200 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -603,8 +603,8 @@ AC97_SINGLE("Tone Control - Treble", AC97_MASTER_TONE, 0, 15, 1) }; static const struct snd_kcontrol_new snd_ac97_controls_pc_beep[2] = { -AC97_SINGLE("PC Speaker Playback Switch", AC97_PC_BEEP, 15, 1, 1), -AC97_SINGLE("PC Speaker Playback Volume", AC97_PC_BEEP, 1, 15, 1) +AC97_SINGLE("Beep Playback Switch", AC97_PC_BEEP, 15, 1, 1), +AC97_SINGLE("Beep Playback Volume", AC97_PC_BEEP, 1, 15, 1) }; static const struct snd_kcontrol_new snd_ac97_controls_mic_boost = @@ -1393,7 +1393,7 @@ static int snd_ac97_mixer_build(struct snd_ac97 * ac97) } } - /* build PC Speaker controls */ + /* build Beep controls */ if (!(ac97->flags & AC97_HAS_NO_PC_BEEP) && ((ac97->flags & AC97_HAS_PC_BEEP) || snd_ac97_try_volume_mix(ac97, AC97_PC_BEEP))) { diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 7337abdbe4e3..139cf3b2b9d7 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -800,12 +800,12 @@ AC97_SINGLE("Mono Switch", AC97_MASTER_TONE, 7, 1, 1), AC97_SINGLE("Mono ZC Switch", AC97_MASTER_TONE, 6, 1, 0), AC97_SINGLE("Mono Volume", AC97_MASTER_TONE, 0, 31, 1), -AC97_SINGLE("PC Beep to Headphone Switch", AC97_AUX, 15, 1, 1), -AC97_SINGLE("PC Beep to Headphone Volume", AC97_AUX, 12, 7, 1), -AC97_SINGLE("PC Beep to Master Switch", AC97_AUX, 11, 1, 1), -AC97_SINGLE("PC Beep to Master Volume", AC97_AUX, 8, 7, 1), -AC97_SINGLE("PC Beep to Mono Switch", AC97_AUX, 7, 1, 1), -AC97_SINGLE("PC Beep to Mono Volume", AC97_AUX, 4, 7, 1), +AC97_SINGLE("Beep to Headphone Switch", AC97_AUX, 15, 1, 1), +AC97_SINGLE("Beep to Headphone Volume", AC97_AUX, 12, 7, 1), +AC97_SINGLE("Beep to Master Switch", AC97_AUX, 11, 1, 1), +AC97_SINGLE("Beep to Master Volume", AC97_AUX, 8, 7, 1), +AC97_SINGLE("Beep to Mono Switch", AC97_AUX, 7, 1, 1), +AC97_SINGLE("Beep to Mono Volume", AC97_AUX, 4, 7, 1), AC97_SINGLE("Voice to Headphone Switch", AC97_PCM, 15, 1, 1), AC97_SINGLE("Voice to Headphone Volume", AC97_PCM, 12, 7, 1), diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 8451a0169f32..69867ace7860 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c @@ -830,8 +830,8 @@ static struct snd_kcontrol_new snd_azf3328_mixer_controls[] __devinitdata = { AZF3328_MIXER_SWITCH("Mic Boost (+20dB)", IDX_MIXER_MIC, 6, 0), AZF3328_MIXER_SWITCH("Line Playback Switch", IDX_MIXER_LINEIN, 15, 1), AZF3328_MIXER_VOL_STEREO("Line Playback Volume", IDX_MIXER_LINEIN, 0x1f, 1), - AZF3328_MIXER_SWITCH("PC Speaker Playback Switch", IDX_MIXER_PCBEEP, 15, 1), - AZF3328_MIXER_VOL_SPECIAL("PC Speaker Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), + AZF3328_MIXER_SWITCH("Beep Playback Switch", IDX_MIXER_PCBEEP, 15, 1), + AZF3328_MIXER_VOL_SPECIAL("Beep Playback Volume", IDX_MIXER_PCBEEP, 0x0f, 1, 1), AZF3328_MIXER_SWITCH("Video Playback Switch", IDX_MIXER_VIDEO, 15, 1), AZF3328_MIXER_VOL_STEREO("Video Playback Volume", IDX_MIXER_VIDEO, 0x1f, 1), AZF3328_MIXER_SWITCH("Aux Playback Switch", IDX_MIXER_AUX, 15, 1), diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index c8c6f437f5b3..8f443a9d61ec 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c @@ -792,8 +792,8 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) "Phone Playback Volume", "Video Playback Switch", "Video Playback Volume", - "PC Speaker Playback Switch", - "PC Speaker Playback Volume", + "Beep Playback Switch", + "Beep Playback Volume", "Mono Output Select", "Capture Source", "Capture Switch", diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index ddcd4a9fd7e6..a312bae08f52 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -2302,7 +2302,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { CMIPCI_SB_VOL_MONO("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), CMIPCI_SB_SW_MONO("Mic Playback Switch", 0), CMIPCI_DOUBLE("Mic Capture Switch", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0, 1, 0, 0), - CMIPCI_SB_VOL_MONO("PC Speaker Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3), + CMIPCI_SB_VOL_MONO("Beep Playback Volume", SB_DSP4_SPEAKER_DEV, 6, 3), CMIPCI_MIXER_VOL_STEREO("Aux Playback Volume", CM_REG_AUX_VOL, 4, 0, 15), CMIPCI_MIXER_SW_STEREO("Aux Playback Switch", CM_REG_MIXER2, CM_VAUXLM_SHIFT, CM_VAUXRM_SHIFT, 0), CMIPCI_MIXER_SW_STEREO("Aux Capture Switch", CM_REG_MIXER2, CM_RAUXLEN_SHIFT, CM_RAUXREN_SHIFT, 0), @@ -2310,7 +2310,7 @@ static struct snd_kcontrol_new snd_cmipci_mixers[] __devinitdata = { CMIPCI_MIXER_VOL_MONO("Mic Capture Volume", CM_REG_MIXER2, CM_VADMIC_SHIFT, 7), CMIPCI_SB_VOL_MONO("Phone Playback Volume", CM_REG_EXTENT_IND, 5, 7), CMIPCI_DOUBLE("Phone Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 4, 4, 1, 0, 0), - CMIPCI_DOUBLE("PC Speaker Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), + CMIPCI_DOUBLE("Beep Playback Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 3, 3, 1, 0, 0), CMIPCI_DOUBLE("Mic Boost Capture Switch", CM_REG_EXTENT_IND, CM_REG_EXTENT_IND, 0, 0, 1, 0, 0), }; diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index b0fb6c917c38..05afe06e353a 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c @@ -1818,8 +1818,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, "Master Playback Switch", "Master Capture Switch", "Master Playback Volume", "Master Capture Volume", "Wave Master Playback Volume", "Master Playback Volume", - "PC Speaker Playback Switch", "PC Speaker Capture Switch", - "PC Speaker Playback Volume", "PC Speaker Capture Volume", + "Beep Playback Switch", "Beep Capture Switch", + "Beep Playback Volume", "Beep Capture Volume", "Phone Playback Switch", "Phone Capture Switch", "Phone Playback Volume", "Phone Capture Volume", "Mic Playback Switch", "Mic Capture Switch", diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index 820318ee62c1..fb83e1ffa5cb 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c @@ -1387,7 +1387,7 @@ ES1938_DOUBLE_TLV("Aux Playback Volume", 0, 0x3a, 0x3a, 4, 0, 15, 0, db_scale_line), ES1938_DOUBLE_TLV("Capture Volume", 0, 0xb4, 0xb4, 4, 0, 15, 0, db_scale_capture), -ES1938_SINGLE("PC Speaker Volume", 0, 0x3c, 0, 7, 0), +ES1938_SINGLE("Beep Volume", 0, 0x3c, 0, 7, 0), ES1938_SINGLE("Record Monitor", 0, 0xa8, 3, 1, 0), ES1938_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), { diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 780e1a72114a..85c81feb10cf 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -197,8 +197,8 @@ static struct snd_kcontrol_new cmi9880_basic_mixer[] = { HDA_CODEC_VOLUME_IDX("Capture Volume", 1, 0x09, 0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x08, 0, HDA_INPUT), HDA_CODEC_MUTE_IDX("Capture Switch", 1, 0x09, 0, HDA_INPUT), - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x23, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x23, 0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x23, 0, HDA_OUTPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x23, 0, HDA_OUTPUT), { } /* end */ }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c08ca660daba..08a5b8a55408 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -7334,8 +7334,8 @@ static struct snd_kcontrol_new alc882_macpro_mixer[] = { HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x01, HDA_INPUT), HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x01, HDA_INPUT), /* FIXME: this looks suspicious... - HDA_CODEC_VOLUME("PC Speaker Playback Volume", 0x0b, 0x02, HDA_INPUT), - HDA_CODEC_MUTE("PC Speaker Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Beep Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Beep Playback Switch", 0x0b, 0x02, HDA_INPUT), */ { } /* end */ }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 66c0876bf734..426edfa476a2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3221,7 +3221,7 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, /* check for mute support for the the amp */ if ((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT) { err = stac92xx_add_control(spec, STAC_CTL_WIDGET_MUTE, - "PC Beep Playback Switch", + "Beep Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -3230,7 +3230,7 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, /* 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, - "PC Beep Playback Volume", + "Beep Playback Volume", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) return err; @@ -3271,7 +3271,7 @@ static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { static int stac92xx_beep_switch_ctl(struct hda_codec *codec) { return stac92xx_add_control_temp(codec->spec, &stac92xx_dig_beep_ctrl, - 0, "PC Beep Playback Switch", 0); + 0, "Beep Playback Switch", 0); } #endif diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c index abed37acf787..60e360b10468 100644 --- a/sound/soc/codecs/wm9713.c +++ b/sound/soc/codecs/wm9713.c @@ -165,9 +165,9 @@ SOC_SINGLE("Mono Playback Switch", AC97_MASTER_TONE, 7, 1, 1), SOC_SINGLE("Mono Playback ZC Switch", AC97_MASTER_TONE, 6, 1, 0), SOC_SINGLE("Mono Playback Volume", AC97_MASTER_TONE, 0, 31, 1), -SOC_SINGLE("PC Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), -SOC_SINGLE("PC Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), -SOC_SINGLE("PC Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), +SOC_SINGLE("Beep Playback Headphone Volume", AC97_AUX, 12, 7, 1), +SOC_SINGLE("Beep Playback Speaker Volume", AC97_AUX, 8, 7, 1), +SOC_SINGLE("Beep Playback Mono Volume", AC97_AUX, 4, 7, 1), SOC_SINGLE("Voice Playback Headphone Volume", AC97_PCM, 12, 7, 1), SOC_SINGLE("Voice Playback Master Volume", AC97_PCM, 8, 7, 1), @@ -266,7 +266,7 @@ static int mixer_event(struct snd_soc_dapm_widget *w, /* Left Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", HPL_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0), @@ -276,7 +276,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0), /* Right Headphone Mixers */ static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", HPR_MIXER, 5, 1, 0), +SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0), SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0), SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0), SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0), @@ -294,7 +294,7 @@ SOC_DAPM_ENUM("Route", wm9713_enum[0]); /* Speaker Mixer */ static const struct snd_kcontrol_new wm9713_speaker_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 11, 1, 1), +SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 11, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 11, 1, 1), SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 11, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 14, 1, 1), @@ -304,7 +304,7 @@ SOC_DAPM_SINGLE("Bypass Playback Switch", AC97_PC_BEEP, 14, 1, 1), /* Mono Mixer */ static const struct snd_kcontrol_new wm9713_mono_mixer_controls[] = { -SOC_DAPM_SINGLE("PC Beep Playback Switch", AC97_AUX, 7, 1, 1), +SOC_DAPM_SINGLE("Beep Playback Switch", AC97_AUX, 7, 1, 1), SOC_DAPM_SINGLE("Voice Playback Switch", AC97_PCM, 7, 1, 1), SOC_DAPM_SINGLE("Aux Playback Switch", AC97_REC_SEL, 7, 1, 1), SOC_DAPM_SINGLE("PCM Playback Switch", AC97_PHONE, 13, 1, 1), @@ -463,7 +463,7 @@ SND_SOC_DAPM_VMID("VMID"), static const struct snd_soc_dapm_route audio_map[] = { /* left HP mixer */ - {"Left HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Left HP Mixer", "Beep Playback Switch", "PCBEEP"}, {"Left HP Mixer", "Voice Playback Switch", "Voice DAC"}, {"Left HP Mixer", "Aux Playback Switch", "Aux DAC"}, {"Left HP Mixer", "Bypass Playback Switch", "Left Line In"}, @@ -472,7 +472,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Left HP Mixer", NULL, "Capture Headphone Mux"}, /* right HP mixer */ - {"Right HP Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Right HP Mixer", "Beep Playback Switch", "PCBEEP"}, {"Right HP Mixer", "Voice Playback Switch", "Voice DAC"}, {"Right HP Mixer", "Aux Playback Switch", "Aux DAC"}, {"Right HP Mixer", "Bypass Playback Switch", "Right Line In"}, @@ -491,7 +491,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Capture Mixer", NULL, "Right Capture Source"}, /* speaker mixer */ - {"Speaker Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Speaker Mixer", "Beep Playback Switch", "PCBEEP"}, {"Speaker Mixer", "Voice Playback Switch", "Voice DAC"}, {"Speaker Mixer", "Aux Playback Switch", "Aux DAC"}, {"Speaker Mixer", "Bypass Playback Switch", "Line Mixer"}, @@ -499,7 +499,7 @@ static const struct snd_soc_dapm_route audio_map[] = { {"Speaker Mixer", "MonoIn Playback Switch", "Mono In"}, /* mono mixer */ - {"Mono Mixer", "PC Beep Playback Switch", "PCBEEP"}, + {"Mono Mixer", "Beep Playback Switch", "PCBEEP"}, {"Mono Mixer", "Voice Playback Switch", "Voice DAC"}, {"Mono Mixer", "Aux Playback Switch", "Aux DAC"}, {"Mono Mixer", "Bypass Playback Switch", "Line Mixer"}, -- cgit v1.2.3 From ad1cd745060ae2f24026b3b3d09da3426df6ab36 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 4 Nov 2009 14:30:36 +0100 Subject: ALSA: rename "PC Speaker" controls to "Speaker" To unify control names, rename "PC Speaker" to "Speaker" for PPC ALSA drivers. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/core/oss/mixer_oss.c | 1 + sound/ppc/awacs.c | 12 ++++++------ sound/ppc/burgundy.c | 8 ++++---- sound/ppc/tumbler.c | 2 +- 4 files changed, 12 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index b935ac9dce8d..54e2eb56e4c2 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c @@ -1253,6 +1253,7 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer) { SOUND_MIXER_PCM, "PCM", 0 }, { SOUND_MIXER_SPEAKER, "Beep", 0 }, { SOUND_MIXER_SPEAKER, "PC Speaker", 0 }, /* fallback */ + { SOUND_MIXER_SPEAKER, "Speaker", 0 }, /* fallback */ { SOUND_MIXER_LINE, "Line", 0 }, { SOUND_MIXER_MIC, "Mic", 0 }, { SOUND_MIXER_CD, "CD", 0 }, diff --git a/sound/ppc/awacs.c b/sound/ppc/awacs.c index 2cc0eda4f20e..2e156467b814 100644 --- a/sound/ppc/awacs.c +++ b/sound/ppc/awacs.c @@ -479,7 +479,7 @@ static int snd_pmac_awacs_put_master_amp(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new snd_pmac_awacs_amp_vol[] __devinitdata = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Volume", + .name = "Speaker Playback Volume", .info = snd_pmac_awacs_info_volume_amp, .get = snd_pmac_awacs_get_volume_amp, .put = snd_pmac_awacs_put_volume_amp, @@ -525,7 +525,7 @@ static struct snd_kcontrol_new snd_pmac_awacs_amp_hp_sw __devinitdata = { static struct snd_kcontrol_new snd_pmac_awacs_amp_spk_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Switch", + .name = "Speaker Playback Switch", .info = snd_pmac_boolean_stereo_info, .get = snd_pmac_awacs_get_switch_amp, .put = snd_pmac_awacs_put_switch_amp, @@ -696,17 +696,17 @@ static struct snd_kcontrol_new snd_pmac_screamer_mic_boost_imac[] __devinitdata }; static struct snd_kcontrol_new snd_pmac_awacs_speaker_vol[] __devinitdata = { - AWACS_VOLUME("PC Speaker Playback Volume", 4, 6, 1), + AWACS_VOLUME("Speaker Playback Volume", 4, 6, 1), }; static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_SPKMUTE, 1); static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac1 __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 1); static struct snd_kcontrol_new snd_pmac_awacs_speaker_sw_imac2 __devinitdata = -AWACS_SWITCH("PC Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); +AWACS_SWITCH("Speaker Playback Switch", 1, SHIFT_PAROUT1, 0); /* diff --git a/sound/ppc/burgundy.c b/sound/ppc/burgundy.c index 16ed240e423c..0accfe49735b 100644 --- a/sound/ppc/burgundy.c +++ b/sound/ppc/burgundy.c @@ -505,7 +505,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_imac[] __devinitdata = { MASK_ADDR_BURGUNDY_GAINLINE, 1, 0), BURGUNDY_VOLUME_B("Mic Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), - BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, + BURGUNDY_VOLUME_B("Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENLINEOUT, 1, 1), @@ -527,7 +527,7 @@ static struct snd_kcontrol_new snd_pmac_burgundy_mixers_pmac[] __devinitdata = { MASK_ADDR_BURGUNDY_VOLMIC, 16), BURGUNDY_VOLUME_B("Line in Gain Capture Volume", 0, MASK_ADDR_BURGUNDY_GAINMIC, 1, 0), - BURGUNDY_VOLUME_B("PC Speaker Playback Volume", 0, + BURGUNDY_VOLUME_B("Speaker Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENMONO, 0, 1), BURGUNDY_VOLUME_B("Line out Playback Volume", 0, MASK_ADDR_BURGUNDY_ATTENSPEAKER, 1, 1), @@ -549,11 +549,11 @@ BURGUNDY_SWITCH_B("Master Playback Switch", 0, BURGUNDY_OUTPUT_INTERN | BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_imac __devinitdata = -BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, +BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_LEFT, BURGUNDY_OUTPUT_RIGHT, 1); static struct snd_kcontrol_new snd_pmac_burgundy_speaker_sw_pmac __devinitdata = -BURGUNDY_SWITCH_B("PC Speaker Playback Switch", 0, +BURGUNDY_SWITCH_B("Speaker Playback Switch", 0, MASK_ADDR_BURGUNDY_MORE_OUTPUTENABLES, BURGUNDY_OUTPUT_INTERN, 0, 0); static struct snd_kcontrol_new snd_pmac_burgundy_line_sw_imac __devinitdata = diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c index 08e584d1453a..789f44f4ac78 100644 --- a/sound/ppc/tumbler.c +++ b/sound/ppc/tumbler.c @@ -905,7 +905,7 @@ static struct snd_kcontrol_new tumbler_hp_sw __devinitdata = { }; static struct snd_kcontrol_new tumbler_speaker_sw __devinitdata = { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "PC Speaker Playback Switch", + .name = "Speaker Playback Switch", .info = snd_pmac_boolean_mono_info, .get = tumbler_get_mute_switch, .put = tumbler_put_mute_switch, -- cgit v1.2.3 From f702cf463e1308fbb0c1faa9f3d8e3fa9cb5630f Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Wed, 4 Nov 2009 16:04:52 -0800 Subject: sound: Use KERN_WARNING instead of KERN_WARN, which does not exist Reported-by: Andrew Lyon Signed-off-by: Randy Dunlap Signed-off-by: Takashi Iwai --- sound/oss/sb_common.c | 4 ++-- sound/oss/sb_ess.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/oss/sb_common.c b/sound/oss/sb_common.c index 77d0e5efda76..ce4db49291f7 100644 --- a/sound/oss/sb_common.c +++ b/sound/oss/sb_common.c @@ -157,7 +157,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } @@ -177,7 +177,7 @@ static void sb_intr (sb_devc *devc) break; default: - /* printk(KERN_WARN "Sound Blaster: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "Sound Blaster: Unexpected interrupt\n"); */ ; } } diff --git a/sound/oss/sb_ess.c b/sound/oss/sb_ess.c index 180e95c87e3e..51a3d381a59e 100644 --- a/sound/oss/sb_ess.c +++ b/sound/oss/sb_ess.c @@ -782,7 +782,7 @@ printk(KERN_INFO "FKS: ess_handle_channel %s irq_mode=%d\n", channel, irq_mode); break; default:; - /* printk(KERN_WARN "ESS: Unexpected interrupt\n"); */ + /* printk(KERN_WARNING "ESS: Unexpected interrupt\n"); */ } } -- cgit v1.2.3 From d114cd84a1c5ce42bb10cd3a2da57b2bbcef909b Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Thu, 5 Nov 2009 18:32:41 +0100 Subject: ALSA: cs4236: detect chip in one pass The cs4236 was two step detection with call to the snd_wss_free() between two steps. The snd_wss_free() did not free a sound device created in the snd_wss_create(). This caused an OOPS during module removal as the same sound device was released twice. The same OOPS happened if the cs4236 module loading failed. Fix this by adapting the snd_cs4236_create() to correctly work with chips less capable then cs4236. The snd_cs4236_create() behaves the same as the snd_wss_create() if the chip is less capable than the cs4236. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236.c | 13 +++-------- sound/isa/cs423x/cs4236_lib.c | 50 +++++++++++++++++++++++++++---------------- sound/isa/wss/wss_lib.c | 3 +-- 3 files changed, 35 insertions(+), 31 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce8071..93fa6720d197 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -394,21 +394,15 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) return -EBUSY; } - err = snd_wss_create(card, port[dev], cport[dev], + err = snd_cs4236_create(card, port[dev], cport[dev], irq[dev], dma1[dev], dma2[dev], WSS_HW_DETECT3, 0, &chip); if (err < 0) return err; + + acard->chip = chip; if (chip->hardware & WSS_HW_CS4236B_MASK) { - snd_wss_free(chip); - err = snd_cs4236_create(card, - port[dev], cport[dev], - irq[dev], dma1[dev], dma2[dev], - WSS_HW_DETECT, 0, &chip); - if (err < 0) - return err; - acard->chip = chip; err = snd_cs4236_pcm(chip, 0, &pcm); if (err < 0) @@ -418,7 +412,6 @@ static int __devinit snd_cs423x_probe(struct snd_card *card, int dev) if (err < 0) return err; } else { - acard->chip = chip; err = snd_wss_pcm(chip, 0, &pcm); if (err < 0) return err; diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 38835f31298b..1b1ad1cad328 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -87,6 +87,7 @@ #include #include #include +#include /* * @@ -264,7 +265,10 @@ static void snd_cs4236_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ - +/* + * This function does no fail if the chip is not CS4236B or compatible. + * It just an equivalent to the snd_wss_create() then. + */ int snd_cs4236_create(struct snd_card *card, unsigned long port, unsigned long cport, @@ -281,21 +285,17 @@ int snd_cs4236_create(struct snd_card *card, *rchip = NULL; if (hardware == WSS_HW_DETECT) hardware = WSS_HW_DETECT3; - if (cport < 0x100) { - snd_printk(KERN_ERR "please, specify control port " - "for CS4236+ chips\n"); - return -ENODEV; - } + err = snd_wss_create(card, port, cport, irq, dma1, dma2, hardware, hwshare, &chip); if (err < 0) return err; - if (!(chip->hardware & WSS_HW_CS4236B_MASK)) { - snd_printk(KERN_ERR "CS4236+: MODE3 and extended registers " - "not available, hardware=0x%x\n", chip->hardware); - snd_device_free(card, chip); - return -ENODEV; + if ((chip->hardware & WSS_HW_CS4236B_MASK) == 0) { + snd_printd("chip is not CS4236+, hardware=0x%x\n", + chip->hardware); + *rchip = chip; + return 0; } #if 0 { @@ -308,9 +308,16 @@ int snd_cs4236_create(struct snd_card *card, idx, snd_cs4236_ctrl_in(chip, idx)); } #endif + if (cport < 0x100 || cport == SNDRV_AUTO_PORT) { + snd_printk(KERN_ERR "please, specify control port " + "for CS4236+ chips\n"); + snd_device_free(card, chip); + return -ENODEV; + } ver1 = snd_cs4236_ctrl_in(chip, 1); ver2 = snd_cs4236_ext_in(chip, CS4236_VERSION); - snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", cport, ver1, ver2); + snd_printdd("CS4236: [0x%lx] C1 (version) = 0x%x, ext = 0x%x\n", + cport, ver1, ver2); if (ver1 != ver2) { snd_printk(KERN_ERR "CS4236+ chip detected, but " "control port 0x%lx is not valid\n", cport); @@ -321,13 +328,17 @@ int snd_cs4236_create(struct snd_card *card, snd_cs4236_ctrl_out(chip, 2, 0xff); snd_cs4236_ctrl_out(chip, 3, 0x00); snd_cs4236_ctrl_out(chip, 4, 0x80); - snd_cs4236_ctrl_out(chip, 5, ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | IEC958_AES0_CON_EMPHASIS_NONE); + reg = ((IEC958_AES1_CON_PCM_CODER & 3) << 6) | + IEC958_AES0_CON_EMPHASIS_NONE; + snd_cs4236_ctrl_out(chip, 5, reg); snd_cs4236_ctrl_out(chip, 6, IEC958_AES1_CON_PCM_CODER >> 2); snd_cs4236_ctrl_out(chip, 7, 0x00); - /* 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 output */ - /* is working with this setup, other hardware should have */ - /* different signal paths and this value should be selectable */ - /* in the future */ + /* + * 0x8c for C8 is valid for Turtle Beach Malibu - the IEC-958 + * output is working with this setup, other hardware should + * have different signal paths and this value should be + * selectable in the future + */ snd_cs4236_ctrl_out(chip, 8, 0x8c); chip->rate_constraint = snd_cs4236_xrate; chip->set_playback_format = snd_cs4236_playback_format; @@ -339,9 +350,10 @@ int snd_cs4236_create(struct snd_card *card, /* initialize extended registers */ for (reg = 0; reg < sizeof(snd_cs4236_ext_map); reg++) - snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), snd_cs4236_ext_map[reg]); + snd_cs4236_ext_out(chip, CS4236_I23VAL(reg), + snd_cs4236_ext_map[reg]); - /* initialize compatible but more featured registers */ + /* initialize compatible but more featured registers */ snd_wss_out(chip, CS4231_LEFT_INPUT, 0x40); snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x40); snd_wss_out(chip, CS4231_AUX1_LEFT_INPUT, 0xff); diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 2ba18978b419..705db0924375 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -1682,7 +1682,7 @@ static void snd_wss_resume(struct snd_wss *chip) } #endif /* CONFIG_PM */ -int snd_wss_free(struct snd_wss *chip) +static int snd_wss_free(struct snd_wss *chip) { release_and_free_resource(chip->res_port); release_and_free_resource(chip->res_cport); @@ -1705,7 +1705,6 @@ int snd_wss_free(struct snd_wss *chip) kfree(chip); return 0; } -EXPORT_SYMBOL(snd_wss_free); static int snd_wss_dev_free(struct snd_device *device) { -- cgit v1.2.3 From 78987bdc4e41a425ac113c2c51474f0368fe653a Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 5 Nov 2009 09:22:30 -0800 Subject: ALSA: hda, move hp_bseries_system Function hp_bseries_system() is always used, outside of CONFIG_ boundaries/controls, so move it. sound/pci/hda/patch_sigmatel.c:5458: error: implicit declaration of function 'hp_bseries_system' Signed-off-by: Randy Dunlap Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index b513eba2d2f7..8eb6508cd991 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4668,6 +4668,26 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } +static int hp_bseries_system(u32 subsystem_id) +{ + switch (subsystem_id) { + case 0x103c307e: + case 0x103c307f: + case 0x103c3080: + case 0x103c3081: + case 0x103c1722: + case 0x103c1723: + case 0x103c1724: + case 0x103c1725: + case 0x103c1726: + case 0x103c1727: + case 0x103c1728: + case 0x103c1729: + return 1; + } + return 0; +} + #ifdef CONFIG_PROC_FS static void stac92hd_proc_hook(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid) @@ -4733,26 +4753,6 @@ static int stac92xx_resume(struct hda_codec *codec) return 0; } -static int hp_bseries_system(u32 subsystem_id) -{ - switch (subsystem_id) { - case 0x103c307e: - case 0x103c307f: - case 0x103c3080: - case 0x103c3081: - case 0x103c1722: - case 0x103c1723: - case 0x103c1724: - case 0x103c1725: - case 0x103c1726: - case 0x103c1727: - case 0x103c1728: - case 0x103c1729: - return 1; - } - return 0; -} - /* * using power check for controlling mute led of HP notebooks * check for mute state only on Speakers (nid = 0x10) -- cgit v1.2.3 From 31cef7076ed9409a33f19ea372d6dc5fdefe27ae Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 Nov 2009 09:34:16 +0100 Subject: control: remove snd_konctrol_volatile::owner_pid field We do not need to save the ID of the process that locked a control because that information is already available in the owner's file data. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/control.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645e..814d2cf1a34c 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -672,7 +672,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = vd->owner_pid; + info->owner = vd->owner->pid; } else { info->owner = -1; } @@ -827,7 +827,6 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file, result = -EBUSY; else { vd->owner = file; - vd->owner_pid = current->pid; result = 0; } } @@ -858,7 +857,6 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file, result = -EPERM; else { vd->owner = NULL; - vd->owner_pid = 0; result = 0; } } -- cgit v1.2.3 From 25d27eded1f4fc728e64f443adc339b5229be5d7 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 2 Nov 2009 09:35:44 +0100 Subject: control: use reference-counted pid Instead of storing the PID number, take a reference to the task's pid structure. This protects against duplicates due to PID overflows, and using pid_vnr() ensures that the PID returned by snd_ctl_elem_info() is correct as seen from the current namespace. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/control.c | 5 +++-- sound/core/pcm.c | 2 +- sound/core/rawmidi.c | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index 814d2cf1a34c..73dc10ac33f6 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -75,7 +75,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file) ctl->card = card; ctl->prefer_pcm_subdevice = -1; ctl->prefer_rawmidi_subdevice = -1; - ctl->pid = current->pid; + ctl->pid = get_pid(task_pid(current)); file->private_data = ctl; write_lock_irqsave(&card->ctl_files_rwlock, flags); list_add_tail(&ctl->list, &card->ctl_files); @@ -125,6 +125,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file) control->vd[idx].owner = NULL; up_write(&card->controls_rwsem); snd_ctl_empty_read_queue(ctl); + put_pid(ctl->pid); kfree(ctl); module_put(card->module); snd_card_file_remove(card, file); @@ -672,7 +673,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl, info->access |= SNDRV_CTL_ELEM_ACCESS_LOCK; if (vd->owner == ctl) info->access |= SNDRV_CTL_ELEM_ACCESS_OWNER; - info->owner = vd->owner->pid; + info->owner = pid_vnr(vd->owner->pid); } else { info->owner = -1; } diff --git a/sound/core/pcm.c b/sound/core/pcm.c index c69c60b2a48a..8e2c7833614c 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -809,7 +809,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, card = pcm->card; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { prefer_subdevice = kctl->prefer_pcm_subdevice; if (prefer_subdevice != -1) break; diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c0adc14c91f0..8a81bdafce6e 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -415,7 +415,7 @@ static int snd_rawmidi_open(struct inode *inode, struct file *file) subdevice = -1; read_lock(&card->ctl_files_rwlock); list_for_each_entry(kctl, &card->ctl_files, list) { - if (kctl->pid == current->pid) { + if (kctl->pid == task_pid(current)) { subdevice = kctl->prefer_rawmidi_subdevice; if (subdevice != -1) break; -- cgit v1.2.3 From 167eae5a17b3cd44a324dbb972c338e489413f54 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 6 Nov 2009 15:47:50 +0100 Subject: ALSA: hda - Reset pins of IDT/STAC codecs at free Some laptops cause annoying clicks or noises at shutdown/reboot since the speaker pin is set still high. Apply the same procedure used for the suspend to avoid such clicks/noises for freeing the codec, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 42 ++++++++++++++++++++++++------------------ 1 file changed, 24 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8eb6508cd991..3087705a8e51 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4327,6 +4327,28 @@ static void stac92xx_free_kctls(struct hda_codec *codec) snd_array_free(&spec->kctls); } +static void stac92xx_shutup(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + int i; + hda_nid_t nid; + + /* reset each pin before powering down DAC/ADC to avoid click noise */ + nid = codec->start_nid; + for (i = 0; i < codec->num_nodes; i++, nid++) { + unsigned int wcaps = get_wcaps(codec, nid); + unsigned int wid_type = get_wcaps_type(wcaps); + if (wid_type == AC_WID_PIN) + snd_hda_codec_read(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } + + if (spec->eapd_mask) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data & + ~spec->eapd_mask); +} + static void stac92xx_free(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -4334,6 +4356,7 @@ static void stac92xx_free(struct hda_codec *codec) if (! spec) return; + stac92xx_shutup(codec); stac92xx_free_jacks(codec); snd_array_free(&spec->events); @@ -4793,24 +4816,7 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) { - struct sigmatel_spec *spec = codec->spec; - int i; - hda_nid_t nid; - - /* reset each pin before powering down DAC/ADC to avoid click noise */ - nid = codec->start_nid; - for (i = 0; i < codec->num_nodes; i++, nid++) { - unsigned int wcaps = get_wcaps(codec, nid); - unsigned int wid_type = get_wcaps_type(wcaps); - if (wid_type == AC_WID_PIN) - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, 0); - } - - if (spec->eapd_mask) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data & - ~spec->eapd_mask); + stac92xx_shutup(codec); return 0; } #endif -- cgit v1.2.3 From 70edc800a39327174d3244f9226ce8cacd01dc91 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 6 Nov 2009 22:41:29 +0000 Subject: sound: Replace old style lock initializer SPIN_LOCK_UNLOCKED is deprecated. Use __SPIN_LOCK_UNLOCKED instead. Signed-off-by: Thomas Gleixner Signed-off-by: Takashi Iwai --- sound/oss/dmasound/dmasound_core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/dmasound/dmasound_core.c b/sound/oss/dmasound/dmasound_core.c index 793b7f478433..3f3c3f71db4b 100644 --- a/sound/oss/dmasound/dmasound_core.c +++ b/sound/oss/dmasound/dmasound_core.c @@ -219,7 +219,9 @@ static int shared_resources_initialised; * Mid level stuff */ -struct sound_settings dmasound = { .lock = SPIN_LOCK_UNLOCKED }; +struct sound_settings dmasound = { + .lock = __SPIN_LOCK_UNLOCKED(dmasound.lock) +}; static inline void sound_silence(void) { -- cgit v1.2.3 From f495088210c8b9e20791d995a8210170c68d2deb Mon Sep 17 00:00:00 2001 From: Julian Anastasov Date: Fri, 6 Nov 2009 23:44:53 +0200 Subject: ALSA: usb-audio: fix combine_word problem Fix combine_word problem where first octet is not read properly. The only affected place seems to be the INPUT_TERMINAL type. Before now, sound controls can be created with the output terminal's name which is a fallback mechanism used only for unknown input terminal types. For example, Line can wrongly appear as Speaker. After the change it should appear as Line. The side effect of this change can be that users can expect the wrong control name in their scripts or programs while now we return the correct one. Probably, these defines should use get_unaligned_le16 and friends. Signed-off-by: Julian Anastasov Cc: Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 8e7f78941ba6..e9a3a9dca15c 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -210,7 +210,7 @@ struct snd_usb_midi_endpoint_info { /* */ -#define combine_word(s) ((*s) | ((unsigned int)(s)[1] << 8)) +#define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) -- cgit v1.2.3 From 1a6969788ef2d5bc3169eee59def6b267182f136 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 7 Nov 2009 09:49:04 +0100 Subject: ALSA: hda - Don't initialize CORB/RIRB for single_cmd mode So far, CORB/RIRB still remains even if the driver is switched to the single_cmd mode. The specification says that this should be disabled, but I hoped this isn't the case; indeed most devices worked together with CORB/RIRB. However, Poulsbo (US15W) seems problematic with this setup, and it requires to disable CORB/RIRB when single_cmd is used. Now this patch disables CORB/RIRB initialization when the single_cmd mode is used. Also the unsolicited event is disabled because it can't work without RIRB. Reported-and-tested-by: Troy Kisky Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e340792f6cb3..6517f589d01d 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -722,9 +722,10 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus, chip->last_cmd[addr]); chip->single_cmd = 1; bus->response_reset = 0; - /* re-initialize CORB/RIRB */ + /* release CORB/RIRB */ azx_free_cmd_io(chip); - azx_init_cmd_io(chip); + /* disable unsolicited responses */ + azx_writel(chip, GCTL, azx_readl(chip, GCTL) & ~ICH6_GCTL_UNSOL); return -1; } @@ -865,7 +866,9 @@ static int azx_reset(struct azx *chip) } /* Accept unsolicited responses */ - azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); + if (!chip->single_cmd) + azx_writel(chip, GCTL, azx_readl(chip, GCTL) | + ICH6_GCTL_UNSOL); /* detect codecs */ if (!chip->codec_mask) { @@ -980,7 +983,8 @@ static void azx_init_chip(struct azx *chip) azx_int_enable(chip); /* initialize the codec command I/O */ - azx_init_cmd_io(chip); + if (!chip->single_cmd) + azx_init_cmd_io(chip); /* program the position buffer */ azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); -- cgit v1.2.3 From f37325a956f0ee4356793da7d93c699a25b21d92 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Sat, 7 Nov 2009 22:13:39 +0000 Subject: ALSA: snd-aica: declare MODULE_FIRMWARE Signed-off-by: Ben Hutchings Signed-off-by: Takashi Iwai --- sound/sh/aica.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/sh/aica.c b/sound/sh/aica.c index 583a3693df75..a0df401ebb9f 100644 --- a/sound/sh/aica.c +++ b/sound/sh/aica.c @@ -49,6 +49,7 @@ MODULE_AUTHOR("Adrian McMenamin "); MODULE_DESCRIPTION("Dreamcast AICA sound (pcm) driver"); MODULE_LICENSE("GPL"); MODULE_SUPPORTED_DEVICE("{{Yamaha/SEGA, AICA}}"); +MODULE_FIRMWARE("aica_firmware.bin"); /* module parameters */ #define CARD_NAME "AICA" -- cgit v1.2.3 From faa1242c59311525b0f337e95ae3c324a833a8eb Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 8 Nov 2009 11:58:08 +0100 Subject: ALSA: es18xx: code improvements 1. Set the third argument of the snd_device_new to not NULL, so there is no warning about bug during chip detection. The third argument is not used in this driver. It was changed in my previous patch. 2. Remove the fm_port and mpu_port fields from the snd_es18xx structure. They can be converted to function arguments. 3. Remove the dmaN_size fields from the snd_es18xx structure. These values are used only in pointer functions and can be easily calculated. 4. Remove the ctrl_lock spinlock which is used only in one read function which is called once during chip initialization. There are many writes to the same register and they are not protected on purpose (see the comment ina the snd_es18xx_config_write()). 5. Use the first part of the text5Sources string table as the text4Soruces table (they are the same). 6. Merge the same cases for the ES1887 and ES1888 when setting chip's caps. 7. Move the snd_es18xx_reset() to __devinit section. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/es18xx.c | 91 ++++++++++++++++++++++++------------------------------ 1 file changed, 41 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c index 5cf42b4d65fd..06e871e66c97 100644 --- a/sound/isa/es18xx.c +++ b/sound/isa/es18xx.c @@ -102,8 +102,6 @@ struct snd_es18xx { unsigned long port; /* port of ESS chip */ - unsigned long mpu_port; /* MPU-401 port of ESS chip */ - unsigned long fm_port; /* FM port */ unsigned long ctrl_port; /* Control port of ESS chip */ struct resource *res_port; struct resource *res_mpu_port; @@ -116,8 +114,6 @@ struct snd_es18xx { unsigned short audio2_vol; /* volume level of audio2 */ unsigned short active; /* active channel mask */ - unsigned int dma1_size; - unsigned int dma2_size; unsigned int dma1_shift; unsigned int dma2_shift; @@ -135,7 +131,6 @@ struct snd_es18xx { spinlock_t reg_lock; spinlock_t mixer_lock; - spinlock_t ctrl_lock; #ifdef CONFIG_PM unsigned char pm_reg; #endif @@ -354,7 +349,7 @@ static inline int snd_es18xx_mixer_writable(struct snd_es18xx *chip, unsigned ch } -static int snd_es18xx_reset(struct snd_es18xx *chip) +static int __devinit snd_es18xx_reset(struct snd_es18xx *chip) { int i; outb(0x03, chip->port + 0x06); @@ -490,8 +485,6 @@ static int snd_es18xx_playback1_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma2_size = size; - snd_es18xx_rate_set(chip, substream, DAC2); /* Transfer Count Reload */ @@ -591,8 +584,6 @@ static int snd_es18xx_capture_prepare(struct snd_pcm_substream *substream) unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -659,8 +650,6 @@ static int snd_es18xx_playback2_prepare(struct snd_es18xx *chip, unsigned int size = snd_pcm_lib_buffer_bytes(substream); unsigned int count = snd_pcm_lib_period_bytes(substream); - chip->dma1_size = size; - snd_es18xx_reset_fifo(chip); /* Set stereo/mono */ @@ -821,17 +810,18 @@ static irqreturn_t snd_es18xx_interrupt(int irq, void *dev_id) static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (substream->number == 0 && (chip->caps & ES18XX_PCM2)) { if (!(chip->active & DAC2)) return 0; - pos = snd_dma_pointer(chip->dma2, chip->dma2_size); + pos = snd_dma_pointer(chip->dma2, size); return pos >> chip->dma2_shift; } else { if (!(chip->active & DAC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } } @@ -839,11 +829,12 @@ static snd_pcm_uframes_t snd_es18xx_playback_pointer(struct snd_pcm_substream *s static snd_pcm_uframes_t snd_es18xx_capture_pointer(struct snd_pcm_substream *substream) { struct snd_es18xx *chip = snd_pcm_substream_chip(substream); + unsigned int size = snd_pcm_lib_buffer_bytes(substream); int pos; if (!(chip->active & ADC1)) return 0; - pos = snd_dma_pointer(chip->dma1, chip->dma1_size); + pos = snd_dma_pointer(chip->dma1, size); return pos >> chip->dma1_shift; } @@ -974,9 +965,6 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream) static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { - static char *texts4Source[4] = { - "Mic", "CD", "Line", "Master" - }; static char *texts5Source[5] = { "Mic", "CD", "Line", "Master", "Mix" }; @@ -994,7 +982,8 @@ static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_ele uinfo->value.enumerated.items = 4; if (uinfo->value.enumerated.item > 3) uinfo->value.enumerated.item = 3; - strcpy(uinfo->value.enumerated.name, texts4Source[uinfo->value.enumerated.item]); + strcpy(uinfo->value.enumerated.name, + texts5Source[uinfo->value.enumerated.item]); break; case 0x1887: case 0x1888: @@ -1378,11 +1367,9 @@ ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), static int __devinit snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) { int data; - unsigned long flags; - spin_lock_irqsave(&chip->ctrl_lock, flags); + outb(reg, chip->ctrl_port); data = inb(chip->ctrl_port + 1); - spin_unlock_irqrestore(&chip->ctrl_lock, flags); return data; } @@ -1398,7 +1385,9 @@ static void __devinit snd_es18xx_config_write(struct snd_es18xx *chip, #endif } -static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) +static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { int mask = 0; @@ -1412,15 +1401,15 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) if (chip->caps & ES18XX_CONTROL) { /* Hardware volume IRQ */ snd_es18xx_config_write(chip, 0x27, chip->irq); - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { /* FM I/O */ - snd_es18xx_config_write(chip, 0x62, chip->fm_port >> 8); - snd_es18xx_config_write(chip, 0x63, chip->fm_port & 0xff); + snd_es18xx_config_write(chip, 0x62, fm_port >> 8); + snd_es18xx_config_write(chip, 0x63, fm_port & 0xff); } - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU-401 I/O */ - snd_es18xx_config_write(chip, 0x64, chip->mpu_port >> 8); - snd_es18xx_config_write(chip, 0x65, chip->mpu_port & 0xff); + snd_es18xx_config_write(chip, 0x64, mpu_port >> 8); + snd_es18xx_config_write(chip, 0x65, mpu_port & 0xff); /* MPU-401 IRQ */ snd_es18xx_config_write(chip, 0x28, chip->irq); } @@ -1507,11 +1496,12 @@ static int __devinit snd_es18xx_initialize(struct snd_es18xx *chip) snd_es18xx_mixer_write(chip, 0x7A, 0x68); /* Enable and set hardware volume interrupt */ snd_es18xx_mixer_write(chip, 0x64, 0x06); - if (chip->mpu_port > 0 && chip->mpu_port != SNDRV_AUTO_PORT) { + if (mpu_port > 0 && mpu_port != SNDRV_AUTO_PORT) { /* MPU401 share irq with audio Joystick enabled FM enabled */ - snd_es18xx_mixer_write(chip, 0x40, 0x43 | (chip->mpu_port & 0xf0) >> 1); + snd_es18xx_mixer_write(chip, 0x40, + 0x43 | (mpu_port & 0xf0) >> 1); } snd_es18xx_mixer_write(chip, 0x7f, ((irqmask + 1) << 1) | 0x01); } @@ -1629,7 +1619,9 @@ static int __devinit snd_es18xx_identify(struct snd_es18xx *chip) return 0; } -static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) +static int __devinit snd_es18xx_probe(struct snd_es18xx *chip, + unsigned long mpu_port, + unsigned long fm_port) { if (snd_es18xx_identify(chip) < 0) { snd_printk(KERN_ERR PFX "[0x%lx] ESS chip not found\n", chip->port); @@ -1650,8 +1642,6 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_I2S | ES18XX_CONTROL | ES18XX_HWV; break; case 0x1887: - chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; - break; case 0x1888: chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; break; @@ -1666,7 +1656,7 @@ static int __devinit snd_es18xx_probe(struct snd_es18xx *chip) if (chip->dma1 == chip->dma2) chip->caps &= ~(ES18XX_PCM2 | ES18XX_DUPLEX_SAME); - return snd_es18xx_initialize(chip); + return snd_es18xx_initialize(chip, mpu_port, fm_port); } static struct snd_pcm_ops snd_es18xx_playback_ops = { @@ -1802,10 +1792,7 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, spin_lock_init(&chip->reg_lock); spin_lock_init(&chip->mixer_lock); - spin_lock_init(&chip->ctrl_lock); chip->port = port; - chip->mpu_port = mpu_port; - chip->fm_port = fm_port; chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; @@ -1841,11 +1828,11 @@ static int __devinit snd_es18xx_new_device(struct snd_card *card, } chip->dma2 = dma2; - if (snd_es18xx_probe(chip) < 0) { + if (snd_es18xx_probe(chip, mpu_port, fm_port) < 0) { snd_es18xx_free(card); - return -ENODEV; - } - err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, NULL, &ops); + return -ENODEV; + } + err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); if (err < 0) { snd_es18xx_free(card); return err; @@ -1980,7 +1967,7 @@ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ #ifdef CONFIG_PNP -static int isapnp[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; +static int isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; #endif static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* 0x220,0x240,0x260,0x280 */ #ifndef CONFIG_PNP @@ -2160,19 +2147,23 @@ static int __devinit snd_audiodrive_probe(struct snd_card *card, int dev) return err; if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { - if (snd_opl3_create(card, chip->fm_port, chip->fm_port + 2, OPL3_HW_OPL3, 0, &opl3) < 0) { - snd_printk(KERN_WARNING PFX "opl3 not detected at 0x%lx\n", chip->fm_port); + if (snd_opl3_create(card, fm_port[dev], fm_port[dev] + 2, + OPL3_HW_OPL3, 0, &opl3) < 0) { + snd_printk(KERN_WARNING PFX + "opl3 not detected at 0x%lx\n", + fm_port[dev]); } else { - if ((err = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) + err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); + if (err < 0) return err; } } if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { - if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, - chip->mpu_port, 0, - irq[dev], 0, - &chip->rmidi)) < 0) + err = snd_mpu401_uart_new(card, 0, MPU401_HW_ES18XX, + mpu_port[dev], 0, + irq[dev], 0, &chip->rmidi); + if (err < 0) return err; } -- cgit v1.2.3 From 7c5af6ffd69bb2bb3c86b374153627529d67598c Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 24 Oct 2009 15:55:12 +0200 Subject: pcmcia: use dynamic debug infrastructure, deprecate CS_CHECK (sound) Convert PCMCIA drivers to use the dynamic debug infrastructure, instead of requiring manual settings of PCMCIA_DEBUG. Also, remove all usages of the CS_CHECK macro and replace them with proper Linux style calling and return value checking. The extra error reporting may be dropped, as the PCMCIA core already complains about any (non-driver-author) errors. CC: Jaroslav Kysela CC: alsa-devel@alsa-project.org Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 21 ++++++++++++--------- sound/pcmcia/vx/vxpocket.c | 21 ++++++++++++--------- 2 files changed, 24 insertions(+), 18 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 7dea74b71cf1..64b859925c0b 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -217,20 +217,25 @@ static void snd_pdacf_detach(struct pcmcia_device *link) * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int pdacf_config(struct pcmcia_device *link) { struct snd_pdacf *pdacf = link->priv; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "pdacf_config called\n"); link->conf.ConfigIndex = 0x5; - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; if (snd_pdacf_assign_resources(pdacf, link->io.BasePort1, link->irq.AssignedIRQ) < 0) goto failed; @@ -238,8 +243,6 @@ static int pdacf_config(struct pcmcia_device *link) link->dev_node = &pdacf->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 7445cc8a47d3..1492744ad67f 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -213,14 +213,11 @@ static int snd_vxpocket_assign_resources(struct vx_core *chip, int port, int irq * configuration callback */ -#define CS_CHECK(fn, ret) \ -do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0) - static int vxpocket_config(struct pcmcia_device *link) { struct vx_core *chip = link->priv; struct snd_vxpocket *vxp = (struct snd_vxpocket *)chip; - int last_fn, last_ret; + int ret; snd_printdd(KERN_DEBUG "vxpocket_config called\n"); @@ -235,9 +232,17 @@ static int vxpocket_config(struct pcmcia_device *link) strcpy(chip->card->driver, vxp440_hw.name); } - CS_CHECK(RequestIO, pcmcia_request_io(link, &link->io)); - CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq)); - CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf)); + ret = pcmcia_request_io(link, &link->io); + if (ret) + goto failed; + + ret = pcmcia_request_irq(link, &link->irq); + if (ret) + goto failed; + + ret = pcmcia_request_configuration(link, &link->conf); + if (ret) + goto failed; chip->dev = &handle_to_dev(link); snd_card_set_dev(chip->card, chip->dev); @@ -248,8 +253,6 @@ static int vxpocket_config(struct pcmcia_device *link) link->dev_node = &vxp->node; return 0; -cs_failed: - cs_error(link, last_fn, last_ret); failed: pcmcia_disable_device(link); return -ENODEV; -- cgit v1.2.3 From 06fe9fb4182177fb046e6d934f80254dd90956ea Mon Sep 17 00:00:00 2001 From: Dirk Hohndel Date: Mon, 28 Sep 2009 21:43:57 -0400 Subject: tree-wide: fix a very frequent spelling mistake something-bility is spelled as something-blity so a grep for 'blit' would find these lines this is so trivial that I didn't split it by subsystem / copy additional maintainers - all changes are to comments The only purpose is to get fewer false positives when grepping around the kernel sources. Signed-off-by: Dirk Hohndel Signed-off-by: Jiri Kosina --- sound/pci/ice1712/juli.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9aef..9c0f78ea2c41 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -380,7 +380,7 @@ static struct snd_kcontrol_new juli_mute_controls[] __devinitdata = { * inputs) are fed from Xilinx. * * I even checked traces on board and coded a support in driver for - * an alternative possiblity - the unused I2S ICE output channels + * an alternative possibility - the unused I2S ICE output channels * switched to HW-IN/SPDIF-IN and providing the monitoring signal to * the DAC - to no avail. The I2S outputs seem to be unconnected. * -- cgit v1.2.3 From fa3012318bfb395552baef69bb1ebe87e64945c8 Mon Sep 17 00:00:00 2001 From: Michael Roth Date: Sun, 4 Oct 2009 18:14:29 +0200 Subject: Kconfig: Remove useless and sometimes wrong comments Additionally, some excessive newlines removed. Signed-off-by: Michael Roth Signed-off-by: Jiri Kosina --- sound/Kconfig | 4 ---- sound/oss/Kconfig | 2 -- 2 files changed, 6 deletions(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa3..4b5365ad6b46 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -1,6 +1,3 @@ -# sound/Config.in -# - menuconfig SOUND tristate "Sound card support" depends on HAS_IOMEM @@ -136,4 +133,3 @@ config AC97_BUS sound subsystem and other function drivers completely unrelated to sound although they're sharing the AC97 bus. Concerned drivers should "select" this. - diff --git a/sound/oss/Kconfig b/sound/oss/Kconfig index bcf2a0698d54..ea0b1aeffe66 100644 --- a/sound/oss/Kconfig +++ b/sound/oss/Kconfig @@ -1,5 +1,3 @@ -# drivers/sound/Config.in -# # 18 Apr 1998, Michael Elizabeth Chastain, # More hacking for modularisation. # -- cgit v1.2.3 From b71a8eb0fa64ec6d00175f479e3ef851703568af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Tue, 6 Oct 2009 12:42:51 +0200 Subject: tree-wide: fix typos "selct" + "slect" -> "select" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch was generated by git grep -E -i -l 's(le|el)ct' | xargs -r perl -p -i -e 's/([Ss])(le|el)ct/$1elect/ with only skipping net/netfilter/xt_SECMARK.c and include/linux/netfilter/xt_SECMARK.h which have a struct member called selctx. Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- sound/pci/hda/patch_cirrus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 8ba306856d38..7b0446fa6009 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -947,7 +947,7 @@ static void init_input(struct hda_codec *codec) coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ if (is_active_pin(codec, CS_DMIC1_PIN_NID)) coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 - * No effect if SPDIF_OUT2 is slected in + * No effect if SPDIF_OUT2 is selected in * IDX_SPDIF_CTL. */ cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); -- cgit v1.2.3 From 95491d902b4ed1bfd8f602aada793d74cc85428b Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 8 Nov 2009 19:03:55 -0500 Subject: ALSA: hda: Use model=auto quirk for Sony VAIO VGN-FW170J using ALC262 BugLink: https://bugs.launchpad.net/bugs/478309 The internal microphone on this VAIO model does not work unless the "auto" quirk is used. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff20048504b6..9bb4f75ca436 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11460,6 +11460,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x820f, "Sony ASSAMD", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), + SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", -- cgit v1.2.3 From dbaccc0cca830efe9bb3c9e4a1cfcd6503790079 Mon Sep 17 00:00:00 2001 From: Daniel Drake Date: Mon, 9 Nov 2009 15:17:24 +0000 Subject: ALSA: hda - Tweak OLPC XO-1.5 microphone bias Our contacts at Conexant suggested that we reduce the external microphone bias to 50% in order to center the input signal with the DC input range of the codec. This is because the microphone port is DC coupled for potential use with sensors. Signed-off-by: Daniel Drake Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 6479e65858d3..905859d4f4df 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -110,6 +110,7 @@ struct conexant_spec { unsigned int dell_automute; unsigned int port_d_mode; + unsigned char ext_mic_bias; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -1927,6 +1928,11 @@ static hda_nid_t cxt5066_adc_nids[3] = { 0x14, 0x15, 0x16 }; static hda_nid_t cxt5066_capsrc_nids[1] = { 0x17 }; #define CXT5066_SPDIF_OUT 0x21 +/* 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 struct hda_channel_mode cxt5066_modes[1] = { { 2, NULL }, }; @@ -1980,9 +1986,10 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, /* toggle input of built-in and mic jack appropriately */ static void cxt5066_automic(struct hda_codec *codec) { - static struct hda_verb ext_mic_present[] = { + struct conexant_spec *spec = codec->spec; + struct hda_verb ext_mic_present[] = { /* enable external mic, port B */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, /* switch to external mic input */ {0x17, AC_VERB_SET_CONNECT_SEL, 0}, @@ -2235,7 +2242,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ /* Port B: external microphone */ - {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, /* Port C: internal microphone */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, @@ -2353,6 +2360,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->input_mux = &cxt5066_capture_source; spec->port_d_mode = PIN_HP; + spec->ext_mic_bias = PIN_VREF80; spec->num_init_verbs = 1; spec->init_verbs[0] = cxt5066_init_verbs; @@ -2384,6 +2392,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; spec->port_d_mode = 0; + spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; -- cgit v1.2.3 From fb8d1a344dbe963f16249d07eee8415e93f9f3c2 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Nov 2009 16:02:29 +0100 Subject: ALSA: hda - Add reboot notifier to each codec Add reboot notifier to each codec so that it can do some workarounds needed for reboot. So far, patch_sigmatel.c calls its shutup routine for avoiding noises at reboot on some HP machines. References: Novell bnc#544779 http://bugzilla.novell.com/show_bug.cgi?id=544779 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 17 +++++++++++++++++ sound/pci/hda/hda_codec.h | 2 ++ sound/pci/hda/hda_intel.c | 1 + sound/pci/hda/patch_sigmatel.c | 1 + 4 files changed, 21 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2c1366343335..146f95be8737 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3404,6 +3404,23 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) } } +/* call each reboot notifier */ +void snd_hda_bus_reboot_notify(struct hda_bus *bus) +{ + struct hda_codec *codec; + + if (!bus) + return; + list_for_each_entry(codec, &bus->codec_list, list) { +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + if (codec->patch_ops.reboot_notify) + codec->patch_ops.reboot_notify(codec); + } +} + /* * open the digital out in the exclusive mode */ diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 99552fb5f756..624060837653 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -674,6 +674,7 @@ struct hda_codec_ops { #ifdef CONFIG_SND_HDA_POWER_SAVE int (*check_power_status)(struct hda_codec *codec, hda_nid_t nid); #endif + void (*reboot_notify)(struct hda_codec *codec); }; /* record for amp information cache */ @@ -910,6 +911,7 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, * 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); /* * power management diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 55c7da30bb61..0d3e0c9ea812 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2150,6 +2150,7 @@ static int azx_resume(struct pci_dev *pci) static int azx_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; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3087705a8e51..9c33700b21a8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4831,6 +4831,7 @@ static struct hda_codec_ops stac92xx_patch_ops = { .suspend = stac92xx_suspend, .resume = stac92xx_resume, #endif + .reboot_notify = stac92xx_shutup, }; static int patch_stac9200(struct hda_codec *codec) -- cgit v1.2.3 From e3303235209c0496b490e10ab131e72a9568c153 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 10 Nov 2009 14:53:02 +0100 Subject: ALSA: hda - proc - show which I/O NID is associated to PCM device Output something like: Node 0x02 [Audio Output] wcaps 0x11: Stereo Device: name="ALC888 Analog", type="Audio", device=0, substream=0 Converter: stream=0, channel=0 ... Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 9 +++++---- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_proc.c | 16 +++++++++++++++- 3 files changed, 21 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 146f95be8737..480d1ec49c99 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -2877,14 +2877,15 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { + "Audio", "SPDIF", "HDMI", "Modem" +}; + /* * get the empty PCM device number to assign */ static int get_empty_pcm_device(struct hda_bus *bus, int type) { - static const char *dev_name[HDA_PCM_NTYPES] = { - "Audio", "SPDIF", "HDMI", "Modem" - }; /* audio device indices; not linear to keep compatibility */ static int audio_idx[HDA_PCM_NTYPES][5] = { [HDA_PCM_TYPE_AUDIO] = { 0, 2, 4, 5, -1 }, @@ -2903,7 +2904,7 @@ static int get_empty_pcm_device(struct hda_bus *bus, int type) if (!test_and_set_bit(audio_idx[type][i], bus->pcm_dev_bits)) return audio_idx[type][i]; - snd_printk(KERN_WARNING "Too many %s devices\n", dev_name[type]); + snd_printk(KERN_WARNING "Too many %s devices\n", snd_hda_pcm_type_name[type]); return -EAGAIN; } diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 624060837653..cbf199a98ab2 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -894,6 +894,7 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM */ +extern const char *snd_hda_pcm_type_name[]; int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_build_pcms(struct hda_codec *codec); void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 95f24e4729f8..f5639c2988ab 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -309,7 +309,21 @@ static void print_audio_io(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, unsigned int wid_type) { - int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + int pcm, conv; + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + int type; + struct hda_pcm *cpcm = &codec->pcm_info[pcm]; + for (type = 0; type < 2; type++) { + if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) + continue; + snd_iprintf(buffer, " Device: name=\"%s\", type=\"%s\", device=%i, substream=%i\n", + cpcm->name, + snd_hda_pcm_type_name[cpcm->pcm_type], + cpcm->pcm->device, + cpcm->pcm->streams[type].substream->number); + } + } + conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); snd_iprintf(buffer, " Converter: stream=%d, channel=%d\n", (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, -- cgit v1.2.3 From 4ac55982907e1d48e64feaa56be91b9b52d3714d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Nov 2009 16:08:45 +0100 Subject: ALSA: hda - Avoid quirk for HP dc5750 The present quirk for HP dc5750 seems broken and maps the pins wrongly. Since the auto-parser works well for this device, set the default entry to use model=auto. Reference: Novell bnc#552154 https://bugzilla.novell.com/show_bug.cgi?id=552154 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 9bb4f75ca436..d1ccb6eaf9fc 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6249,7 +6249,7 @@ static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), - SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_HP_3013), + SND_PCI_QUIRK(0x103c, 0x280a, "HP d5750", ALC260_AUTO), /* no quirk */ SND_PCI_QUIRK(0x103c, 0x3010, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3011, "HP", ALC260_HP_3013), SND_PCI_QUIRK(0x103c, 0x3012, "HP", ALC260_HP_DC7600), -- cgit v1.2.3 From 8579d2d7779d7ff41ea2a0183015e0e5038f1043 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:09:38 +0200 Subject: sound: rawmidi: fix double init when opening MIDI device with O_APPEND Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 moved the substream initialization code to where it would be executed every time the substream is opened. This had the consequence that any further opening would drop and leak the data in the existing buffer, and that the device driver's open callback would be called multiple times, unexpectedly. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index c0adc14c91f0..3071e6f5801e 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -266,17 +266,19 @@ static int open_substream(struct snd_rawmidi *rmidi, { int err; - err = snd_rawmidi_runtime_create(substream); - if (err < 0) - return err; - err = substream->ops->open(substream); - if (err < 0) - return err; - substream->opened = 1; - if (substream->use_count++ == 0) + if (substream->use_count == 0) { + err = snd_rawmidi_runtime_create(substream); + if (err < 0) + return err; + err = substream->ops->open(substream); + if (err < 0) + return err; + substream->opened = 1; substream->active_sensing = 0; - if (mode & SNDRV_RAWMIDI_LFLG_APPEND) - substream->append = 1; + if (mode & SNDRV_RAWMIDI_LFLG_APPEND) + substream->append = 1; + } + substream->use_count++; rmidi->streams[substream->stream].substream_opened++; return 0; } -- cgit v1.2.3 From 16fb109644b5644e42ececeff644514de6f4bd03 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:10:16 +0200 Subject: sound: rawmidi: fix checking of O_APPEND when opening MIDI device Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 dropped the check that a substream must already have been opened with O_APPEND to be able to open it a second time. This would make it possible for a substream to be switched to append mode, which would mean that non-atomic writes would fail unexpectedly. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 3071e6f5801e..091405385e15 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -248,7 +248,8 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, list_for_each_entry(substream, &s->substreams, list) { if (substream->opened) { if (stream == SNDRV_RAWMIDI_STREAM_INPUT || - !(mode & SNDRV_RAWMIDI_LFLG_APPEND)) + !(mode & SNDRV_RAWMIDI_LFLG_APPEND) || + !substream->append) continue; } if (subdevice < 0 || subdevice == substream->number) { -- cgit v1.2.3 From b7fe750fcceda4fa6bef399b0e2812562728ea82 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:11:43 +0200 Subject: sound: rawmidi: fix MIDI device O_APPEND error handling Commit 9a1b64caac82aa02cb74587ffc798e6f42c6170a in 2.6.30 broke the error handling code in rawmidi_open_priv(). If only the output substream of a RawMIDI device has been opened and if this device is then opened with O_RDWR | O_APPEND and if the initialization of the input substream fails (either because of low memory or because the device driver's open callback fails), then the runtime structure of the already open output substream will be freed and all following writes through the first handle will cause snd_rawmidi_write() to use the NULL runtime pointer. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 091405385e15..70d6f25ba526 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -272,8 +272,10 @@ static int open_substream(struct snd_rawmidi *rmidi, if (err < 0) return err; err = substream->ops->open(substream); - if (err < 0) + if (err < 0) { + snd_rawmidi_runtime_free(substream); return err; + } substream->opened = 1; substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) @@ -300,27 +302,27 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, SNDRV_RAWMIDI_STREAM_INPUT, mode, &sinput); if (err < 0) - goto __error; + return err; } if (mode & SNDRV_RAWMIDI_LFLG_OUTPUT) { err = assign_substream(rmidi, subdevice, SNDRV_RAWMIDI_STREAM_OUTPUT, mode, &soutput); if (err < 0) - goto __error; + return err; } if (sinput) { err = open_substream(rmidi, sinput, mode); if (err < 0) - goto __error; + return err; } if (soutput) { err = open_substream(rmidi, soutput, mode); if (err < 0) { if (sinput) close_substream(rmidi, sinput, 0); - goto __error; + return err; } } @@ -328,13 +330,6 @@ static int rawmidi_open_priv(struct snd_rawmidi *rmidi, int subdevice, int mode, rfile->input = sinput; rfile->output = soutput; return 0; - - __error: - if (sinput && sinput->runtime) - snd_rawmidi_runtime_free(sinput); - if (soutput && soutput->runtime) - snd_rawmidi_runtime_free(soutput); - return err; } /* called from sound/core/seq/seq_midi.c */ -- cgit v1.2.3 From 91d12c485b8949cce6c13ab641147c5bc86ce8b9 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Wed, 21 Oct 2009 09:12:26 +0200 Subject: sound: rawmidi: fix opened substreams count The substream_opened field is to count the number of opened substreams, not the number of times that any substreams have been opened. Furthermore, all substreams being opened does not imply that the next open would fail, due to the possibility of O_APPEND. With this wrong check, opening a substream multiple times would succeed only if the device had more unopened substreams. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 4e26563431c8..818b1299ed91 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -242,8 +242,6 @@ static int assign_substream(struct snd_rawmidi *rmidi, int subdevice, return -ENXIO; if (subdevice >= 0 && subdevice >= s->substream_count) return -ENODEV; - if (s->substream_opened >= s->substream_count) - return -EAGAIN; list_for_each_entry(substream, &s->substreams, list) { if (substream->opened) { @@ -280,9 +278,9 @@ static int open_substream(struct snd_rawmidi *rmidi, substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; + rmidi->streams[substream->stream].substream_opened++; } substream->use_count++; - rmidi->streams[substream->stream].substream_opened++; return 0; } @@ -466,7 +464,6 @@ static void close_substream(struct snd_rawmidi *rmidi, struct snd_rawmidi_substream *substream, int cleanup) { - rmidi->streams[substream->stream].substream_opened--; if (--substream->use_count) return; @@ -491,6 +488,7 @@ static void close_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); substream->opened = 0; substream->append = 0; + rmidi->streams[substream->stream].substream_opened--; } static void rawmidi_release_priv(struct snd_rawmidi_file *rfile) -- cgit v1.2.3 From e7373b702f6eab35f315e016a4159860a7a4d686 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 Nov 2009 10:13:30 +0100 Subject: sound: pcm: record a substream's owner process Record the pid of the task that opened a PCM substream. For sound cards with hardware mixing, this allows determining which process is associated with a specific substream's volume control. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/pcm.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 8e2c7833614c..6884ae031f6f 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c @@ -435,6 +435,7 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry, return; } snd_iprintf(buffer, "state: %s\n", snd_pcm_state_name(status.state)); + snd_iprintf(buffer, "owner_pid : %d\n", pid_vnr(substream->pid)); snd_iprintf(buffer, "trigger_time: %ld.%09ld\n", status.trigger_tstamp.tv_sec, status.trigger_tstamp.tv_nsec); snd_iprintf(buffer, "tstamp : %ld.%09ld\n", @@ -900,6 +901,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, substream->private_data = pcm->private_data; substream->ref_count = 1; substream->f_flags = file->f_flags; + substream->pid = get_pid(task_pid(current)); pstr->substream_opened++; *rsubstream = substream; return 0; @@ -921,6 +923,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) kfree(runtime->hw_constraints.rules); kfree(runtime); substream->runtime = NULL; + put_pid(substream->pid); + substream->pid = NULL; substream->pstr->substream_opened--; } -- cgit v1.2.3 From 7584af10cf46e0f4aa1696f1be79fa0f19a945ba Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Tue, 10 Nov 2009 10:14:04 +0100 Subject: sound: rawmidi: record a substream's owner process Record the pid of the task that opened a RawMIDI substream. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/core/rawmidi.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 818b1299ed91..2f766123b158 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -278,6 +278,7 @@ static int open_substream(struct snd_rawmidi *rmidi, substream->active_sensing = 0; if (mode & SNDRV_RAWMIDI_LFLG_APPEND) substream->append = 1; + substream->pid = get_pid(task_pid(current)); rmidi->streams[substream->stream].substream_opened++; } substream->use_count++; @@ -488,6 +489,8 @@ static void close_substream(struct snd_rawmidi *rmidi, snd_rawmidi_runtime_free(substream); substream->opened = 0; substream->append = 0; + put_pid(substream->pid); + substream->pid = NULL; rmidi->streams[substream->stream].substream_opened--; } @@ -1336,6 +1339,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Mode : %s\n" @@ -1357,6 +1363,9 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry, substream->number, (unsigned long) substream->bytes); if (substream->opened) { + snd_iprintf(buffer, + " Owner PID : %d\n", + pid_vnr(substream->pid)); runtime = substream->runtime; snd_iprintf(buffer, " Buffer size : %lu\n" -- cgit v1.2.3 From 8f217a226cfa7b960b8a6c00cef6b4de2c5dd030 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 10 Nov 2009 18:26:12 +0100 Subject: ALSA: hda - Add missing export for snd_hda_bus_reboot_notify ... forgot to add for modules. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 480d1ec49c99..2b787b013e93 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -3421,6 +3421,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); /* * open the digital out in the exclusive mode -- cgit v1.2.3 From 71121d9fcc494453b9311992de220abb47dde3f1 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Tue, 10 Nov 2009 20:11:55 +0100 Subject: ALSA: hda - possible read past array alc88[02]_parse_auto_config() The test of index `i' is after the read - too late - and unsafe: if snd_hda_get_connections() fails in the last iteration a read beyond the array is possible. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d1ccb6eaf9fc..daf6975b0c2e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4684,9 +4684,9 @@ static int alc880_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = dig_nid; else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - spec->slave_dig_outs[i - 1] = dig_nid; - if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; + spec->slave_dig_outs[i - 1] = dig_nid; } } if (spec->autocfg.dig_in_pin) @@ -9813,9 +9813,9 @@ static int alc882_parse_auto_config(struct hda_codec *codec) spec->multiout.dig_out_nid = dig_nid; else { spec->multiout.slave_dig_outs = spec->slave_dig_outs; - spec->slave_dig_outs[i - 1] = dig_nid; - if (i == ARRAY_SIZE(spec->slave_dig_outs) - 1) + if (i >= ARRAY_SIZE(spec->slave_dig_outs) - 1) break; + spec->slave_dig_outs[i - 1] = dig_nid; } } if (spec->autocfg.dig_in_pin) -- cgit v1.2.3 From a2f6309e8392e2c14c04594fca8b4876c8c9bc36 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 11 Nov 2009 09:34:25 +0100 Subject: ALSA: hda - Add power on/off counter Added the power on/off counter and expose via sysfs files. The sysfs files, power_on_acct and power_off_acct, are created under each codec hwdep sysfs directory (e.g. /sys/class/sound/hwC0D0). The files show the msec length of the codec power-on and power-off, respectively. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 16 ++++++++++++++++ sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_hwdep.c | 38 ++++++++++++++++++++++++++++++++++++++ sound/pci/hda/hda_local.h | 9 +++++++++ 4 files changed, 67 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2b787b013e93..444d9039c1ac 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -515,6 +515,7 @@ static int snd_hda_bus_dev_register(struct snd_device *device) 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); } return 0; } @@ -2452,9 +2453,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec) codec->afg ? codec->afg : codec->mfg, AC_PWRST_D3); #ifdef CONFIG_SND_HDA_POWER_SAVE + snd_hda_update_power_acct(codec); cancel_delayed_work(&codec->power_work); codec->power_on = 0; codec->power_transition = 0; + codec->power_jiffies = jiffies; #endif } @@ -3191,6 +3194,17 @@ static void hda_keep_power_on(struct hda_codec *codec) { codec->power_count++; codec->power_on = 1; + codec->power_jiffies = jiffies; +} + +void snd_hda_update_power_acct(struct hda_codec *codec) +{ + unsigned long delta = jiffies - codec->power_jiffies; + if (codec->power_on) + codec->power_on_acct += delta; + else + codec->power_off_acct += delta; + codec->power_jiffies += delta; } void snd_hda_power_up(struct hda_codec *codec) @@ -3201,7 +3215,9 @@ void snd_hda_power_up(struct hda_codec *codec) if (codec->power_on || codec->power_transition) return; + snd_hda_update_power_acct(codec); codec->power_on = 1; + codec->power_jiffies = jiffies; if (bus->ops.pm_notify) bus->ops.pm_notify(bus); hda_call_codec_resume(codec); diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index cbf199a98ab2..b16678cade18 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -812,6 +812,9 @@ struct hda_codec { unsigned int power_transition :1; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ + unsigned long power_on_acct; + unsigned long power_off_acct; + unsigned long power_jiffies; #endif /* codec-specific additional proc output */ @@ -936,6 +939,7 @@ const char *snd_hda_get_jack_location(u32 cfg); void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); #define snd_hda_codec_needs_resume(codec) codec->power_count +void snd_hda_update_power_acct(struct hda_codec *codec); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index cc24e6721d74..d24328661c6a 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -154,6 +154,44 @@ int /*__devinit*/ snd_hda_create_hwdep(struct hda_codec *codec) return 0; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +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_SND_HDA_POWER_SAVE */ + #ifdef CONFIG_SND_HDA_RECONFIG /* diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 461e0c15c77a..015fbac914b3 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -437,6 +437,15 @@ int snd_hda_create_hwdep(struct hda_codec *codec); static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif +#ifdef CONFIG_SND_HDA_POWER_SAVE +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 + #ifdef CONFIG_SND_HDA_RECONFIG int snd_hda_hwdep_add_sysfs(struct hda_codec *codec); #else -- cgit v1.2.3 From 46ef6ec9da420b298b1f197e445bf5b06fe01ef4 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 11 Nov 2009 14:32:10 -0500 Subject: ALSA: hda: Use model=mb5 for MacBookPro 5,2 BugLink: https://bugs.launchpad.net/bugs/462098 Until we can look closer at the verbs, let's use ALC885_MB5 for codec SSID 0x106b4600 to enable playback and capture for MacBookPro 5,2s. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index daf6975b0c2e..84a52efdb2d6 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8911,10 +8911,11 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), - /* FIXME: HP jack sense seems not working for MBP 5,1, so apparently - * no perfect solution yet + /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, + * so apparently no perfect solution yet */ SND_PCI_QUIRK(0x106b, 0x4000, "MacbookPro 5,1", ALC885_MB5), + SND_PCI_QUIRK(0x106b, 0x4600, "MacbookPro 5,2", ALC885_MB5), {} /* terminator */ }; -- cgit v1.2.3 From f8b7163529831ee3ad6a1aeaa0f1256cb527008d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Nov 2009 09:50:28 +0100 Subject: ALSA: hda - Don't access invalid substream in proc file The commit e3303235209c0496b490e10ab131e72a9568c153 "ALSA: hda - proc - show which I/O NID is associated to PCM device" introduces the access to substream pointer. But, PCMs may have no substreams in one or both directions, and this results in NULL dereference. Also, print the first substream number doesn't make sense. This patch removes the access to the substream pointer, and reformat to fit to the standard coding style. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_proc.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f5639c2988ab..f5b783ce450d 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -316,11 +316,11 @@ static void print_audio_io(struct snd_info_buffer *buffer, for (type = 0; type < 2; type++) { if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) continue; - snd_iprintf(buffer, " Device: name=\"%s\", type=\"%s\", device=%i, substream=%i\n", - cpcm->name, - snd_hda_pcm_type_name[cpcm->pcm_type], - cpcm->pcm->device, - cpcm->pcm->streams[type].substream->number); + snd_iprintf(buffer, " Device: name=\"%s\", " + "type=\"%s\", device=%i\n", + cpcm->name, + snd_hda_pcm_type_name[cpcm->pcm_type], + cpcm->pcm->device); } } conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); -- cgit v1.2.3 From 7288561af9a931c59e431336b553d897ee37b67d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 12 Nov 2009 10:01:18 +0100 Subject: ALSA: hda - Fix build error without CONFIG_SND_HDA_HWDEP=y CONFIG_SND_HDA_POWER_SAVE is independent from CONFIG_SND_HDA_HWDEP. Thus snd_hda_hwdep_add_power_sysfs() needs the check of both kconfigs. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_local.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 015fbac914b3..c1ca3182e6a4 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -437,7 +437,7 @@ int snd_hda_create_hwdep(struct hda_codec *codec); static inline int snd_hda_create_hwdep(struct hda_codec *codec) { return 0; } #endif -#ifdef CONFIG_SND_HDA_POWER_SAVE +#if defined(CONFIG_SND_HDA_POWER_SAVE) && 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) -- cgit v1.2.3 From 0d26ce3403b3841fa2656df08a819fc7eaebaa17 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Thu, 12 Nov 2009 17:43:11 +0100 Subject: sound: OSS: fix error return in dma_ioctl() The returned error should stay negative Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/audio.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/audio.c b/sound/oss/audio.c index b69c05b7ea7b..7df48a25c4ee 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c @@ -838,7 +838,7 @@ static int dma_ioctl(int dev, unsigned int cmd, void __user *arg) if ((err = audio_devs[dev]->d->prepare_for_input(dev, dmap_in->fragment_size, dmap_in->nbufs)) < 0) { spin_unlock_irqrestore(&dmap_in->lock,flags); - return -err; + return err; } dmap_in->dma_mode = DMODE_INPUT; audio_devs[dev]->enable_bits |= PCM_ENABLE_INPUT; -- cgit v1.2.3 From e2e527ae7fb07caa58f8fa8fa7e90ada0b175dd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 13 Nov 2009 08:28:03 +0100 Subject: ALSA: hda - Add another Nvidia HDMI codec id (10de:0005) Found on Nvidia 9800M GTS. Reported-by: Chris Balcum Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_nvhdmi.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 9fb60276f5c9..6afdab09bab7 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -397,6 +397,7 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0003, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, + { .id = 0x10de0005, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, @@ -406,6 +407,7 @@ static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { MODULE_ALIAS("snd-hda-codec-id:10de0002"); MODULE_ALIAS("snd-hda-codec-id:10de0003"); +MODULE_ALIAS("snd-hda-codec-id:10de0005"); MODULE_ALIAS("snd-hda-codec-id:10de0006"); MODULE_ALIAS("snd-hda-codec-id:10de0007"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); -- cgit v1.2.3 From 401de8184a4d94688962b9258fe10ab309ffda9c Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 13 Nov 2009 16:02:56 +0900 Subject: ALSA: ice1712: Use bitrev8 Signed-off-by: Akinobu Mita Signed-off-by: Takashi Iwai --- sound/i2c/cs8427.c | 15 ++------------- sound/pci/Kconfig | 1 + 2 files changed, 3 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/i2c/cs8427.c b/sound/i2c/cs8427.c index 020a5d512472..04ae8704cdcd 100644 --- a/sound/i2c/cs8427.c +++ b/sound/i2c/cs8427.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -55,18 +56,6 @@ struct cs8427 { struct cs8427_stream capture; }; -static unsigned char swapbits(unsigned char val) -{ - int bit; - unsigned char res = 0; - for (bit = 0; bit < 8; bit++) { - res <<= 1; - res |= val & 1; - val >>= 1; - } - return res; -} - int snd_cs8427_reg_write(struct snd_i2c_device *device, unsigned char reg, unsigned char val) { @@ -149,7 +138,7 @@ static int snd_cs8427_send_corudata(struct snd_i2c_device *device, } data[0] = CS8427_REG_AUTOINC | CS8427_REG_CORU_DATABUF; for (idx = 0; idx < count; idx++) - data[idx + 1] = swapbits(ndata[idx]); + data[idx + 1] = bitrev8(ndata[idx]); if (snd_i2c_sendbytes(device, data, count + 1) != count + 1) return -EIO; return 1; diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 75c602b5b132..351654cf7b09 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -570,6 +570,7 @@ config SND_ICE1712 tristate "ICEnsemble ICE1712 (Envy24)" select SND_MPU401_UART select SND_AC97_CODEC + select BITREVERSE help Say Y here to include support for soundcards based on the ICE1712 (Envy24) chip. -- cgit v1.2.3 From 01a1796bc52f625edc23bf995d200e1556eec544 Mon Sep 17 00:00:00 2001 From: "akpm@linux-foundation.org" Date: Fri, 13 Nov 2009 16:47:10 -0800 Subject: sound/pci/hda/patch_via.c: work around gcc-4.0.2 ICE sound/pci/hda/patch_via.c: In function 'via_hp_bind_automute': sound/pci/hda/patch_via.c:2074: internal compiler error: in do_SUBST, at combine.c:462 Please submit a full bug report, with preprocessed source if appropriate. See for instructions. [added a comment by tiwai] Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_via.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 5ec0e39593b5..5a856009c916 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -2043,7 +2043,10 @@ static void via_speaker_automute(struct hda_codec *codec) /* mute line-out and internal speaker if HP is plugged */ static void via_hp_bind_automute(struct hda_codec *codec) { - unsigned int hp_present, present = 0; + /* use long instead of int below just to avoid an internal compiler + * error with gcc 4.0.x + */ + unsigned long hp_present, present = 0; struct via_spec *spec = codec->spec; int i; -- cgit v1.2.3 From 50d40f187f9182ee8caa1b83f80a0e11e2226baa Mon Sep 17 00:00:00 2001 From: Aleksey Kunitskiy Date: Sat, 14 Nov 2009 15:18:54 +0200 Subject: ALSA: ice1724 - Patch for suspend/resume for ESI Juli@ Add proper suspend/resume code for Juli@ cards. Based on ice1724 suspend/resume work of Igor Chernyshev. Fixes bug https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4413 Tested on linux-2.6.31.6 Signed-off-by: Aleksey Kunitskiy Signed-off-by: Takashi Iwai --- sound/pci/ice1712/juli.c | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'sound') diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c index fd948bfd9aef..f5020ad99a10 100644 --- a/sound/pci/ice1712/juli.c +++ b/sound/pci/ice1712/juli.c @@ -503,6 +503,31 @@ static int __devinit juli_add_controls(struct snd_ice1712 *ice) return 0; } +/* + * suspend/resume + * */ + +#ifdef CONFIG_PM +static int juli_resume(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + struct juli_spec *spec = ice->spec; + /* akm4358 un-reset, un-mute */ + snd_akm4xxx_reset(ak, 0); + /* reinit ak4114 */ + snd_ak4114_reinit(spec->ak4114); + return 0; +} + +static int juli_suspend(struct snd_ice1712 *ice) +{ + struct snd_akm4xxx *ak = ice->akm; + /* akm4358 reset and soft-mute */ + snd_akm4xxx_reset(ak, 1); + return 0; +} +#endif + /* * initialize the chip */ @@ -646,6 +671,13 @@ static int __devinit juli_init(struct snd_ice1712 *ice) ice->set_spdif_clock = juli_set_spdif_clock; ice->spdif.ops.open = juli_spdif_in_open; + +#ifdef CONFIG_PM + ice->pm_resume = juli_resume; + ice->pm_suspend = juli_suspend; + ice->pm_suspend_enabled = 1; +#endif + return 0; } -- cgit v1.2.3 From 5e08fe570c2dbabb5015c37049eb9a451e55c890 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 14 Nov 2009 14:37:19 +0100 Subject: ALSA: ice1724 - Fix section mismatch in prodigy_hd2_resume() Remove invlid __devinit prefix from the suspend callback. Signed-off-by: Takashi Iwai --- sound/pci/ice1712/prodigy_hifi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index c75515f5be6f..6a9fee3ee78f 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c @@ -1100,7 +1100,7 @@ static void ak4396_init(struct snd_ice1712 *ice) } #ifdef CONFIG_PM -static int __devinit prodigy_hd2_resume(struct snd_ice1712 *ice) +static int prodigy_hd2_resume(struct snd_ice1712 *ice) { /* initialize ak4396 codec and restore previous mixer volumes */ struct prodigy_hifi_spec *spec = ice->spec; -- cgit v1.2.3 From 8ef5837a47f73faee18fa7ce2f9a9eb7675be8de Mon Sep 17 00:00:00 2001 From: Daniel J Blueman Date: Sat, 14 Nov 2009 18:20:04 +0000 Subject: ALSA: hda - Dell Studio 1557 hd-audio quirk Add the Dell Studio 15 (model 1557, Core i7) laptop to the hd-audio quirk list, enabling audio. Signed-off-by: Daniel J Blueman Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8eb6508cd991..86de305fc9f2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1590,6 +1590,8 @@ static struct snd_pci_quirk stac92hd73xx_cfg_tbl[] = { "Dell Studio 17", STAC_DELL_M6_DMIC), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02be, "Dell Studio 1555", STAC_DELL_M6_DMIC), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02bd, + "Dell Studio 1557", STAC_DELL_M6_DMIC), {} /* terminator */ }; -- cgit v1.2.3 From e8e63cbf9a339c972eeb5ccf8777c8067bdfd869 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Fri, 16 Oct 2009 16:03:49 -0700 Subject: oss: Mark loadhex static in hex2hex.c Nothing outside of hex2hex.c references loadhex. Signed-off-by: Josh Triplett --- sound/oss/hex2hex.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/oss/hex2hex.c b/sound/oss/hex2hex.c index 5460faae98c9..041ef5c52bc2 100644 --- a/sound/oss/hex2hex.c +++ b/sound/oss/hex2hex.c @@ -12,7 +12,7 @@ #define MAX_SIZE (256*1024) unsigned char buf[MAX_SIZE]; -int loadhex(FILE *inf, unsigned char *buf) +static int loadhex(FILE *inf, unsigned char *buf) { int l=0, c, i; -- cgit v1.2.3 From bf97402052483c125a9ea7bf13df0dd9b4134078 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Mon, 16 Nov 2009 11:07:17 +0200 Subject: ALSA: ice1724 - make some bitfields unsigned This is a clean up and doesn't change the behavior. Bit fields should always be unsigned. Otherwise pm_suspend_enabled will be -1 when you want it to be 1. The other bad thing is that the sparse checker will complain 36 times if they aren't unsigned. The other bitfields in that struct are unsigned already. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/pci/ice1712/ice1712.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index 9da2dae64c5b..d063149e7047 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h @@ -382,8 +382,8 @@ struct snd_ice1712 { #ifdef CONFIG_PM int (*pm_suspend)(struct snd_ice1712 *); int (*pm_resume)(struct snd_ice1712 *); - int pm_suspend_enabled:1; - int pm_saved_is_spdif_master:1; + unsigned int pm_suspend_enabled:1; + unsigned int pm_saved_is_spdif_master:1; unsigned int pm_saved_spdif_ctrl; unsigned char pm_saved_spdif_cfg; unsigned int pm_saved_route; -- cgit v1.2.3 From 123c07aeddd71fbb295842a8c19866e780b9a100 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 21 Oct 2009 14:48:23 +0200 Subject: ALSA: hda_intel: Digital PC Beep - change behaviour for input layer Original implementation was keeping registered input device for SND_BEEP and SND_TONE events all time. This patch changes this behaviour: If digital PC Beep is turned off using universal control switch, the input device is unregistered. Explanation: The kd_mksound() send SND_BEEP and SND_TONE only to last registered device acceping those events. It means that the HDA Intel audio driver blocks also the internal PC Speaker device (pcspkr.c driver) even if the HDA Beep is muted. The user can easy disable all beeps using 'setterm -blength 0' or 'xset b off' command. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 88 +++++++++++++++++++++++++++++++++--------- sound/pci/hda/hda_beep.h | 4 ++ sound/pci/hda/hda_codec.c | 12 ++++++ sound/pci/hda/hda_local.h | 15 +++++++ sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_sigmatel.c | 16 ++++---- 7 files changed, 111 insertions(+), 28 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 3f51a981e604..0e986537d570 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -113,23 +113,25 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, return 0; } -int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) +static void snd_hda_do_detach(struct hda_beep *beep) +{ + input_unregister_device(beep->dev); + beep->dev = NULL; + cancel_work_sync(&beep->beep_work); + /* turn off beep for sure */ + snd_hda_codec_write_cache(beep->codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, 0); +} + +static int snd_hda_do_attach(struct hda_beep *beep) { struct input_dev *input_dev; - struct hda_beep *beep; + struct hda_codec *codec = beep->codec; int err; - if (!snd_hda_get_bool_hint(codec, "beep")) - return 0; /* disabled explicitly */ - - beep = kzalloc(sizeof(*beep), GFP_KERNEL); - if (beep == NULL) - return -ENOMEM; - snprintf(beep->phys, sizeof(beep->phys), - "card%d/codec#%d/beep0", codec->bus->card->number, codec->addr); input_dev = input_allocate_device(); if (!input_dev) { - kfree(beep); + printk(KERN_INFO "hda_beep: unable to allocate input device\n"); return -ENOMEM; } @@ -151,21 +153,71 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) err = input_register_device(input_dev); if (err < 0) { input_free_device(input_dev); - kfree(beep); + printk(KERN_INFO "hda_beep: unable to register input device\n"); return err; } + beep->dev = input_dev; + return 0; +} + +static void snd_hda_do_register(struct work_struct *work) +{ + struct hda_beep *beep = + container_of(work, struct hda_beep, register_work); + int request; + + mutex_lock(&beep->mutex); + request = beep->request_enable; + if (beep->enabled != request) { + if (!request) { + snd_hda_do_detach(beep); + } else { + if (snd_hda_do_attach(beep) < 0) + goto __out; + } + beep->enabled = request; + } + __out: + mutex_unlock(&beep->mutex); +} + +int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) +{ + struct hda_beep *beep = codec->beep; + enable = !!enable; + if (beep && beep->enabled != enable) { + beep->request_enable = enable; + schedule_work(&beep->register_work); + return 1; + } + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_enable_beep_device); + +int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) +{ + struct hda_beep *beep; + + if (!snd_hda_get_bool_hint(codec, "beep")) + return 0; /* disabled explicitly */ + beep = kzalloc(sizeof(*beep), GFP_KERNEL); + if (beep == NULL) + return -ENOMEM; + 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, AC_VERB_SET_DIGI_CONVERT_2, 0x01); beep->nid = nid; - beep->dev = input_dev; beep->codec = codec; - beep->enabled = 1; codec->beep = beep; + INIT_WORK(&beep->register_work, &snd_hda_do_register); INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); + mutex_init(&beep->mutex); + return 0; } EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); @@ -174,11 +226,11 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) { struct hda_beep *beep = codec->beep; if (beep) { - cancel_work_sync(&beep->beep_work); - - input_unregister_device(beep->dev); - kfree(beep); + cancel_work_sync(&beep->register_work); + if (beep->enabled) + snd_hda_do_detach(beep); codec->beep = NULL; + kfree(beep); } } EXPORT_SYMBOL_HDA(snd_hda_detach_beep_device); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 0c3de787c717..68465f679d8c 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -32,11 +32,15 @@ struct hda_beep { int tone; hda_nid_t nid; unsigned int enabled:1; + unsigned int request_enable:1; unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ + struct work_struct register_work; /* scheduled task for beep event */ struct work_struct beep_work; /* scheduled task for beep event */ + struct mutex mutex; }; #ifdef CONFIG_SND_HDA_INPUT_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); #else diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 444d9039c1ac..7fd2abe1129d 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -30,6 +30,7 @@ #include #include #include "hda_local.h" +#include "hda_beep.h" #include /* @@ -1734,6 +1735,17 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); +int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct hda_codec *codec = snd_kcontrol_chip(kcontrol); + long *valp = ucontrol->value.integer.value; + + snd_hda_enable_beep_device(codec, *valp); + return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); +} +EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); + /* * bound volume controls * diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index c1ca3182e6a4..3001794ad291 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -66,6 +66,19 @@ /* stereo mute switch */ #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) +/* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ +#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ + { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ + .info = snd_hda_mixer_amp_switch_info, \ + .get = snd_hda_mixer_amp_switch_get, \ + .put = snd_hda_mixer_amp_switch_put_beep, \ + .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } +/* special beep mono mute switch */ +#define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \ + HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction) +/* special beep stereo mute switch */ +#define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \ + HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction) int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); @@ -81,6 +94,8 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); /* lowlevel accessor with caching; use carefully */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2d603f6aba63..a0293614a0b9 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -159,7 +159,7 @@ static void ad198x_free_kctls(struct hda_codec *codec); /* additional beep mixers; the actual parameters are overwritten at build */ static struct snd_kcontrol_new ad_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_OUTPUT), + HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_OUTPUT), { } /* end */ }; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 49de107db16b..8c04e0e0f655 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2413,7 +2413,7 @@ static void alc_free_kctls(struct hda_codec *codec); /* additional beep mixers; the actual parameters are overwritten at build */ static struct snd_kcontrol_new alc_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), - HDA_CODEC_MUTE("Beep Playback Switch", 0, 0, HDA_INPUT), + HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), { } /* end */ }; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8d65d2b25234..87ba239ff1c9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2648,6 +2648,7 @@ static int stac92xx_clfe_switch_put(struct snd_kcontrol *kcontrol, 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, @@ -2658,6 +2659,7 @@ enum { static 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), @@ -3221,11 +3223,14 @@ static int stac92xx_auto_create_beep_ctls(struct hda_codec *codec, { struct sigmatel_spec *spec = codec->spec; u32 caps = query_amp_caps(codec, nid, HDA_OUTPUT); - int err; + 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, STAC_CTL_WIDGET_MUTE, + err = stac92xx_add_control(spec, type, "Beep Playback Switch", HDA_COMPOSE_AMP_VAL(nid, 1, 0, HDA_OUTPUT)); if (err < 0) @@ -3258,12 +3263,7 @@ 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); - int enabled = !!ucontrol->value.integer.value[0]; - if (codec->beep->enabled != enabled) { - codec->beep->enabled = enabled; - return 1; - } - return 0; + return snd_hda_enable_beep_device(codec, ucontrol->value.integer.value[0]); } static struct snd_kcontrol_new stac92xx_dig_beep_ctrl = { -- cgit v1.2.3 From 13dab0808bb41b18888e1758a060a685deee1f30 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Tue, 3 Nov 2009 14:29:50 +0100 Subject: ALSA: hda_intel: Digital PC Beep - delay input device unregistration The massive register/unregister calls for input device layer might be overkill. Delay unregister call by one HZ as workaround. Also, as benefit, beep->enabled variable is changed immediately now (not from workqueue). Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 42 +++++++++++++++++++++++++++--------------- sound/pci/hda/hda_beep.h | 3 ++- 2 files changed, 29 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 0e986537d570..74db40edb336 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -164,20 +164,21 @@ static void snd_hda_do_register(struct work_struct *work) { struct hda_beep *beep = container_of(work, struct hda_beep, register_work); - int request; mutex_lock(&beep->mutex); - request = beep->request_enable; - if (beep->enabled != request) { - if (!request) { - snd_hda_do_detach(beep); - } else { - if (snd_hda_do_attach(beep) < 0) - goto __out; - } - beep->enabled = request; - } - __out: + if (beep->enabled && !beep->dev) + snd_hda_do_attach(beep); + mutex_unlock(&beep->mutex); +} + +static void snd_hda_do_unregister(struct work_struct *work) +{ + struct hda_beep *beep = + container_of(work, struct hda_beep, unregister_work.work); + + mutex_lock(&beep->mutex); + if (!beep->enabled && beep->dev) + snd_hda_do_detach(beep); mutex_unlock(&beep->mutex); } @@ -185,9 +186,19 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) { struct hda_beep *beep = codec->beep; enable = !!enable; - if (beep && beep->enabled != enable) { - beep->request_enable = enable; - schedule_work(&beep->register_work); + if (beep == NULL) + return 0; + if (beep->enabled != enable) { + beep->enabled = enable; + if (enable) { + cancel_delayed_work(&beep->unregister_work); + schedule_work(&beep->register_work); + } else { + /* turn off beep */ + snd_hda_codec_write_cache(beep->codec, beep->nid, 0, + AC_VERB_SET_BEEP_CONTROL, 0); + schedule_delayed_work(&beep->unregister_work, HZ); + } return 1; } return 0; @@ -215,6 +226,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) codec->beep = beep; INIT_WORK(&beep->register_work, &snd_hda_do_register); + INIT_DELAYED_WORK(&beep->unregister_work, &snd_hda_do_unregister); INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); mutex_init(&beep->mutex); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 68465f679d8c..53eba8d8414d 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -34,7 +34,8 @@ struct hda_beep { unsigned int enabled:1; unsigned int request_enable:1; unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ - struct work_struct register_work; /* scheduled task for beep event */ + struct work_struct register_work; /* registration work */ + struct delayed_work unregister_work; /* unregistration work */ struct work_struct beep_work; /* scheduled task for beep event */ struct mutex mutex; }; -- cgit v1.2.3 From 5f81669750504b1e7e00acde5068d972af466f29 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 4 Nov 2009 12:46:49 +0100 Subject: ALSA: hda: beep - add missing cancel_delayed_work The unregister work should be also canceled in snd_hda_detach_beep_device() function. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 74db40edb336..c819152de79b 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -239,6 +239,7 @@ void snd_hda_detach_beep_device(struct hda_codec *codec) struct hda_beep *beep = codec->beep; if (beep) { cancel_work_sync(&beep->register_work); + cancel_delayed_work(&beep->unregister_work); if (beep->enabled) snd_hda_do_detach(beep); codec->beep = NULL; -- cgit v1.2.3 From 2dca0bba70ce3c233be152e384580c134935332d Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Fri, 13 Nov 2009 18:41:52 +0100 Subject: ALSA: hda - add beep_mode module parameter The beep_mode parameter for snd-hda-intel module allows to choose among different digital beep device registation to the input layer. 0 = do not register to the input layer 1 = register to the input layer all time 2 = use "Beep Switch" control exported to user space mixer applications Also, introduce CONFIG_SND_HDA_INPUT_BEEP_MODE for default value. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 11 +++++++++++ sound/pci/hda/hda_beep.c | 21 ++++++++++++++++----- sound/pci/hda/hda_beep.h | 5 +++++ sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_intel.c | 15 +++++++++++++++ 5 files changed, 48 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 55545e0818b5..25ae10e16f59 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -38,6 +38,17 @@ config SND_HDA_INPUT_BEEP Say Y here to build a digital beep interface for HD-audio driver. This interface is used to generate digital beeps. +config SND_HDA_INPUT_BEEP_MODE + int "Digital beep registration mode (0=off, 1=on, 2=mute sw on/off)" + depends on SND_HDA_INPUT_BEEP=y + default "1" + range 0 2 + help + Set 0 to disable the digital beep interface for HD-audio by default. + Set 1 to always enable the digital beep interface for HD-audio by + default. Set 2 to control the beep device registration to input + layer using a "Beep Switch" in mixer applications. + config SND_HDA_INPUT_JACK bool "Support jack plugging notification via input layer" depends on INPUT=y || INPUT=SND_HDA_INTEL diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index c819152de79b..9e48798b415b 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -190,14 +190,19 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable) return 0; if (beep->enabled != enable) { beep->enabled = enable; - if (enable) { - cancel_delayed_work(&beep->unregister_work); - schedule_work(&beep->register_work); - } else { + if (!enable) { /* turn off beep */ snd_hda_codec_write_cache(beep->codec, beep->nid, 0, AC_VERB_SET_BEEP_CONTROL, 0); - schedule_delayed_work(&beep->unregister_work, HZ); + } + if (beep->mode == HDA_BEEP_MODE_SWREG) { + if (enable) { + cancel_delayed_work(&beep->unregister_work); + schedule_work(&beep->register_work); + } else { + schedule_delayed_work(&beep->unregister_work, + HZ); + } } return 1; } @@ -223,6 +228,7 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) beep->nid = nid; beep->codec = codec; + beep->mode = codec->beep_mode; codec->beep = beep; INIT_WORK(&beep->register_work, &snd_hda_do_register); @@ -230,6 +236,11 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) INIT_WORK(&beep->beep_work, &snd_hda_generate_beep); mutex_init(&beep->mutex); + if (beep->mode == HDA_BEEP_MODE_ON) { + beep->enabled = 1; + snd_hda_do_register(&beep->register_work); + } + return 0; } EXPORT_SYMBOL_HDA(snd_hda_attach_beep_device); diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 53eba8d8414d..17dd1c325e32 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -24,10 +24,15 @@ #include "hda_codec.h" +#define HDA_BEEP_MODE_ON 0 +#define HDA_BEEP_MODE_OFF 1 +#define HDA_BEEP_MODE_SWREG 2 + /* beep information */ struct hda_beep { struct input_dev *dev; struct hda_codec *codec; + unsigned int mode; char phys[32]; int tone; hda_nid_t nid; diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index b16678cade18..51920563bc7f 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -772,6 +772,7 @@ struct hda_codec { /* beep device */ struct hda_beep *beep; + unsigned int beep_mode; /* widget capabilities cache */ unsigned int num_nodes; diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e73e395e7601..91bcbdad5af5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -64,6 +64,10 @@ static int enable_msi = -1; #ifdef CONFIG_SND_HDA_PATCH_LOADER static char *patch[SNDRV_CARDS]; #endif +#ifdef CONFIG_SND_HDA_INPUT_BEEP +static int beep_mode[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS-1)] = + CONFIG_SND_HDA_INPUT_BEEP_MODE}; +#endif module_param_array(index, int, NULL, 0444); MODULE_PARM_DESC(index, "Index value for Intel HD audio interface."); @@ -91,6 +95,11 @@ MODULE_PARM_DESC(enable_msi, "Enable Message Signaled Interrupt (MSI)"); module_param_array(patch, charp, NULL, 0444); MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface."); #endif +#ifdef CONFIG_SND_HDA_INPUT_BEEP +module_param_array(beep_mode, int, NULL, 0444); +MODULE_PARM_DESC(beep_mode, "Select HDA Beep registration mode " + "(0=off, 1=on, 2=mute switch on/off) (default=1)."); +#endif #ifdef CONFIG_SND_HDA_POWER_SAVE static int power_save = CONFIG_SND_HDA_POWER_SAVE_DEFAULT; @@ -404,6 +413,7 @@ struct azx { 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; @@ -1404,6 +1414,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) err = snd_hda_codec_new(chip->bus, c, &codec); if (err < 0) continue; + codec->beep_mode = chip->beep_mode; codecs++; } } @@ -2579,6 +2590,10 @@ static int __devinit azx_probe(struct pci_dev *pci, goto out_free; card->private_data = chip; +#ifdef CONFIG_SND_HDA_INPUT_BEEP + chip->beep_mode = beep_mode[dev]; +#endif + /* create codec instances */ err = azx_codec_create(chip, model[dev]); if (err < 0) -- cgit v1.2.3 From 3911a4c19e927738766003839aa447becbdbaa27 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 11 Nov 2009 13:43:01 +0100 Subject: ALSA: hda - proc - introduce Control: lines to show mixer<->NID assignment This is an initial patch to show universal control<->NID assigment in proc codec file. The change helps to debug codec related problems. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 32 ++++++++++++------------ sound/pci/hda/hda_generic.c | 17 ++++++++----- sound/pci/hda/hda_local.h | 11 +++++++-- sound/pci/hda/hda_proc.c | 55 ++++++++++++++++++++++++++++++------------ sound/pci/hda/patch_analog.c | 4 ++- sound/pci/hda/patch_ca0110.c | 4 +-- sound/pci/hda/patch_cirrus.c | 12 ++++----- sound/pci/hda/patch_realtek.c | 3 ++- sound/pci/hda/patch_sigmatel.c | 4 +-- 9 files changed, 92 insertions(+), 50 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 7fd2abe1129d..1ed1d88e1834 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -946,7 +946,7 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr mutex_init(&codec->control_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); - snd_array_init(&codec->mixers, sizeof(struct snd_kcontrol *), 32); + snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); if (codec->bus->modelname) { @@ -1517,18 +1517,20 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); /* Add a control element and assign to the codec */ -int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl) +int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, + struct snd_kcontrol *kctl) { int err; - struct snd_kcontrol **knewp; + struct hda_nid_item *item; err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; - knewp = snd_array_new(&codec->mixers); - if (!knewp) + item = snd_array_new(&codec->mixers); + if (!item) return -ENOMEM; - *knewp = kctl; + item->kctl = kctl; + item->nid = nid; return 0; } EXPORT_SYMBOL_HDA(snd_hda_ctl_add); @@ -1537,9 +1539,9 @@ EXPORT_SYMBOL_HDA(snd_hda_ctl_add); void snd_hda_ctls_clear(struct hda_codec *codec) { int i; - struct snd_kcontrol **kctls = codec->mixers.list; + struct hda_nid_item *items = codec->mixers.list; for (i = 0; i < codec->mixers.used; i++) - snd_ctl_remove(codec->bus->card, kctls[i]); + snd_ctl_remove(codec->bus->card, items[i].kctl); snd_array_free(&codec->mixers); } @@ -1645,7 +1647,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, kctl = snd_ctl_make_virtual_master(name, tlv); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; @@ -2139,7 +2141,7 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, hda_nid_t nid) return -ENOMEM; kctl->id.index = idx; kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } @@ -2184,8 +2186,8 @@ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, if (!mout->dig_out_nid) return 0; /* ATTENTION: here mout is passed as private_data, instead of codec */ - return snd_hda_ctl_add(codec, - snd_ctl_new1(&spdif_share_sw, mout)); + return snd_hda_ctl_add(codec, mout->dig_out_nid, + snd_ctl_new1(&spdif_share_sw, mout)); } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_share_sw); @@ -2289,7 +2291,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) if (!kctl) return -ENOMEM; kctl->private_value = nid; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, nid, kctl); if (err < 0) return err; } @@ -3165,7 +3167,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) kctl = snd_ctl_new1(knew, codec); if (!kctl) return -ENOMEM; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) { if (!codec->addr) return err; @@ -3173,7 +3175,7 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) if (!kctl) return -ENOMEM; kctl->id.device = codec->addr; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index b36f6c5a92df..092c6a7c2ff3 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c @@ -727,7 +727,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, 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, snd_ctl_new1(&knew, codec)); + err = snd_hda_ctl_add(codec, node->nid, + snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; @@ -737,7 +738,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, 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, snd_ctl_new1(&knew, codec)); + err = snd_hda_ctl_add(codec, node->nid, + snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; @@ -751,7 +753,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (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, snd_ctl_new1(&knew, codec)); + err = snd_hda_ctl_add(codec, node->nid, + snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; @@ -759,7 +762,8 @@ static int create_mixer(struct hda_codec *codec, struct hda_gnode *node, (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, snd_ctl_new1(&knew, codec)); + err = snd_hda_ctl_add(codec, node->nid, + snd_ctl_new1(&knew, codec)); if (err < 0) return err; created = 1; @@ -857,7 +861,7 @@ static int build_input_controls(struct hda_codec *codec) } /* create input MUX if multiple sources are available */ - err = snd_hda_ctl_add(codec, snd_ctl_new1(&cap_sel, codec)); + err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec)); if (err < 0) return err; @@ -875,7 +879,8 @@ static int build_input_controls(struct hda_codec *codec) HDA_CODEC_VOLUME(name, adc_node->nid, spec->input_mux.items[i].index, HDA_INPUT); - err = snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); + err = snd_hda_ctl_add(codec, adc_node->nid, + snd_ctl_new1(&knew, codec)); if (err < 0) return err; } diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 3001794ad291..e6a0918f70d3 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -440,7 +440,13 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps); u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); -int snd_hda_ctl_add(struct hda_codec *codec, struct snd_kcontrol *kctl); +struct hda_nid_item { + struct snd_kcontrol *kctl; + hda_nid_t nid; +}; + +int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, + struct snd_kcontrol *kctl); void snd_hda_ctls_clear(struct hda_codec *codec); /* @@ -514,7 +520,8 @@ int snd_hda_check_amp_list_power(struct hda_codec *codec, * AMP control callbacks */ /* retrieve parameters from private_value */ -#define get_amp_nid(kc) ((kc)->private_value & 0xffff) +#define get_amp_nid_(pv) ((pv) & 0xffff) +#define get_amp_nid(kc) get_amp_nid_((kc)->private_value) #define get_amp_channels(kc) (((kc)->private_value >> 16) & 0x3) #define get_amp_direction(kc) (((kc)->private_value >> 18) & 0x1) #define get_amp_index(kc) (((kc)->private_value >> 19) & 0xf) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f5b783ce450d..f465cff28041 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -46,6 +46,41 @@ static const char *get_wid_type_name(unsigned int wid_value) return "UNKNOWN Widget"; } +static void print_nid_mixers(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int i; + struct hda_nid_item *items = codec->mixers.list; + struct snd_kcontrol *kctl; + for (i = 0; i < codec->mixers.used; i++) { + if (items[i].nid == nid) { + kctl = items[i].kctl; + snd_iprintf(buffer, + " Control: name=\"%s\", index=%i, device=%i\n", + kctl->id.name, kctl->id.index, kctl->id.device); + } + } +} + +static void print_nid_pcms(struct snd_info_buffer *buffer, + struct hda_codec *codec, hda_nid_t nid) +{ + int pcm, type; + struct hda_pcm *cpcm; + for (pcm = 0; pcm < codec->num_pcms; pcm++) { + cpcm = &codec->pcm_info[pcm]; + for (type = 0; type < 2; type++) { + if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) + continue; + snd_iprintf(buffer, " Device: name=\"%s\", " + "type=\"%s\", device=%i\n", + cpcm->name, + snd_hda_pcm_type_name[cpcm->pcm_type], + cpcm->pcm->device); + } + } +} + static void print_amp_caps(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, int dir) { @@ -309,21 +344,7 @@ static void print_audio_io(struct snd_info_buffer *buffer, struct hda_codec *codec, hda_nid_t nid, unsigned int wid_type) { - int pcm, conv; - for (pcm = 0; pcm < codec->num_pcms; pcm++) { - int type; - struct hda_pcm *cpcm = &codec->pcm_info[pcm]; - for (type = 0; type < 2; type++) { - if (cpcm->stream[type].nid != nid || cpcm->pcm == NULL) - continue; - snd_iprintf(buffer, " Device: name=\"%s\", " - "type=\"%s\", device=%i\n", - cpcm->name, - snd_hda_pcm_type_name[cpcm->pcm_type], - cpcm->pcm->device); - } - } - conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); + int conv = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0); snd_iprintf(buffer, " Converter: stream=%d, channel=%d\n", (conv & AC_CONV_STREAM) >> AC_CONV_STREAM_SHIFT, @@ -471,6 +492,7 @@ static void print_gpio(struct snd_info_buffer *buffer, (data & (1<private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, + get_amp_nid_(spec->beep_amp), + kctl); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c index d08353d3bb7f..af478019088e 100644 --- a/sound/pci/hda/patch_ca0110.c +++ b/sound/pci/hda/patch_ca0110.c @@ -144,7 +144,7 @@ static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, 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, snd_ctl_new1(&knew, codec)); + 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, @@ -155,7 +155,7 @@ static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, 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, snd_ctl_new1(&knew, codec)); + 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) diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 8ba306856d38..9ac09e4568b3 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -500,7 +500,7 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, knew.private_value = pval; snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); - return snd_hda_ctl_add(codec, *kctlp); + return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); } static int add_volume(struct hda_codec *codec, const char *name, @@ -513,7 +513,7 @@ static int add_volume(struct hda_codec *codec, const char *name, knew.private_value = pval; snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); *kctlp = snd_ctl_new1(&knew, codec); - return snd_hda_ctl_add(codec, *kctlp); + return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); } static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) @@ -536,14 +536,14 @@ static int add_vmaster(struct hda_codec *codec, hda_nid_t dac) spec->vmaster_sw = snd_ctl_make_virtual_master("Master Playback Switch", NULL); - err = snd_hda_ctl_add(codec, spec->vmaster_sw); + 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, spec->vmaster_vol); + err = snd_hda_ctl_add(codec, dac, spec->vmaster_vol); if (err < 0) return err; return 0; @@ -756,13 +756,13 @@ static int build_input(struct hda_codec *codec) if (!kctl) return -ENOMEM; kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; } if (spec->num_inputs > 1 && !spec->mic_detect) { - err = snd_hda_ctl_add(codec, + err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cs_capture_source, codec)); if (err < 0) return err; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8c04e0e0f655..fff9de245646 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2461,7 +2461,8 @@ static int alc_build_controls(struct hda_codec *codec) if (!kctl) return -ENOMEM; kctl->private_value = spec->beep_amp; - err = snd_hda_ctl_add(codec, kctl); + err = snd_hda_ctl_add(codec, + get_amp_nid_(spec->beep_amp), kctl); if (err < 0) return err; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 87ba239ff1c9..a3872b90d6ed 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1085,7 +1085,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) 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, + err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&stac_dmux_mixer, codec)); if (err < 0) return err; @@ -1101,7 +1101,7 @@ static int stac92xx_build_controls(struct hda_codec *codec) spec->spdif_mute = 1; } stac_smux_mixer.count = spec->num_smuxes; - err = snd_hda_ctl_add(codec, + err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&stac_smux_mixer, codec)); if (err < 0) return err; -- cgit v1.2.3 From 4d02d1b638af580ae3d69367248539a8b3893064 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 12 Nov 2009 10:15:48 +0100 Subject: ALSA: hda - proc - add support for dynamic controls to mixer<->NID mapping This patch adds support for dynamically created controls to proc codec file (Control: lines). Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 7 ++++++- sound/pci/hda/hda_local.h | 3 +++ sound/pci/hda/patch_analog.c | 2 ++ sound/pci/hda/patch_realtek.c | 2 ++ sound/pci/hda/patch_sigmatel.c | 10 +++++++--- sound/pci/hda/patch_via.c | 2 ++ 6 files changed, 22 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 1ed1d88e1834..d71e651046eb 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1523,6 +1523,11 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, int err; struct hda_nid_item *item; + if (kctl->id.subdevice & (1<<31)) { + if (nid == 0) + nid = kctl->id.subdevice & 0xffff; + kctl->id.subdevice = 0; + } err = snd_ctl_add(codec->bus->card, kctl); if (err < 0) return err; @@ -3160,7 +3165,7 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_codec_sid_config); */ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) { - int err; + int err; for (; knew->name; knew++) { struct snd_kcontrol *kctl; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index e6a0918f70d3..3bfcf42ff6cf 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -33,6 +33,7 @@ /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ + .subdevice = (1<<31)|(nid), \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ @@ -53,6 +54,7 @@ /* mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ + .subdevice = (1<<31)|(nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put, \ @@ -69,6 +71,7 @@ /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ + .subdevice = (1<<31)|(nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put_beep, \ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index ef3383912b6e..2d345606265b 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2571,6 +2571,8 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, knew->name = kstrdup(name, GFP_KERNEL); if (! knew->name) return -ENOMEM; + if (get_amp_nid_(val)) + knew->subdevice = (1<<31)|get_amp_nid_(val); knew->private_value = val; return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index fff9de245646..c0a98e724a25 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4323,6 +4323,8 @@ static int add_control(struct alc_spec *spec, int type, const char *name, knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; + if (get_amp_nid_(val)) + knew->subdevice = (1<<31)|get_amp_nid_(val); knew->private_value = val; return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index a3872b90d6ed..d2ddb959c290 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2671,7 +2671,8 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { static struct snd_kcontrol_new * stac_control_new(struct sigmatel_spec *spec, struct snd_kcontrol_new *ktemp, - const char *name) + const char *name, + hda_nid_t nid) { struct snd_kcontrol_new *knew; @@ -2687,6 +2688,8 @@ stac_control_new(struct sigmatel_spec *spec, spec->kctls.alloced--; return NULL; } + if (nid) + knew->subdevice = (1<<31)|nid; return knew; } @@ -2695,7 +2698,8 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, int idx, const char *name, unsigned long val) { - struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name); + struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, + get_amp_nid_(val)); if (!knew) return -ENOMEM; knew->index = idx; @@ -2766,7 +2770,7 @@ static int stac92xx_add_input_source(struct sigmatel_spec *spec) 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); + stac_input_src_temp.name, 0); if (!knew) return -ENOMEM; knew->count = spec->num_adcs; diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 5a856009c916..14219d898b2e 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -442,6 +442,8 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, knew->name = kstrdup(name, GFP_KERNEL); if (!knew->name) return -ENOMEM; + if (get_amp_nid_(val)) + knew->subdevice = (1<<31)|get_amp_nid_(val); knew->private_value = val; return 0; } -- cgit v1.2.3 From 9c96fa599fe4f0ccc6e3e606df6652335afe28e8 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Nov 2009 11:25:33 +0100 Subject: ALSA: hda - Get rid of magic digits for subdev hack Define a proper const for a magic 31bit flag for subdev / NID setup with a brief comment. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 +- sound/pci/hda/hda_local.h | 15 ++++++++++++--- sound/pci/hda/patch_analog.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/hda/patch_sigmatel.c | 2 +- sound/pci/hda/patch_via.c | 2 +- 6 files changed, 17 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index d71e651046eb..5e21b35207ab 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1523,7 +1523,7 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, int err; struct hda_nid_item *item; - if (kctl->id.subdevice & (1<<31)) { + if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { if (nid == 0) nid = kctl->id.subdevice & 0xffff; kctl->id.subdevice = 0; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 3bfcf42ff6cf..4e77f4747291 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -23,6 +23,15 @@ #ifndef __SOUND_HDA_LOCAL_H #define __SOUND_HDA_LOCAL_H +/* We abuse kcontrol_new.subdev field to pass the NID corresponding to + * the given new control. If id.subdev has a bit flag HDA_SUBDEV_NID_FLAG, + * snd_hda_ctl_add() takes the lower-bit subdev value as a valid NID. + * + * Note that the subdevice field is cleared again before the real registration + * in snd_hda_ctl_add(), so that this value won't appear in the outside. + */ +#define HDA_SUBDEV_NID_FLAG (1U << 31) + /* * for mixer controls */ @@ -33,7 +42,7 @@ /* mono volume with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = (1<<31)|(nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ @@ -54,7 +63,7 @@ /* mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = (1<<31)|(nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put, \ @@ -71,7 +80,7 @@ /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ - .subdevice = (1<<31)|(nid), \ + .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ .info = snd_hda_mixer_amp_switch_info, \ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put_beep, \ diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 2d345606265b..ceb0c603da04 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -2572,7 +2572,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, if (! knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = (1<<31)|get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); knew->private_value = val; return 0; } diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c0a98e724a25..eee3143eef75 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -4324,7 +4324,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = (1<<31)|get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); knew->private_value = val; return 0; } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d2ddb959c290..7f76a97954f9 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2689,7 +2689,7 @@ stac_control_new(struct sigmatel_spec *spec, return NULL; } if (nid) - knew->subdevice = (1<<31)|nid; + knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; return knew; } diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 14219d898b2e..0c621d74b165 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -443,7 +443,7 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, if (!knew->name) return -ENOMEM; if (get_amp_nid_(val)) - knew->subdevice = (1<<31)|get_amp_nid_(val); + knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); knew->private_value = val; return 0; } -- cgit v1.2.3 From 85dd662ff4d2967084acfc761a33717383297e42 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 11 Nov 2009 13:49:07 +0100 Subject: ALSA: hda - move snd_hda_pcm_type_name from hda_codec.h to hda_local.h The snd_hda_pcm_type_name array is local only. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 1 - sound/pci/hda/hda_local.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 51920563bc7f..be6c5f443cd9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -898,7 +898,6 @@ int snd_hda_codec_build_controls(struct hda_codec *codec); /* * PCM */ -extern const char *snd_hda_pcm_type_name[]; int snd_hda_build_pcms(struct hda_bus *bus); int snd_hda_codec_build_pcms(struct hda_codec *codec); void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 4e77f4747291..7c049839ea26 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -92,6 +92,8 @@ #define HDA_CODEC_MUTE_BEEP(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_BEEP_MONO(xname, nid, 3, xindex, direction) +extern const char *snd_hda_pcm_type_name[]; + int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo); int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, -- cgit v1.2.3 From d5191e50b251594bdde10d4839a952ff1646ef62 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Nov 2009 14:58:17 +0100 Subject: ALSA: hda - Update / add kerneldoc comments to exported functions Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 432 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 391 insertions(+), 41 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5e21b35207ab..e344235da491 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -94,6 +94,13 @@ static void hda_keep_power_on(struct hda_codec *codec); static inline void hda_keep_power_on(struct hda_codec *codec) {} #endif +/** + * snd_hda_get_jack_location - Give a location string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack location, e.g. "Rear", "Front", etc. + */ const char *snd_hda_get_jack_location(u32 cfg) { static char *bases[7] = { @@ -121,6 +128,13 @@ const char *snd_hda_get_jack_location(u32 cfg) } EXPORT_SYMBOL_HDA(snd_hda_get_jack_location); +/** + * snd_hda_get_jack_connectivity - Give a connectivity string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack connectivity, i.e. external or internal connection. + */ const char *snd_hda_get_jack_connectivity(u32 cfg) { static char *jack_locations[4] = { "Ext", "Int", "Sep", "Oth" }; @@ -129,6 +143,13 @@ const char *snd_hda_get_jack_connectivity(u32 cfg) } EXPORT_SYMBOL_HDA(snd_hda_get_jack_connectivity); +/** + * snd_hda_get_jack_type - Give a type string of the jack + * @cfg: pin default config value + * + * Parse the pin default config value and returns the string of the + * jack type, i.e. the purpose of the jack, such as Line-Out or CD. + */ const char *snd_hda_get_jack_type(u32 cfg) { static char *jack_types[16] = { @@ -822,6 +843,16 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, return 0; } +/** + * snd_hda_codec_set_pincfg - Override a pin default configuration + * @codec: the HDA codec + * @nid: NID to set the pin config + * @cfg: the pin default config value + * + * Override a pin default configuration value in the cache. + * This value can be read by snd_hda_codec_get_pincfg() in a higher + * priority than the real hardware value. + */ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, unsigned int cfg) { @@ -829,7 +860,15 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_codec_set_pincfg); -/* get the current pin config value of the given pin NID */ +/** + * snd_hda_codec_get_pincfg - Obtain a pin-default configuration + * @codec: the HDA codec + * @nid: NID to get the pin config + * + * Get the current pin config value of the given pin NID. + * If the pincfg value is cached or overridden via sysfs or driver, + * returns the cached value. + */ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid) { struct hda_pincfg *pin; @@ -1028,6 +1067,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr } EXPORT_SYMBOL_HDA(snd_hda_codec_new); +/** + * snd_hda_codec_configure - (Re-)configure the HD-audio codec + * @codec: the HDA codec + * + * Start parsing of the given codec tree and (re-)initialize the whole + * patch instance. + * + * Returns 0 if successful or a negative error code. + */ int snd_hda_codec_configure(struct hda_codec *codec) { int err; @@ -1090,6 +1138,11 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_setup_stream); +/** + * snd_hda_codec_cleanup_stream - clean up the codec for closing + * @codec: the CODEC to clean up + * @nid: the NID to clean up + */ void snd_hda_codec_cleanup_stream(struct hda_codec *codec, hda_nid_t nid) { if (!nid) @@ -1165,8 +1218,17 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key) return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); } -/* - * query AMP capabilities for the given widget and direction +/** + * query_amp_caps - query AMP capabilities + * @codec: the HD-auio codec + * @nid: the NID to query + * @direction: either #HDA_INPUT or #HDA_OUTPUT + * + * Query AMP capabilities for the given widget and direction. + * Returns the obtained capability bits. + * + * When cap bits have been already read, this doesn't read again but + * returns the cached value. */ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) { @@ -1189,6 +1251,19 @@ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) } EXPORT_SYMBOL_HDA(query_amp_caps); +/** + * snd_hda_override_amp_caps - Override the AMP capabilities + * @codec: the CODEC to clean up + * @nid: the NID to clean up + * @direction: either #HDA_INPUT or #HDA_OUTPUT + * @caps: the capability bits to set + * + * Override the cached AMP caps bits value by the given one. + * This function is useful if the driver needs to adjust the AMP ranges, + * e.g. limit to 0dB, etc. + * + * Returns zero if successful or a negative error code. + */ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) { @@ -1224,6 +1299,17 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); } +/** + * snd_hda_query_pin_caps - Query PIN capabilities + * @codec: the HD-auio codec + * @nid: the NID to query + * + * Query PIN capabilities for the given widget. + * Returns the obtained capability bits. + * + * When cap bits have been already read, this doesn't read again but + * returns the cached value. + */ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) { return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), @@ -1271,8 +1357,15 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, info->vol[ch] = val; } -/* - * read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. +/** + * snd_hda_codec_amp_read - Read 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 + * @index: the index value (only for input direction) + * + * Read AMP value. The volume is between 0 to 0x7f, 0x80 = mute bit. */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) @@ -1285,8 +1378,18 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); -/* - * update the AMP value, mask = bit mask to set, val = the value +/** + * 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) @@ -1305,8 +1408,17 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_update); -/* - * update the AMP stereo with the same mask and value +/** + * snd_hda_codec_amp_stereo - update the AMP stereo values + * @codec: HD-audio codec + * @nid: NID to read the AMP value + * @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 values like snd_hda_codec_amp_update(), but for a + * stereo widget with the same mask and value. */ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int direction, int idx, int mask, int val) @@ -1320,7 +1432,12 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); #ifdef SND_HDA_NEEDS_RESUME -/* resume the all amp commands from the cache */ +/** + * snd_hda_codec_resume_amp - Resume all AMP commands from the cache + * @codec: HD-audio codec + * + * Resume the all amp commands from the cache. + */ void snd_hda_codec_resume_amp(struct hda_codec *codec) { struct hda_amp_info *buffer = codec->amp_cache.buf.list; @@ -1346,7 +1463,12 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); #endif /* SND_HDA_NEEDS_RESUME */ -/* volume */ +/** + * snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1402,6 +1524,12 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid, HDA_AMP_VOLMASK, val); } +/** + * snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1421,6 +1549,12 @@ int snd_hda_mixer_amp_volume_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_get); +/** + * snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1445,6 +1579,12 @@ int snd_hda_mixer_amp_volume_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_volume_put); +/** + * snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { @@ -1474,8 +1614,16 @@ int snd_hda_mixer_amp_tlv(struct snd_kcontrol *kcontrol, int op_flag, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_tlv); -/* - * set (static) TLV for virtual master volume; recalculated as max 0dB +/** + * snd_hda_set_vmaster_tlv - Set TLV for a virtual master control + * @codec: HD-audio codec + * @nid: NID of a reference widget + * @dir: #HDA_INPUT or #HDA_OUTPUT + * @tlv: TLV data to be stored, at least 4 elements + * + * Set (static) TLV data for a virtual master volume using the AMP caps + * obtained from the reference NID. + * The volume range is recalculated as if the max volume is 0dB. */ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int *tlv) @@ -1509,6 +1657,13 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, return snd_ctl_find_id(codec->bus->card, &id); } +/** + * snd_hda_find_mixer_ctl - Find a mixer control element with the given name + * @codec: HD-audio codec + * @name: ctl id name string + * + * Get the control element with the given id string and IFACE_MIXER. + */ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, const char *name) { @@ -1516,7 +1671,24 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); -/* Add a control element and assign to the codec */ +/** + * snd_hda_ctl-add - Add a control element and assign to the codec + * @codec: HD-audio codec + * @nid: corresponding NID (optional) + * @kctl: the control element to assign + * + * Add the given control element to an array inside the codec instance. + * All control elements belonging to a codec are supposed to be added + * by this function so that a proper clean-up works at the free or + * reconfiguration time. + * + * If non-zero @nid is passed, the NID is assigned to the control element. + * The assignment is shown in the codec proc file. + * + * snd_hda_ctl_add() checks the control subdev id field whether + * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower + * bits value is taken as the NID to assign. + */ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, struct snd_kcontrol *kctl) { @@ -1540,7 +1712,10 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_ctl_add); -/* Clear all controls assigned to the given codec */ +/** + * snd_hda_ctls_clear - Clear all controls assigned to the given codec + * @codec: HD-audio codec + */ void snd_hda_ctls_clear(struct hda_codec *codec) { int i; @@ -1572,6 +1747,16 @@ static void hda_unlock_devices(struct snd_card *card) spin_unlock(&card->files_lock); } +/** + * snd_hda_codec_reset - Clear all objects assigned to the codec + * @codec: HD-audio codec + * + * This frees the all PCM and control elements assigned to the codec, and + * clears the caches and restores the pin default configurations. + * + * When a device is being used, it returns -EBSY. If successfully freed, + * returns zero. + */ int snd_hda_codec_reset(struct hda_codec *codec) { struct snd_card *card = codec->bus->card; @@ -1635,7 +1820,22 @@ int snd_hda_codec_reset(struct hda_codec *codec) return 0; } -/* create a virtual master control and add slaves */ +/** + * snd_hda_add_vmaster - create a virtual master control and add slaves + * @codec: HD-audio codec + * @name: vmaster control name + * @tlv: TLV data (optional) + * @slaves: slave control names (optional) + * + * Create a virtual master control with the given name. The TLV data + * must be either NULL or a valid data. + * + * @slaves is a NULL-terminated array of strings, each of which is a + * slave control name. All controls with these names are assigned to + * the new virtual master control. + * + * This function returns zero if successful or a negative error code. + */ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, unsigned int *tlv, const char **slaves) { @@ -1677,7 +1877,12 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, } EXPORT_SYMBOL_HDA(snd_hda_add_vmaster); -/* switch */ +/** + * snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { @@ -1691,6 +1896,12 @@ int snd_hda_mixer_amp_switch_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_info); +/** + * snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1711,6 +1922,12 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_get); +/** + * snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch + * + * The control element is supposed to have the private_value field + * set up via HDA_COMPOSE_AMP_VAL*() or related macros. + */ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1742,6 +1959,12 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); +/** + * snd_hda_mixer_amp_switch_put_beep - Put callback for a beep AMP switch + * + * This function calls snd_hda_enable_beep_device(), which behaves differently + * depending on beep_mode option. + */ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1762,6 +1985,12 @@ EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); #define AMP_VAL_IDX_SHIFT 19 #define AMP_VAL_IDX_MASK (0x0f<<19) +/** + * snd_hda_mixer_bind_switch_get - Get callback for a bound volume control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_MUTE*() macros. + */ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1779,6 +2008,12 @@ int snd_hda_mixer_bind_switch_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_get); +/** + * snd_hda_mixer_bind_switch_put - Put callback for a bound volume control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_MUTE*() macros. + */ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1803,8 +2038,11 @@ int snd_hda_mixer_bind_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_switch_put); -/* - * generic bound volume/swtich controls +/** + * snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. */ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) @@ -1823,6 +2061,12 @@ int snd_hda_mixer_bind_ctls_info(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_info); +/** + * snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. + */ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1840,6 +2084,12 @@ int snd_hda_mixer_bind_ctls_get(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_get); +/** + * snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() or HDA_BIND_SW() macros. + */ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -1863,6 +2113,12 @@ int snd_hda_mixer_bind_ctls_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_bind_ctls_put); +/** + * snd_hda_mixer_bind_tlv - TLV callback for a generic bound control + * + * The control element is supposed to have the private_value field + * set up via HDA_BIND_VOL() macro. + */ int snd_hda_mixer_bind_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *tlv) { @@ -2185,6 +2441,11 @@ static struct snd_kcontrol_new spdif_share_sw = { .put = spdif_share_sw_put, }; +/** + * snd_hda_create_spdif_share_sw - create Default PCM switch + * @codec: the HDA codec + * @mout: multi-out instance + */ int snd_hda_create_spdif_share_sw(struct hda_codec *codec, struct hda_multi_out *mout) { @@ -2352,7 +2613,12 @@ int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); -/* resume the all commands from the cache */ +/** + * snd_hda_codec_resume_cache - Resume the all commands from the cache + * @codec: HD-audio codec + * + * Execute all verbs recorded in the command caches to resume. + */ void snd_hda_codec_resume_cache(struct hda_codec *codec) { struct hda_cache_head *buffer = codec->cmd_cache.buf.list; @@ -2778,8 +3044,12 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, } /** - * snd_hda_is_supported_format - check whether the given node supports - * the format val + * snd_hda_is_supported_format - Check the validity of the format + * @codec: HD-audio codec + * @nid: NID to check + * @format: the HD-audio format value to check + * + * Check whether the given node supports the format value. * * Returns 1 if supported, 0 if not. */ @@ -2899,6 +3169,7 @@ static int set_pcm_default_values(struct hda_codec *codec, return 0; } +/* global */ const char *snd_hda_pcm_type_name[HDA_PCM_NTYPES] = { "Audio", "SPDIF", "HDMI", "Modem" }; @@ -3216,6 +3487,7 @@ static void hda_keep_power_on(struct hda_codec *codec) codec->power_jiffies = jiffies; } +/* update the power on/off account with the current jiffies */ void snd_hda_update_power_acct(struct hda_codec *codec) { unsigned long delta = jiffies - codec->power_jiffies; @@ -3226,6 +3498,13 @@ void snd_hda_update_power_acct(struct hda_codec *codec) codec->power_jiffies += delta; } +/** + * snd_hda_power_up - Power-up the codec + * @codec: HD-audio codec + * + * Increment the power-up counter and power up the hardware really when + * not turned on yet. + */ void snd_hda_power_up(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; @@ -3248,9 +3527,13 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up); #define power_save(codec) \ ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) -#define power_save(codec) \ - ((codec)->bus->power_save ? *(codec)->bus->power_save : 0) - +/** + * snd_hda_power_down - Power-down the codec + * @codec: HD-audio codec + * + * Decrement the power-up counter and schedules the power-off work if + * the counter rearches to zero. + */ void snd_hda_power_down(struct hda_codec *codec) { --codec->power_count; @@ -3264,6 +3547,19 @@ void snd_hda_power_down(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_power_down); +/** + * snd_hda_check_amp_list_power - Check the amp list and update the power + * @codec: HD-audio codec + * @check: the object containing an AMP list and the status + * @nid: NID to check / update + * + * Check whether the given NID is in the amp list. If it's in the list, + * check the current AMP status, and update the the power-status according + * to the mute status. + * + * This function is supposed to be set or called from the check_power_status + * patch ops. + */ int snd_hda_check_amp_list_power(struct hda_codec *codec, struct hda_loopback_check *check, hda_nid_t nid) @@ -3305,6 +3601,10 @@ EXPORT_SYMBOL_HDA(snd_hda_check_amp_list_power); /* * Channel mode helper */ + +/** + * snd_hda_ch_mode_info - Info callback helper for the channel mode enum + */ int snd_hda_ch_mode_info(struct hda_codec *codec, struct snd_ctl_elem_info *uinfo, const struct hda_channel_mode *chmode, @@ -3321,6 +3621,9 @@ int snd_hda_ch_mode_info(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_ch_mode_info); +/** + * snd_hda_ch_mode_get - Get callback helper for the channel mode enum + */ int snd_hda_ch_mode_get(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, const struct hda_channel_mode *chmode, @@ -3339,6 +3642,9 @@ int snd_hda_ch_mode_get(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_ch_mode_get); +/** + * snd_hda_ch_mode_put - Put callback helper for the channel mode enum + */ int snd_hda_ch_mode_put(struct hda_codec *codec, struct snd_ctl_elem_value *ucontrol, const struct hda_channel_mode *chmode, @@ -3363,6 +3669,10 @@ EXPORT_SYMBOL_HDA(snd_hda_ch_mode_put); /* * input MUX helper */ + +/** + * snd_hda_input_mux_info_info - Info callback helper for the input-mux enum + */ int snd_hda_input_mux_info(const struct hda_input_mux *imux, struct snd_ctl_elem_info *uinfo) { @@ -3381,6 +3691,9 @@ int snd_hda_input_mux_info(const struct hda_input_mux *imux, } EXPORT_SYMBOL_HDA(snd_hda_input_mux_info); +/** + * snd_hda_input_mux_info_put - Put callback helper for the input-mux enum + */ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, @@ -3440,7 +3753,10 @@ static void cleanup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid) } } -/* call each reboot notifier */ +/** + * snd_hda_bus_reboot_notify - call the reboot notifier of each codec + * @bus: HD-audio bus + */ void snd_hda_bus_reboot_notify(struct hda_bus *bus) { struct hda_codec *codec; @@ -3458,8 +3774,8 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus) } EXPORT_SYMBOL_HDA(snd_hda_bus_reboot_notify); -/* - * open the digital out in the exclusive mode +/** + * snd_hda_multi_out_dig_open - open the digital out in the exclusive mode */ int snd_hda_multi_out_dig_open(struct hda_codec *codec, struct hda_multi_out *mout) @@ -3474,6 +3790,9 @@ int snd_hda_multi_out_dig_open(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_open); +/** + * snd_hda_multi_out_dig_prepare - prepare the digital out stream + */ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, struct hda_multi_out *mout, unsigned int stream_tag, @@ -3487,6 +3806,9 @@ int snd_hda_multi_out_dig_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_prepare); +/** + * snd_hda_multi_out_dig_cleanup - clean-up the digital out stream + */ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) { @@ -3497,8 +3819,8 @@ int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_cleanup); -/* - * release the digital out +/** + * snd_hda_multi_out_dig_close - release the digital out stream */ int snd_hda_multi_out_dig_close(struct hda_codec *codec, struct hda_multi_out *mout) @@ -3510,8 +3832,12 @@ int snd_hda_multi_out_dig_close(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_dig_close); -/* - * set up more restrictions for analog out +/** + * snd_hda_multi_out_analog_open - open analog outputs + * + * Open analog outputs and set up the hw-constraints. + * If the digital outputs can be opened as slave, open the digital + * outputs, too. */ int snd_hda_multi_out_analog_open(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3556,9 +3882,11 @@ int snd_hda_multi_out_analog_open(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_open); -/* - * set up the i/o for analog out - * when the digital out is available, copy the front out to digital out, too. +/** + * snd_hda_multi_out_analog_prepare - Preapre the analog outputs. + * + * Set up the i/o for analog out. + * When the digital out is available, copy the front out to digital out, too. */ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, struct hda_multi_out *mout, @@ -3615,8 +3943,8 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_prepare); -/* - * clean up the setting for analog out +/** + * snd_hda_multi_out_analog_cleanup - clean up the setting for analog out */ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, struct hda_multi_out *mout) @@ -4002,8 +4330,14 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); * generic arrays */ -/* get a new element from the given array - * if it exceeds the pre-allocated array size, re-allocate the array +/** + * snd_array_new - get a new element from the given array + * @array: the array object + * + * Get a new element from the given array. If it exceeds the + * pre-allocated array size, re-allocate the array. + * + * Returns NULL if allocation failed. */ void *snd_array_new(struct snd_array *array) { @@ -4027,7 +4361,10 @@ void *snd_array_new(struct snd_array *array) } EXPORT_SYMBOL_HDA(snd_array_new); -/* free the given array elements */ +/** + * snd_array_free - free the given array elements + * @array: the array object + */ void snd_array_free(struct snd_array *array) { kfree(array->list); @@ -4037,7 +4374,12 @@ void snd_array_free(struct snd_array *array) } EXPORT_SYMBOL_HDA(snd_array_free); -/* +/** + * snd_print_pcm_rates - Print the supported PCM rates to the string buffer + * @pcm: PCM caps bits + * @buf: the string buffer to write + * @buflen: the max buffer length + * * used by hda_proc.c and hda_eld.c */ void snd_print_pcm_rates(int pcm, char *buf, int buflen) @@ -4056,6 +4398,14 @@ void snd_print_pcm_rates(int pcm, char *buf, int buflen) } EXPORT_SYMBOL_HDA(snd_print_pcm_rates); +/** + * snd_print_pcm_bits - Print the supported PCM fmt bits to the string buffer + * @pcm: PCM caps bits + * @buf: the string buffer to write + * @buflen: the max buffer length + * + * used by hda_proc.c and hda_eld.c + */ void snd_print_pcm_bits(int pcm, char *buf, int buflen) { static unsigned int bits[] = { 8, 16, 20, 24, 32 }; -- cgit v1.2.3 From 9bb1fe390de3e1def0dd162dbdaf62e0981105fa Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Nov 2009 15:33:49 +0100 Subject: ALSA: hda - Fix beep_mode option value The beep_mode option value was wrongly defined: it must be 0 = off and 1 = on. Also, evaluate the beep_mode value at snd_hda_attach_beep_device() properly so that no device is created when beep_mode=0 is given. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_beep.c | 4 +++- sound/pci/hda/hda_beep.h | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 9e48798b415b..5fe34a8d8c81 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c @@ -215,7 +215,9 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid) struct hda_beep *beep; if (!snd_hda_get_bool_hint(codec, "beep")) - return 0; /* disabled explicitly */ + return 0; /* disabled explicitly by hints */ + if (codec->beep_mode == HDA_BEEP_MODE_OFF) + return 0; /* disabled by module option */ beep = kzalloc(sizeof(*beep), GFP_KERNEL); if (beep == NULL) diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 17dd1c325e32..f1de1bac042c 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h @@ -24,8 +24,8 @@ #include "hda_codec.h" -#define HDA_BEEP_MODE_ON 0 -#define HDA_BEEP_MODE_OFF 1 +#define HDA_BEEP_MODE_OFF 0 +#define HDA_BEEP_MODE_ON 1 #define HDA_BEEP_MODE_SWREG 2 /* beep information */ -- cgit v1.2.3 From 67d634c07afd8f70973d925463e775fdb89ad536 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 16 Nov 2009 15:35:59 +0100 Subject: ALSA: hda - Fix build errors with CONFIG_SND_HDA_INPUT_BEEP=n Disable beep-related codes when CONFIG_SND_HDA_INPUT_BEEP isn't set. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 2 ++ sound/pci/hda/hda_local.h | 8 ++++++++ sound/pci/hda/patch_analog.c | 6 ++++++ sound/pci/hda/patch_realtek.c | 8 ++++++++ 4 files changed, 24 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index e344235da491..2be61b31fb3c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1959,6 +1959,7 @@ int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put); +#ifdef CONFIG_SND_HDA_INPUT_BEEP /** * snd_hda_mixer_amp_switch_put_beep - Put callback for a beep AMP switch * @@ -1975,6 +1976,7 @@ int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, return snd_hda_mixer_amp_switch_put(kcontrol, ucontrol); } EXPORT_SYMBOL_HDA(snd_hda_mixer_amp_switch_put_beep); +#endif /* CONFIG_SND_HDA_INPUT_BEEP */ /* * bound volume controls diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 7c049839ea26..d4a3d0942c00 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -77,6 +77,7 @@ /* stereo mute switch */ #define HDA_CODEC_MUTE(xname, nid, xindex, direction) \ HDA_CODEC_MUTE_MONO(xname, nid, 3, xindex, direction) +#ifdef CONFIG_SND_HDA_INPUT_BEEP /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ @@ -85,6 +86,11 @@ .get = snd_hda_mixer_amp_switch_get, \ .put = snd_hda_mixer_amp_switch_put_beep, \ .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, xindex, direction) } +#else +/* no digital beep - just the standard one */ +#define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, ch, xidx, dir) \ + HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, ch, xidx, dir) +#endif /* CONFIG_SND_HDA_INPUT_BEEP */ /* special beep mono mute switch */ #define HDA_CODEC_MUTE_BEEP_MONO(xname, nid, channel, xindex, direction) \ HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, 0, nid, channel, xindex, direction) @@ -108,8 +114,10 @@ int snd_hda_mixer_amp_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); int snd_hda_mixer_amp_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +#ifdef CONFIG_SND_HDA_INPUT_BEEP int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol); +#endif /* lowlevel accessor with caching; use carefully */ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index); diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index ceb0c603da04..8a1064bdf4c6 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -156,6 +156,7 @@ static const char *ad_slave_sws[] = { 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 */ static struct snd_kcontrol_new ad_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_OUTPUT), @@ -165,6 +166,9 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { #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) { @@ -194,6 +198,7 @@ static int ad198x_build_controls(struct hda_codec *codec) } /* create beep controls if needed */ +#ifdef CONFIG_SND_HDA_INPUT_BEEP if (spec->beep_amp) { struct snd_kcontrol_new *knew; for (knew = ad_beep_mixer; knew->name; knew++) { @@ -209,6 +214,7 @@ static int ad198x_build_controls(struct hda_codec *codec) return err; } } +#endif /* if we have no master control, let's create it */ if (!snd_hda_find_mixer_ctl(codec, "Master Playback Volume")) { diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eee3143eef75..ef7d21097eeb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2410,12 +2410,14 @@ static const char *alc_slave_sws[] = { 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 */ static struct snd_kcontrol_new alc_beep_mixer[] = { HDA_CODEC_VOLUME("Beep Playback Volume", 0, 0, HDA_INPUT), HDA_CODEC_MUTE_BEEP("Beep Playback Switch", 0, 0, HDA_INPUT), { } /* end */ }; +#endif static int alc_build_controls(struct hda_codec *codec) { @@ -2452,6 +2454,7 @@ static int alc_build_controls(struct hda_codec *codec) return err; } +#ifdef CONFIG_SND_HDA_INPUT_BEEP /* create beep controls if needed */ if (spec->beep_amp) { struct snd_kcontrol_new *knew; @@ -2467,6 +2470,7 @@ static int alc_build_controls(struct hda_codec *codec) return err; } } +#endif /* if we have no master control, let's create it */ if (!spec->no_analog && @@ -4780,8 +4784,12 @@ static void set_capture_mixer(struct hda_codec *codec) } } +#ifdef CONFIG_SND_HDA_INPUT_BEEP #define set_beep_amp(spec, nid, idx, dir) \ ((spec)->beep_amp = HDA_COMPOSE_AMP_VAL(nid, 3, idx, dir)) +#else +#define set_beep_amp(spec, nid, idx, dir) /* NOP */ +#endif /* * OK, here we have finally the patch for ALC880 -- cgit v1.2.3 From 02bb57aeb092cbb0dfdb50c6026dbd0c60af7644 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Mon, 16 Nov 2009 17:05:02 +0100 Subject: sound: OSS: keep index within bounds of midi_devs[] When the {orig,midi}_dev equals num_midis, that's one too large already. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/midi_synth.c | 2 +- sound/oss/mpu401.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/oss/midi_synth.c b/sound/oss/midi_synth.c index 9e450988ed36..3bc7104c5379 100644 --- a/sound/oss/midi_synth.c +++ b/sound/oss/midi_synth.c @@ -426,7 +426,7 @@ midi_synth_open(int dev, int mode) int err; struct midi_input_info *inc; - if (orig_dev < 0 || orig_dev > num_midis || midi_devs[orig_dev] == NULL) + if (orig_dev < 0 || orig_dev >= num_midis || midi_devs[orig_dev] == NULL) return -ENXIO; midi2synth[orig_dev] = dev; diff --git a/sound/oss/mpu401.c b/sound/oss/mpu401.c index 734b8f9e2f78..0af9d24feb8f 100644 --- a/sound/oss/mpu401.c +++ b/sound/oss/mpu401.c @@ -770,7 +770,7 @@ static int mpu_synth_ioctl(int dev, unsigned int cmd, void __user *arg) midi_dev = synth_devs[dev]->midi_dev; - if (midi_dev < 0 || midi_dev > num_midis || midi_devs[midi_dev] == NULL) + if (midi_dev < 0 || midi_dev >= num_midis || midi_devs[midi_dev] == NULL) return -ENXIO; devc = &dev_conf[midi_dev]; -- cgit v1.2.3 From baac805fc591b562f22d8f1cd0b65cdbbe9e9518 Mon Sep 17 00:00:00 2001 From: Timothy Knoll Date: Mon, 16 Nov 2009 19:55:46 -0500 Subject: sound: Kconfig typo fix Fix a typo in the help text in sound/Kconfig. Signed-off-by: Timothy Knoll Signed-off-by: Takashi Iwai --- sound/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 439e15c8faa3..b3e53e616ec9 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -58,7 +58,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" -- cgit v1.2.3 From 0c3cee57efcb1c79d62b1238c0d22afef4599247 Mon Sep 17 00:00:00 2001 From: Javier Kohen Date: Tue, 17 Nov 2009 15:36:13 +0100 Subject: ALSA: usb - Quirk to disable master volume control in PCM2702 Disable the master volume control in the PCM2702 chipset. The datasheet documents two independent channel volume controls, one master mute control and one master volume control. All controls are fully functional except for the master volume control, which returns USB stalls on all GET requests. Signed-off-by: Javier Kohen Signed-off-by: Takashi Iwai --- sound/usb/usbmixer.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index 9efcfd08d747..c998220b99c6 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c @@ -1071,6 +1071,15 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig channels = (ftr[0] - 7) / csize - 1; master_bits = snd_usb_combine_bytes(ftr + 6, csize); + /* master configuration quirks */ + switch (state->chip->usb_id) { + case USB_ID(0x08bb, 0x2702): + snd_printk(KERN_INFO + "usbmixer: master volume quirk for PCM2702 chip\n"); + /* disable non-functional volume control */ + master_bits &= ~(1 << (USB_FEATURE_VOLUME - 1)); + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); else -- cgit v1.2.3 From 12929baea4b29d70525f764034b3dac771dd69e5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Nov 2009 15:58:35 +0100 Subject: ALSA: hda - Fix quirk for VAIO type G Vaio type G laptop doesn't work with the current quirk setup. After some tests, it turned out that it should be model=auto as default. Reported-by: Mattia Dongili Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 84a52efdb2d6..70583719282b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11462,6 +11462,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9016, "Sony VAIO", ALC262_AUTO), /* dig-only */ SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), + SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", -- cgit v1.2.3 From c5b5165ce28099484d5fa733abeae48540680440 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 17 Nov 2009 16:01:58 +0100 Subject: ALSA: hda - Disable default quirk for Sony VAIO with ALC262 codec The ALC262 has a quirk entry matching with all Sony Vaio laptops to use model=sony-assamd as default. But, model=auto works much better for new models in the recent driver versions, thus it's safer to disable that default quirk entry. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ba339d745aab..578420523606 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -11471,8 +11471,10 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = { SND_PCI_QUIRK(0x104d, 0x9025, "Sony VAIO Z21MN", ALC262_TOSHIBA_S06), SND_PCI_QUIRK(0x104d, 0x9035, "Sony VAIO VGN-FW170J", ALC262_AUTO), SND_PCI_QUIRK(0x104d, 0x9047, "Sony VAIO Type G", ALC262_AUTO), +#if 0 /* disable the quirk since model=auto works better in recent versions */ SND_PCI_QUIRK_MASK(0x104d, 0xff00, 0x9000, "Sony VAIO", ALC262_SONY_ASSAMD), +#endif SND_PCI_QUIRK(0x1179, 0x0001, "Toshiba dynabook SS RX1", ALC262_TOSHIBA_RX1), SND_PCI_QUIRK(0x1179, 0xff7b, "Toshiba S06", ALC262_TOSHIBA_S06), -- cgit v1.2.3 From b753e03e5e7c6ee60e81cd6335c80dc26519f9d0 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 17 Nov 2009 18:34:54 +0100 Subject: ALSA: cs4236: update control names Update control names to be more closer to their meaning. Change the "Mono" name to the "Beep" as this line is usually used to forward the PC beeper signal to sound card's output. Update names for both cs423x and wss. Clean up cs4235 controls according to the cs4235 doc. Rename some of the cs4235 controls to be consistent with the cs4236's ones. Also, delete one misnamed cs4231 register define. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236_lib.c | 49 +++++++++++++++++++------------------------ sound/isa/wss/wss_lib.c | 8 +++---- 2 files changed, 25 insertions(+), 32 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 1b1ad1cad328..4c4024a73c6b 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -777,7 +777,7 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), -CS4236_DOUBLE("Mic Playback Boost", 0, +CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, @@ -798,10 +798,10 @@ WSS_DOUBLE("CD Capture Switch", 0, CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), -CS4236_DOUBLE1("Mono Playback Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), -WSS_SINGLE("Mono Playback Bypass", 0, CS4231_MONO_CTRL, 5, 1, 0), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), WSS_DOUBLE("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), @@ -815,31 +815,27 @@ CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, static struct snd_kcontrol_new snd_cs4235_controls[] = { -WSS_DOUBLE("Master Switch", 0, +WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Volume", 0, +WSS_DOUBLE("Master Playback Volume", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), CS4235_OUTPUT_ACCU("Playback Volume", 0), -CS4236_DOUBLE("Master Digital Playback Switch", 0, - CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), -CS4236_DOUBLE("Master Digital Capture Switch", 0, - CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), - -WSS_DOUBLE("Master Digital Playback Switch", 1, +WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Master Digital Capture Switch", 1, +WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Master Digital Volume", 1, +WSS_DOUBLE("Synth Volume", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), CS4236_DOUBLE("Capture Volume", 0, CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), -WSS_DOUBLE("PCM Switch", 0, +WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), +WSS_DOUBLE("PCM Capture Switch", 0, + CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), WSS_DOUBLE("PCM Volume", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), @@ -855,28 +851,25 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), -CS4236_SINGLE("Mic Playback Boost", 0, CS4236_LEFT_MIC, 5, 1, 0), +CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), -WSS_DOUBLE("Aux Playback Switch", 0, +WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 0, +WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 0, +WSS_DOUBLE("Line Volume", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), -WSS_DOUBLE("Aux Playback Switch", 1, +WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Aux Capture Switch", 1, +WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Aux Volume", 1, +WSS_DOUBLE("CD Volume", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), -CS4236_DOUBLE1("Master Mono Switch", 0, - CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), - -CS4236_DOUBLE1("Mono Switch", 0, +CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Mono Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), WSS_DOUBLE("Analog Loopback Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 705db0924375..5b9d6c18bc45 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c @@ -2224,7 +2224,7 @@ WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, .get = snd_wss_get_mux, .put = snd_wss_put_mux, }, -WSS_DOUBLE("Mic Boost", 0, +WSS_DOUBLE("Mic Boost (+20dB)", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0), @@ -2235,14 +2235,14 @@ WSS_DOUBLE("Line Playback Switch", 0, WSS_DOUBLE_TLV("Line Playback Volume", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, db_scale_5bit_12db_max), -WSS_SINGLE("Mono Playback Switch", 0, +WSS_SINGLE("Beep Playback Switch", 0, CS4231_MONO_CTRL, 7, 1, 1), -WSS_SINGLE_TLV("Mono Playback Volume", 0, +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, db_scale_4bit), WSS_SINGLE("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, 6, 1, 1), -WSS_SINGLE("Mono Output Playback Bypass", 0, +WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), }; -- cgit v1.2.3 From b67cad932c4e45edca2f4da2ee4f46001ba17363 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Tue, 17 Nov 2009 18:35:41 +0100 Subject: ALSA: opti-miro: use variables directly in the probe function Use the fm_port and mpu_port variables directly in a probe function. This completely eliminates a need to copy the fm_port value to the snd_miro structure. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a93..b8170adeeff6 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -118,8 +118,6 @@ struct snd_miro { int dma1; int dma2; - long fm_port; - long mpu_port; int mpu_irq; @@ -757,7 +755,6 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->irq = -1; chip->dma1 = -1; chip->dma2 = -1; - chip->fm_port = -1; chip->mpu_port = -1; chip->mpu_irq = -1; @@ -1261,7 +1258,6 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } miro->wss_base = port; - miro->fm_port = fm_port; miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; @@ -1276,11 +1272,12 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } } - if (miro->mpu_port == SNDRV_AUTO_PORT) { - if ((miro->mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2)) < 0) { + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; + return -EBUSY } } if (miro->irq == SNDRV_AUTO_IRQ) { @@ -1380,20 +1377,24 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->shortname, miro->name, pcm->name, miro->wss_base + 4, miro->irq, miro->dma1, miro->dma2); - if (miro->mpu_port <= 0 || miro->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - miro->mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, - &rmidi))) - snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", miro->mpu_port); + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, miro->mpu_irq, IRQF_DISABLED, + &rmidi); + if (error < 0) + snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", + mpu_port); + } - if (miro->fm_port > 0 && miro->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; - if (snd_opl4_create(card, miro->fm_port, miro->fm_port - 8, + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) - snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", miro->fm_port); + snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", + fm_port); } if ((error = snd_set_aci_init_values(miro)) < 0) { -- cgit v1.2.3 From 6f539a98614a014a7d6b64ab62b0dddb14e2d8cc Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:37:59 +0800 Subject: ALSA: intelhdmi - fix audio infoframe fill size MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-by: David Härdeman Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 4f25f08d332b..ad1aa5d87dda 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -509,12 +509,12 @@ static void hdmi_fill_audio_infoframe(struct hda_codec *codec, hdmi_debug_dip_size(codec, pin_nid); hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ - for (i = 0; i < sizeof(ai); i++) + for (i = 0; i < sizeof(*ai); i++) sum += params[i]; ai->checksum = - sum; hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); - for (i = 0; i < sizeof(ai); i++) + for (i = 0; i < sizeof(*ai); i++) hdmi_write_dip_byte(codec, pin_nid, params[i]); } -- cgit v1.2.3 From 1e7c10fefadb42d9300305c7de57bea365855e9b Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:00 +0800 Subject: ALSA: intelhdmi - fix channel mapping slot mask Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index ad1aa5d87dda..82312c67f8dd 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -433,7 +433,7 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) slot = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_CHAN_SLOT, i); printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", - slot >> 4, slot & 0x7); + slot >> 4, slot & 0xf); } #endif } -- cgit v1.2.3 From 23ccc2bd246a5bdb1ac03dc9040a0585c1890ef3 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:01 +0800 Subject: ALSA: intelhdmi - export monitor-presence and ELD-valid status Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_eld.c | 8 +++++++- sound/pci/hda/hda_local.h | 4 +++- sound/pci/hda/patch_intelhdmi.c | 8 +++----- 3 files changed, 13 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 20fa6aee29c0..de50cfcf644e 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -477,6 +477,8 @@ 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); 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]); @@ -518,7 +520,11 @@ static void hdmi_write_eld_info(struct snd_info_entry *entry, * monitor_name manufacture_id product_id * eld_version edid_version */ - if (!strcmp(name, "connection_type")) + if (!strcmp(name, "monitor_present")) + e->monitor_present = val; + else if (!strcmp(name, "eld_valid")) + e->eld_valid = val; + else if (!strcmp(name, "connection_type")) e->conn_type = val; else if (!strcmp(name, "port_id")) e->port_id = val; diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index d4a3d0942c00..070b74384d43 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -569,9 +569,11 @@ struct cea_sad { * ELD: EDID Like Data */ struct hdmi_eld { + bool monitor_present; + bool eld_valid; int eld_size; int baseline_len; - int eld_ver; /* (eld_ver == 0) indicates invalid ELD */ + int eld_ver; int cea_edid_ver; char monitor_name[ELD_MAX_MNL + 1]; int manufacture_id; diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 82312c67f8dd..095c993f4b76 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -62,8 +62,6 @@ struct intel_hdmi_spec { /* * HDMI sink attached to each pin */ - bool sink_present[INTEL_HDMI_PINS]; - bool sink_eldv[INTEL_HDMI_PINS]; struct hdmi_eld sink_eld[INTEL_HDMI_PINS]; /* @@ -645,7 +643,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, for (i = 0; i < spec->num_pins; i++) { if (spec->pin_cvt[i] != nid) continue; - if (spec->sink_present[i] != true) + if (!spec->sink_eld[i].monitor_present) continue; pin_nid = spec->pin[i]; @@ -675,8 +673,8 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) if (index < 0) return; - spec->sink_present[index] = pind; - spec->sink_eldv[index] = eldv; + spec->sink_eld[index].monitor_present = pind; + spec->sink_eld[index].eld_valid = eldv; if (pind && eldv) { hdmi_parse_eld(codec, index); -- cgit v1.2.3 From 864f92be7e8d4a0ba11d912e3f03d1a92a031dee Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:02 +0800 Subject: ALSA: hda - introduce snd_hda_jack_detect() and snd_hda_pin_sense() This helps merge duplicate code. v2: add snd_hda_jack_detect() and comments recommended by Takashi. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 34 +++++++ sound/pci/hda/hda_eld.c | 7 +- sound/pci/hda/hda_local.h | 2 + sound/pci/hda/patch_cirrus.c | 19 +--- sound/pci/hda/patch_realtek.c | 206 ++++++++++-------------------------------- 5 files changed, 91 insertions(+), 177 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 2be61b31fb3c..9cfdb771928c 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1317,6 +1317,40 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); +/** + * snd_hda_pin_sense - execute pin sense measurement + * @codec: the CODEC to sense + * @nid: the pin NID to sense + * + * Execute necessary pin sense measurement and return its Presence Detect, + * Impedance, ELD Valid etc. status bits. + */ +u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) +{ + u32 pincap = snd_hda_query_pin_caps(codec, nid); + + if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ + snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); + + return snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_SENSE, 0); +} +EXPORT_SYMBOL_HDA(snd_hda_pin_sense); + +/** + * snd_hda_jack_detect - 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. + */ +int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid) +{ + u32 sense = snd_hda_pin_sense(codec, nid); + return !!(sense & AC_PINSENSE_PRESENCE); +} +EXPORT_SYMBOL_HDA(snd_hda_jack_detect); + /* * read the current volume to info * if the cache exists, read the cache value. diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index de50cfcf644e..4228f2fe5956 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -309,17 +309,12 @@ out_fail: return -EINVAL; } -static int hdmi_present_sense(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0); -} - static int hdmi_eld_valid(struct hda_codec *codec, hda_nid_t nid) { int eldv; int present; - present = hdmi_present_sense(codec, nid); + present = snd_hda_pin_sense(codec, nid); eldv = (present & AC_PINSENSE_ELDV); present = (present & AC_PINSENSE_PRESENCE); diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 070b74384d43..5778ae882b83 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h @@ -461,6 +461,8 @@ 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); u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t 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); struct hda_nid_item { struct snd_kcontrol *kctl; diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 9ac09e4568b3..2439e84dcb21 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -807,7 +807,7 @@ static void cs_automute(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; - unsigned int caps, present, hp_present; + unsigned int caps, hp_present; hda_nid_t nid; int i; @@ -817,12 +817,7 @@ static void cs_automute(struct hda_codec *codec) caps = snd_hda_query_pin_caps(codec, nid); if (!(caps & AC_PINCAP_PRES_DETECT)) continue; - if (caps & AC_PINCAP_TRIG_REQ) - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - hp_present |= (present & AC_PINSENSE_PRESENCE) != 0; + hp_present = snd_hda_jack_detect(codec, nid); if (hp_present) break; } @@ -844,15 +839,11 @@ static void cs_automic(struct hda_codec *codec) struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; - unsigned int caps, present; + unsigned int present; nid = cfg->input_pins[spec->automic_idx]; - caps = snd_hda_query_pin_caps(codec, nid); - if (caps & AC_PINCAP_TRIG_REQ) - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (present & AC_PINSENSE_PRESENCE) + present = snd_hda_jack_detect(codec, nid); + if (present) change_cur_input(codec, spec->automic_idx, 0); else { unsigned int imic = (spec->automic_idx == AUTO_PIN_MIC) ? diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 578420523606..cbb2d326e6ad 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -961,18 +961,12 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, static void alc_automute_pin(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int present, pincap; unsigned int nid = spec->autocfg.hp_pins[0]; int i; if (!nid) return; - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ - snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->jack_present = snd_hda_jack_detect(codec, nid); for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { nid = spec->autocfg.speaker_pins[i]; if (!nid) @@ -1012,9 +1006,7 @@ static void alc_mic_automute(struct hda_codec *codec) cap_nid = spec->capsrc_nids ? spec->capsrc_nids[0] : spec->adc_nids[0]; - present = snd_hda_codec_read(codec, spec->ext_mic.pin, 0, - AC_VERB_GET_PIN_SENSE, 0); - present &= AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, spec->ext_mic.pin); if (present) { alive = &spec->ext_mic; dead = &spec->int_mic; @@ -1513,7 +1505,7 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { static void alc_automute_amp(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int val, mute, pincap; + unsigned int mute; hda_nid_t nid; int i; @@ -1522,13 +1514,7 @@ static void alc_automute_amp(struct hda_codec *codec) nid = spec->autocfg.hp_pins[i]; if (!nid) break; - pincap = snd_hda_query_pin_caps(codec, nid); - if (pincap & AC_PINCAP_TRIG_REQ) /* need trigger? */ - snd_hda_codec_read(codec, nid, 0, - AC_VERB_SET_PIN_SENSE, 0); - val = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (val & AC_PINSENSE_PRESENCE) { + if (snd_hda_jack_detect(codec, nid)) { spec->jack_present = 1; break; } @@ -2784,8 +2770,7 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x18); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } @@ -5102,11 +5087,8 @@ static struct hda_verb alc260_hp_unsol_verbs[] = { static void alc260_hp_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int present; - present = snd_hda_codec_read(codec, 0x10, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x10); alc260_hp_master_update(codec, 0x0f, 0x10, 0x11); } @@ -5171,11 +5153,8 @@ static struct hda_verb alc260_hp_3013_unsol_verbs[] = { static void alc260_hp_3013_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int present; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x15); alc260_hp_master_update(codec, 0x15, 0x10, 0x11); } @@ -5188,12 +5167,8 @@ static void alc260_hp_3013_unsol_event(struct hda_codec *codec, static void alc260_hp_3012_automute(struct hda_codec *codec) { - unsigned int present, bits; + unsigned int bits = snd_hda_jack_detect(codec, 0x10) ? 0 : PIN_OUT; - present = snd_hda_codec_read(codec, 0x10, 0, - AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; - - bits = present ? 0 : PIN_OUT; snd_hda_codec_write(codec, 0x0f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, bits); snd_hda_codec_write(codec, 0x11, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, @@ -5763,8 +5738,7 @@ static void alc260_replacer_672v_automute(struct hda_codec *codec) unsigned int present; /* speaker --> GPIO Data 0, hp or spdif --> GPIO data 1 */ - present = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x0f); if (present) { snd_hda_codec_write_cache(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 1); @@ -8196,12 +8170,8 @@ static void alc883_mitac_setup(struct hda_codec *codec) /* static void alc883_mitac_mic_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + unsigned char bits = snd_hda_jack_detect(codec, 0x18) ? HDA_AMP_MUTE : 0; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } */ @@ -8423,10 +8393,8 @@ static struct hda_channel_mode alc888_3st_hp_modes[3] = { /* toggle front-jack and RCA according to the hp-jack state */ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) { - unsigned int present; + unsigned int present = snd_hda_jack_detect(codec, 0x1b); - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, @@ -8436,10 +8404,8 @@ static void alc888_lenovo_ms7195_front_automute(struct hda_codec *codec) /* toggle RCA according to the front-jack state */ static void alc888_lenovo_ms7195_rca_automute(struct hda_codec *codec) { - unsigned int present; + unsigned int present = snd_hda_jack_detect(codec, 0x14); - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } @@ -8532,24 +8498,16 @@ static void alc883_haier_w66_setup(struct hda_codec *codec) static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + int bits = snd_hda_jack_detect(codec, 0x14) ? HDA_AMP_MUTE : 0; - present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); } static void alc883_lenovo_101e_all_automute(struct hda_codec *codec) { - unsigned int present; - unsigned char bits; + int bits = snd_hda_jack_detect(codec, 0x1b) ? HDA_AMP_MUTE : 0; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, @@ -8700,8 +8658,7 @@ static void alc889A_mb31_automute(struct hda_codec *codec) /* Mute only in 2ch or 4ch mode */ if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) == 0x00) { - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x15); snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, @@ -10044,10 +10001,8 @@ static void alc262_hp_master_update(struct hda_codec *codec) static void alc262_hp_bpc_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int presence; - presence = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); + + spec->jack_present = snd_hda_jack_detect(codec, 0x1b); alc262_hp_master_update(codec); } @@ -10061,10 +10016,8 @@ static void alc262_hp_bpc_unsol_event(struct hda_codec *codec, unsigned int res) static void alc262_hp_wildwest_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - unsigned int presence; - presence = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = !!(presence & AC_PINSENSE_PRESENCE); + + spec->jack_present = snd_hda_jack_detect(codec, 0x15); alc262_hp_master_update(codec); } @@ -10298,13 +10251,8 @@ static void alc262_hippo_automute(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, hp_nid, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; + spec->jack_present = snd_hda_jack_detect(codec, hp_nid); alc262_hippo_master_update(codec); } @@ -10630,21 +10578,8 @@ static void alc262_fujitsu_automute(struct hda_codec *codec, int force) unsigned int mute; if (force || !spec->sense_updated) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); - /* check laptop HP jack */ - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0); - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - /* check docking HP jack */ - present |= snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - if (present & AC_PINSENSE_PRESENCE) - spec->jack_present = 1; - else - spec->jack_present = 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x14) || + snd_hda_jack_detect(codec, 0x1b); spec->sense_updated = 1; } /* unmute internal speaker only if both HPs are unplugged and @@ -10689,12 +10624,7 @@ static void alc262_lenovo_3000_automute(struct hda_codec *codec, int force) unsigned int mute; if (force || !spec->sense_updated) { - unsigned int present_int_hp; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); - present_int_hp = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present_int_hp & 0x80000000) != 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x1b); spec->sense_updated = 1; } if (spec->jack_present) { @@ -10886,12 +10816,7 @@ static void alc262_ultra_automute(struct hda_codec *codec) mute = 0; /* auto-mute only when HP is used as HP */ if (!spec->cur_mux[0]) { - unsigned int present; - /* need to execute and sync at first */ - snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x15); if (spec->jack_present) mute = HDA_AMP_MUTE; } @@ -11933,10 +11858,7 @@ static void alc268_acer_automute(struct hda_codec *codec, int force) unsigned int mute; if (force || !spec->sense_updated) { - unsigned int present; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = (present & 0x80000000) != 0; + spec->jack_present = snd_hda_jack_detect(codec, 0x14); spec->sense_updated = 1; } if (spec->jack_present) @@ -12055,8 +11977,7 @@ static void alc268_aspire_one_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x15); bits = present ? AMP_IN_MUTE(0) : 0; snd_hda_codec_amp_stereo(codec, 0x0f, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -13039,8 +12960,7 @@ static void alc269_quanta_fl1_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x15); bits = present ? AMP_IN_MUTE(0) : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -13065,12 +12985,10 @@ static void alc269_lifebook_speaker_automute(struct hda_codec *codec) unsigned char bits; /* Check laptop headphone socket */ - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x15); /* Check port replicator headphone socket */ - present |= snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present |= snd_hda_jack_detect(codec, 0x1a); bits = present ? AMP_IN_MUTE(0) : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, @@ -13094,11 +13012,8 @@ static void alc269_lifebook_mic_autoswitch(struct hda_codec *codec) unsigned int present_laptop; unsigned int present_dock; - present_laptop = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; - - present_dock = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present_laptop = snd_hda_jack_detect(codec, 0x18); + present_dock = snd_hda_jack_detect(codec, 0x1b); /* Laptop mic port overrides dock mic port, design decision */ if (present_dock) @@ -13183,8 +13098,7 @@ static void alc269_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x15); bits = present ? AMP_IN_MUTE(0) : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -14162,10 +14076,8 @@ static struct hda_verb alc861_toshiba_init_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc861_toshiba_automute(struct hda_codec *codec) { - unsigned int present; + unsigned int present = snd_hda_jack_detect(codec, 0x0f); - present = snd_hda_codec_read(codec, 0x0f, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; snd_hda_codec_amp_stereo(codec, 0x16, HDA_INPUT, 0, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); snd_hda_codec_amp_stereo(codec, 0x1a, HDA_INPUT, 3, @@ -15070,9 +14982,9 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x18); bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); } @@ -16383,9 +16295,9 @@ static void alc662_lenovo_101e_ispeaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x14); bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); } @@ -16395,9 +16307,9 @@ static void alc662_lenovo_101e_all_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x1b); bits = present ? HDA_AMP_MUTE : 0; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, @@ -16456,9 +16368,7 @@ static void alc663_m51va_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x21); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -16471,9 +16381,7 @@ static void alc663_21jd_two_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x21); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -16490,9 +16398,7 @@ static void alc663_15jd_two_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x15); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -16509,9 +16415,7 @@ static void alc662_f5z_speaker_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x1b); bits = present ? 0 : PIN_OUT; snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, bits); @@ -16521,12 +16425,8 @@ static void alc663_two_hp_m1_speaker_automute(struct hda_codec *codec) { unsigned int present1, present2; - present1 = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present1 = snd_hda_jack_detect(codec, 0x21); + present2 = snd_hda_jack_detect(codec, 0x15); if (present1 || present2) { snd_hda_codec_write_cache(codec, 0x14, 0, @@ -16541,12 +16441,8 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) { unsigned int present1, present2; - present1 = snd_hda_codec_read(codec, 0x1b, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; - present2 = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present1 = snd_hda_jack_detect(codec, 0x1b); + present2 = snd_hda_jack_detect(codec, 0x15); if (present1 || present2) { snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, @@ -16706,9 +16602,7 @@ static void alc663_g71v_hp_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x21, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x21); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); @@ -16721,9 +16615,7 @@ static void alc663_g71v_front_automute(struct hda_codec *codec) unsigned int present; unsigned char bits; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x15); bits = present ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); -- cgit v1.2.3 From 3f54aa5091f48e9d8ce6e99b248449d08acccb26 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:03 +0800 Subject: ALSA: intelhdmi - probe for monitor/eld presence at module init time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This avoids lost of presence info on module reloading. The presence info used to be only updated at the (rare) hotplug events. Proposed by David, thanks! CC: David Härdeman Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 32 ++++++++++++++++++++++---------- 1 file changed, 22 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 095c993f4b76..c5fd011567fb 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -259,6 +259,25 @@ static int intel_hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) return 0; } +static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld) +{ + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + snd_hdmi_show_eld(eld); +} + +static void hdmi_present_sense(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld) +{ + int present = snd_hda_pin_sense(codec, pin_nid); + + eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE); + eld->eld_valid = !!(present & AC_PINSENSE_ELDV); + + if (present & AC_PINSENSE_ELDV) + hdmi_get_show_eld(codec, pin_nid, eld); +} + static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) { struct intel_hdmi_spec *spec = codec->spec; @@ -269,6 +288,8 @@ static int intel_hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) return -EINVAL; } + hdmi_present_sense(codec, pin_nid, &spec->sink_eld[spec->num_pins]); + spec->pin[spec->num_pins] = pin_nid; spec->num_pins++; @@ -436,15 +457,6 @@ static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) #endif } -static void hdmi_parse_eld(struct hda_codec *codec, int index) -{ - struct intel_hdmi_spec *spec = codec->spec; - struct hdmi_eld *eld = &spec->sink_eld[index]; - - if (!snd_hdmi_get_eld(eld, codec, spec->pin[index])) - snd_hdmi_show_eld(eld); -} - /* * Audio InfoFrame routines @@ -677,7 +689,7 @@ static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) spec->sink_eld[index].eld_valid = eldv; if (pind && eldv) { - hdmi_parse_eld(codec, index); + hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]); /* TODO: do real things about ELD */ } } -- cgit v1.2.3 From 978be6d711be237e0344eca21c3922ae88a240bc Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:04 +0800 Subject: ALSA: intelhdmi - separate out infoframe checksum routine And make it right when called for more than one times. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index c5fd011567fb..d68dba9ac113 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -508,24 +508,35 @@ static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) #endif } +static void hdmi_checksum_audio_infoframe(struct hdmi_audio_infoframe *ai) +{ + u8 *bytes = (u8 *)ai; + u8 sum = 0; + int i; + + ai->checksum = 0; + + for (i = 0; i < sizeof(*ai); i++) + sum += bytes[i]; + + ai->checksum = - sum; +} + static void hdmi_fill_audio_infoframe(struct hda_codec *codec, hda_nid_t pin_nid, struct hdmi_audio_infoframe *ai) { - u8 *params = (u8 *)ai; - u8 sum = 0; + u8 *bytes = (u8 *)ai; int i; hdmi_debug_dip_size(codec, pin_nid); hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ - for (i = 0; i < sizeof(*ai); i++) - sum += params[i]; - ai->checksum = - sum; + hdmi_checksum_audio_infoframe(ai); hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); for (i = 0; i < sizeof(*ai); i++) - hdmi_write_dip_byte(codec, pin_nid, params[i]); + hdmi_write_dip_byte(codec, pin_nid, bytes[i]); } /* -- cgit v1.2.3 From 848de598eef9603d6f2c174f90fded4e63ac5e23 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:05 +0800 Subject: ALSA: intelhdmi - sticky infoframe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remember the active infoframe, so as to avoid stop/restart infoframe transmission when switching between audio clips of the same format. Proposed by Shang and David. CC: Shane W CC: David Härdeman Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 38 ++++++++++++++++++++++++++------------ 1 file changed, 26 insertions(+), 12 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index d68dba9ac113..abb056fde67a 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -646,6 +646,27 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, hdmi_debug_channel_mapping(codec, nid); } +static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) +{ + u8 *bytes = (u8 *)ai; + u8 val; + int i; + + if (snd_hda_codec_read(codec, pin_nid, 0, AC_VERB_GET_HDMI_DIP_XMIT, 0) + != AC_DIPXMIT_BEST) + return false; + + hdmi_set_dip_index(codec, pin_nid, 0x0, 0x0); + for (i = 0; i < sizeof(*ai); i++) { + val = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_DATA, 0); + if (val != bytes[i]) + return false; + } + + return true; +} static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, struct snd_pcm_substream *substream) @@ -670,8 +691,11 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, continue; pin_nid = spec->pin[i]; - hdmi_fill_audio_infoframe(codec, pin_nid, &ai); - hdmi_start_infoframe_trans(codec, pin_nid); + if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { + hdmi_stop_infoframe_trans(codec, pin_nid); + hdmi_fill_audio_infoframe(codec, pin_nid, &ai); + hdmi_start_infoframe_trans(codec, pin_nid); + } } } @@ -767,16 +791,6 @@ static int intel_hdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct intel_hdmi_spec *spec = codec->spec; - int i; - - for (i = 0; i < spec->num_pins; i++) { - if (spec->pin_cvt[i] != hinfo->nid) - continue; - - hdmi_stop_infoframe_trans(codec, spec->pin[i]); - } - snd_hda_codec_cleanup_stream(codec, hinfo->nid); return 0; } -- cgit v1.2.3 From 5779191e0efd851fb0d54698c13cb4f5325caca6 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:06 +0800 Subject: ALSA: intelhdmi - sticky stream id and format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We tracked down the first-0.5s-hdmi-audio-samples-lost problem to the AC_VERB_SET_CHANNEL_STREAMID command. It is suspected that many HDMI sinks need some time to adapt to the new state. The workaround is to avoid changing stream id/format whenever possible. Proposed by David. Signed-off-by: David Härdeman Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index abb056fde67a..8a1cf9d7e5ce 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -772,6 +772,31 @@ static void intel_hdmi_unsol_event(struct hda_codec *codec, unsigned int res) * Callbacks */ +static void hdmi_setup_stream(struct hda_codec *codec, hda_nid_t nid, + u32 stream_tag, int format) +{ + int tag; + int fmt; + + tag = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CONV, 0) >> 4; + fmt = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_STREAM_FORMAT, 0); + + snd_printdd("hdmi_setup_stream: " + "NID=0x%x, %sstream=0x%x, %sformat=0x%x\n", + nid, + tag == stream_tag ? "" : "new-", + stream_tag, + fmt == format ? "" : "new-", + format); + + if (tag != stream_tag) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CHANNEL_STREAMID, stream_tag << 4); + if (fmt != format) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_STREAM_FORMAT, format); +} + static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -783,7 +808,7 @@ static int intel_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo, hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); - snd_hda_codec_setup_stream(codec, hinfo->nid, stream_tag, 0, format); + hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); return 0; } @@ -791,7 +816,6 @@ static int intel_hdmi_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); return 0; } -- cgit v1.2.3 From 81bf31e2d0a6a9f5d83da0a757f8ca03db908162 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:07 +0800 Subject: ALSA: intelhdmi - sticky channel count Don't change channel count if not necessary. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 8a1cf9d7e5ce..928df59be5d8 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -422,24 +422,18 @@ static void hdmi_stop_infoframe_trans(struct hda_codec *codec, AC_DIPXMIT_DISABLE); } -#ifdef CONFIG_SND_DEBUG_VERBOSE static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t nid) { return 1 + snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_CVT_CHAN_COUNT, 0); } -#endif static void hdmi_set_channel_count(struct hda_codec *codec, hda_nid_t nid, int chs) { - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); - -#ifdef CONFIG_SND_DEBUG_VERBOSE if (chs != hdmi_get_channel_count(codec, nid)) - snd_printd(KERN_INFO "HDMI channel count: expect %d, get %d\n", - chs, hdmi_get_channel_count(codec, nid)); -#endif + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); } static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) -- cgit v1.2.3 From 83d605fd63e704419ccb92d48b735c6890ce3d6a Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Wed, 18 Nov 2009 12:38:08 +0800 Subject: ALSA: hda - show EPSS capability in proc Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 4 ++++ sound/pci/hda/hda_proc.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index be6c5f443cd9..2d627613aea3 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -286,6 +286,10 @@ enum { #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) diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index f465cff28041..09476fc1ab64 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -26,6 +26,21 @@ #include "hda_codec.h" #include "hda_local.h" +static char *bits_names(unsigned int bits, char *names[], int size) +{ + int i, n; + static char buf[128]; + + for (i = 0, n = 0; i < size; i++) { + if (bits & (1U<> -- cgit v1.2.3 From d56757abc11a21996d9839c0d4e3b2c3666cd318 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Nov 2009 08:00:14 +0100 Subject: ALSA: hda - Replace the rest of jack-detections with snd_hda_jack_detect() Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 47 ++++++++++++++---------------------------- sound/pci/hda/patch_conexant.c | 37 ++++++++++----------------------- sound/pci/hda/patch_realtek.c | 3 +-- sound/pci/hda/patch_sigmatel.c | 7 ++----- sound/pci/hda/patch_via.c | 46 ++++++++++++++--------------------------- 5 files changed, 45 insertions(+), 95 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 8a1064bdf4c6..455a0494f907 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -720,10 +720,10 @@ static struct snd_kcontrol_new ad1986a_laptop_intmic_mixers[] = { static void ad1986a_automic(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x1f, 0, AC_VERB_GET_PIN_SENSE, 0); + 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 & AC_PINSENSE_PRESENCE) ? 0 : 2); + present ? 0 : 2); } #define AD1986A_MIC_EVENT 0x36 @@ -762,10 +762,8 @@ static void ad1986a_update_hp(struct hda_codec *codec) static void ad1986a_hp_automute(struct hda_codec *codec) { struct ad198x_spec *spec = codec->spec; - unsigned int present; - present = snd_hda_codec_read(codec, 0x1a, 0, AC_VERB_GET_PIN_SENSE, 0); - spec->jack_present = !!(present & 0x80000000); + spec->jack_present = snd_hda_jack_detect(codec, 0x1a); if (spec->inv_jack_detect) spec->jack_present = !spec->jack_present; ad1986a_update_hp(codec); @@ -1555,8 +1553,7 @@ static void ad1981_hp_automute(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x06, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + 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); } @@ -1576,8 +1573,7 @@ static void ad1981_hp_automic(struct hda_codec *codec) }; unsigned int present; - present = snd_hda_codec_read(codec, 0x08, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x08); if (present) snd_hda_sequence_write(codec, mic_jack_on); else @@ -2532,7 +2528,7 @@ static void ad1988_laptop_unsol_event(struct hda_codec *codec, unsigned int res) { if ((res >> 26) != AD1988_HP_EVENT) return; - if (snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) & (1 << 31)) + 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); @@ -3778,8 +3774,7 @@ static void ad1884a_hp_automute(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x11, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + 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, @@ -3791,8 +3786,7 @@ static void ad1884a_hp_automic(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x14, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x14); snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, present ? 0 : 1); } @@ -3827,13 +3821,9 @@ static void ad1884a_laptop_automute(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0); - present &= AC_PINSENSE_PRESENCE; - if (!present) { - present = snd_hda_codec_read(codec, 0x12, 0, - AC_VERB_GET_PIN_SENSE, 0); - present &= AC_PINSENSE_PRESENCE; - } + 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, @@ -3845,11 +3835,9 @@ static void ad1884a_laptop_automic(struct hda_codec *codec) { unsigned int idx; - if (snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE) + if (snd_hda_jack_detect(codec, 0x14)) idx = 0; - else if (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE) + else if (snd_hda_jack_detect(codec, 0x1c)) idx = 4; else idx = 1; @@ -4018,8 +4006,7 @@ static void ad1984a_thinkpad_automute(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x11, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + 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); } @@ -4127,14 +4114,12 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { /* switch to external mic if plugged */ static void ad1984a_touchsmart_automic(struct hda_codec *codec) { - if (snd_hda_codec_read(codec, 0x1c, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000) { + if (snd_hda_jack_detect(codec, 0x1c)) snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, 0x4); - } else { + else snd_hda_codec_write(codec, 0x0c, 0, AC_VERB_SET_CONNECT_SEL, 0x5); - } } diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 905859d4f4df..0b097fa5421f 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -397,9 +397,7 @@ static void conexant_report_jack(struct hda_codec *codec, hda_nid_t nid) for (i = 0; i < spec->jacks.used; i++) { if (jacks->nid == nid) { unsigned int present; - present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, nid); present = (present) ? jacks->type : 0 ; @@ -750,8 +748,7 @@ static void cxt5045_hp_automic(struct hda_codec *codec) }; unsigned int present; - present = snd_hda_codec_read(codec, 0x12, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x12); if (present) snd_hda_sequence_write(codec, mic_jack_on); else @@ -765,8 +762,7 @@ static void cxt5045_hp_automute(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int bits; - spec->hp_present = snd_hda_codec_read(codec, 0x11, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + spec->hp_present = snd_hda_jack_detect(codec, 0x11); bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; snd_hda_codec_amp_stereo(codec, 0x10, HDA_OUTPUT, 0, @@ -1243,8 +1239,7 @@ static void cxt5047_hp_automute(struct hda_codec *codec) struct conexant_spec *spec = codec->spec; unsigned int bits; - spec->hp_present = snd_hda_codec_read(codec, 0x13, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + spec->hp_present = snd_hda_jack_detect(codec, 0x13); bits = (spec->hp_present || !spec->cur_eapd) ? HDA_AMP_MUTE : 0; /* See the note in cxt5047_hp_master_sw_put */ @@ -1267,8 +1262,7 @@ static void cxt5047_hp_automic(struct hda_codec *codec) }; unsigned int present; - present = snd_hda_codec_read(codec, 0x15, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x15); if (present) snd_hda_sequence_write(codec, mic_jack_on); else @@ -1621,9 +1615,7 @@ static void cxt5051_portb_automic(struct hda_codec *codec) if (spec->no_auto_mic) return; - present = snd_hda_codec_read(codec, 0x17, 0, - AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x17); snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_CONNECT_SEL, present ? 0x01 : 0x00); @@ -1638,9 +1630,7 @@ static void cxt5051_portc_automic(struct hda_codec *codec) if (spec->no_auto_mic) return; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE; + present = snd_hda_jack_detect(codec, 0x18); if (present) spec->cur_adc_idx = 1; else @@ -1661,9 +1651,7 @@ static void cxt5051_hp_automute(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; - spec->hp_present = snd_hda_codec_read(codec, 0x16, 0, - AC_VERB_GET_PIN_SENSE, 0) & - AC_PINSENSE_PRESENCE; + spec->hp_present = snd_hda_jack_detect(codec, 0x16); cxt5051_update_speaker(codec); } @@ -2011,8 +1999,7 @@ static void cxt5066_automic(struct hda_codec *codec) }; unsigned int present; - present = snd_hda_codec_read(codec, 0x1a, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x1a); if (present) { snd_printdd("CXT5066: external microphone detected\n"); snd_hda_sequence_write(codec, ext_mic_present); @@ -2029,12 +2016,10 @@ static void cxt5066_hp_automute(struct hda_codec *codec) unsigned int portA, portD; /* Port A */ - portA = snd_hda_codec_read(codec, 0x19, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE; + portA = snd_hda_jack_detect(codec, 0x19); /* Port D */ - portD = (snd_hda_codec_read(codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) - & AC_PINSENSE_PRESENCE) << 1; + portD = snd_hda_jack_detect(codec, 0x1c); spec->hp_present = !!(portA | portD); snd_printdd("CXT5066: hp automute portA=%x portD=%x present=%d\n", diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cbb2d326e6ad..28acbe63dfc8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8446,8 +8446,7 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) { unsigned int present; - present = snd_hda_codec_read(codec, 0x18, 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x18); snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); } diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 7f76a97954f9..d83649c25fb2 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4413,14 +4413,11 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, pin_ctl & ~flag); } -static int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) +static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) { if (!nid) return 0; - if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0x00) - & (1 << 31)) - return 1; - return 0; + return snd_hda_jack_detect(codec, nid); } static void stac92xx_line_out_detect(struct hda_codec *codec, diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index 0c621d74b165..b70e26ad263f 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c @@ -547,8 +547,7 @@ static void set_pin_power_state(struct hda_codec *codec, hda_nid_t nid, unsigned no_presence = (def_conf & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT & AC_DEFCFG_MISC_NO_PRESENCE; /* do not support pin sense */ - unsigned present = snd_hda_codec_read(codec, nid, 0, - AC_VERB_GET_PIN_SENSE, 0) >> 31; + unsigned present = snd_hda_jack_detect(codec, nid); struct via_spec *spec = codec->spec; if ((spec->smart51_enabled && is_smart51_pins(spec, nid)) || ((no_presence || present) @@ -786,14 +785,11 @@ static void set_jack_power_state(struct hda_codec *codec) /* Mono out */ /* SW4(28h)->MW1(29h)-> PW12 (2ah)*/ - present = snd_hda_codec_read( - codec, 0x1c, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x1c); if (present) mono_out = 0; else { - present = snd_hda_codec_read( - codec, 0x1d, 0, AC_VERB_GET_PIN_SENSE, 0) - & 0x80000000; + present = snd_hda_jack_detect(codec, 0x1d); if (!spec->hp_independent_mode && present) mono_out = 0; else @@ -872,8 +868,7 @@ static void set_jack_power_state(struct hda_codec *codec) /* Class-D */ /* PW0 (24h), MW0(18h), MUX0(34h) */ - present = snd_hda_codec_read( - codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x25); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (present) { @@ -894,8 +889,7 @@ static void set_jack_power_state(struct hda_codec *codec) /* Mono Out */ /* PW15 (31h), MW8(17h), MUX8(3bh) */ - present = snd_hda_codec_read( - codec, 0x26, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x26); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x31, &parm); if (present) { @@ -973,8 +967,7 @@ static void set_jack_power_state(struct hda_codec *codec) /* Internal Speaker */ /* PW0 (24h), MW0(14h), MUX0(34h) */ - present = snd_hda_codec_read( - codec, 0x25, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x25); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x24, &parm); if (present) { @@ -994,8 +987,7 @@ static void set_jack_power_state(struct hda_codec *codec) } /* Mono Out */ /* PW13 (31h), MW13(1ch), MUX13(3ch), MW14(3eh) */ - present = snd_hda_codec_read( - codec, 0x28, 0, AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, 0x28); parm = AC_PWRST_D3; set_pin_power_state(codec, 0x31, &parm); if (present) { @@ -1920,8 +1912,7 @@ static void via_hp_automute(struct hda_codec *codec) unsigned int present = 0; struct via_spec *spec = codec->spec; - present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); if (!spec->hp_independent_mode) { struct snd_ctl_elem_id id; @@ -1947,9 +1938,8 @@ static void via_mono_automute(struct hda_codec *codec) if (spec->codec_type != VT1716S) return; - lineout_present = snd_hda_codec_read( - codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + lineout_present = snd_hda_jack_detect(codec, + spec->autocfg.line_out_pins[0]); /* Mute Mono Out if Line Out is plugged */ if (lineout_present) { @@ -1958,9 +1948,7 @@ static void via_mono_automute(struct hda_codec *codec) return; } - hp_present = snd_hda_codec_read( - codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); if (!spec->hp_independent_mode) snd_hda_codec_amp_stereo( @@ -2025,8 +2013,7 @@ static void via_speaker_automute(struct hda_codec *codec) if (spec->codec_type != VT2002P && spec->codec_type != VT1812) return; - hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); if (!spec->hp_independent_mode) { struct snd_ctl_elem_id id; @@ -2055,11 +2042,9 @@ static void via_hp_bind_automute(struct hda_codec *codec) if (!spec->autocfg.hp_pins[0] || !spec->autocfg.line_out_pins[0]) return; - hp_present = snd_hda_codec_read(codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + hp_present = snd_hda_jack_detect(codec, spec->autocfg.hp_pins[0]); - present = snd_hda_codec_read(codec, spec->autocfg.line_out_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + present = snd_hda_jack_detect(codec, spec->autocfg.line_out_pins[0]); if (!spec->hp_independent_mode) { /* Mute Line-Outs */ @@ -2529,8 +2514,7 @@ static void vt1708_update_hp_jack_state(struct work_struct *work) return; /* if jack state toggled */ if (spec->vt1708_hp_present - != (snd_hda_codec_read(spec->codec, spec->autocfg.hp_pins[0], 0, - AC_VERB_GET_PIN_SENSE, 0) >> 31)) { + != snd_hda_jack_detect(spec->codec, spec->autocfg.hp_pins[0])) { spec->vt1708_hp_present ^= 1; via_hp_automute(spec->codec); } -- cgit v1.2.3 From 67f2db24fbfdb63495d995d6fbbbe42980004ee0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Nov 2009 08:37:59 +0100 Subject: ALSA: opti-miro: Fix missing semicolon To fix a build error sound/isa/opti9xx/miro.c:1281: error: expected ';' before '}' token Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index b8170adeeff6..17761030affa 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1277,7 +1277,7 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) if (mpu_port < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY + return -EBUSY; } } if (miro->irq == SNDRV_AUTO_IRQ) { -- cgit v1.2.3 From bec145ae6f6978f0319e5600a742f45f76ecc4dd Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Wed, 18 Nov 2009 10:31:57 +0200 Subject: ALSA: remove unnecessary null check This function is only called from snd_ctl_ioctl() and the file parameter can never be null so there is no need to check it here. We dereference file at the start of the function: struct snd_card *card = file->card; and it confuses static checkers to dereference a pointer before checking it. Signed-off-by: Dan Carpenter Signed-off-by: Takashi Iwai --- sound/core/control.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/control.c b/sound/core/control.c index a8b7fabe645e..b586019faf3f 100644 --- a/sound/core/control.c +++ b/sound/core/control.c @@ -1120,7 +1120,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, goto __kctl_end; } if (vd->access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) { - if (file && vd->owner != NULL && vd->owner != file) { + if (vd->owner != NULL && vd->owner != file) { err = -EPERM; goto __kctl_end; } -- cgit v1.2.3 From 8af3aeb498197f6fdf5acc913ffe8a392cb921c9 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Nov 2009 14:23:37 +0100 Subject: ALSA: hda - Fix detection of dual headphones The dual-headphone mode with STAC/IDT codecs is useful only for machines that have two (or more) built-in headphones. But, some HP laptops give multiple headphone pin configs, one for the built-in and another for the separate (likely a docking station) one. This results in a missing speaker volume control. This patch adds more check for the dual-headphone mode to avoid this problem. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index d83649c25fb2..39001c47e627 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3635,6 +3635,26 @@ static void stac92xx_auto_init_hp_out(struct hda_codec *codec) } } +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, hda_nid_t dig_out, hda_nid_t dig_in) { struct sigmatel_spec *spec = codec->spec; @@ -3651,8 +3671,7 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out /* If we have no real line-out pin and multiple hp-outs, HPs should * be set up as multi-channel outputs. */ - if (spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT && - spec->autocfg.hp_outs > 1) { + 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. -- cgit v1.2.3 From b4e818768d50a5b7aa1635676839682bcf0691b6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 18 Nov 2009 17:20:24 +0100 Subject: ALSA: hda - Fix mute-LED sync on HP laptops with IDT92HD83xxx codecs The mute-LED isn't synchronized with the actual mute state on some HP laptops with IDT 92HD83xxx codecs. A similar hack using check_power_status callback is added for this codec, too. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 39001c47e627..2a45375d79f8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -93,6 +93,7 @@ enum { STAC_92HD83XXX_REF, STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, + STAC_92HD83XXX_HP, STAC_92HD83XXX_MODELS }; @@ -1624,6 +1625,7 @@ static const char *stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = "ref", [STAC_92HD83XXX_PWR_REF] = "mic-ref", [STAC_DELL_S14] = "dell-s14", + [STAC_92HD83XXX_HP] = "hp", }; static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { @@ -1634,6 +1636,8 @@ static struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { "DFI LanParty", STAC_92HD83XXX_REF), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), + SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, + "HP", STAC_92HD83XXX_HP), {} /* terminator */ }; @@ -4834,6 +4838,23 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, return 0; } + +static int idt92hd83xxx_hp_check_power_status(struct hda_codec *codec, + hda_nid_t nid) +{ + struct sigmatel_spec *spec = codec->spec; + + if (nid != 0x13) + return 0; + if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & HDA_AMP_MUTE) + spec->gpio_data |= spec->gpio_led; /* mute LED on */ + else + spec->gpio_data &= ~spec->gpio_led; /* mute LED off */ + stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); + + return 0; +} + #endif static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) @@ -5199,6 +5220,22 @@ again: break; } + codec->patch_ops = stac92xx_patch_ops; + + if (spec->board_config == STAC_92HD83XXX_HP) + spec->gpio_led = 0x01; + +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (spec->gpio_led) { + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + spec->gpio_data |= spec->gpio_led; + /* register check_power_status callback. */ + codec->patch_ops.check_power_status = + idt92hd83xxx_hp_check_power_status; + } +#endif + err = stac92xx_parse_auto_config(codec, 0x1d, 0); if (!err) { if (spec->board_config < 0) { @@ -5234,8 +5271,6 @@ again: snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, num_dacs); - codec->patch_ops = stac92xx_patch_ops; - codec->proc_widget_hook = stac92hd_proc_hook; return 0; -- cgit v1.2.3 From f2624791a0c2a2d7664b12d75ca327917141fd3b Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 19 Nov 2009 11:48:44 +0100 Subject: ALSA: hda - Change quirk for Acer Aspire 5930G Change the quirk for Acer Aspire 5930G from model=acer-aspire-4930g to model=acer-aspre-6530g. The tuba bass gets muted along with the other built-in speakers upon headphones insertion, the internal mic works perfectly etc. Reported-by: Claudio Viano Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 28acbe63dfc8..d29fa18232ad 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8754,7 +8754,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", - ALC888_ACER_ASPIRE_4930G), + ALC888_ACER_ASPIRE_6530G), SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", -- cgit v1.2.3 From 4b28dca86066596721a6243c94611dab41970079 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 18 Nov 2009 17:29:36 +0100 Subject: ALSA: cs4236: add dB scale for all volume controls Use db scale for all volume controls according to Crystal's datasheets. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/cs423x/cs4236_lib.c | 152 ++++++++++++++++++++++++++++++------------ 1 file changed, 108 insertions(+), 44 deletions(-) (limited to 'sound') diff --git a/sound/isa/cs423x/cs4236_lib.c b/sound/isa/cs423x/cs4236_lib.c index 4c4024a73c6b..c5adca300632 100644 --- a/sound/isa/cs423x/cs4236_lib.c +++ b/sound/isa/cs423x/cs4236_lib.c @@ -88,6 +88,7 @@ #include #include #include +#include /* * @@ -399,6 +400,14 @@ int snd_cs4236_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } +#define CS4236_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_single, \ + .get = snd_cs4236_get_single, .put = snd_cs4236_put_single, \ + .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 16) & 0xff; @@ -502,6 +511,16 @@ static int snd_cs4236_put_singlec(struct snd_kcontrol *kcontrol, struct snd_ctl_ .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double, .put = snd_cs4236_put_double, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) { int mask = (kcontrol->private_value >> 24) & 0xff; @@ -572,12 +591,23 @@ static int snd_cs4236_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert) \ +#define CS4236_DOUBLE1(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | (shift_right << 19) | (mask << 24) | (invert << 22) } +#define CS4236_DOUBLE1_TLV(xname, xindex, left_reg, right_reg, shift_left, \ + shift_right, mask, invert, xtlv) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ + .info = snd_cs4236_info_double, \ + .get = snd_cs4236_get_double1, .put = snd_cs4236_put_double1, \ + .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ + (shift_right << 19) | (mask << 24) | (invert << 22), \ + .tlv = { .p = (xtlv) } } + static int snd_cs4236_get_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_wss *chip = snd_kcontrol_chip(kcontrol); @@ -631,16 +661,18 @@ static int snd_cs4236_put_double1(struct snd_kcontrol *kcontrol, struct snd_ctl_ return change; } -#define CS4236_MASTER_DIGITAL(xname, xindex) \ +#define CS4236_MASTER_DIGITAL(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4236_get_master_digital, .put = snd_cs4236_put_master_digital, \ - .private_value = 71 << 24 } + .private_value = 71 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4236_mixer_master_digital_invert_volume(int vol) { return (vol < 64) ? 63 - vol : 64 + (71 - vol); -} +} static int snd_cs4236_get_master_digital(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -673,11 +705,13 @@ static int snd_cs4236_put_master_digital(struct snd_kcontrol *kcontrol, struct s return change; } -#define CS4235_OUTPUT_ACCU(xname, xindex) \ +#define CS4235_OUTPUT_ACCU(xname, xindex, xtlv) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ + .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ .info = snd_cs4236_info_double, \ .get = snd_cs4235_get_output_accu, .put = snd_cs4235_put_output_accu, \ - .private_value = 3 << 24 } + .private_value = 3 << 24, \ + .tlv = { .p = (xtlv) } } static inline int snd_cs4235_mixer_output_accu_get_volume(int vol) { @@ -732,41 +766,56 @@ static int snd_cs4235_put_output_accu(struct snd_kcontrol *kcontrol, struct snd_ return change; } +static const DECLARE_TLV_DB_SCALE(db_scale_7bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_6bit_12db_max, -8250, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_22db_max, -2400, 150, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_4bit, -4500, 300, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit, -1800, 600, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0); + static struct snd_kcontrol_new snd_cs4236_controls[] = { CS4236_DOUBLE("Master Digital Playback Switch", 0, CS4236_LEFT_MASTER, CS4236_RIGHT_MASTER, 7, 7, 1, 1), CS4236_DOUBLE("Master Digital Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -CS4236_MASTER_DIGITAL("Master Digital Volume", 0), +CS4236_MASTER_DIGITAL("Master Digital Volume", 0, db_scale_7bit), -CS4236_DOUBLE("Capture Boost Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Boost Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), -WSS_DOUBLE("PCM Playback Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Playback Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Playback Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), -CS4236_DOUBLE("DSP Playback Volume", 0, - CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("DSP Playback Volume", 0, + CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("FM Playback Switch", 0, CS4236_LEFT_FM, CS4236_RIGHT_FM, 7, 7, 1, 1), -CS4236_DOUBLE("FM Playback Volume", 0, - CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("FM Playback Volume", 0, + CS4236_LEFT_FM, CS4236_RIGHT_FM, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("Wavetable Playback Switch", 0, CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 7, 7, 1, 1), -CS4236_DOUBLE("Wavetable Playback Volume", 0, - CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1), +CS4236_DOUBLE_TLV("Wavetable Playback Volume", 0, + CS4236_LEFT_WAVE, CS4236_RIGHT_WAVE, 0, 0, 63, 1, + db_scale_6bit_12db_max), WSS_DOUBLE("Synth Playback Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), -WSS_DOUBLE("Synth Volume", 0, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 0, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Synth Capture Switch", 0, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), WSS_DOUBLE("Synth Capture Bypass", 0, @@ -776,14 +825,16 @@ CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), -CS4236_DOUBLE("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 0, 0, 31, 1), +CS4236_DOUBLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, + 0, 0, 31, 1, db_scale_5bit_22db_max), CS4236_DOUBLE("Mic Playback Boost (+20dB)", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 5, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), WSS_DOUBLE("Line Capture Bypass", 0, @@ -791,8 +842,9 @@ WSS_DOUBLE("Line Capture Bypass", 0, WSS_DOUBLE("CD Playback Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), -WSS_DOUBLE("CD Volume", 0, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 0, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Capture Switch", 0, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), @@ -800,44 +852,53 @@ CS4236_DOUBLE1("Mono Output Playback Switch", 0, CS4231_MONO_CTRL, CS4236_RIGHT_MIX_CTRL, 6, 7, 1, 1), CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -WSS_SINGLE("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1), +WSS_SINGLE_TLV("Beep Playback Volume", 0, CS4231_MONO_CTRL, 0, 15, 1, + db_scale_4bit), WSS_SINGLE("Beep Bypass Playback Switch", 0, CS4231_MONO_CTRL, 5, 1, 0), -WSS_DOUBLE("Capture Volume", 0, - CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), +WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, + 0, 0, 15, 0, db_scale_rec_gain), WSS_DOUBLE("Analog Loopback Capture Switch", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 7, 7, 1, 0), -WSS_SINGLE("Digital Loopback Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), -CS4236_DOUBLE1("Digital Loopback Playback Volume", 0, - CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1) +WSS_SINGLE("Loopback Digital Playback Switch", 0, CS4231_LOOPBACK, 0, 1, 0), +CS4236_DOUBLE1_TLV("Loopback Digital Playback Volume", 0, + CS4231_LOOPBACK, CS4236_RIGHT_LOOPBACK, 2, 0, 63, 1, + db_scale_6bit), }; +static const DECLARE_TLV_DB_SCALE(db_scale_5bit_6db_max, -5600, 200, 0); +static const DECLARE_TLV_DB_SCALE(db_scale_2bit_16db_max, -2400, 800, 0); + static struct snd_kcontrol_new snd_cs4235_controls[] = { WSS_DOUBLE("Master Playback Switch", 0, CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 7, 7, 1, 1), -WSS_DOUBLE("Master Playback Volume", 0, - CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Master Playback Volume", 0, + CS4235_LEFT_MASTER, CS4235_RIGHT_MASTER, 0, 0, 31, 1, + db_scale_5bit_6db_max), -CS4235_OUTPUT_ACCU("Playback Volume", 0), +CS4235_OUTPUT_ACCU("Playback Volume", 0, db_scale_2bit_16db_max), WSS_DOUBLE("Synth Playback Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), WSS_DOUBLE("Synth Capture Switch", 1, CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 6, 6, 1, 1), -WSS_DOUBLE("Synth Volume", 1, - CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Synth Volume", 1, + CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 31, 1, + db_scale_5bit_12db_max), -CS4236_DOUBLE("Capture Volume", 0, - CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1), +CS4236_DOUBLE_TLV("Capture Volume", 0, + CS4236_LEFT_MIX_CTRL, CS4236_RIGHT_MIX_CTRL, 5, 5, 3, 1, + db_scale_2bit), WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), WSS_DOUBLE("PCM Capture Switch", 0, CS4236_DAC_MUTE, CS4236_DAC_MUTE, 7, 6, 1, 1), -WSS_DOUBLE("PCM Volume", 0, - CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1), +WSS_DOUBLE_TLV("PCM Volume", 0, + CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1, + db_scale_6bit), CS4236_DOUBLE("DSP Switch", 0, CS4236_LEFT_DSP, CS4236_RIGHT_DSP, 7, 7, 1, 1), @@ -850,22 +911,25 @@ CS4236_DOUBLE("Mic Capture Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 7, 7, 1, 1), CS4236_DOUBLE("Mic Playback Switch", 0, CS4236_LEFT_MIC, CS4236_RIGHT_MIC, 6, 6, 1, 1), -CS4236_SINGLE("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1), +CS4236_SINGLE_TLV("Mic Volume", 0, CS4236_LEFT_MIC, 0, 31, 1, + db_scale_5bit_22db_max), CS4236_SINGLE("Mic Boost (+20dB)", 0, CS4236_LEFT_MIC, 5, 1, 0), WSS_DOUBLE("Line Playback Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE("Line Capture Switch", 0, CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("Line Volume", 0, - CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("Line Volume", 0, + CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), WSS_DOUBLE("CD Playback Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), WSS_DOUBLE("CD Capture Switch", 1, CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 6, 6, 1, 1), -WSS_DOUBLE("CD Volume", 1, - CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1), +WSS_DOUBLE_TLV("CD Volume", 1, + CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1, + db_scale_5bit_12db_max), CS4236_DOUBLE1("Beep Playback Switch", 0, CS4231_MONO_CTRL, CS4236_LEFT_MIX_CTRL, 7, 7, 1, 1), -- cgit v1.2.3 From d867bba94513cf149cb8462a6e006848acb91d38 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 19 Nov 2009 14:34:33 +0100 Subject: sound: usb-audio: add Roland UA-1G support Add support for the Roland UA-1G audio interface. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbquirks.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f6f201eb24ce..a892bda03df9 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1563,6 +1563,29 @@ YAMAHA_DEVICE(0x7010, "UB99"), } } }, +{ + /* has ID 0x00ea when not in Advanced Driver mode */ + USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9), + .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { + /* .vendor_name = "Roland", */ + /* .product_name = "UA-1G", */ + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = (const struct snd_usb_audio_quirk[]) { + { + .ifnum = 0, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = 1, + .type = QUIRK_AUDIO_STANDARD_INTERFACE + }, + { + .ifnum = -1 + } + } + } +}, /* Guillemot devices */ { -- cgit v1.2.3 From fbc543915ffb8ec5c35403f294ab799f1936f42a Mon Sep 17 00:00:00 2001 From: Akinobu Mita Date: Fri, 20 Nov 2009 14:56:52 +0900 Subject: ALSA: sound: usbmidi: Use hweight16 Use hweight16 instead of Brian Kernighan's/Peter Wegner's method Signed-off-by: Akinobu Mita Signed-off-by: Takashi Iwai --- sound/usb/usbmidi.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 0eff19ceb7e1..e5b068996371 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1062,15 +1062,6 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, return 0; } -static unsigned int snd_usbmidi_count_bits(unsigned int x) -{ - unsigned int bits; - - for (bits = 0; x; ++bits) - x &= x - 1; - return bits; -} - /* * Frees an output endpoint. * May be called when ep hasn't been initialized completely. @@ -1914,8 +1905,8 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, out_ports = 0; in_ports = 0; for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) { - out_ports += snd_usbmidi_count_bits(endpoints[i].out_cables); - in_ports += snd_usbmidi_count_bits(endpoints[i].in_cables); + out_ports += hweight16(endpoints[i].out_cables); + in_ports += hweight16(endpoints[i].in_cables); } err = snd_usbmidi_create_rawmidi(umidi, out_ports, in_ports); if (err < 0) { -- cgit v1.2.3 From 7cef4cf1c5e9d81554137f52b96a5ab7f6241cdd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Wojni=C5=82owicz?= Date: Fri, 20 Nov 2009 12:14:35 +0100 Subject: ALSA: hda - 4930g mute lfe and side when pluging in headphones MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes first issue from comment 0021423 in bug 0004317 for Acer Aspire 5930g Signed-off-by: Łukasz Wojniłowicz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d29fa18232ad..eedbe19306a0 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1772,6 +1772,8 @@ static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) spec->autocfg.hp_pins[0] = 0x15; spec->autocfg.speaker_pins[0] = 0x14; + spec->autocfg.speaker_pins[1] = 0x16; + spec->autocfg.speaker_pins[2] = 0x17; } static void alc888_acer_aspire_6530g_setup(struct hda_codec *codec) -- cgit v1.2.3 From fc08722510494e8185e176713de8c47238512591 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Sat, 21 Nov 2009 19:57:11 +0100 Subject: ALSA: hda - Fix input and jack Kconfig depenencies CONFIG_SND_JACK needs to be selected explicitly only when INPUT=y or INPUT_SND. The current way, INPUT=SND_HDA_INTEL isn't strict enough. Reported-by: Randy Dunlap Signed-off-by: Takashi Iwai --- sound/pci/hda/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 25ae10e16f59..556cff937be7 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -51,7 +51,7 @@ config SND_HDA_INPUT_BEEP_MODE config SND_HDA_INPUT_JACK bool "Support jack plugging notification via input layer" - depends on INPUT=y || INPUT=SND_HDA_INTEL + depends on INPUT=y || INPUT=SND select SND_JACK help Say Y here to enable the jack plugging notification via -- cgit v1.2.3 From 616ad593fe37ef265e5cb1282db6ca264197ffb2 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 21 Nov 2009 01:01:18 +0100 Subject: ALSA: opti-miro: remove snd_card pointer from snd_miro structure Remove the snd_card pointer from the snd_miro structure and do some small code improvements. Also, move Opti chipset detection before detection of the ACI mixer, so the mci_base value is set in one place only. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 53 +++++++++++++++++++++--------------------------- 1 file changed, 23 insertions(+), 30 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 17761030affa..db4a4fbdc5ca 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -110,7 +110,6 @@ struct snd_miro { unsigned long pwd_reg; spinlock_t lock; - struct snd_card *card; struct snd_pcm *pcm; long wss_base; @@ -132,8 +131,6 @@ struct snd_miro { struct mutex aci_mutex; }; -static void snd_miro_proc_init(struct snd_miro * miro); - static char * snd_opti9xx_names[] = { "unkown", "82C928", "82C929", @@ -457,11 +454,9 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right = ucontrol->value.integer.value[1]; setreg_right = (kcontrol->private_value >> 8) & 0xff; - if (setreg_right == ACI_SET_MASTER) { - setreg_left = setreg_right + 1; - } else { - setreg_left = setreg_right + 8; - } + setreg_left = setreg_right + 8; + if (setreg_right == ACI_SET_MASTER) + setreg_left -= 7; getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; @@ -667,17 +662,15 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) return 0; } -static int __devinit snd_miro_mixer(struct snd_miro *miro) +static int __devinit snd_miro_mixer(struct snd_card *card, + struct snd_miro *miro) { - struct snd_card *card; unsigned int idx; int err; - if (snd_BUG_ON(!miro || !miro->card)) + if (snd_BUG_ON(!miro || !card)) return -EINVAL; - card = miro->card; - switch (miro->hardware) { case OPTi9XX_HW_82C924: strcpy(card->mixername, "ACI & OPTi924"); @@ -950,11 +943,12 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); } -static void __devinit snd_miro_proc_init(struct snd_miro * miro) +static void __devinit snd_miro_proc_init(struct snd_card *card, + struct snd_miro *miro) { struct snd_info_entry *entry; - if (! snd_card_proc_new(miro->card, "miro", &entry)) + if (!snd_card_proc_new(card, "miro", &entry)) snd_info_set_text_ops(entry, miro, snd_miro_proc_read); } @@ -971,20 +965,18 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) unsigned char mpu_irq_bits; unsigned long flags; + snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); + snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ + snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); + switch (chip->hardware) { case OPTi9XX_HW_82C924: snd_miro_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; case OPTi9XX_HW_82C929: /* untested init commands for OPTi929 */ - snd_miro_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); /* OPL4 */ snd_miro_write_mask(chip, OPTi9XX_MC_REG(4), 0x00, 0x0c); - snd_miro_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); break; default: snd_printk(KERN_ERR "chip %d not supported\n", chip->hardware); @@ -1156,7 +1148,6 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, /* get ACI port from OPTi9xx MC 4 */ - miro->mc_base = 0xf8c; regval=inb(miro->mc_base + 4); miro->aci_port = (regval & 0x10) ? 0x344: 0x354; @@ -1232,7 +1223,13 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) card->private_free = snd_card_miro_free; miro = card->private_data; - miro->card = card; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { snd_card_free(card); @@ -1241,13 +1238,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } /* init proc interface */ - snd_miro_proc_init(miro); + snd_miro_proc_init(card, miro); - if ((error = snd_card_miro_detect(card, miro)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); - return -ENODEV; - } if (! miro->res_mc_base && (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, @@ -1341,7 +1333,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) miro->pcm = pcm; - if ((error = snd_miro_mixer(miro)) < 0) { + error = snd_miro_mixer(card, miro); + if (error < 0) { snd_card_free(card); return error; } -- cgit v1.2.3 From 9aeba6297151abcb1b34f3237e4c028aae500ce4 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 22 Nov 2009 17:23:45 +0100 Subject: ALSA: opti-miro: make miro.h header available outside the alsa directory Move the miro.h header to the include/sound directory. It can be used in the Miro PCM20 radio driver (v4l). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 2 +- sound/isa/opti9xx/miro.h | 73 ------------------------------------------------ 2 files changed, 1 insertion(+), 74 deletions(-) delete mode 100644 sound/isa/opti9xx/miro.h (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index db4a4fbdc5ca..932a067ef980 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -40,7 +40,7 @@ #define SNDRV_LEGACY_FIND_FREE_IRQ #define SNDRV_LEGACY_FIND_FREE_DMA #include -#include "miro.h" +#include MODULE_AUTHOR("Martin Langer "); MODULE_LICENSE("GPL"); diff --git a/sound/isa/opti9xx/miro.h b/sound/isa/opti9xx/miro.h deleted file mode 100644 index 6e1385b8e07e..000000000000 --- a/sound/isa/opti9xx/miro.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef _MIRO_H_ -#define _MIRO_H_ - -#define ACI_REG_COMMAND 0 /* write register offset */ -#define ACI_REG_STATUS 1 /* read register offset */ -#define ACI_REG_BUSY 2 /* busy register offset */ -#define ACI_REG_RDS 2 /* PCM20: RDS register offset */ -#define ACI_MINTIME 500 /* ACI time out limit */ - -#define ACI_SET_MUTE 0x0d -#define ACI_SET_POWERAMP 0x0f -#define ACI_SET_TUNERMUTE 0xa3 -#define ACI_SET_TUNERMONO 0xa4 -#define ACI_SET_IDE 0xd0 -#define ACI_SET_WSS 0xd1 -#define ACI_SET_SOLOMODE 0xd2 -#define ACI_SET_PREAMP 0x03 -#define ACI_GET_PREAMP 0x21 -#define ACI_WRITE_TUNE 0xa7 -#define ACI_READ_TUNERSTEREO 0xa8 -#define ACI_READ_TUNERSTATION 0xa9 -#define ACI_READ_VERSION 0xf1 -#define ACI_READ_IDCODE 0xf2 -#define ACI_INIT 0xff -#define ACI_STATUS 0xf0 -#define ACI_S_GENERAL 0x00 -#define ACI_ERROR_OP 0xdf - -/* ACI Mixer */ - -/* These are the values for the right channel GET registers. - Add an offset of 0x01 for the left channel register. - (left=right+0x01) */ - -#define ACI_GET_MASTER 0x03 -#define ACI_GET_MIC 0x05 -#define ACI_GET_LINE 0x07 -#define ACI_GET_CD 0x09 -#define ACI_GET_SYNTH 0x0b -#define ACI_GET_PCM 0x0d -#define ACI_GET_LINE1 0x10 /* Radio on PCM20 */ -#define ACI_GET_LINE2 0x12 - -#define ACI_GET_EQ1 0x22 /* from Bass ... */ -#define ACI_GET_EQ2 0x24 -#define ACI_GET_EQ3 0x26 -#define ACI_GET_EQ4 0x28 -#define ACI_GET_EQ5 0x2a -#define ACI_GET_EQ6 0x2c -#define ACI_GET_EQ7 0x2e /* ... to Treble */ - -/* And these are the values for the right channel SET registers. - For left channel access you have to add an offset of 0x08. - MASTER is an exception, which needs an offset of 0x01 */ - -#define ACI_SET_MASTER 0x00 -#define ACI_SET_MIC 0x30 -#define ACI_SET_LINE 0x31 -#define ACI_SET_CD 0x34 -#define ACI_SET_SYNTH 0x33 -#define ACI_SET_PCM 0x32 -#define ACI_SET_LINE1 0x35 /* Radio on PCM20 */ -#define ACI_SET_LINE2 0x36 - -#define ACI_SET_EQ1 0x40 /* from Bass ... */ -#define ACI_SET_EQ2 0x41 -#define ACI_SET_EQ3 0x42 -#define ACI_SET_EQ4 0x43 -#define ACI_SET_EQ5 0x44 -#define ACI_SET_EQ6 0x45 -#define ACI_SET_EQ7 0x46 /* ... to Treble */ - -#endif /* _MIRO_H_ */ -- cgit v1.2.3 From 9dc9120c774e1d7e3d939542200bd44829c0059d Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 22 Nov 2009 17:26:34 +0100 Subject: ALSA: opti-miro: expose ACI mixer to outside drivers The ACI mixer is used to control the radio FM module installed on the Miro PCM20 sound card. Expose ACI mixer outside the sound card driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 250 +++++++++++++++++++++++++++-------------------- 1 file changed, 145 insertions(+), 105 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 932a067ef980..40b64cd54c85 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -96,7 +96,6 @@ MODULE_PARM_DESC(ide, "enable ide port"); #define OPTi9XX_MC_REG(n) n - struct snd_miro { unsigned short hardware; unsigned char password; @@ -120,17 +119,11 @@ struct snd_miro { long mpu_port; int mpu_irq; - unsigned long aci_port; - int aci_vendor; - int aci_product; - int aci_version; - int aci_amp; - int aci_preamp; - int aci_solomode; - - struct mutex aci_mutex; + struct snd_miro_aci *aci; }; +static struct snd_miro_aci aci_device; + static char * snd_opti9xx_names[] = { "unkown", "82C928", "82C929", @@ -142,13 +135,14 @@ static char * snd_opti9xx_names[] = { * ACI control */ -static int aci_busy_wait(struct snd_miro * miro) +static int aci_busy_wait(struct snd_miro_aci *aci) { long timeout; unsigned char byte; - for (timeout = 1; timeout <= ACI_MINTIME+30; timeout++) { - if (((byte=inb(miro->aci_port + ACI_REG_BUSY)) & 1) == 0) { + for (timeout = 1; timeout <= ACI_MINTIME + 30; timeout++) { + byte = inb(aci->aci_port + ACI_REG_BUSY); + if ((byte & 1) == 0) { if (timeout >= ACI_MINTIME) snd_printd("aci ready in round %ld.\n", timeout-ACI_MINTIME); @@ -174,10 +168,10 @@ static int aci_busy_wait(struct snd_miro * miro) return -EBUSY; } -static inline int aci_write(struct snd_miro * miro, unsigned char byte) +static inline int aci_write(struct snd_miro_aci *aci, unsigned char byte) { - if (aci_busy_wait(miro) >= 0) { - outb(byte, miro->aci_port + ACI_REG_COMMAND); + if (aci_busy_wait(aci) >= 0) { + outb(byte, aci->aci_port + ACI_REG_COMMAND); return 0; } else { snd_printk(KERN_ERR "aci busy, aci_write(0x%x) stopped.\n", byte); @@ -185,12 +179,12 @@ static inline int aci_write(struct snd_miro * miro, unsigned char byte) } } -static inline int aci_read(struct snd_miro * miro) +static inline int aci_read(struct snd_miro_aci *aci) { unsigned char byte; - if (aci_busy_wait(miro) >= 0) { - byte=inb(miro->aci_port + ACI_REG_STATUS); + if (aci_busy_wait(aci) >= 0) { + byte = inb(aci->aci_port + ACI_REG_STATUS); return byte; } else { snd_printk(KERN_ERR "aci busy, aci_read() stopped.\n"); @@ -198,39 +192,49 @@ static inline int aci_read(struct snd_miro * miro) } } -static int aci_cmd(struct snd_miro * miro, int write1, int write2, int write3) +int snd_aci_cmd(struct snd_miro_aci *aci, int write1, int write2, int write3) { int write[] = {write1, write2, write3}; int value, i; - if (mutex_lock_interruptible(&miro->aci_mutex)) + if (mutex_lock_interruptible(&aci->aci_mutex)) return -EINTR; for (i=0; i<3; i++) { if (write[i]< 0 || write[i] > 255) break; else { - value = aci_write(miro, write[i]); + value = aci_write(aci, write[i]); if (value < 0) goto out; } } - value = aci_read(miro); + value = aci_read(aci); -out: mutex_unlock(&miro->aci_mutex); +out: mutex_unlock(&aci->aci_mutex); return value; } +EXPORT_SYMBOL(snd_aci_cmd); + +static int aci_getvalue(struct snd_miro_aci *aci, unsigned char index) +{ + return snd_aci_cmd(aci, ACI_STATUS, index, -1); +} -static int aci_getvalue(struct snd_miro * miro, unsigned char index) +static int aci_setvalue(struct snd_miro_aci *aci, unsigned char index, + int value) { - return aci_cmd(miro, ACI_STATUS, index, -1); + return snd_aci_cmd(aci, index, value, -1); } -static int aci_setvalue(struct snd_miro * miro, unsigned char index, int value) +struct snd_miro_aci *snd_aci_get_aci(void) { - return aci_cmd(miro, index, value, -1); + if (aci_device.aci_port == 0) + return NULL; + return &aci_device; } +EXPORT_SYMBOL(snd_aci_get_aci); /* * MIXER part @@ -244,8 +248,10 @@ static int snd_miro_get_capture(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if ((value = aci_getvalue(miro, ACI_S_GENERAL)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_S_GENERAL); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_capture() failed: %d\n", + value); return value; } @@ -262,13 +268,15 @@ static int snd_miro_put_capture(struct snd_kcontrol *kcontrol, value = !(ucontrol->value.integer.value[0]); - if ((error = aci_setvalue(miro, ACI_SET_SOLOMODE, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_SOLOMODE, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_capture() failed: %d\n", + error); return error; } - change = (value != miro->aci_solomode); - miro->aci_solomode = value; + change = (value != miro->aci->aci_solomode); + miro->aci->aci_solomode = value; return change; } @@ -290,7 +298,7 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, struct snd_miro *miro = snd_kcontrol_chip(kcontrol); int value; - if (miro->aci_version <= 176) { + if (miro->aci->aci_version <= 176) { /* OSS says it's not readable with versions < 176. @@ -298,12 +306,14 @@ static int snd_miro_get_preamp(struct snd_kcontrol *kcontrol, which is a PCM12 with aci_version = 176. */ - ucontrol->value.integer.value[0] = miro->aci_preamp; + ucontrol->value.integer.value[0] = miro->aci->aci_preamp; return 0; } - if ((value = aci_getvalue(miro, ACI_GET_PREAMP)) < 0) { - snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", value); + value = aci_getvalue(miro->aci, ACI_GET_PREAMP); + if (value < 0) { + snd_printk(KERN_ERR "snd_miro_get_preamp() failed: %d\n", + value); return value; } @@ -320,13 +330,15 @@ static int snd_miro_put_preamp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_PREAMP, value)) < 0) { - snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", error); + error = aci_setvalue(miro->aci, ACI_SET_PREAMP, value); + if (error < 0) { + snd_printk(KERN_ERR "snd_miro_put_preamp() failed: %d\n", + error); return error; } - change = (value != miro->aci_preamp); - miro->aci_preamp = value; + change = (value != miro->aci->aci_preamp); + miro->aci->aci_preamp = value; return change; } @@ -337,7 +349,7 @@ static int snd_miro_get_amp(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); - ucontrol->value.integer.value[0] = miro->aci_amp; + ucontrol->value.integer.value[0] = miro->aci->aci_amp; return 0; } @@ -350,13 +362,14 @@ static int snd_miro_put_amp(struct snd_kcontrol *kcontrol, value = ucontrol->value.integer.value[0]; - if ((error = aci_setvalue(miro, ACI_SET_POWERAMP, value)) < 0) { + error = aci_setvalue(miro->aci, ACI_SET_POWERAMP, value); + if (error < 0) { snd_printk(KERN_ERR "snd_miro_put_amp() to %d failed: %d\n", value, error); return error; } - change = (value != miro->aci_amp); - miro->aci_amp = value; + change = (value != miro->aci->aci_amp); + miro->aci->aci_amp = value; return change; } @@ -405,12 +418,14 @@ static int snd_miro_get_double(struct snd_kcontrol *kcontrol, int right_reg = kcontrol->private_value & 0xff; int left_reg = right_reg + 1; - if ((right_val = aci_getvalue(miro, right_reg)) < 0) { + right_val = aci_getvalue(miro->aci, right_reg); + if (right_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", right_reg, right_val); return right_val; } - if ((left_val = aci_getvalue(miro, left_reg)) < 0) { + left_val = aci_getvalue(miro->aci, left_reg); + if (left_val < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", left_reg, left_val); return left_val; } @@ -446,6 +461,7 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { struct snd_miro *miro = snd_kcontrol_chip(kcontrol); + struct snd_miro_aci *aci = miro->aci; int left, right, left_old, right_old; int setreg_left, setreg_right, getreg_left, getreg_right; int change, error; @@ -461,12 +477,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, getreg_right = kcontrol->private_value & 0xff; getreg_left = getreg_right + 1; - if ((left_old = aci_getvalue(miro, getreg_left)) < 0) { + left_old = aci_getvalue(aci, getreg_left); + if (left_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_left, left_old); return left_old; } - if ((right_old = aci_getvalue(miro, getreg_right)) < 0) { + right_old = aci_getvalue(aci, getreg_right); + if (right_old < 0) { snd_printk(KERN_ERR "aci_getvalue(%d) failed: %d\n", getreg_right, right_old); return right_old; } @@ -485,13 +503,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, right_old = 0x80 - right_old; if (left >= 0) { - if ((error = aci_setvalue(miro, setreg_left, left)) < 0) { + error = aci_setvalue(aci, setreg_left, left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", left, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_left, 0x80 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x80 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - left, error); return error; @@ -499,13 +519,15 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, } if (right >= 0) { - if ((error = aci_setvalue(miro, setreg_right, right)) < 0) { + error = aci_setvalue(aci, setreg_right, right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", right, error); return error; } } else { - if ((error = aci_setvalue(miro, setreg_right, 0x80 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x80 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x80 - right, error); return error; @@ -523,12 +545,14 @@ static int snd_miro_put_double(struct snd_kcontrol *kcontrol, left_old = 0x20 - left_old; right_old = 0x20 - right_old; - if ((error = aci_setvalue(miro, setreg_left, 0x20 - left)) < 0) { + error = aci_setvalue(aci, setreg_left, 0x20 - left); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - left, error); return error; } - if ((error = aci_setvalue(miro, setreg_right, 0x20 - right)) < 0) { + error = aci_setvalue(aci, setreg_right, 0x20 - right); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", 0x20 - right, error); return error; @@ -626,11 +650,13 @@ static unsigned char aci_init_values[][2] __devinitdata = { static int __devinit snd_set_aci_init_values(struct snd_miro *miro) { int idx, error; + struct snd_miro_aci *aci = miro->aci; /* enable WSS on PCM1 */ - if ((miro->aci_product == 'A') && wss) { - if ((error = aci_setvalue(miro, ACI_SET_WSS, wss)) < 0) { + if ((aci->aci_product == 'A') && wss) { + error = aci_setvalue(aci, ACI_SET_WSS, wss); + if (error < 0) { snd_printk(KERN_ERR "enabling WSS mode failed\n"); return error; } @@ -639,7 +665,8 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* enable IDE port */ if (ide) { - if ((error = aci_setvalue(miro, ACI_SET_IDE, ide)) < 0) { + error = aci_setvalue(aci, ACI_SET_IDE, ide); + if (error < 0) { snd_printk(KERN_ERR "enabling IDE port failed\n"); return error; } @@ -647,17 +674,18 @@ static int __devinit snd_set_aci_init_values(struct snd_miro *miro) /* set common aci values */ - for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) - if ((error = aci_setvalue(miro, aci_init_values[idx][0], - aci_init_values[idx][1])) < 0) { + for (idx = 0; idx < ARRAY_SIZE(aci_init_values); idx++) { + error = aci_setvalue(aci, aci_init_values[idx][0], + aci_init_values[idx][1]); + if (error < 0) { snd_printk(KERN_ERR "aci_setvalue(%d) failed: %d\n", aci_init_values[idx][0], error); return error; } - - miro->aci_amp = 0; - miro->aci_preamp = 0; - miro->aci_solomode = 1; + } + aci->aci_amp = 0; + aci->aci_preamp = 0; + aci->aci_solomode = 1; return 0; } @@ -688,7 +716,8 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return err; } - if ((miro->aci_product == 'A') || (miro->aci_product == 'B')) { + if ((miro->aci->aci_product == 'A') || + (miro->aci->aci_product == 'B')) { /* PCM1/PCM12 with power-amp and Line 2 */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_line_control[0], miro))) < 0) return err; @@ -696,16 +725,17 @@ static int __devinit snd_miro_mixer(struct snd_card *card, return err; } - if ((miro->aci_product == 'B') || (miro->aci_product == 'C')) { + if ((miro->aci->aci_product == 'B') || + (miro->aci->aci_product == 'C')) { /* PCM12/PCM20 with mic-preamp */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_preamp_control[0], miro))) < 0) return err; - if (miro->aci_version >= 176) + if (miro->aci->aci_version >= 176) if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_capture_control[0], miro))) < 0) return err; } - if (miro->aci_product == 'C') { + if (miro->aci->aci_product == 'C') { /* PCM20 with radio and 7 band equalizer */ if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_miro_radio_control[0], miro))) < 0) return err; @@ -843,14 +873,15 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, struct snd_info_buffer *buffer) { struct snd_miro *miro = (struct snd_miro *) entry->private_data; + struct snd_miro_aci *aci = miro->aci; char* model = "unknown"; /* miroSOUND PCM1 pro, early PCM12 */ if ((miro->hardware == OPTi9XX_HW_82C929) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'A')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'A')) { + switch (aci->aci_version) { case 3: model = "miroSOUND PCM1 pro"; break; @@ -863,9 +894,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM12, PCM12 (Rev. E), PCM12 pnp */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'B')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'B')) { + switch (aci->aci_version) { case 4: model = "miroSOUND PCM12"; break; @@ -881,9 +912,9 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, /* miroSOUND PCM20 radio */ if ((miro->hardware == OPTi9XX_HW_82C924) && - (miro->aci_vendor == 'm') && - (miro->aci_product == 'C')) { - switch(miro->aci_version) { + (aci->aci_vendor == 'm') && + (aci->aci_product == 'C')) { + switch (aci->aci_version) { case 7: model = "miroSOUND PCM20 radio (Rev. E)"; break; @@ -907,17 +938,17 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "ACI information:\n"); snd_iprintf(buffer, " vendor : "); - switch(miro->aci_vendor) { + switch (aci->aci_vendor) { case 'm': snd_iprintf(buffer, "Miro\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_vendor); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_vendor); break; } snd_iprintf(buffer, " product : "); - switch(miro->aci_product) { + switch (aci->aci_product) { case 'A': snd_iprintf(buffer, "miroSOUND PCM1 pro / (early) PCM12\n"); break; @@ -928,19 +959,19 @@ static void snd_miro_proc_read(struct snd_info_entry * entry, snd_iprintf(buffer, "miroSOUND PCM20 radio\n"); break; default: - snd_iprintf(buffer, "unknown (0x%x)\n", miro->aci_product); + snd_iprintf(buffer, "unknown (0x%x)\n", aci->aci_product); break; } snd_iprintf(buffer, " firmware: %d (0x%x)\n", - miro->aci_version, miro->aci_version); + aci->aci_version, aci->aci_version); snd_iprintf(buffer, " port : 0x%lx-0x%lx\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); snd_iprintf(buffer, " wss : 0x%x\n", wss); snd_iprintf(buffer, " ide : 0x%x\n", ide); - snd_iprintf(buffer, " solomode: 0x%x\n", miro->aci_solomode); - snd_iprintf(buffer, " amp : 0x%x\n", miro->aci_amp); - snd_iprintf(buffer, " preamp : 0x%x\n", miro->aci_preamp); + snd_iprintf(buffer, " solomode: 0x%x\n", aci->aci_solomode); + snd_iprintf(buffer, " amp : 0x%x\n", aci->aci_amp); + snd_iprintf(buffer, " preamp : 0x%x\n", aci->aci_preamp); } static void __devinit snd_miro_proc_init(struct snd_card *card, @@ -1139,46 +1170,53 @@ static int __devinit snd_card_miro_detect(struct snd_card *card, } static int __devinit snd_card_miro_aci_detect(struct snd_card *card, - struct snd_miro * miro) + struct snd_miro *miro) { unsigned char regval; int i; + struct snd_miro_aci *aci = &aci_device; + + miro->aci = aci; - mutex_init(&miro->aci_mutex); + mutex_init(&aci->aci_mutex); /* get ACI port from OPTi9xx MC 4 */ regval=inb(miro->mc_base + 4); - miro->aci_port = (regval & 0x10) ? 0x344: 0x354; + aci->aci_port = (regval & 0x10) ? 0x344 : 0x354; - if ((miro->res_aci_port = request_region(miro->aci_port, 3, "miro aci")) == NULL) { + miro->res_aci_port = request_region(aci->aci_port, 3, "miro aci"); + if (miro->res_aci_port == NULL) { snd_printk(KERN_ERR "aci i/o area 0x%lx-0x%lx already used.\n", - miro->aci_port, miro->aci_port+2); + aci->aci_port, aci->aci_port+2); return -ENOMEM; } /* force ACI into a known state */ for (i = 0; i < 3; i++) - if (aci_cmd(miro, ACI_ERROR_OP, -1, -1) < 0) { + if (snd_aci_cmd(aci, ACI_ERROR_OP, -1, -1) < 0) { snd_printk(KERN_ERR "can't force aci into known state.\n"); return -ENXIO; } - if ((miro->aci_vendor=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0 || - (miro->aci_product=aci_cmd(miro, ACI_READ_IDCODE, -1, -1)) < 0) { - snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", miro->aci_port); + aci->aci_vendor = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + aci->aci_product = snd_aci_cmd(aci, ACI_READ_IDCODE, -1, -1); + if (aci->aci_vendor < 0 || aci->aci_product < 0) { + snd_printk(KERN_ERR "can't read aci id on 0x%lx.\n", + aci->aci_port); return -ENXIO; } - if ((miro->aci_version=aci_cmd(miro, ACI_READ_VERSION, -1, -1)) < 0) { + aci->aci_version = snd_aci_cmd(aci, ACI_READ_VERSION, -1, -1); + if (aci->aci_version < 0) { snd_printk(KERN_ERR "can't read aci version on 0x%lx.\n", - miro->aci_port); + aci->aci_port); return -ENXIO; } - if (aci_cmd(miro, ACI_INIT, -1, -1) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || - aci_cmd(miro, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { + if (snd_aci_cmd(aci, ACI_INIT, -1, -1) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0 || + snd_aci_cmd(aci, ACI_ERROR_OP, ACI_ERROR_OP, ACI_ERROR_OP) < 0) { snd_printk(KERN_ERR "can't initialize aci.\n"); return -ENXIO; } @@ -1191,6 +1229,7 @@ static void snd_card_miro_free(struct snd_card *card) struct snd_miro *miro = card->private_data; release_and_free_resource(miro->res_aci_port); + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } @@ -1250,7 +1289,6 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) } miro->wss_base = port; - miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; @@ -1272,6 +1310,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return -EBUSY; } } + miro->mpu_port = mpu_port; + if (miro->irq == SNDRV_AUTO_IRQ) { if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { snd_card_free(card); @@ -1339,9 +1379,9 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return error; } - if (miro->aci_vendor == 'm') { + if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ - switch (miro->aci_product) { + switch (miro->aci->aci_product) { case 'A': sprintf(card->shortname, "miroSOUND PCM1 pro / PCM12"); -- cgit v1.2.3 From 88cdca9c7376f2220171d09dfc2f9e41b4834435 Mon Sep 17 00:00:00 2001 From: Russell King Date: Mon, 23 Nov 2009 09:44:10 +0100 Subject: ALSA: AACI cleanup Fix the buffer size calculation to use the size which ALSA is expecting. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d5..a03fe80a7a73 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -18,10 +18,7 @@ #include #include #include - -#include -#include -#include +#include #include #include @@ -534,7 +531,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream) struct aaci_runtime *aacirun = runtime->private_data; aacirun->start = (void *)runtime->dma_area; - aacirun->end = aacirun->start + runtime->dma_bytes; + aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); aacirun->ptr = aacirun->start; aacirun->period = aacirun->bytes = frames_to_bytes(runtime, runtime->period_size); -- cgit v1.2.3 From 83dd7408b59c1945069199d712df8c7c64a76e1f Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 24 Nov 2009 08:57:53 +0100 Subject: Revert "ALSA: hda - Change quirk for Acer Aspire 5930G" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit f2624791a0c2a2d7664b12d75ca327917141fd3b. Łukasz Wojniłowicz reported that the change causes both internal and external mics not working any more. The headphone jacking issue was fixed by his previous patch, it's better to revert to acer-aspire-4930g model. Reported-by: Łukasz Wojniłowicz Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index eedbe19306a0..7e8b17a1769a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8756,7 +8756,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x013e, "Acer Aspire 4930G", ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", - ALC888_ACER_ASPIRE_6530G), + ALC888_ACER_ASPIRE_4930G), SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", ALC888_ACER_ASPIRE_8930G), SND_PCI_QUIRK(0x1025, 0x0146, "Acer Aspire 6935G", -- cgit v1.2.3 From 95a618bdac29c7b0f1a516aec9fc37626dec1af9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Einar=20R=C3=BCnkaru?= Date: Mon, 23 Nov 2009 22:23:49 +0200 Subject: ALSA: hda - Make Dell Vostro 1015n mic and speaker switching work MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dell Vostro 1015n uses Conexant CX20583-10Z (0x14f1:5067). Patch is based on "olpc-xo-1_5" branch. Dell uses digital mic. Signed-off-by: Einar Rünkaru Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 134 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 0b097fa5421f..36dd5a6bf874 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -2009,6 +2009,46 @@ static void cxt5066_automic(struct hda_codec *codec) } } +/* toggle input of built-in digital mic and mic jack appropriately */ +static void cxt5066_vostro_automic(struct hda_codec *codec) +{ + struct conexant_spec *spec = codec->spec; + unsigned int present; + + struct hda_verb ext_mic_present[] = { + /* enable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, + + /* switch to external mic input */ + {0x17, AC_VERB_SET_CONNECT_SEL, 0}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0}, + + /* disable internal digital mic */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + static struct hda_verb ext_mic_absent[] = { + /* enable internal mic, port C */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* switch to internal mic input */ + {0x14, AC_VERB_SET_CONNECT_SEL, 2}, + + /* disable external mic, port B */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {} + }; + + present = snd_hda_jack_detect(codec, 0x1a); + if (present) { + snd_printdd("CXT5066: external microphone detected\n"); + snd_hda_sequence_write(codec, ext_mic_present); + } else { + snd_printdd("CXT5066: external microphone absent\n"); + snd_hda_sequence_write(codec, ext_mic_absent); + } +} + /* mute internal speaker if HP is plugged */ static void cxt5066_hp_automute(struct hda_codec *codec) { @@ -2041,6 +2081,20 @@ static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) } } +/* unsolicited event for jack sensing */ +static void cxt5066_vostro_event(struct hda_codec *codec, unsigned int res) +{ + snd_printdd("CXT5066_vostro: unsol event %x (%x)\n", res, res >> 26); + switch (res >> 26) { + case CONEXANT_HP_EVENT: + cxt5066_hp_automute(codec); + break; + case CONEXANT_MIC_EVENT: + cxt5066_vostro_automic(codec); + break; + } +} + static const struct hda_input_mux cxt5066_analog_mic_boost = { .num_items = 5, .items = { @@ -2282,6 +2336,67 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { { } /* end */ }; +static struct hda_verb cxt5066_init_verbs_vostro[] = { + /* Port A: headphones */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ + + /* Port B: external microphone */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, + + /* Port C: unused */ + {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: unused */ + {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_MUTE(0)}, + {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)}, + + /* Digital microphone port */ + {0x23, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + + /* 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 struct hda_verb cxt5066_init_verbs_portd_lo[] = { {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, { } /* end */ @@ -2303,6 +2418,7 @@ enum { CXT5066_LAPTOP, /* Laptops w/ EAPD support */ CXT5066_DELL_LAPTOP, /* Dell Laptop */ CXT5066_OLPC_XO_1_5, /* OLPC XO 1.5 */ + CXT5066_DELL_VOSTO, /* Dell Vostro 1015i */ CXT5066_MODELS }; @@ -2310,6 +2426,7 @@ static const char *cxt5066_models[CXT5066_MODELS] = { [CXT5066_LAPTOP] = "laptop", [CXT5066_DELL_LAPTOP] = "dell-laptop", [CXT5066_OLPC_XO_1_5] = "olpc-xo-1_5", + [CXT5066_DELL_VOSTO] = "dell-vostro" }; static struct snd_pci_quirk cxt5066_cfg_tbl[] = { @@ -2318,6 +2435,7 @@ static struct snd_pci_quirk cxt5066_cfg_tbl[] = { SND_PCI_QUIRK(0x1028, 0x02f5, "Dell", CXT5066_DELL_LAPTOP), SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT5066_OLPC_XO_1_5), + SND_PCI_QUIRK(0x1028, 0x0402, "Dell Vostro", CXT5066_DELL_VOSTO), {} }; @@ -2382,6 +2500,19 @@ static int patch_cxt5066(struct hda_codec *codec) /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ + spec->input_mux = NULL; + break; + case CXT5066_DELL_VOSTO: + codec->patch_ops.unsol_event = cxt5066_vostro_event; + spec->init_verbs[0] = cxt5066_init_verbs_vostro; + spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; + spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->port_d_mode = 0; + + /* no S/PDIF out */ + spec->multiout.dig_out_nid = 0; + /* input source automatically selected */ spec->input_mux = NULL; break; @@ -2402,6 +2533,8 @@ static struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_cxt5051 }, { .id = 0x14f15066, .name = "CX20582 (Pebble)", .patch = patch_cxt5066 }, + { .id = 0x14f15067, .name = "CX20583 (Pebble HSF)", + .patch = patch_cxt5066 }, {} /* terminator */ }; @@ -2409,6 +2542,7 @@ MODULE_ALIAS("snd-hda-codec-id:14f15045"); MODULE_ALIAS("snd-hda-codec-id:14f15047"); MODULE_ALIAS("snd-hda-codec-id:14f15051"); MODULE_ALIAS("snd-hda-codec-id:14f15066"); +MODULE_ALIAS("snd-hda-codec-id:14f15067"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); -- cgit v1.2.3 From 96f61d9ade82f3e9503df36809175325e8f5eaca Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Thu, 22 Oct 2009 09:06:19 +0200 Subject: sound: usb-audio: allow switching altsetting on Roland USB MIDI devices Add a mixer control to select between the two altsettings on Roland USB MIDI devices where the input endpoint is either bulk or interrupt. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbmidi.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 106 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index e5b068996371..80b2845bc486 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -1,7 +1,7 @@ /* * usbmidi.c - ALSA USB MIDI driver * - * Copyright (c) 2002-2007 Clemens Ladisch + * Copyright (c) 2002-2009 Clemens Ladisch * All rights reserved. * * Based on the OSS usb-midi driver by NAGANO Daisuke, @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include "usbaudio.h" @@ -109,13 +110,17 @@ struct snd_usb_midi { struct list_head list; struct timer_list error_timer; spinlock_t disc_lock; + struct mutex mutex; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; struct snd_usb_midi_in_endpoint *in; } endpoints[MIDI_MAX_ENDPOINTS]; unsigned long input_triggered; + unsigned int opened; unsigned char disconnected; + + struct snd_kcontrol *roland_load_ctl; }; struct snd_usb_midi_out_endpoint { @@ -879,6 +884,50 @@ static struct usb_protocol_ops snd_usbmidi_emagic_ops = { }; +static void update_roland_altsetting(struct snd_usb_midi* umidi) +{ + struct usb_interface *intf; + struct usb_host_interface *hostif; + struct usb_interface_descriptor *intfd; + int is_light_load; + + intf = umidi->iface; + is_light_load = intf->cur_altsetting != intf->altsetting; + if (umidi->roland_load_ctl->private_value == is_light_load) + return; + hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; + intfd = get_iface_desc(hostif); + snd_usbmidi_input_stop(&umidi->list); + usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + intfd->bAlternateSetting); + snd_usbmidi_input_start(&umidi->list); +} + +static void substream_open(struct snd_rawmidi_substream *substream, int open) +{ + struct snd_usb_midi* umidi = substream->rmidi->private_data; + struct snd_kcontrol *ctl; + + mutex_lock(&umidi->mutex); + if (open) { + if (umidi->opened++ == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + update_roland_altsetting(umidi); + } + } else { + if (--umidi->opened == 0 && umidi->roland_load_ctl) { + ctl = umidi->roland_load_ctl; + ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; + snd_ctl_notify(umidi->chip->card, + SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); + } + } + mutex_unlock(&umidi->mutex); +} + static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) { struct snd_usb_midi* umidi = substream->rmidi->private_data; @@ -898,11 +947,13 @@ static int snd_usbmidi_output_open(struct snd_rawmidi_substream *substream) } substream->runtime->private_data = port; port->state = STATE_UNKNOWN; + substream_open(substream, 1); return 0; } static int snd_usbmidi_output_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -954,11 +1005,13 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) static int snd_usbmidi_input_open(struct snd_rawmidi_substream *substream) { + substream_open(substream, 1); return 0; } static int snd_usbmidi_input_close(struct snd_rawmidi_substream *substream) { + substream_open(substream, 0); return 0; } @@ -1163,6 +1216,7 @@ static void snd_usbmidi_free(struct snd_usb_midi* umidi) if (ep->in) snd_usbmidi_in_endpoint_delete(ep->in); } + mutex_destroy(&umidi->mutex); kfree(umidi); } @@ -1524,6 +1578,52 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, return 0; } +static int roland_load_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *info) +{ + static const char *const names[] = { "High Load", "Light Load" }; + + info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; + info->count = 1; + info->value.enumerated.items = 2; + if (info->value.enumerated.item > 1) + info->value.enumerated.item = 1; + strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); + return 0; +} + +static int roland_load_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + value->value.enumerated.item[0] = kcontrol->private_value; + return 0; +} + +static int roland_load_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *value) +{ + struct snd_usb_midi* umidi = kcontrol->private_data; + int changed; + + if (value->value.enumerated.item[0] > 1) + return -EINVAL; + mutex_lock(&umidi->mutex); + changed = value->value.enumerated.item[0] != kcontrol->private_value; + if (changed) + kcontrol->private_value = value->value.enumerated.item[0]; + mutex_unlock(&umidi->mutex); + return changed; +} + +static struct snd_kcontrol_new roland_load_ctl = { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "MIDI Input Mode", + .info = roland_load_info, + .get = roland_load_get, + .put = roland_load_put, + .private_value = 1, +}; + /* * On Roland devices, use the second alternate setting to be able to use * the interrupt input endpoint. @@ -1549,6 +1649,10 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) intfd->bAlternateSetting); usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); + + umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); + if (snd_ctl_add(umidi->chip->card, umidi->roland_load_ctl) < 0) + umidi->roland_load_ctl = NULL; } /* @@ -1834,6 +1938,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); + mutex_init(&umidi->mutex); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; -- cgit v1.2.3 From d82af9f9aab69e82b86450272588c861364f8879 Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 16 Nov 2009 12:23:46 +0100 Subject: sound: usb: make the USB MIDI module more independent Remove the dependecy from the USB MIDI code on the snd_usb_audio structure. This allows using the USB MIDI module from another driver without having to pretend to be the generic USB audio driver. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usbaudio.c | 38 +++++++++------- sound/usb/usbaudio.h | 7 +-- sound/usb/usbmidi.c | 96 ++++++++++++++++++++++------------------- sound/usb/usx2y/us122l.c | 22 +++++----- sound/usb/usx2y/us122l.h | 1 + sound/usb/usx2y/usX2Yhwdep.c | 2 +- sound/usb/usx2y/usbusx2y.c | 4 +- sound/usb/usx2y/usbusx2y.h | 1 + sound/usb/usx2y/usbusx2yaudio.c | 4 +- 9 files changed, 96 insertions(+), 79 deletions(-) (limited to 'sound') diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 8db0374e10d5..b074a594c595 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2893,7 +2893,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { - if (snd_usb_create_midi_interface(chip, iface, NULL) < 0) { + int err = snd_usbmidi_create(chip->card, iface, + &chip->midi_list, NULL); + if (err < 0) { snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); continue; } @@ -3038,12 +3040,11 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &uaxx_ep }; - if (chip->usb_id == USB_ID(0x0582, 0x002b)) - return snd_usb_create_midi_interface(chip, iface, - &ua700_quirk); - else - return snd_usb_create_midi_interface(chip, iface, - &uaxx_quirk); + const struct snd_usb_audio_quirk *quirk = + chip->usb_id == USB_ID(0x0582, 0x002b) + ? &ua700_quirk : &uaxx_quirk; + return snd_usbmidi_create(chip->card, iface, + &chip->midi_list, quirk); } if (altsd->bNumEndpoints != 1) @@ -3370,6 +3371,13 @@ static int audiophile_skip_setting_quirk(struct snd_usb_audio *chip, return 0; /* keep this altsetting */ } +static int create_any_midi_quirk(struct snd_usb_audio *chip, + struct usb_interface *intf, + const struct snd_usb_audio_quirk *quirk) +{ + return snd_usbmidi_create(chip->card, intf, &chip->midi_list, quirk); +} + /* * audio-interface quirks * @@ -3387,14 +3395,14 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, static const quirk_func_t quirk_funcs[] = { [QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk, [QUIRK_COMPOSITE] = create_composite_quirk, - [QUIRK_MIDI_STANDARD_INTERFACE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FIXED_ENDPOINT] = snd_usb_create_midi_interface, - [QUIRK_MIDI_YAMAHA] = snd_usb_create_midi_interface, - [QUIRK_MIDI_MIDIMAN] = snd_usb_create_midi_interface, - [QUIRK_MIDI_NOVATION] = snd_usb_create_midi_interface, - [QUIRK_MIDI_FASTLANE] = snd_usb_create_midi_interface, - [QUIRK_MIDI_EMAGIC] = snd_usb_create_midi_interface, - [QUIRK_MIDI_CME] = snd_usb_create_midi_interface, + [QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk, + [QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk, + [QUIRK_MIDI_YAMAHA] = create_any_midi_quirk, + [QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk, + [QUIRK_MIDI_NOVATION] = create_any_midi_quirk, + [QUIRK_MIDI_FASTLANE] = create_any_midi_quirk, + [QUIRK_MIDI_EMAGIC] = create_any_midi_quirk, + [QUIRK_MIDI_CME] = create_any_midi_quirk, [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index e9a3a9dca15c..40ba8115fb81 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -132,7 +132,6 @@ struct snd_usb_audio { int pcm_devs; struct list_head midi_list; /* list of midi interfaces */ - int next_midi_device; struct list_head mixer_list; /* list of mixer interfaces */ }; @@ -227,8 +226,10 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, int ignore_error); void snd_usb_mixer_disconnect(struct list_head *p); -int snd_usb_create_midi_interface(struct snd_usb_audio *chip, struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk); +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface *iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk *quirk); void snd_usbmidi_input_stop(struct list_head* p); void snd_usbmidi_input_start(struct list_head* p); void snd_usbmidi_disconnect(struct list_head *p); diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index 80b2845bc486..6e89b8368d9a 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c @@ -102,7 +102,8 @@ struct usb_protocol_ops { }; struct snd_usb_midi { - struct snd_usb_audio *chip; + struct usb_device *dev; + struct snd_card *card; struct usb_interface *iface; const struct snd_usb_audio_quirk *quirk; struct snd_rawmidi *rmidi; @@ -111,6 +112,8 @@ struct snd_usb_midi { struct timer_list error_timer; spinlock_t disc_lock; struct mutex mutex; + u32 usb_id; + int next_midi_device; struct snd_usb_midi_endpoint { struct snd_usb_midi_out_endpoint *out; @@ -260,7 +263,7 @@ static void snd_usbmidi_in_urb_complete(struct urb* urb) } } - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_ATOMIC); } @@ -301,7 +304,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) unsigned long flags; spin_lock_irqsave(&ep->buffer_lock, flags); - if (ep->umidi->chip->shutdown) { + if (ep->umidi->disconnected) { spin_unlock_irqrestore(&ep->buffer_lock, flags); return; } @@ -317,7 +320,7 @@ static void snd_usbmidi_do_output(struct snd_usb_midi_out_endpoint* ep) dump_urb("sending", urb->transfer_buffer, urb->transfer_buffer_length); - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; if (snd_usbmidi_submit_urb(urb, GFP_ATOMIC) < 0) break; ep->active_urbs |= 1 << urb_index; @@ -354,7 +357,7 @@ static void snd_usbmidi_error_timer(unsigned long data) if (in && in->error_resubmit) { in->error_resubmit = 0; for (j = 0; j < INPUT_URBS; ++j) { - in->urbs[j]->dev = umidi->chip->dev; + in->urbs[j]->dev = umidi->dev; snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC); } } @@ -374,7 +377,7 @@ static int send_bulk_static_data(struct snd_usb_midi_out_endpoint* ep, return -ENOMEM; dump_urb("sending", buf, len); if (ep->urbs[0].urb) - err = usb_bulk_msg(ep->umidi->chip->dev, ep->urbs[0].urb->pipe, + err = usb_bulk_msg(ep->umidi->dev, ep->urbs[0].urb->pipe, buf, len, NULL, 250); kfree(buf); return err; @@ -729,8 +732,7 @@ static void snd_usbmidi_us122l_output(struct snd_usb_midi_out_endpoint *ep, if (!ep->ports[0].active) return; - count = snd_usb_get_speed(ep->umidi->chip->dev) == USB_SPEED_HIGH - ? 1 : 2; + count = snd_usb_get_speed(ep->umidi->dev) == USB_SPEED_HIGH ? 1 : 2; count = snd_rawmidi_transmit(ep->ports[0].substream, urb->transfer_buffer, count); @@ -898,7 +900,7 @@ static void update_roland_altsetting(struct snd_usb_midi* umidi) hostif = &intf->altsetting[umidi->roland_load_ctl->private_value]; intfd = get_iface_desc(hostif); snd_usbmidi_input_stop(&umidi->list); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); snd_usbmidi_input_start(&umidi->list); } @@ -913,7 +915,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) if (umidi->opened++ == 0 && umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; ctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->chip->card, + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); update_roland_altsetting(umidi); } @@ -921,7 +923,7 @@ static void substream_open(struct snd_rawmidi_substream *substream, int open) if (--umidi->opened == 0 && umidi->roland_load_ctl) { ctl = umidi->roland_load_ctl; ctl->vd[0].access &= ~SNDRV_CTL_ELEM_ACCESS_INACTIVE; - snd_ctl_notify(umidi->chip->card, + snd_ctl_notify(umidi->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); } } @@ -963,7 +965,7 @@ static void snd_usbmidi_output_trigger(struct snd_rawmidi_substream *substream, port->active = up; if (up) { - if (port->ep->umidi->chip->shutdown) { + if (port->ep->umidi->disconnected) { /* gobble up remaining bytes to prevent wait in * snd_rawmidi_drain_output */ while (!snd_rawmidi_transmit_empty(substream)) @@ -1041,7 +1043,7 @@ static struct snd_rawmidi_ops snd_usbmidi_input_ops = { static void free_urb_and_buffer(struct snd_usb_midi *umidi, struct urb *urb, unsigned int buffer_length) { - usb_buffer_free(umidi->chip->dev, buffer_length, + usb_buffer_free(umidi->dev, buffer_length, urb->transfer_buffer, urb->transfer_dma); usb_free_urb(urb); } @@ -1088,24 +1090,24 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, } } if (ep_info->in_interval) - pipe = usb_rcvintpipe(umidi->chip->dev, ep_info->in_ep); + pipe = usb_rcvintpipe(umidi->dev, ep_info->in_ep); else - pipe = usb_rcvbulkpipe(umidi->chip->dev, ep_info->in_ep); - length = usb_maxpacket(umidi->chip->dev, pipe, 0); + pipe = usb_rcvbulkpipe(umidi->dev, ep_info->in_ep); + length = usb_maxpacket(umidi->dev, pipe, 0); for (i = 0; i < INPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, length, GFP_KERNEL, + buffer = usb_buffer_alloc(umidi->dev, length, GFP_KERNEL, &ep->urbs[i]->transfer_dma); if (!buffer) { snd_usbmidi_in_endpoint_delete(ep); return -ENOMEM; } if (ep_info->in_interval) - usb_fill_int_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep, ep_info->in_interval); else - usb_fill_bulk_urb(ep->urbs[i], umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i], umidi->dev, pipe, buffer, length, snd_usbmidi_in_urb_complete, ep); ep->urbs[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP; @@ -1157,15 +1159,15 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, ep->urbs[i].ep = ep; } if (ep_info->out_interval) - pipe = usb_sndintpipe(umidi->chip->dev, ep_info->out_ep); + pipe = usb_sndintpipe(umidi->dev, ep_info->out_ep); else - pipe = usb_sndbulkpipe(umidi->chip->dev, ep_info->out_ep); - if (umidi->chip->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ + pipe = usb_sndbulkpipe(umidi->dev, ep_info->out_ep); + if (umidi->usb_id == USB_ID(0x0a92, 0x1020)) /* ESI M4U */ ep->max_transfer = 4; else - ep->max_transfer = usb_maxpacket(umidi->chip->dev, pipe, 1); + ep->max_transfer = usb_maxpacket(umidi->dev, pipe, 1); for (i = 0; i < OUTPUT_URBS; ++i) { - buffer = usb_buffer_alloc(umidi->chip->dev, + buffer = usb_buffer_alloc(umidi->dev, ep->max_transfer, GFP_KERNEL, &ep->urbs[i].urb->transfer_dma); if (!buffer) { @@ -1173,12 +1175,12 @@ static int snd_usbmidi_out_endpoint_create(struct snd_usb_midi* umidi, return -ENOMEM; } if (ep_info->out_interval) - usb_fill_int_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_int_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i], ep_info->out_interval); else - usb_fill_bulk_urb(ep->urbs[i].urb, umidi->chip->dev, + usb_fill_bulk_urb(ep->urbs[i].urb, umidi->dev, pipe, buffer, ep->max_transfer, snd_usbmidi_out_urb_complete, &ep->urbs[i]); @@ -1412,7 +1414,7 @@ static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) int i; for (i = 0; i < ARRAY_SIZE(snd_usbmidi_port_info); ++i) { - if (snd_usbmidi_port_info[i].id == umidi->chip->usb_id && + if (snd_usbmidi_port_info[i].id == umidi->usb_id && snd_usbmidi_port_info[i].port == number) return &snd_usbmidi_port_info[i]; } @@ -1450,7 +1452,7 @@ static void snd_usbmidi_init_substream(struct snd_usb_midi* umidi, port_info = find_port_info(umidi, number); name_format = port_info ? port_info->name : "%s MIDI %d"; snprintf(substream->name, sizeof(substream->name), - name_format, umidi->chip->card->shortname, number + 1); + name_format, umidi->card->shortname, number + 1); *rsubstream = substream; } @@ -1548,7 +1550,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].out_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].out_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) /* * Low speed bulk transfers don't exist, so * force interrupt transfers for devices like @@ -1568,7 +1570,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, endpoints[epidx].in_ep = usb_endpoint_num(ep); if (usb_endpoint_xfer_int(ep)) endpoints[epidx].in_interval = ep->bInterval; - else if (snd_usb_get_speed(umidi->chip->dev) == USB_SPEED_LOW) + else if (snd_usb_get_speed(umidi->dev) == USB_SPEED_LOW) endpoints[epidx].in_interval = 1; endpoints[epidx].in_cables = (1 << ms_ep->bNumEmbMIDIJack) - 1; snd_printdd(KERN_INFO "EP %02X: %d jack(s)\n", @@ -1647,11 +1649,11 @@ static void snd_usbmidi_switch_roland_altsetting(struct snd_usb_midi* umidi) snd_printdd(KERN_INFO "switching to altsetting %d with int ep\n", intfd->bAlternateSetting); - usb_set_interface(umidi->chip->dev, intfd->bInterfaceNumber, + usb_set_interface(umidi->dev, intfd->bInterfaceNumber, intfd->bAlternateSetting); umidi->roland_load_ctl = snd_ctl_new1(&roland_load_ctl, umidi); - if (snd_ctl_add(umidi->chip->card, umidi->roland_load_ctl) < 0) + if (snd_ctl_add(umidi->card, umidi->roland_load_ctl) < 0) umidi->roland_load_ctl = NULL; } @@ -1668,7 +1670,7 @@ static int snd_usbmidi_detect_endpoints(struct snd_usb_midi* umidi, struct usb_endpoint_descriptor* epd; int i, out_eps = 0, in_eps = 0; - if (USB_ID_VENDOR(umidi->chip->usb_id) == 0x0582) + if (USB_ID_VENDOR(umidi->usb_id) == 0x0582) snd_usbmidi_switch_roland_altsetting(umidi); if (endpoint[0].out_ep || endpoint[0].in_ep) @@ -1855,12 +1857,12 @@ static int snd_usbmidi_create_rawmidi(struct snd_usb_midi* umidi, struct snd_rawmidi *rmidi; int err; - err = snd_rawmidi_new(umidi->chip->card, "USB MIDI", - umidi->chip->next_midi_device++, + err = snd_rawmidi_new(umidi->card, "USB MIDI", + umidi->next_midi_device++, out_ports, in_ports, &rmidi); if (err < 0) return err; - strcpy(rmidi->name, umidi->chip->card->shortname); + strcpy(rmidi->name, umidi->card->shortname); rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX; @@ -1899,7 +1901,7 @@ static void snd_usbmidi_input_start_ep(struct snd_usb_midi_in_endpoint* ep) return; for (i = 0; i < INPUT_URBS; ++i) { struct urb* urb = ep->urbs[i]; - urb->dev = ep->umidi->chip->dev; + urb->dev = ep->umidi->dev; snd_usbmidi_submit_urb(urb, GFP_KERNEL); } } @@ -1920,9 +1922,10 @@ void snd_usbmidi_input_start(struct list_head* p) /* * Creates and registers everything needed for a MIDI streaming interface. */ -int snd_usb_create_midi_interface(struct snd_usb_audio* chip, - struct usb_interface* iface, - const struct snd_usb_audio_quirk* quirk) +int snd_usbmidi_create(struct snd_card *card, + struct usb_interface* iface, + struct list_head *midi_list, + const struct snd_usb_audio_quirk* quirk) { struct snd_usb_midi* umidi; struct snd_usb_midi_endpoint_info endpoints[MIDI_MAX_ENDPOINTS]; @@ -1932,13 +1935,16 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, umidi = kzalloc(sizeof(*umidi), GFP_KERNEL); if (!umidi) return -ENOMEM; - umidi->chip = chip; + umidi->dev = interface_to_usbdev(iface); + umidi->card = card; umidi->iface = iface; umidi->quirk = quirk; umidi->usb_protocol_ops = &snd_usbmidi_standard_ops; init_timer(&umidi->error_timer); spin_lock_init(&umidi->disc_lock); mutex_init(&umidi->mutex); + umidi->usb_id = USB_ID(le16_to_cpu(umidi->dev->descriptor.idVendor), + le16_to_cpu(umidi->dev->descriptor.idProduct)); umidi->error_timer.function = snd_usbmidi_error_timer; umidi->error_timer.data = (unsigned long)umidi; @@ -1947,7 +1953,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, switch (quirk ? quirk->type : QUIRK_MIDI_STANDARD_INTERFACE) { case QUIRK_MIDI_STANDARD_INTERFACE: err = snd_usbmidi_get_ms_info(umidi, endpoints); - if (chip->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ + if (umidi->usb_id == USB_ID(0x0763, 0x0150)) /* M-Audio Uno */ umidi->usb_protocol_ops = &snd_usbmidi_maudio_broken_running_status_ops; break; @@ -1983,7 +1989,7 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, * interface 0, so we have to make sure that the USB core looks * again at interface 0 by calling usb_set_interface() on it. */ - usb_set_interface(umidi->chip->dev, 0, 0); + usb_set_interface(umidi->dev, 0, 0); err = snd_usbmidi_detect_per_port_endpoints(umidi, endpoints); break; case QUIRK_MIDI_EMAGIC: @@ -2029,14 +2035,14 @@ int snd_usb_create_midi_interface(struct snd_usb_audio* chip, return err; } - list_add(&umidi->list, &umidi->chip->midi_list); + list_add_tail(&umidi->list, midi_list); for (i = 0; i < MIDI_MAX_ENDPOINTS; ++i) snd_usbmidi_input_start_ep(umidi->endpoints[i].in); return 0; } -EXPORT_SYMBOL(snd_usb_create_midi_interface); +EXPORT_SYMBOL(snd_usbmidi_create); EXPORT_SYMBOL(snd_usbmidi_input_stop); EXPORT_SYMBOL(snd_usbmidi_input_start); EXPORT_SYMBOL(snd_usbmidi_disconnect); diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 00cd54c236b4..0ad061e5728b 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -62,8 +62,8 @@ static int us122l_create_usbmidi(struct snd_card *card) struct usb_device *dev = US122L(card)->chip.dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } static int us144_create_usbmidi(struct snd_card *card) @@ -84,8 +84,8 @@ static int us144_create_usbmidi(struct snd_card *card) struct usb_device *dev = US122L(card)->chip.dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); - return snd_usb_create_midi_interface(&US122L(card)->chip, - iface, &quirk); + return snd_usbmidi_create(card, iface, + &US122L(card)->midi_list, &quirk); } /* @@ -297,7 +297,7 @@ static unsigned int usb_stream_hwdep_poll(struct snd_hwdep *hw, static void us122l_stop(struct us122l *us122l) { struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); usb_stream_stop(&us122l->sk); @@ -363,7 +363,7 @@ static bool us122l_start(struct us122l *us122l, snd_printk(KERN_ERR "us122l_start error %i \n", err); goto out; } - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); success = true; out: @@ -508,7 +508,7 @@ static bool us122l_create_card(struct snd_card *card) if (err < 0) { /* release the midi resources */ struct list_head *p; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_disconnect(p); us122l_stop(us122l); @@ -546,7 +546,7 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) US122L(card)->chip.card = card; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); - INIT_LIST_HEAD(&US122L(card)->chip.midi_list); + INIT_LIST_HEAD(&US122L(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -638,7 +638,7 @@ static void snd_us122l_disconnect(struct usb_interface *intf) us122l->chip.shutdown = 1; /* release the midi resources */ - list_for_each(p, &us122l->chip.midi_list) { + list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } @@ -667,7 +667,7 @@ static int snd_us122l_suspend(struct usb_interface *intf, pm_message_t message) if (!us122l) return 0; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_stop(p); mutex_lock(&us122l->mutex); @@ -720,7 +720,7 @@ static int snd_us122l_resume(struct usb_interface *intf) if (err) goto unlock; - list_for_each(p, &us122l->chip.midi_list) + list_for_each(p, &us122l->midi_list) snd_usbmidi_input_start(p); unlock: mutex_unlock(&us122l->mutex); diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 3d10c4b2a0f5..61ce5d7de0b9 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -12,6 +12,7 @@ struct us122l { unsigned second_periods_polled; struct file *master; struct file *slave; + struct list_head midi_list; atomic_t mmap_count; }; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index 52e04b2f35d3..f96ab86259d0 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -171,7 +171,7 @@ static int usX2Y_create_usbmidi(struct snd_card *card) &quirk_2 : &quirk_1; snd_printdd("usX2Y_create_usbmidi \n"); - return snd_usb_create_midi_interface(&usX2Y(card)->chip, iface, quirk); + return snd_usbmidi_create(card, iface, &usX2Y(card)->midi_list, quirk); } static int usX2Y_create_alsa_devices(struct snd_card *card) diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index cb4bb8373ca2..181337090e48 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -354,7 +354,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) usX2Y(card)->chip.card = card; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); - INIT_LIST_HEAD(&usX2Y(card)->chip.midi_list); + INIT_LIST_HEAD(&usX2Y(card)->midi_list); strcpy(card->driver, "USB "NAME_ALLCAPS""); sprintf(card->shortname, "TASCAM "NAME_ALLCAPS""); sprintf(card->longname, "%s (%x:%x if %d at %03d/%03d)", @@ -451,7 +451,7 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) usb_kill_urb(usX2Y->In04urb); snd_card_disconnect(card); /* release the midi resources */ - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_disconnect(p); } if (usX2Y->us428ctls_sharedmem) diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 456b5fdbc339..231866ea3491 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -42,6 +42,7 @@ struct usX2Ydev { struct snd_usX2Y_substream *subs[4]; struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; + struct list_head midi_list; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index 9efd27f6b52f..b8e2f4691493 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -740,7 +740,7 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) alternate = 1; usX2Y->stride = 4; } - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); @@ -750,7 +750,7 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) } usX2Y->In04urb->dev = usX2Y->chip.dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); - list_for_each(p, &usX2Y->chip.midi_list) { + list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); } usX2Y->format = format; -- cgit v1.2.3 From a014bbadb53121e243cac254593e79e3ca89742d Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Mon, 16 Nov 2009 12:26:30 +0100 Subject: sound: usxxx: cleanup chip field The chip field is no longer needed. Move those of its fields that are actually used to the device structure itself. Signed-off-by: Clemens Ladisch Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 68 ++++++++++++++++++++--------------------- sound/usb/usx2y/us122l.h | 3 +- sound/usb/usx2y/usX2Yhwdep.c | 6 ++-- sound/usb/usx2y/usbusx2y.c | 24 +++++++-------- sound/usb/usx2y/usbusx2y.h | 5 ++- sound/usb/usx2y/usbusx2yaudio.c | 30 +++++++++--------- sound/usb/usx2y/usx2yhwdeppcm.c | 8 ++--- 7 files changed, 72 insertions(+), 72 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 0ad061e5728b..f71cd28eca6b 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -59,7 +59,7 @@ static int us122l_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 1); return snd_usbmidi_create(card, iface, @@ -81,7 +81,7 @@ static int us144_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_US122L, .data = &quirk_data }; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); return snd_usbmidi_create(card, iface, @@ -194,11 +194,11 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - iface = usb_ifnum_to_if(us122l->chip.dev, 0); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_get_interface(iface); return 0; } @@ -209,11 +209,11 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - iface = usb_ifnum_to_if(us122l->chip.dev, 0); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } - iface = usb_ifnum_to_if(us122l->chip.dev, 1); + iface = usb_ifnum_to_if(us122l->dev, 1); usb_autopm_put_interface(iface); if (us122l->first == file) us122l->first = NULL; @@ -330,7 +330,7 @@ static bool us122l_start(struct us122l *us122l, unsigned use_packsize = 0; bool success = false; - if (us122l->chip.dev->speed == USB_SPEED_HIGH) { + if (us122l->dev->speed == USB_SPEED_HIGH) { /* The us-122l's descriptor defaults to iso max_packsize 78, which isn't needed for samplerates <= 48000. Lets save some memory: @@ -347,11 +347,11 @@ static bool us122l_start(struct us122l *us122l, break; } } - if (!usb_stream_new(&us122l->sk, us122l->chip.dev, 1, 2, + if (!usb_stream_new(&us122l->sk, us122l->dev, 1, 2, rate, use_packsize, period_frames, 6)) goto out; - err = us122l_set_sample_rate(us122l->chip.dev, rate); + err = us122l_set_sample_rate(us122l->dev, rate); if (err < 0) { us122l_stop(us122l); snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); @@ -390,7 +390,7 @@ static int usb_stream_hwdep_ioctl(struct snd_hwdep *hw, struct file *file, err = -ENXIO; goto free; } - high_speed = us122l->chip.dev->speed == USB_SPEED_HIGH; + high_speed = us122l->dev->speed == USB_SPEED_HIGH; if ((cfg->sample_rate != 44100 && cfg->sample_rate != 48000 && (!high_speed || (cfg->sample_rate != 88200 && cfg->sample_rate != 96000))) || @@ -450,7 +450,7 @@ static int usb_stream_hwdep_new(struct snd_card *card) { int err; struct snd_hwdep *hw; - struct usb_device *dev = US122L(card)->chip.dev; + struct usb_device *dev = US122L(card)->dev; err = snd_hwdep_new(card, SND_USB_STREAM_ID, 0, &hw); if (err < 0) @@ -476,26 +476,26 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - err = usb_set_interface(us122l->chip.dev, 0, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } } - err = usb_set_interface(us122l->chip.dev, 1, 1); + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); return false; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) + if (us122l->dev->descriptor.idProduct == USB_ID_US144) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); @@ -520,7 +520,7 @@ static bool us122l_create_card(struct snd_card *card) static void snd_us122l_free(struct snd_card *card) { struct us122l *us122l = US122L(card); - int index = us122l->chip.index; + int index = us122l->card_index; if (index >= 0 && index < SNDRV_CARDS) snd_us122l_card_used[index] = 0; } @@ -540,10 +540,9 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct us122l), &card); if (err < 0) return err; - snd_us122l_card_used[US122L(card)->chip.index = dev] = 1; + snd_us122l_card_used[US122L(card)->card_index = dev] = 1; card->private_free = snd_us122l_free; - US122L(card)->chip.dev = device; - US122L(card)->chip.card = card; + US122L(card)->dev = device; mutex_init(&US122L(card)->mutex); init_waitqueue_head(&US122L(card)->sk.sleep); INIT_LIST_HEAD(&US122L(card)->midi_list); @@ -554,8 +553,8 @@ static int usx2y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0, - US122L(card)->chip.dev->bus->busnum, - US122L(card)->chip.dev->devnum + US122L(card)->dev->bus->busnum, + US122L(card)->dev->devnum ); *cardp = card; return 0; @@ -635,16 +634,15 @@ static void snd_us122l_disconnect(struct usb_interface *intf) mutex_lock(&us122l->mutex); us122l_stop(us122l); mutex_unlock(&us122l->mutex); - us122l->chip.shutdown = 1; /* release the midi resources */ list_for_each(p, &us122l->midi_list) { snd_usbmidi_disconnect(p); } - usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 0)); - usb_put_intf(usb_ifnum_to_if(us122l->chip.dev, 1)); - usb_put_dev(us122l->chip.dev); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 0)); + usb_put_intf(usb_ifnum_to_if(us122l->dev, 1)); + usb_put_dev(us122l->dev); while (atomic_read(&us122l->mmap_count)) msleep(500); @@ -694,23 +692,23 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->chip.dev->descriptor.idProduct == USB_ID_US144) { - err = usb_set_interface(us122l->chip.dev, 0, 1); + if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } } - err = usb_set_interface(us122l->chip.dev, 1, 1); + err = usb_set_interface(us122l->dev, 1, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); goto unlock; } - pt_info_set(us122l->chip.dev, 0x11); - pt_info_set(us122l->chip.dev, 0x10); + pt_info_set(us122l->dev, 0x11); + pt_info_set(us122l->dev, 0x10); - err = us122l_set_sample_rate(us122l->chip.dev, + err = us122l_set_sample_rate(us122l->dev, us122l->sk.s->cfg.sample_rate); if (err < 0) { snd_printk(KERN_ERR "us122l_set_sample_rate error \n"); diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 61ce5d7de0b9..4daf1982e821 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -3,7 +3,8 @@ struct us122l { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct usb_stream_kernel sk; diff --git a/sound/usb/usx2y/usX2Yhwdep.c b/sound/usb/usx2y/usX2Yhwdep.c index f96ab86259d0..1879b72c40f8 100644 --- a/sound/usb/usx2y/usX2Yhwdep.c +++ b/sound/usb/usx2y/usX2Yhwdep.c @@ -114,7 +114,7 @@ static int snd_usX2Y_hwdep_dsp_status(struct snd_hwdep *hw, struct usX2Ydev *us428 = hw->private_data; int id = -1; - switch (le16_to_cpu(us428->chip.dev->descriptor.idProduct)) { + switch (le16_to_cpu(us428->dev->descriptor.idProduct)) { case USB_ID_US122: id = USX2Y_TYPE_122; break; @@ -164,7 +164,7 @@ static int usX2Y_create_usbmidi(struct snd_card *card) .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &quirk_data_2 }; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; struct usb_interface *iface = usb_ifnum_to_if(dev, 0); struct snd_usb_audio_quirk *quirk = le16_to_cpu(dev->descriptor.idProduct) == USB_ID_US428 ? @@ -202,7 +202,7 @@ static int snd_usX2Y_hwdep_dsp_load(struct snd_hwdep *hw, snd_printdd( "dsp_load %s\n", dsp->name); if (access_ok(VERIFY_READ, dsp->image, dsp->length)) { - struct usb_device* dev = priv->chip.dev; + struct usb_device* dev = priv->dev; char *buf; buf = memdup_user(dsp->image, dsp->length); diff --git a/sound/usb/usx2y/usbusx2y.c b/sound/usb/usx2y/usbusx2y.c index 181337090e48..c42350eed2eb 100644 --- a/sound/usb/usx2y/usbusx2y.c +++ b/sound/usb/usx2y/usbusx2y.c @@ -239,8 +239,8 @@ static void i_usX2Y_In04Int(struct urb *urb) for (j = 0; j < URBS_AsyncSeq && !err; ++j) if (0 == usX2Y->AS04.urb[j]->status) { struct us428_p4out *p4out = us428ctls->p4out + send; // FIXME if more than 1 p4out is new, 1 gets lost. - usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), &p4out->val.vol, + usb_fill_bulk_urb(usX2Y->AS04.urb[j], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), &p4out->val.vol, p4out->type == eLT_Light ? sizeof(struct us428_lights) : 5, i_usX2Y_Out04Int, usX2Y); err = usb_submit_urb(usX2Y->AS04.urb[j], GFP_ATOMIC); @@ -253,7 +253,7 @@ static void i_usX2Y_In04Int(struct urb *urb) if (err) snd_printk(KERN_ERR "In04Int() usb_submit_urb err=%i\n", err); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; usb_submit_urb(urb, GFP_ATOMIC); } @@ -273,8 +273,8 @@ int usX2Y_AsyncSeq04_init(struct usX2Ydev *usX2Y) err = -ENOMEM; break; } - usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->chip.dev, - usb_sndbulkpipe(usX2Y->chip.dev, 0x04), + usb_fill_bulk_urb( usX2Y->AS04.urb[i], usX2Y->dev, + usb_sndbulkpipe(usX2Y->dev, 0x04), usX2Y->AS04.buffer + URB_DataLen_AsyncSeq*i, 0, i_usX2Y_Out04Int, usX2Y ); @@ -293,7 +293,7 @@ int usX2Y_In04_init(struct usX2Ydev *usX2Y) } init_waitqueue_head(&usX2Y->In04WaitQueue); - usb_fill_int_urb(usX2Y->In04urb, usX2Y->chip.dev, usb_rcvintpipe(usX2Y->chip.dev, 0x4), + usb_fill_int_urb(usX2Y->In04urb, usX2Y->dev, usb_rcvintpipe(usX2Y->dev, 0x4), usX2Y->In04Buf, 21, i_usX2Y_In04Int, usX2Y, 10); @@ -348,10 +348,9 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) sizeof(struct usX2Ydev), &card); if (err < 0) return err; - snd_usX2Y_card_used[usX2Y(card)->chip.index = dev] = 1; + snd_usX2Y_card_used[usX2Y(card)->card_index = dev] = 1; card->private_free = snd_usX2Y_card_private_free; - usX2Y(card)->chip.dev = device; - usX2Y(card)->chip.card = card; + usX2Y(card)->dev = device; init_waitqueue_head(&usX2Y(card)->prepare_wait_queue); mutex_init(&usX2Y(card)->prepare_mutex); INIT_LIST_HEAD(&usX2Y(card)->midi_list); @@ -362,7 +361,7 @@ static int usX2Y_create_card(struct usb_device *device, struct snd_card **cardp) le16_to_cpu(device->descriptor.idVendor), le16_to_cpu(device->descriptor.idProduct), 0,//us428(card)->usbmidi.ifnum, - usX2Y(card)->chip.dev->bus->busnum, usX2Y(card)->chip.dev->devnum + usX2Y(card)->dev->bus->busnum, usX2Y(card)->dev->devnum ); *cardp = card; return 0; @@ -432,8 +431,8 @@ static void snd_usX2Y_card_private_free(struct snd_card *card) usb_free_urb(usX2Y(card)->In04urb); if (usX2Y(card)->us428ctls_sharedmem) snd_free_pages(usX2Y(card)->us428ctls_sharedmem, sizeof(*usX2Y(card)->us428ctls_sharedmem)); - if (usX2Y(card)->chip.index >= 0 && usX2Y(card)->chip.index < SNDRV_CARDS) - snd_usX2Y_card_used[usX2Y(card)->chip.index] = 0; + if (usX2Y(card)->card_index >= 0 && usX2Y(card)->card_index < SNDRV_CARDS) + snd_usX2Y_card_used[usX2Y(card)->card_index] = 0; } /* @@ -445,7 +444,6 @@ static void usX2Y_usb_disconnect(struct usb_device *device, void* ptr) struct snd_card *card = ptr; struct usX2Ydev *usX2Y = usX2Y(card); struct list_head *p; - usX2Y->chip.shutdown = 1; usX2Y->chip_status = USX2Y_STAT_CHIP_HUP; usX2Y_unlinkSeq(&usX2Y->AS04); usb_kill_urb(usX2Y->In04urb); diff --git a/sound/usb/usx2y/usbusx2y.h b/sound/usb/usx2y/usbusx2y.h index 231866ea3491..1d174cea352b 100644 --- a/sound/usb/usx2y/usbusx2y.h +++ b/sound/usb/usx2y/usbusx2y.h @@ -22,7 +22,8 @@ struct snd_usX2Y_urbSeq { #include "usx2yhwdeppcm.h" struct usX2Ydev { - struct snd_usb_audio chip; + struct usb_device *dev; + int card_index; int stride; struct urb *In04urb; void *In04Buf; @@ -43,6 +44,8 @@ struct usX2Ydev { struct snd_usX2Y_substream * volatile prepare_subs; wait_queue_head_t prepare_wait_queue; struct list_head midi_list; + struct list_head pcm_list; + int pcm_devs; }; diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c index b8e2f4691493..74a67a85aa81 100644 --- a/sound/usb/usx2y/usbusx2yaudio.c +++ b/sound/usb/usx2y/usbusx2yaudio.c @@ -199,7 +199,7 @@ static int usX2Y_urb_submit(struct snd_usX2Y_substream *subs, struct urb *urb, i return -ENODEV; urb->start_frame = (frame + NRURBS * nr_of_packs()); // let hcd do rollover sanity checks urb->hcpriv = NULL; - urb->dev = subs->usX2Y->chip.dev; /* we need to set this at each time */ + urb->dev = subs->usX2Y->dev; /* we need to set this at each time */ if ((err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { snd_printk(KERN_ERR "usb_submit_urb() returned %i\n", err); return err; @@ -300,7 +300,7 @@ static void usX2Y_error_sequence(struct usX2Ydev *usX2Y, "Sequence Error!(hcd_frame=%i ep=%i%s;wait=%i,frame=%i).\n" "Most propably some urb of usb-frame %i is still missing.\n" "Cause could be too long delays in usb-hcd interrupt handling.\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", usX2Y->wait_iso_frame, urb->start_frame, usX2Y->wait_iso_frame); usX2Y_clients_stop(usX2Y); @@ -313,7 +313,7 @@ static void i_usX2Y_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -424,7 +424,7 @@ static int usX2Y_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -500,7 +500,7 @@ static int usX2Y_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == i) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * pack; @@ -692,7 +692,7 @@ static int usX2Y_rate_set(struct usX2Ydev *usX2Y, int rate) } ((char*)(usbdata + i))[0] = ra[i].c1; ((char*)(usbdata + i))[1] = ra[i].c2; - usb_fill_bulk_urb(us->urb[i], usX2Y->chip.dev, usb_sndbulkpipe(usX2Y->chip.dev, 4), + usb_fill_bulk_urb(us->urb[i], usX2Y->dev, usb_sndbulkpipe(usX2Y->dev, 4), usbdata + i, 2, i_usX2Y_04Int, usX2Y); #ifdef OLD_USB us->urb[i]->transfer_flags = USB_QUEUE_BULK; @@ -744,11 +744,11 @@ static int usX2Y_format_set(struct usX2Ydev *usX2Y, snd_pcm_format_t format) snd_usbmidi_input_stop(p); } usb_kill_urb(usX2Y->In04urb); - if ((err = usb_set_interface(usX2Y->chip.dev, 0, alternate))) { + if ((err = usb_set_interface(usX2Y->dev, 0, alternate))) { snd_printk(KERN_ERR "usb_set_interface error \n"); return err; } - usX2Y->In04urb->dev = usX2Y->chip.dev; + usX2Y->In04urb->dev = usX2Y->dev; err = usb_submit_urb(usX2Y->In04urb, GFP_KERNEL); list_for_each(p, &usX2Y->midi_list) { snd_usbmidi_input_start(p); @@ -955,7 +955,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, struct snd_pcm *pcm; int err, i; struct snd_usX2Y_substream **usX2Y_substream = - usX2Y(card)->subs + 2 * usX2Y(card)->chip.pcm_devs; + usX2Y(card)->subs + 2 * usX2Y(card)->pcm_devs; for (i = playback_endpoint ? SNDRV_PCM_STREAM_PLAYBACK : SNDRV_PCM_STREAM_CAPTURE; i <= SNDRV_PCM_STREAM_CAPTURE; ++i) { @@ -971,7 +971,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, usX2Y_substream[SNDRV_PCM_STREAM_PLAYBACK]->endpoint = playback_endpoint; usX2Y_substream[SNDRV_PCM_STREAM_CAPTURE]->endpoint = capture_endpoint; - err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->chip.pcm_devs, + err = snd_pcm_new(card, NAME_ALLCAPS" Audio", usX2Y(card)->pcm_devs, playback_endpoint ? 1 : 0, 1, &pcm); if (err < 0) { @@ -987,7 +987,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, pcm->private_free = snd_usX2Y_pcm_private_free; pcm->info_flags = 0; - sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->chip.pcm_devs); + sprintf(pcm->name, NAME_ALLCAPS" Audio #%d", usX2Y(card)->pcm_devs); if ((playback_endpoint && 0 > (err = snd_pcm_lib_preallocate_pages(pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream, @@ -1001,7 +1001,7 @@ static int usX2Y_audio_stream_new(struct snd_card *card, int playback_endpoint, snd_usX2Y_pcm_private_free(pcm); return err; } - usX2Y(card)->chip.pcm_devs++; + usX2Y(card)->pcm_devs++; return 0; } @@ -1013,14 +1013,14 @@ int usX2Y_audio_create(struct snd_card *card) { int err = 0; - INIT_LIST_HEAD(&usX2Y(card)->chip.pcm_list); + INIT_LIST_HEAD(&usX2Y(card)->pcm_list); if (0 > (err = usX2Y_audio_stream_new(card, 0xA, 0x8))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) == USB_ID_US428) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) == USB_ID_US428) if (0 > (err = usX2Y_audio_stream_new(card, 0, 0xA))) return err; - if (le16_to_cpu(usX2Y(card)->chip.dev->descriptor.idProduct) != USB_ID_US122) + if (le16_to_cpu(usX2Y(card)->dev->descriptor.idProduct) != USB_ID_US122) err = usX2Y_rate_set(usX2Y(card), 44100); // Lets us428 recognize output-volume settings, disturbs us122. return err; } diff --git a/sound/usb/usx2y/usx2yhwdeppcm.c b/sound/usb/usx2y/usx2yhwdeppcm.c index 4b2304c2e02d..9ed6c3956ca7 100644 --- a/sound/usb/usx2y/usx2yhwdeppcm.c +++ b/sound/usb/usx2y/usx2yhwdeppcm.c @@ -234,7 +234,7 @@ static void i_usX2Y_usbpcm_urb_complete(struct urb *urb) if (unlikely(atomic_read(&subs->state) < state_PREPARED)) { snd_printdd("hcd_frame=%i ep=%i%s status=%i start_frame=%i\n", - usb_get_current_frame_number(usX2Y->chip.dev), + usb_get_current_frame_number(usX2Y->dev), subs->endpoint, usb_pipein(urb->pipe) ? "in" : "out", urb->status, urb->start_frame); return; @@ -318,7 +318,7 @@ static int usX2Y_usbpcm_urbs_allocate(struct snd_usX2Y_substream *subs) int i; unsigned int pipe; int is_playback = subs == subs->usX2Y->subs[SNDRV_PCM_STREAM_PLAYBACK]; - struct usb_device *dev = subs->usX2Y->chip.dev; + struct usb_device *dev = subs->usX2Y->dev; pipe = is_playback ? usb_sndisocpipe(dev, subs->endpoint) : usb_rcvisocpipe(dev, subs->endpoint); @@ -441,7 +441,7 @@ static int usX2Y_usbpcm_urbs_start(struct snd_usX2Y_substream *subs) unsigned long pack; if (0 == u) atomic_set(&subs->state, state_STARTING3); - urb->dev = usX2Y->chip.dev; + urb->dev = usX2Y->dev; urb->transfer_flags = URB_ISO_ASAP; for (pack = 0; pack < nr_of_packs(); pack++) { urb->iso_frame_desc[pack].offset = subs->maxpacksize * (pack + u * nr_of_packs()); @@ -741,7 +741,7 @@ int usX2Y_hwdep_pcm_new(struct snd_card *card) int err; struct snd_hwdep *hw; struct snd_pcm *pcm; - struct usb_device *dev = usX2Y(card)->chip.dev; + struct usb_device *dev = usX2Y(card)->dev; if (1 != nr_of_packs()) return 0; -- cgit v1.2.3 From bbb3c644bd9967753ce8c214c5e64b27c361d2a4 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Tue, 24 Nov 2009 22:51:05 -0500 Subject: ALSA: intel8x0: Mute External Amplifier by default for Gateway 4525GZ BugLink: https://bugs.launchpad.net/bugs/487884 This Gateway model needs External Amplifier muted for audible playback, so set the inv_eapd quirk for it. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/intel8x0.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index aac20fb4aad2..b990143636f1 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c @@ -2062,6 +2062,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { .name = "MSI P4 ATX 645 Ultra", .type = AC97_TUNE_HP_ONLY }, + { + .subvendor = 0x161f, + .subdevice = 0x203a, + .name = "Gateway 4525GZ", /* AD1981B */ + .type = AC97_TUNE_INV_EAPD + }, { .subvendor = 0x1734, .subdevice = 0x0088, -- cgit v1.2.3 From 0b587fc4d35afb1bc0fc3d890084bb14c78372dc Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Wed, 25 Nov 2009 18:27:20 -0500 Subject: ALSA: hda: Fix max PCM level to 0 dB for Fujitsu-Siemens laptops using CX20549 (Venice) BugLink: https://bugtrack.alsa-project.org/alsa-bug/view.php?id=4792 Cristian reported that these models have really bad sound above 6 dB and proposed the original patch. I've updated the comment to reflect this change. Signed-off-by: Daniel T Chen Reported-by: Cristian Klein Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 36dd5a6bf874..60810ba899d1 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1171,9 +1171,10 @@ static int patch_cxt5045(struct hda_codec *codec) switch (codec->subsystem_id >> 16) { case 0x103c: - /* HP laptop has a really bad sound over 0dB on NID 0x17. - * Fix max PCM level to 0 dB - * (originall it has 0x2b steps with 0dB offset 0x14) + case 0x1734: + /* HP & Fujitsu-Siemens laptops have really bad sound over 0dB + * on NID 0x17. Fix max PCM level to 0 dB + * (originally it has 0x2b steps with 0dB offset 0x14) */ snd_hda_override_amp_caps(codec, 0x17, HDA_INPUT, (0x14 << AC_AMPCAP_OFFSET_SHIFT) | -- cgit v1.2.3 From 657b1989dacf58e83e7a76bca6d4a91a9f294cf6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:40:21 +0100 Subject: ALSA: pcm - Use dma_mmap_coherent() if available Use dma_mmap_coherent() for mmapping the buffers allocated via dma_alloc_coherent() if available. Currently, only ARM has this function, so we do temporarily have an ifdef pcm_native.c. This should be handled better globally in future. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 49 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 33 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index ab73edf2c89a..f067c5b906e4 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -3094,23 +3095,42 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, return 0; } -static const struct vm_operations_struct snd_pcm_vm_ops_data = -{ +static const struct vm_operations_struct snd_pcm_vm_ops_data = { + .open = snd_pcm_mmap_data_open, + .close = snd_pcm_mmap_data_close, +}; + +static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = { .open = snd_pcm_mmap_data_open, .close = snd_pcm_mmap_data_close, .fault = snd_pcm_mmap_data_fault, }; +#ifndef ARCH_HAS_DMA_MMAP_COHERENT +/* This should be defined / handled globally! */ +#ifdef CONFIG_ARM +#define ARCH_HAS_DMA_MMAP_COHERENT +#endif +#endif + /* * mmap the DMA buffer on RAM */ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *area) { - area->vm_ops = &snd_pcm_vm_ops_data; - area->vm_private_data = substream; area->vm_flags |= VM_RESERVED; - atomic_inc(&substream->mmap_count); +#ifdef ARCH_HAS_DMA_MMAP_COHERENT + if (!substream->ops->page && + substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return dma_mmap_coherent(substream->dma_buffer.dev.dev, + area, + substream->runtime->dma_area, + substream->runtime->dma_addr, + area->vm_end - area->vm_start); +#endif /* ARCH_HAS_DMA_MMAP_COHERENT */ + /* mmap with fault handler */ + area->vm_ops = &snd_pcm_vm_ops_data_fault; return 0; } @@ -3118,12 +3138,6 @@ static int snd_pcm_default_mmap(struct snd_pcm_substream *substream, * mmap the DMA buffer on I/O memory area */ #if SNDRV_PCM_INFO_MMAP_IOMEM -static const struct vm_operations_struct snd_pcm_vm_ops_data_mmio = -{ - .open = snd_pcm_mmap_data_open, - .close = snd_pcm_mmap_data_close, -}; - int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_struct *area) { @@ -3133,8 +3147,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, #ifdef pgprot_noncached area->vm_page_prot = pgprot_noncached(area->vm_page_prot); #endif - area->vm_ops = &snd_pcm_vm_ops_data_mmio; - area->vm_private_data = substream; area->vm_flags |= VM_IO; size = area->vm_end - area->vm_start; offset = area->vm_pgoff << PAGE_SHIFT; @@ -3142,7 +3154,6 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, (substream->runtime->dma_addr + offset) >> PAGE_SHIFT, size, area->vm_page_prot)) return -EAGAIN; - atomic_inc(&substream->mmap_count); return 0; } @@ -3159,6 +3170,7 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, long size; unsigned long offset; size_t dma_bytes; + int err; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { if (!(area->vm_flags & (VM_WRITE|VM_READ))) @@ -3183,10 +3195,15 @@ int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, if (offset > dma_bytes - size) return -EINVAL; + area->vm_ops = &snd_pcm_vm_ops_data; + area->vm_private_data = substream; if (substream->ops->mmap) - return substream->ops->mmap(substream, area); + err = substream->ops->mmap(substream, area); else - return snd_pcm_default_mmap(substream, area); + err = snd_pcm_default_mmap(substream, area); + if (!err) + atomic_inc(&substream->mmap_count); + return err; } EXPORT_SYMBOL(snd_pcm_mmap_data); -- cgit v1.2.3 From 9eb4a06788a598573c751af1a7e46639afc89513 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:43:39 +0100 Subject: ALSA: pcm - define snd_pcm_default_page_ops() Add a helper (inline) function as the default page ops. Any hacks wrt the page address conversion will be applied in this function. Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f067c5b906e4..c906be26c312 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3062,6 +3062,13 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file } #endif /* coherent mmap */ +static inline struct page * +snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) +{ + void *vaddr = substream->runtime->dma_area + ofs; + return virt_to_page(vaddr); +} + /* * fault callback for mmapping a RAM page */ @@ -3072,7 +3079,6 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, struct snd_pcm_runtime *runtime; unsigned long offset; struct page * page; - void *vaddr; size_t dma_bytes; if (substream == NULL) @@ -3082,14 +3088,12 @@ static int snd_pcm_mmap_data_fault(struct vm_area_struct *area, dma_bytes = PAGE_ALIGN(runtime->dma_bytes); if (offset > dma_bytes - PAGE_SIZE) return VM_FAULT_SIGBUS; - if (substream->ops->page) { + if (substream->ops->page) page = substream->ops->page(substream, offset); - if (!page) - return VM_FAULT_SIGBUS; - } else { - vaddr = runtime->dma_area + offset; - page = virt_to_page(vaddr); - } + else + page = snd_pcm_default_page_ops(substream, offset); + if (!page) + return VM_FAULT_SIGBUS; get_page(page); vmf->page = page; return 0; -- cgit v1.2.3 From 66b6cfacfc5aa2fda37b0d40cd54931ca5ef8cd7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 12:50:01 +0100 Subject: ALSA: pcm - fix page conversion on non-coherent MIPS arch The non-coherent MIPS arch doesn't give the correct address by a simple virt_to_page() for pages allocated via dma_alloc_coherent(). Original patch by Wu Zhangjin . [Ralf mentioned: "The origins of this patch go back far further. The oldest patch I could find which is a superset of this was written by Atsushi Nemoto and various incarnations of it have been sumitted to and reject by me a number of times through the years."] A proper check of the buffer allocation type was added to avoid the wrong conversion. Note that this doesn't fix perfectly: the pages should be marked with proper pgprot value. This will be done in a future implementation like the conversion to dma_mmap_coherent(). Acked-by: Ralf Baechle Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index c906be26c312..e48c5f618578 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3066,6 +3066,10 @@ static inline struct page * snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) { void *vaddr = substream->runtime->dma_area + ofs; +#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) + return virt_to_page(CAC_ADDR(vaddr)); +#endif return virt_to_page(vaddr); } -- cgit v1.2.3 From 6985c8877a711c7c307af05203858cb7c3c89d0d Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 15:04:24 +0100 Subject: ALSA: pcm - fix page conversion on non-coherent PPC arch The non-cohernet PPC arch doesn't give the correct address by a simple virt_to_page() for pages allocated via dma_alloc_coherent(). This patch adds a hack to fix the conversion similarly like MIPS. Note that this doesn't fix perfectly: the pages should be marked with proper pgprot value. This will be done in a future implementation like the conversion to dma_mmap_coherent(). Acked-by: Benjamin Herrenschmidt Signed-off-by: Takashi Iwai --- sound/core/pcm_native.c | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'sound') diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index e48c5f618578..29ab46a12e11 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c @@ -3069,6 +3069,16 @@ snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs) #if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT) if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) return virt_to_page(CAC_ADDR(vaddr)); +#endif +#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE) + if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) { + dma_addr_t addr = substream->runtime->dma_addr + ofs; + addr -= get_dma_offset(substream->dma_buffer.dev.dev); + /* assume dma_handle set via pfn_to_phys() in + * mm/dma-noncoherent.c + */ + return pfn_to_page(addr >> PAGE_SHIFT); + } #endif return virt_to_page(vaddr); } -- cgit v1.2.3 From d6797322231af98b9bb4afb175dd614cf511e5f7 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 26 Nov 2009 15:08:54 +0100 Subject: ALSA: Remove old DMA-mmap code from arm/devdma.c The call of dma_mmap_coherent() is done in the PCM core now. Signed-off-by: Takashi Iwai --- sound/arm/Makefile | 2 +- sound/arm/aaci.c | 16 ++++------- sound/arm/devdma.c | 80 ------------------------------------------------------ sound/arm/devdma.h | 3 -- 4 files changed, 6 insertions(+), 95 deletions(-) delete mode 100644 sound/arm/devdma.c delete mode 100644 sound/arm/devdma.h (limited to 'sound') diff --git a/sound/arm/Makefile b/sound/arm/Makefile index 5a549ed6c8aa..8c0c851d4641 100644 --- a/sound/arm/Makefile +++ b/sound/arm/Makefile @@ -3,7 +3,7 @@ # obj-$(CONFIG_SND_ARMAACI) += snd-aaci.o -snd-aaci-objs := aaci.o devdma.o +snd-aaci-objs := aaci.o obj-$(CONFIG_SND_PXA2XX_PCM) += snd-pxa2xx-pcm.o snd-pxa2xx-pcm-objs := pxa2xx-pcm.o diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d5..e59372887f36 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -30,7 +30,6 @@ #include #include "aaci.h" -#include "devdma.h" #define DRIVER_NAME "aaci-pl041" @@ -492,7 +491,7 @@ static int aaci_pcm_hw_free(struct snd_pcm_substream *substream) /* * Clear out the DMA and any allocated buffers. */ - devdma_hw_free(NULL, substream); + snd_pcm_lib_free_pages(substream); return 0; } @@ -505,8 +504,8 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, aaci_pcm_hw_free(substream); - err = devdma_hw_alloc(NULL, substream, - params_buffer_bytes(params)); + err = snd_pcm_lib_malloc_pages(substream, + params_buffer_bytes(params)); if (err < 0) goto out; @@ -551,11 +550,6 @@ static snd_pcm_uframes_t aaci_pcm_pointer(struct snd_pcm_substream *substream) return bytes_to_frames(runtime, bytes); } -static int aaci_pcm_mmap(struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - return devdma_mmap(NULL, substream, vma); -} - /* * Playback specific ALSA stuff @@ -722,7 +716,6 @@ static struct snd_pcm_ops aaci_playback_ops = { .prepare = aaci_pcm_prepare, .trigger = aaci_pcm_playback_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream, @@ -850,7 +843,6 @@ static struct snd_pcm_ops aaci_capture_ops = { .prepare = aaci_pcm_capture_prepare, .trigger = aaci_pcm_capture_trigger, .pointer = aaci_pcm_pointer, - .mmap = aaci_pcm_mmap, }; /* @@ -1040,6 +1032,8 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); + snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, + NULL, 0, 64 * 104); } return ret; diff --git a/sound/arm/devdma.c b/sound/arm/devdma.c deleted file mode 100644 index 9d1e6665b546..000000000000 --- a/sound/arm/devdma.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * linux/sound/arm/devdma.c - * - * Copyright (C) 2003-2004 Russell King, All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * ARM DMA shim for ALSA. - */ -#include -#include - -#include -#include - -#include "devdma.h" - -void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - - if (runtime->dma_area == NULL) - return; - - if (buf != &substream->dma_buffer) { - dma_free_coherent(buf->dev.dev, buf->bytes, buf->area, buf->addr); - kfree(runtime->dma_buffer_p); - } - - snd_pcm_set_runtime_buffer(substream, NULL); -} - -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - struct snd_dma_buffer *buf = runtime->dma_buffer_p; - int ret = 0; - - if (buf) { - if (buf->bytes >= size) - goto out; - devdma_hw_free(dev, substream); - } - - if (substream->dma_buffer.area != NULL && substream->dma_buffer.bytes >= size) { - buf = &substream->dma_buffer; - } else { - buf = kmalloc(sizeof(struct snd_dma_buffer), GFP_KERNEL); - if (!buf) - goto nomem; - - buf->dev.type = SNDRV_DMA_TYPE_DEV; - buf->dev.dev = dev; - buf->area = dma_alloc_coherent(dev, size, &buf->addr, GFP_KERNEL); - buf->bytes = size; - buf->private_data = NULL; - - if (!buf->area) - goto free; - } - snd_pcm_set_runtime_buffer(substream, buf); - ret = 1; - out: - runtime->dma_bytes = size; - return ret; - - free: - kfree(buf); - nomem: - return -ENOMEM; -} - -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma) -{ - struct snd_pcm_runtime *runtime = substream->runtime; - return dma_mmap_coherent(dev, vma, runtime->dma_area, runtime->dma_addr, runtime->dma_bytes); -} diff --git a/sound/arm/devdma.h b/sound/arm/devdma.h deleted file mode 100644 index d025329c8a0f..000000000000 --- a/sound/arm/devdma.h +++ /dev/null @@ -1,3 +0,0 @@ -void devdma_hw_free(struct device *dev, struct snd_pcm_substream *substream); -int devdma_hw_alloc(struct device *dev, struct snd_pcm_substream *substream, size_t size); -int devdma_mmap(struct device *dev, struct snd_pcm_substream *substream, struct vm_area_struct *vma); -- cgit v1.2.3 From 8700055e0a30b3f67c1474b09200b59c32dd3796 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 27 Nov 2009 11:20:56 +0100 Subject: ALSA: opti-miro: fix OOPS if hardware is not detected If a hardware is not detected there is a kernel crash due to not initialized snd_miro->aci pointer. This pointer is initialized after detection of the opti (miro) chip. This bug was introduced by patches to expose ACI mikser outside the snd-miro driver. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 40b64cd54c85..e374869e3e21 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1229,7 +1229,8 @@ static void snd_card_miro_free(struct snd_card *card) struct snd_miro *miro = card->private_data; release_and_free_resource(miro->res_aci_port); - miro->aci->aci_port = 0; + if (miro->aci) + miro->aci->aci_port = 0; release_and_free_resource(miro->res_mc_base); } -- cgit v1.2.3 From bfc9902599549736b9c6445e1e2235b8542f64a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 27 Nov 2009 12:22:44 +0100 Subject: ALSA: hda - Don't trigger pin-sense for STAC/IDT codecs STAC/IDT codecs seem to behave weird when SET_PIN_SENSE verb is issued before reading the jack-detection although the TRIG_REQ pin capability is given by the hardware. Since snd_hda_jack_detect() issues the SET_PIN_SENSE verb simply judging from the pincap, we have to revert the change in the commit d56757abc11a21996d9839c0d4e3b2c3666cd318 ALSA: hda - Replace the rest of jack-detections with snd_hda_jack_detect() to plain GET_PIN_SENSE verb without triggering. Reported-by: Jiri Slaby Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 2a45375d79f8..6b0bc040c3b1 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -4440,7 +4440,14 @@ 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); + /* NOTE: we can't use snd_hda_jack_detect() here because STAC/IDT + * codecs behave wrongly when SET_PIN_SENSE is triggered, although + * the pincap gives TRIG_REQ bit. + */ + if (snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_SENSE, 0) & + AC_PINSENSE_PRESENCE) + return 1; + return 0; } static void stac92xx_line_out_detect(struct hda_codec *codec, -- cgit v1.2.3 From dd2e5a156525f11754d9b1e0583f6bb49c253d62 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Tue, 3 Nov 2009 10:27:34 +0100 Subject: pcmcia: remove deprecated handle_to_dev() macro Update remaining users and remove deprecated handle_to_dev() macro CC: Harald Welte CC: netdev@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-serial@vger.kernel.org Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 2 +- sound/pcmcia/vx/vxpocket.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 64b859925c0b..447aaaee3be6 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -131,7 +131,7 @@ static int snd_pdacf_probe(struct pcmcia_device *link) return err; } - snd_card_set_dev(card, &handle_to_dev(link)); + snd_card_set_dev(card, &link->dev); pdacf->index = i; card_list[i] = card; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 1492744ad67f..5a5db48a91a9 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -244,7 +244,7 @@ static int vxpocket_config(struct pcmcia_device *link) if (ret) goto failed; - chip->dev = &handle_to_dev(link); + chip->dev = &link->dev; snd_card_set_dev(chip->card, chip->dev); if (snd_vxpocket_assign_resources(chip, link->io.BasePort1, link->irq.AssignedIRQ) < 0) -- cgit v1.2.3 From 5fa9167a1bf5f5a4b7282f5e7ac56a4a5a1fa044 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sun, 8 Nov 2009 17:24:46 +0100 Subject: pcmcia: rework the irq_req_t typedef Most of the irq_req_t typedef'd struct can be re-worked quite easily: (1) IRQInfo2 was unused in any case, so drop it. (2) IRQInfo1 was used write-only, so drop it. (3) Instance (private data to be passed to the IRQ handler): Most PCMCIA drivers using pcmcia_request_irq() to actually register an IRQ handler set the "dev_id" to the same pointer as the "priv" pointer in struct pcmcia_device. Modify the two exceptions (ipwireless, ibmtr_cs) to also work this waym and set the IRQ handler's "dev_id" to p_dev->priv unconditionally. (4) Handler is to be of type irq_handler_t. (5) Handler != NULL already tells whether an IRQ handler is present. Therefore, we do not need the IRQ_HANDLER_PRESENT flag in irq_req_t.Attributes. CC: netdev@vger.kernel.org CC: linux-bluetooth@vger.kernel.org CC: linux-ide@vger.kernel.org CC: linux-wireless@vger.kernel.org CC: linux-scsi@vger.kernel.org CC: alsa-devel@alsa-project.org CC: Jaroslav Kysela CC: Jiri Kosina CC: Karsten Keil for the Bluetooth parts: Acked-by: Marcel Holtmann Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 4 +--- sound/pcmcia/vx/vxpocket.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 447aaaee3be6..7717e01fc071 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -142,12 +142,10 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT | IRQ_FORCED_PULSE; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE; // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; - link->irq.IRQInfo1 = 0 /* | IRQ_LEVEL_ID */; link->irq.Handler = pdacf_interrupt; - link->irq.Instance = pdacf; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; link->conf.ConfigIndex = 1; diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c index 5a5db48a91a9..7be3b3357045 100644 --- a/sound/pcmcia/vx/vxpocket.c +++ b/sound/pcmcia/vx/vxpocket.c @@ -161,11 +161,9 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl, link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; link->io.NumPorts1 = 16; - link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; + link->irq.Attributes = IRQ_TYPE_EXCLUSIVE; - link->irq.IRQInfo1 = IRQ_LEVEL_ID; link->irq.Handler = &snd_vx_irq_handler; - link->irq.Instance = chip; link->conf.Attributes = CONF_ENABLE_IRQ; link->conf.IntType = INT_MEMORY_AND_IO; -- cgit v1.2.3 From 70a5f1187bcb3fac93a7d5c5fcfc5fc76b9c3f55 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 30 Nov 2009 07:45:47 +0100 Subject: ALSA: opti-miro: separate comon probing code Separate common probing code in order to use it for PnP probing. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 273 +++++++++++++++++++++++++---------------------- 1 file changed, 147 insertions(+), 126 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index e374869e3e21..c67bc3cd2c65 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1142,28 +1142,39 @@ __skip_mpu: return 0; } +static int __devinit snd_miro_opti_check(struct snd_miro *chip) +{ + unsigned char value; + + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -ENOMEM; + + value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) + return 0; + + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; + + return -ENODEV; +} + static int __devinit snd_card_miro_detect(struct snd_card *card, struct snd_miro *chip) { int i, err; - unsigned char value; for (i = OPTi9XX_HW_82C929; i <= OPTi9XX_HW_82C924; i++) { if ((err = snd_miro_init(chip, i)) < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - value = snd_miro_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_miro_read(chip, OPTi9XX_MC_REG(1))) - return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; - + err = snd_miro_opti_check(chip); + if (err == 0) + return 1; } return -ENODEV; @@ -1234,151 +1245,69 @@ static void snd_card_miro_free(struct snd_card *card) release_and_free_resource(miro->res_mc_base); } -static int __devinit snd_miro_match(struct device *devptr, unsigned int n) -{ - return 1; -} - -static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) +static int __devinit snd_miro_probe(struct snd_card *card) { - static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; - static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; - static int possible_irqs[] = {11, 9, 10, 7, -1}; - static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; - static int possible_dma1s[] = {3, 1, 0, -1}; - static int possible_dma2s[][2] = {{1,-1}, {0,-1}, {-1,-1}, {0,-1}}; - int error; - struct snd_miro *miro; + struct snd_miro *miro = card->private_data; struct snd_wss *codec; struct snd_timer *timer; - struct snd_card *card; struct snd_pcm *pcm; struct snd_rawmidi *rmidi; - error = snd_card_create(index, id, THIS_MODULE, - sizeof(struct snd_miro), &card); - if (error < 0) - return error; - - card->private_free = snd_card_miro_free; - miro = card->private_data; - - error = snd_card_miro_detect(card, miro); - if (error < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); - return -ENODEV; + if (!miro->res_mc_base) { + miro->res_mc_base = request_region(miro->mc_base, + miro->mc_base_size, + "miro (OPTi9xx MC)"); + if (miro->res_mc_base == NULL) { + snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); + return -ENOMEM; + } } - if ((error = snd_card_miro_aci_detect(card, miro)) < 0) { + error = snd_card_miro_aci_detect(card, miro); + if (error < 0) { snd_card_free(card); snd_printk(KERN_ERR "unable to detect aci chip\n"); return -ENODEV; } - /* init proc interface */ - snd_miro_proc_init(card, miro); - - - if (! miro->res_mc_base && - (miro->res_mc_base = request_region(miro->mc_base, miro->mc_base_size, - "miro (OPTi9xx MC)")) == NULL) { - snd_card_free(card); - snd_printk(KERN_ERR "request for OPTI9xx MC failed\n"); - return -ENOMEM; - } - miro->wss_base = port; + miro->mpu_port = mpu_port; miro->irq = irq; miro->mpu_irq = mpu_irq; miro->dma1 = dma1; miro->dma2 = dma2; - if (miro->wss_base == SNDRV_AUTO_PORT) { - if ((miro->wss_base = snd_legacy_find_free_ioport(possible_ports, 4)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free WSS port\n"); - return -EBUSY; - } - } - - if (mpu_port == SNDRV_AUTO_PORT) { - mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); - if (mpu_port < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 port\n"); - return -EBUSY; - } - } - miro->mpu_port = mpu_port; - - if (miro->irq == SNDRV_AUTO_IRQ) { - if ((miro->irq = snd_legacy_find_free_irq(possible_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free IRQ\n"); - return -EBUSY; - } - } - if (miro->mpu_irq == SNDRV_AUTO_IRQ) { - if ((miro->mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free MPU401 IRQ\n"); - return -EBUSY; - } - } - if (miro->dma1 == SNDRV_AUTO_DMA) { - if ((miro->dma1 = snd_legacy_find_free_dma(possible_dma1s)) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA1\n"); - return -EBUSY; - } - } - if (miro->dma2 == SNDRV_AUTO_DMA) { - if ((miro->dma2 = snd_legacy_find_free_dma(possible_dma2s[miro->dma1 % 4])) < 0) { - snd_card_free(card); - snd_printk(KERN_ERR "unable to find a free DMA2\n"); - return -EBUSY; - } - } + /* init proc interface */ + snd_miro_proc_init(card, miro); error = snd_miro_configure(miro); - if (error) { - snd_card_free(card); + if (error) return error; - } error = snd_wss_create(card, miro->wss_base + 4, -1, - miro->irq, miro->dma1, miro->dma2, - WSS_HW_AD1845, 0, &codec); - if (error < 0) { - snd_card_free(card); + miro->irq, miro->dma1, miro->dma2, + WSS_HW_DETECT, 0, &codec); + if (error < 0) return error; - } error = snd_wss_pcm(codec, 0, &pcm); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_mixer(codec); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } + error = snd_wss_timer(codec, 0, &timer); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } miro->pcm = pcm; error = snd_miro_mixer(card, miro); - if (error < 0) { - snd_card_free(card); + if (error < 0) return error; - } if (miro->aci->aci_vendor == 'm') { /* It looks like a miro sound card. */ @@ -1425,20 +1354,111 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; struct snd_opl4 *opl4; + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) snd_printk(KERN_WARNING "no OPL4 device at 0x%lx\n", fm_port); } - if ((error = snd_set_aci_init_values(miro)) < 0) { - snd_card_free(card); + error = snd_set_aci_init_values(miro); + if (error < 0) return error; + + return snd_card_register(card); +} + +static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) +{ + return 1; +} + +static int __devinit snd_miro_isa_probe(struct device *devptr, unsigned int n) +{ + static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; + static long possible_mpu_ports[] = {0x330, 0x300, 0x310, 0x320, -1}; + static int possible_irqs[] = {11, 9, 10, 7, -1}; + static int possible_mpu_irqs[] = {10, 5, 9, 7, -1}; + static int possible_dma1s[] = {3, 1, 0, -1}; + static int possible_dma2s[][2] = { {1, -1}, {0, -1}, {-1, -1}, + {0, -1} }; + + int error; + struct snd_miro *miro; + struct snd_card *card; + + error = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (error < 0) + return error; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + error = snd_card_miro_detect(card, miro); + if (error < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to detect OPTi9xx chip\n"); + return -ENODEV; + } + + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free WSS port\n"); + return -EBUSY; + } + } + + if (mpu_port == SNDRV_AUTO_PORT) { + mpu_port = snd_legacy_find_free_ioport(possible_mpu_ports, 2); + if (mpu_port < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 port\n"); + return -EBUSY; + } + } + + if (irq == SNDRV_AUTO_IRQ) { + irq = snd_legacy_find_free_irq(possible_irqs); + if (irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free IRQ\n"); + return -EBUSY; + } + } + if (mpu_irq == SNDRV_AUTO_IRQ) { + mpu_irq = snd_legacy_find_free_irq(possible_mpu_irqs); + if (mpu_irq < 0) { + snd_card_free(card); + snd_printk(KERN_ERR + "unable to find a free MPU401 IRQ\n"); + return -EBUSY; + } + } + if (dma1 == SNDRV_AUTO_DMA) { + dma1 = snd_legacy_find_free_dma(possible_dma1s); + if (dma1 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA1\n"); + return -EBUSY; + } + } + if (dma2 == SNDRV_AUTO_DMA) { + dma2 = snd_legacy_find_free_dma(possible_dma2s[dma1 % 4]); + if (dma2 < 0) { + snd_card_free(card); + snd_printk(KERN_ERR "unable to find a free DMA2\n"); + return -EBUSY; + } } snd_card_set_dev(card, devptr); - if ((error = snd_card_register(card))) { + error = snd_miro_probe(card); + if (error < 0) { snd_card_free(card); return error; } @@ -1447,7 +1467,8 @@ static int __devinit snd_miro_probe(struct device *devptr, unsigned int n) return 0; } -static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) +static int __devexit snd_miro_isa_remove(struct device *devptr, + unsigned int dev) { snd_card_free(dev_get_drvdata(devptr)); dev_set_drvdata(devptr, NULL); @@ -1457,9 +1478,9 @@ static int __devexit snd_miro_remove(struct device *devptr, unsigned int dev) #define DEV_NAME "miro" static struct isa_driver snd_miro_driver = { - .match = snd_miro_match, - .probe = snd_miro_probe, - .remove = __devexit_p(snd_miro_remove), + .match = snd_miro_isa_match, + .probe = snd_miro_isa_probe, + .remove = __devexit_p(snd_miro_isa_remove), /* FIXME: suspend/resume */ .driver = { .name = DEV_NAME -- cgit v1.2.3 From 306ecee926cf79f1b3b5f6035be09ef3d83f1b76 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Mon, 30 Nov 2009 07:46:56 +0100 Subject: ALSA: opti-miro: add PnP detection The PCM12 and PCM20 can be set into the ISA PnP mode. The PCM12 PnP was sold as the PnP device. Add code to handle detection of these cards using ISA PnP framework. Tested on the PCM20 in PnP mode. The PCM12 PnP has the same MS Windows INF file except for a card name displayed for user. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/miro.c | 203 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 192 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index c67bc3cd2c65..6123c7531110 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -60,6 +61,9 @@ static int dma1 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int dma2 = SNDRV_DEFAULT_DMA1; /* 0,1,3 */ static int wss; static int ide; +#ifdef CONFIG_PNP +static int isapnp = 1; /* Enable ISA PnP detection */ +#endif module_param(index, int, 0444); MODULE_PARM_DESC(index, "Index value for miro soundcard."); @@ -83,6 +87,10 @@ module_param(wss, int, 0444); MODULE_PARM_DESC(wss, "wss mode"); module_param(ide, int, 0444); MODULE_PARM_DESC(ide, "enable ide port"); +#ifdef CONFIG_PNP +module_param(isapnp, bool, 0444); +MODULE_PARM_DESC(isapnp, "Enable ISA PnP detection for specified soundcard."); +#endif #define OPTi9XX_HW_DETECT 0 #define OPTi9XX_HW_82C928 1 @@ -131,6 +139,21 @@ static char * snd_opti9xx_names[] = { "82C930", "82C931", "82C933" }; +static int snd_miro_pnp_is_probed; + +#ifdef CONFIG_PNP + +static struct pnp_card_device_id snd_miro_pnpids[] = { + /* PCM20 and PCM12 in PnP mode */ + { .id = "MIR0924", + .devs = { { "MIR0000" }, { "MIR0002" }, { "MIR0005" } }, }, + { .id = "" } +}; + +MODULE_DEVICE_TABLE(pnp_card, snd_miro_pnpids); + +#endif /* CONFIG_PNP */ + /* * ACI control */ @@ -781,17 +804,23 @@ static int __devinit snd_miro_init(struct snd_miro *chip, chip->mpu_port = -1; chip->mpu_irq = -1; + chip->pwd_reg = 3; + +#ifdef CONFIG_PNP + if (isapnp && chip->mc_base) + /* PnP resource gives the least 10 bits */ + chip->mc_base |= 0xc00; + else +#endif + chip->mc_base = 0xf8c; + switch (hardware) { case OPTi9XX_HW_82C929: - chip->mc_base = 0xf8c; chip->password = 0xe3; - chip->pwd_reg = 3; break; case OPTi9XX_HW_82C924: - chip->mc_base = 0xf8c; chip->password = 0xe5; - chip->pwd_reg = 3; break; default: @@ -1014,17 +1043,22 @@ static int __devinit snd_miro_configure(struct snd_miro *chip) return -EINVAL; } - switch (chip->wss_base) { - case 0x530: + /* PnP resource says it decodes only 10 bits of address */ + switch (chip->wss_base & 0x3ff) { + case 0x130: + chip->wss_base = 0x530; wss_base_bits = 0x00; break; - case 0x604: + case 0x204: + chip->wss_base = 0x604; wss_base_bits = 0x03; break; - case 0xe80: + case 0x280: + chip->wss_base = 0xe80; wss_base_bits = 0x01; break; - case 0xf40: + case 0x340: + chip->wss_base = 0xf40; wss_base_bits = 0x02; break; default: @@ -1238,7 +1272,7 @@ static int __devinit snd_card_miro_aci_detect(struct snd_card *card, static void snd_card_miro_free(struct snd_card *card) { struct snd_miro *miro = card->private_data; - + release_and_free_resource(miro->res_aci_port); if (miro->aci) miro->aci->aci_port = 0; @@ -1370,6 +1404,12 @@ static int __devinit snd_miro_probe(struct snd_card *card) static int __devinit snd_miro_isa_match(struct device *devptr, unsigned int n) { +#ifdef CONFIG_PNP + if (snd_miro_pnp_is_probed) + return 0; + if (isapnp) + return 0; +#endif return 1; } @@ -1487,14 +1527,155 @@ static struct isa_driver snd_miro_driver = { }, }; +#ifdef CONFIG_PNP + +static int __devinit snd_card_miro_pnp(struct snd_miro *chip, + struct pnp_card_link *card, + const struct pnp_card_device_id *pid) +{ + struct pnp_dev *pdev; + int err; + struct pnp_dev *devmpu; + struct pnp_dev *devmc; + + pdev = pnp_request_card_device(card, pid->devs[0].id, NULL); + if (pdev == NULL) + return -EBUSY; + + devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); + if (devmpu == NULL) + return -EBUSY; + + devmc = pnp_request_card_device(card, pid->devs[2].id, NULL); + if (devmc == NULL) + return -EBUSY; + + err = pnp_activate_dev(pdev); + if (err < 0) { + snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); + return err; + } + + err = pnp_activate_dev(devmc); + if (err < 0) { + snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n", + err); + return err; + } + + port = pnp_port_start(pdev, 1); + fm_port = pnp_port_start(pdev, 2) + 8; + + /* + * The MC(0) is never accessed and the miroSOUND PCM20 card does not + * include it in the PnP resource range. OPTI93x include it. + */ + chip->mc_base = pnp_port_start(devmc, 0) - 1; + chip->mc_base_size = pnp_port_len(devmc, 0) + 1; + + irq = pnp_irq(pdev, 0); + dma1 = pnp_dma(pdev, 0); + dma2 = pnp_dma(pdev, 1); + + if (mpu_port > 0) { + err = pnp_activate_dev(devmpu); + if (err < 0) { + snd_printk(KERN_ERR "MPU401 pnp configure failure\n"); + mpu_port = -1; + return err; + } + mpu_port = pnp_port_start(devmpu, 0); + mpu_irq = pnp_irq(devmpu, 0); + } + return 0; +} + +static int __devinit snd_miro_pnp_probe(struct pnp_card_link *pcard, + const struct pnp_card_device_id *pid) +{ + struct snd_card *card; + int err; + struct snd_miro *miro; + + if (snd_miro_pnp_is_probed) + return -EBUSY; + if (!isapnp) + return -ENODEV; + err = snd_card_create(index, id, THIS_MODULE, + sizeof(struct snd_miro), &card); + if (err < 0) + return err; + + card->private_free = snd_card_miro_free; + miro = card->private_data; + + err = snd_card_miro_pnp(miro, pcard, pid); + if (err) { + snd_card_free(card); + return err; + } + + /* only miroSOUND PCM20 and PCM12 == OPTi924 */ + err = snd_miro_init(miro, OPTi9XX_HW_82C924); + if (err) { + snd_card_free(card); + return err; + } + + err = snd_miro_opti_check(miro); + if (err) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return err; + } + + snd_card_set_dev(card, &pcard->card->dev); + err = snd_miro_probe(card); + if (err < 0) { + snd_card_free(card); + return err; + } + pnp_set_card_drvdata(pcard, card); + snd_miro_pnp_is_probed = 1; + return 0; +} + +static void __devexit snd_miro_pnp_remove(struct pnp_card_link * pcard) +{ + snd_card_free(pnp_get_card_drvdata(pcard)); + pnp_set_card_drvdata(pcard, NULL); + snd_miro_pnp_is_probed = 0; +} + +static struct pnp_card_driver miro_pnpc_driver = { + .flags = PNP_DRIVER_RES_DISABLE, + .name = "miro", + .id_table = snd_miro_pnpids, + .probe = snd_miro_pnp_probe, + .remove = __devexit_p(snd_miro_pnp_remove), +}; +#endif + static int __init alsa_card_miro_init(void) { +#ifdef CONFIG_PNP + pnp_register_card_driver(&miro_pnpc_driver); + if (snd_miro_pnp_is_probed) + return 0; + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif return isa_register_driver(&snd_miro_driver, 1); } static void __exit alsa_card_miro_exit(void) { - isa_unregister_driver(&snd_miro_driver); + if (!snd_miro_pnp_is_probed) { + isa_unregister_driver(&snd_miro_driver); + return; + } +#ifdef CONFIG_PNP + pnp_unregister_card_driver(&miro_pnpc_driver); +#endif } module_init(alsa_card_miro_init) -- cgit v1.2.3 From 45d4ebf1a6255f2234a041685789cbecac3453f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Nov 2009 11:58:30 +0100 Subject: ALSA: hda - Add a position_fix quirk for MSI Wind U115 MSI Wind U115 seems to require position_fix=1 explicitly. Otherwise it screws up PulseAudio. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 91bcbdad5af5..238651bab3f5 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2234,6 +2234,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { SND_PCI_QUIRK(0x1028, 0x01cc, "Dell D820", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01de, "Dell Precision 390", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), {} }; -- cgit v1.2.3 From 4acd57c3de62374fe5bb52e5cd24538190f4eab2 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Nov 2009 16:39:52 +0000 Subject: ALSA: AACI: fix AC97 multiple-open bug Signed-off-by: Russell King Cc: Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1f0f8213e2d5..1cb7c282a1fb 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -504,6 +504,10 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, int err; aaci_pcm_hw_free(substream); + if (aacirun->pcm_open) { + snd_ac97_pcm_close(aacirun->pcm); + aacirun->pcm_open = 0; + } err = devdma_hw_alloc(NULL, substream, params_buffer_bytes(params)); -- cgit v1.2.3 From 8ee763b9c82c6ca0a59a7271ce4fa29d7baf5c09 Mon Sep 17 00:00:00 2001 From: Russell King Date: Sun, 29 Nov 2009 16:39:59 +0000 Subject: ALSA: AACI: fix recording bug pcm->r[1].slots is the double rate slot information, not the capture information. For capture, 'pcm' will already be the capture ac97 pcm structure. Signed-off-by: Russell King Cc: Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1cb7c282a1fb..6c160a038b23 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -521,7 +521,7 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, else err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), params_channels(params), - aacirun->pcm->r[1].slots); + aacirun->pcm->r[0].slots); if (err) goto out; -- cgit v1.2.3 From 854206b074581957e7b5c955001c329f94986b4c Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Mon, 30 Nov 2009 18:22:04 +0100 Subject: ALSA: hda - Fix Cxt5047 test mode The NID 0x1a of Conexant 5047 chip is a mic boost volume only with the output amp unlike 5045 chip. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 60810ba899d1..a09c03c3f62b 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1410,16 +1410,7 @@ static struct snd_kcontrol_new cxt5047_test_mixer[] = { .get = conexant_mux_enum_get, .put = conexant_mux_enum_put, }, - HDA_CODEC_VOLUME("Input-1 Volume", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_MUTE("Input-1 Switch", 0x1a, 0x0, HDA_INPUT), - HDA_CODEC_VOLUME("Input-2 Volume", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_MUTE("Input-2 Switch", 0x1a, 0x1, HDA_INPUT), - HDA_CODEC_VOLUME("Input-3 Volume", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_MUTE("Input-3 Switch", 0x1a, 0x2, HDA_INPUT), - HDA_CODEC_VOLUME("Input-4 Volume", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_MUTE("Input-4 Switch", 0x1a, 0x3, HDA_INPUT), - HDA_CODEC_VOLUME("Input-5 Volume", 0x1a, 0x4, HDA_INPUT), - HDA_CODEC_MUTE("Input-5 Switch", 0x1a, 0x4, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost Volume", 0x1a, 0x0, HDA_OUTPUT), { } /* end */ }; -- cgit v1.2.3 From cfc9b06f0befe50ef02253f72b76946363549031 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2009 12:19:37 +0100 Subject: ALSA: hda - Add a pin-fix for FSC Amilo Pi1505 FSC Amilo Pi 1505 has a buggy BIOS and doesn't set up the HP and speaker pins properly. Add the pinfix entry for that. Reference: Novell bnc#557403 https://bugzilla.novell.com/show_bug.cgi?id=557403 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 7e8b17a1769a..a38a81e53863 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -14543,6 +14543,27 @@ static struct alc_config_preset alc861_presets[] = { }, }; +/* Pin config fixes */ +enum { + PINFIX_FSC_AMILO_PI1505, +}; + +static struct alc_pincfg alc861_fsc_amilo_pi1505_pinfix[] = { + { 0x0b, 0x0221101f }, /* HP */ + { 0x0f, 0x90170310 }, /* speaker */ + { } +}; + +static const struct alc_fixup alc861_fixups[] = { + [PINFIX_FSC_AMILO_PI1505] = { + .pins = alc861_fsc_amilo_pi1505_pinfix + }, +}; + +static struct snd_pci_quirk alc861_fixup_tbl[] = { + SND_PCI_QUIRK(0x1734, 0x10c7, "FSC Amilo Pi1505", PINFIX_FSC_AMILO_PI1505), + {} +}; static int patch_alc861(struct hda_codec *codec) { @@ -14566,6 +14587,8 @@ static int patch_alc861(struct hda_codec *codec) board_config = ALC861_AUTO; } + alc_pick_fixup(codec, alc861_fixup_tbl, alc861_fixups); + if (board_config == ALC861_AUTO) { /* automatic parse from the BIOS config */ err = alc861_parse_auto_config(codec); -- cgit v1.2.3 From 2f703e7a2ea5f6d5ea14a7b2cd0d31be07839ac6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2009 14:17:37 +0100 Subject: ALSA: hda - Add position_fix quirk for HP dv3 HP dv3 requires position_fix=1. Reference: Novell bnc#555935 https://bugzilla.novell.com/show_bug.cgi?id=555935 Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 238651bab3f5..d822bfc6cad6 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2233,6 +2233,7 @@ static int azx_dev_free(struct snd_device *device) static struct snd_pci_quirk position_fix_list[] __devinitdata = { 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), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), {} -- cgit v1.2.3 From e0feefc70c1bb3f51aa9bb42acfd22cd7472a5d9 Mon Sep 17 00:00:00 2001 From: Alexey Fisher Date: Tue, 1 Dec 2009 13:40:53 +0100 Subject: ALSA: usb - Fix mixer map for Hercules Gamesurround Muse Pocket LT Muse Pocket use brocken mixer names, so alsamixer and PA can't use it correctly This patch add quirk to overwirte default mixers. Signed-off-by: Alexey Fisher Signed-off-by: Takashi Iwai --- sound/usb/usbmixer_maps.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'sound') diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 3e5d66cf1f5a..77c35885e21c 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c @@ -277,6 +277,22 @@ static struct usbmix_name_map scratch_live_map[] = { { 0 } /* terminator */ }; +/* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+" + * most importand difference is SU[8], it should be set to "Capture Source" + * to make alsamixer and PA working properly. + * FIXME: or mp3plus_map should use "Capture Source" too, + * so this maps can be merget + */ +static struct usbmix_name_map hercules_usb51_map[] = { + { 8, "Capture Source" }, /* SU, default "PCM Capture Source" */ + { 9, "Master Playback" }, /* FU, default "Speaker Playback" */ + { 10, "Mic Boost", 7 }, /* FU, default "Auto Gain Input" */ + { 11, "Line Capture" }, /* FU, default "PCM Capture" */ + { 13, "Mic Bypass Playback" }, /* FU, default "Mic Playback" */ + { 14, "Line Bypass Playback" }, /* FU, default "Line Playback" */ + { 0 } /* terminator */ +}; + /* * Control map entries */ @@ -315,6 +331,13 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .id = USB_ID(0x06f8, 0xd002), .ignore_ctl_error = 1, }, + { + /* Hercules Gamesurround Muse Pocket LT + * (USB 5.1 Channel Audio Adapter) + */ + .id = USB_ID(0x06f8, 0xc000), + .map = hercules_usb51_map, + }, { .id = USB_ID(0x08bb, 0x2702), .map = linex_map, -- cgit v1.2.3 From cf5bd652c384cf58544f43bea097bbc9cf14e4f5 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 1 Dec 2009 16:36:56 +0100 Subject: ALSA: aaci - Clean up duplicate code Now snd_ac97_pcm_open() is called with the exactly same arguments for both playback and capture directions. Remove the unneeded check. Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index eb715e732106..83b0328d389e 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -511,15 +511,9 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, if (err < 0) goto out; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - else - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); if (err) goto out; -- cgit v1.2.3 From d8ea23931ce83b56801976e6f1fa893462c1c477 Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 2 Dec 2009 23:27:12 +0100 Subject: ALSA: opti9xx: remove snd_opti9xx fields Remove snd_opti9xx fields which are indirect arguments to the snd_opti9xx_configure(). Pass these values as function arguments. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 110 +++++++++++++++---------------------- 1 file changed, 43 insertions(+), 67 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 5cd555325b9d..d08c38906449 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -141,15 +141,7 @@ struct snd_opti9xx { spinlock_t lock; - long wss_base; int irq; - int dma1; - int dma2; - - long fm_port; - - long mpu_port; - int mpu_irq; #ifdef CONFIG_PNP struct pnp_dev *dev; @@ -216,13 +208,7 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, spin_lock_init(&chip->lock); - chip->wss_base = -1; chip->irq = -1; - chip->dma1 = -1; - chip->dma2 = -1; - chip->fm_port = -1; - chip->mpu_port = -1; - chip->mpu_irq = -1; switch (hardware) { #ifndef OPTi93X @@ -348,7 +334,10 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, (snd_opti9xx_read(chip, reg) & ~(mask)) | ((value) & (mask))) -static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) +static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, + long wss_base, + int irq, int dma1, int dma2, + long mpu_port, int mpu_irq) { unsigned char wss_base_bits; unsigned char irq_bits; @@ -416,7 +405,7 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) return -EINVAL; } - switch (chip->wss_base) { + switch (wss_base) { case 0x530: wss_base_bits = 0x00; break; @@ -430,14 +419,13 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip) wss_base_bits = 0x02; break; default: - snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", - chip->wss_base); + snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base); goto __skip_base; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30); __skip_base: - switch (chip->irq) { + switch (irq) { //#ifdef OPTi93X case 5: irq_bits = 0x05; @@ -456,11 +444,11 @@ __skip_base: irq_bits = 0x04; break; default: - snd_printk(KERN_WARNING "WSS irq # %d not valid\n", chip->irq); + snd_printk(KERN_WARNING "WSS irq # %d not valid\n", irq); goto __skip_resources; } - switch (chip->dma1) { + switch (dma1) { case 0: dma_bits = 0x01; break; @@ -471,38 +459,36 @@ __skip_base: dma_bits = 0x03; break; default: - snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", - chip->dma1); + snd_printk(KERN_WARNING "WSS dma1 # %d not valid\n", dma1); goto __skip_resources; } #if defined(CS4231) || defined(OPTi93X) - if (chip->dma1 == chip->dma2) { + if (dma1 == dma2) { snd_printk(KERN_ERR "don't want to share dmas\n"); return -EBUSY; } - switch (chip->dma2) { + switch (dma2) { case 0: case 1: break; default: - snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", - chip->dma2); + snd_printk(KERN_WARNING "WSS dma2 # %d not valid\n", dma2); goto __skip_resources; } dma_bits |= 0x04; #endif /* CS4231 || OPTi93X */ #ifndef OPTi93X - outb(irq_bits << 3 | dma_bits, chip->wss_base); + outb(irq_bits << 3 | dma_bits, wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ __skip_resources: if (chip->hardware > OPTi9XX_HW_82C928) { - switch (chip->mpu_port) { + switch (mpu_port) { case 0: case -1: break; @@ -520,12 +506,11 @@ __skip_resources: break; default: snd_printk(KERN_WARNING - "MPU-401 port 0x%lx not valid\n", - chip->mpu_port); + "MPU-401 port 0x%lx not valid\n", mpu_port); goto __skip_mpu; } - switch (chip->mpu_irq) { + switch (mpu_irq) { case 5: mpu_irq_bits = 0x02; break; @@ -540,12 +525,12 @@ __skip_resources: break; default: snd_printk(KERN_WARNING "MPU-401 irq # %d not valid\n", - chip->mpu_irq); + mpu_irq); goto __skip_mpu; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), - (chip->mpu_port <= 0) ? 0x00 : + (mpu_port <= 0) ? 0x00 : 0x80 | mpu_port_bits << 5 | mpu_irq_bits << 3, 0xf8); } @@ -701,6 +686,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) { static long possible_ports[] = {0x530, 0xe80, 0xf40, 0x604, -1}; int error; + int xdma2; struct snd_opti9xx *chip = card->private_data; struct snd_wss *codec; #ifdef CS4231 @@ -715,31 +701,25 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) "OPTi9xx MC")) == NULL) return -ENOMEM; - chip->wss_base = port; - chip->fm_port = fm_port; - chip->mpu_port = mpu_port; - chip->irq = irq; - chip->mpu_irq = mpu_irq; - chip->dma1 = dma1; #if defined(CS4231) || defined(OPTi93X) - chip->dma2 = dma2; + xdma2 = dma2; #else - chip->dma2 = -1; + xdma2 = -1; #endif - if (chip->wss_base == SNDRV_AUTO_PORT) { - chip->wss_base = snd_legacy_find_free_ioport(possible_ports, 4); - if (chip->wss_base < 0) { + if (port == SNDRV_AUTO_PORT) { + port = snd_legacy_find_free_ioport(possible_ports, 4); + if (port < 0) { snd_printk(KERN_ERR "unable to find a free WSS port\n"); return -EBUSY; } } - error = snd_opti9xx_configure(chip); + error = snd_opti9xx_configure(chip, port, irq, dma1, xdma2, + mpu_port, mpu_irq); if (error) return error; - error = snd_wss_create(card, chip->wss_base + 4, -1, - chip->irq, chip->dma1, chip->dma2, + error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2, #ifdef OPTi93X WSS_HW_OPTI93X, WSS_HWSHARE_IRQ, #else @@ -763,35 +743,35 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) return error; #endif #ifdef OPTi93X - error = request_irq(chip->irq, snd_opti93x_interrupt, + error = request_irq(irq, snd_opti93x_interrupt, IRQF_DISABLED, DEV_NAME" - WSS", codec); if (error < 0) { snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); return error; } #endif + chip->irq = irq; strcpy(card->driver, chip->name); sprintf(card->shortname, "OPTi %s", card->driver); #if defined(CS4231) || defined(OPTi93X) sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1, chip->dma2); + card->shortname, pcm->name, port + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, chip->wss_base + 4, - chip->irq, chip->dma1); + card->shortname, pcm->name, port + 4, irq, dma1); #endif /* CS4231 || OPTi93X */ - if (chip->mpu_port <= 0 || chip->mpu_port == SNDRV_AUTO_PORT) + if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) rmidi = NULL; - else - if ((error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, - chip->mpu_port, 0, chip->mpu_irq, IRQF_DISABLED, - &rmidi))) + else { + error = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, + mpu_port, 0, mpu_irq, IRQF_DISABLED, &rmidi); + if (error) snd_printk(KERN_WARNING "no MPU-401 device at 0x%lx?\n", - chip->mpu_port); + mpu_port); + } - if (chip->fm_port > 0 && chip->fm_port != SNDRV_AUTO_PORT) { + if (fm_port > 0 && fm_port != SNDRV_AUTO_PORT) { struct snd_opl3 *opl3 = NULL; #ifndef OPTi93X if (chip->hardware == OPTi9XX_HW_82C928 || @@ -801,9 +781,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) /* assume we have an OPL4 */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x20, 0x20); - if (snd_opl4_create(card, - chip->fm_port, - chip->fm_port - 8, + if (snd_opl4_create(card, fm_port, fm_port - 8, 2, &opl3, &opl4) < 0) { /* no luck, use OPL3 instead */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), @@ -811,12 +789,10 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) } } #endif /* !OPTi93X */ - if (!opl3 && snd_opl3_create(card, - chip->fm_port, - chip->fm_port + 2, + if (!opl3 && snd_opl3_create(card, fm_port, fm_port + 2, OPL3_HW_AUTO, 0, &opl3) < 0) { snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", - chip->fm_port, chip->fm_port + 4 - 1); + fm_port, fm_port + 4 - 1); } if (opl3) { error = snd_opl3_hwdep_new(opl3, 0, 1, &synth); -- cgit v1.2.3 From 274693f37090ada2cadd09944ab883f05ea6ebe6 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 3 Dec 2009 10:07:50 +0100 Subject: ALSA: hda - Add ALC661/259, ALC892/888VD support Fixed List: 1. Add alc_read_coef_idx function 2. Add ALC661 ALC259 3. Add ALC892 ALC888VD Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 44 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index a38a81e53863..98e117bac90a 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1394,6 +1394,17 @@ static void alc_pick_fixup(struct hda_codec *codec, add_verb(codec->spec, fix->verbs); } +static int alc_read_coef_idx(struct hda_codec *codec, + unsigned int coef_idx) +{ + unsigned int val; + snd_hda_codec_write(codec, 0x20, 0, AC_VERB_SET_COEF_INDEX, + coef_idx); + val = snd_hda_codec_read(codec, 0x20, 0, + AC_VERB_GET_PROC_COEF, 0); + return val; +} + /* * ALC888 */ @@ -3472,7 +3483,7 @@ static int alc_build_pcms(struct hda_codec *codec) snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), "%s Analog", codec->chip_name); info->name = spec->stream_name_analog; - + if (spec->stream_analog_playback) { if (snd_BUG_ON(!spec->multiout.dac_nids)) return -EINVAL; @@ -13445,6 +13456,13 @@ static int patch_alc269(struct hda_codec *codec) alc_fix_pll_init(codec, 0x20, 0x04, 15); + if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC259", GFP_KERNEL); + if (!codec->chip_name) + return -ENOMEM; + } + board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, alc269_models, alc269_cfg_tbl); @@ -17444,6 +17462,13 @@ static int patch_alc662(struct hda_codec *codec) alc_fix_pll_init(codec, 0x20, 0x04, 15); + if (alc_read_coef_idx(codec, 0)==0x8020){ + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC661", GFP_KERNEL); + if (!codec->chip_name) + return -ENOMEM; + } + board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, alc662_models, alc662_cfg_tbl); @@ -17510,6 +17535,20 @@ static int patch_alc662(struct hda_codec *codec) return 0; } +static int patch_alc888(struct hda_codec *codec) +{ + if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){ + kfree(codec->chip_name); + codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); + if (!codec->chip_name) + return -ENOMEM; + patch_alc662(codec); + } else { + patch_alc882(codec); + } + return 0; +} + /* * patch entries */ @@ -17541,8 +17580,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0887, .name = "ALC887", .patch = patch_alc882 }, { .id = 0x10ec0888, .rev = 0x100101, .name = "ALC1200", .patch = patch_alc882 }, - { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc882 }, + { .id = 0x10ec0888, .name = "ALC888", .patch = patch_alc888 }, { .id = 0x10ec0889, .name = "ALC889", .patch = patch_alc882 }, + { .id = 0x10ec0892, .name = "ALC892", .patch = patch_alc662 }, {} /* terminator */ }; -- cgit v1.2.3 From ac2c92e0cd06387ecee8115f5fa385fba6413c42 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 3 Dec 2009 10:14:10 +0100 Subject: ALSA: hda - Fix memory leaks in the previous patch The previous hack for replacing the codec name give memory leaks at error paths. This patch fixes them. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 98e117bac90a..d967836f36bb 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -13459,8 +13459,10 @@ static int patch_alc269(struct hda_codec *codec) if ((alc_read_coef_idx(codec, 0) & 0x00f0) == 0x0010){ kfree(codec->chip_name); codec->chip_name = kstrdup("ALC259", GFP_KERNEL); - if (!codec->chip_name) + if (!codec->chip_name) { + alc_free(codec); return -ENOMEM; + } } board_config = snd_hda_check_board_config(codec, ALC269_MODEL_LAST, @@ -17465,8 +17467,10 @@ static int patch_alc662(struct hda_codec *codec) if (alc_read_coef_idx(codec, 0)==0x8020){ kfree(codec->chip_name); codec->chip_name = kstrdup("ALC661", GFP_KERNEL); - if (!codec->chip_name) + if (!codec->chip_name) { + alc_free(codec); return -ENOMEM; + } } board_config = snd_hda_check_board_config(codec, ALC662_MODEL_LAST, @@ -17540,13 +17544,13 @@ static int patch_alc888(struct hda_codec *codec) if ((alc_read_coef_idx(codec, 0) & 0x00f0)==0x0030){ kfree(codec->chip_name); codec->chip_name = kstrdup("ALC888-VD", GFP_KERNEL); - if (!codec->chip_name) + if (!codec->chip_name) { + alc_free(codec); return -ENOMEM; - patch_alc662(codec); - } else { - patch_alc882(codec); + } + return patch_alc662(codec); } - return 0; + return patch_alc882(codec); } /* -- cgit v1.2.3 From 1233faa891451dee9eaddd7f8a616ba1ddd77919 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 27 Nov 2009 18:19:28 +0100 Subject: ALSA: tea575x-tuner: fix mute Fix mute state reporting in tea575x-tuner. This fixes mute function in kradio on SF64-PCR radio card. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/i2c/other/tea575x-tuner.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/i2c/other/tea575x-tuner.c b/sound/i2c/other/tea575x-tuner.c index d31c373e076d..c4c6ef73f9bf 100644 --- a/sound/i2c/other/tea575x-tuner.c +++ b/sound/i2c/other/tea575x-tuner.c @@ -225,7 +225,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, case V4L2_CID_AUDIO_MUTE: if (tea->ops->mute) { tea->ops->mute(tea, ctrl->value); - tea->mute = 1; + tea->mute = ctrl->value; return 0; } } -- cgit v1.2.3 From fb716c0b7bed36064cd41d800c8f339f41adf084 Mon Sep 17 00:00:00 2001 From: Ondrej Zary Date: Fri, 27 Nov 2009 18:18:33 +0100 Subject: snd-fm801: autodetect SF64-PCR (tuner-only) card MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When primary AC97 is not found, don't fail with tons of AC97 errors. Assume that the card is SF64-PCR (tuner-only). This makes the SF64-PCR radio card work "out of the box". Also fixes a bug that can cause an oops here:         if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { when tea575x_tuner == 16, it passes this check and causes problems a couple lines below:         chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; Tested with SF64-PCR, but I don't have any of those sound or sound+radio cards to test if I didn't break anything. Signed-off-by: Ondrej Zary Signed-off-by: Takashi Iwai --- sound/pci/fm801.c | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) (limited to 'sound') diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 60cdb9e0b68d..83508b3964fb 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c @@ -55,7 +55,7 @@ static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; /* Enable this card * * 1 = MediaForte 256-PCS * 2 = MediaForte 256-PCPR * 3 = MediaForte 64-PCR - * 16 = setup tuner only (this is additional bit), i.e. SF-64-PCR FM card + * 16 = setup tuner only (this is additional bit), i.e. SF64-PCR FM card * High 16-bits are video (radio) device number + 1 */ static int tea575x_tuner[SNDRV_CARDS]; @@ -67,7 +67,10 @@ MODULE_PARM_DESC(id, "ID string for the FM801 soundcard."); module_param_array(enable, bool, NULL, 0444); MODULE_PARM_DESC(enable, "Enable FM801 soundcard."); module_param_array(tea575x_tuner, int, NULL, 0444); -MODULE_PARM_DESC(tea575x_tuner, "Enable TEA575x tuner."); +MODULE_PARM_DESC(tea575x_tuner, "TEA575x tuner access method (1 = SF256-PCS, 2=SF256-PCPR, 3=SF64-PCR, +16=tuner-only)."); + +#define TUNER_ONLY (1<<4) +#define TUNER_TYPE_MASK (~TUNER_ONLY & 0xFFFF) /* * Direct registers @@ -160,7 +163,7 @@ struct fm801 { unsigned int multichannel: 1, /* multichannel support */ secondary: 1; /* secondary codec */ unsigned char secondary_addr; /* address of the secondary codec */ - unsigned int tea575x_tuner; /* tuner flags */ + unsigned int tea575x_tuner; /* tuner access method & flags */ unsigned short ply_ctrl; /* playback control */ unsigned short cap_ctrl; /* capture control */ @@ -1287,7 +1290,7 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) { unsigned short cmdw; - if (chip->tea575x_tuner & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __ac97_ok; /* codec cold reset + AC'97 warm reset */ @@ -1296,11 +1299,13 @@ static int snd_fm801_chip_init(struct fm801 *chip, int resume) udelay(100); outw(0, FM801_REG(chip, CODEC_CTRL)); - if (wait_for_codec(chip, 0, AC97_RESET, msecs_to_jiffies(750)) < 0) { - snd_printk(KERN_ERR "Primary AC'97 codec not found\n"); - if (! resume) - return -EIO; - } + 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"); + chip->tea575x_tuner = 3 | TUNER_ONLY; + goto __ac97_ok; + } if (chip->multichannel) { if (chip->secondary_addr) { @@ -1414,7 +1419,7 @@ static int __devinit snd_fm801_create(struct snd_card *card, return err; } chip->port = pci_resource_start(pci, 0); - if ((tea575x_tuner & 0x0010) == 0) { + if ((tea575x_tuner & TUNER_ONLY) == 0) { if (request_irq(pci->irq, snd_fm801_interrupt, IRQF_SHARED, "FM801", chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", chip->irq); @@ -1429,6 +1434,14 @@ static int __devinit snd_fm801_create(struct snd_card *card, chip->multichannel = 1; snd_fm801_chip_init(chip, 0); + /* init might set tuner access method */ + tea575x_tuner = chip->tea575x_tuner; + + if (chip->irq >= 0 && (tea575x_tuner & TUNER_ONLY)) { + pci_clear_master(pci); + free_irq(chip->irq, chip); + chip->irq = -1; + } if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_fm801_free(chip); @@ -1438,12 +1451,13 @@ static int __devinit snd_fm801_create(struct snd_card *card, snd_card_set_dev(card, &pci->dev); #ifdef TEA575X_RADIO - if (tea575x_tuner > 0 && (tea575x_tuner & 0x000f) < 4) { + if ((tea575x_tuner & TUNER_TYPE_MASK) > 0 && + (tea575x_tuner & TUNER_TYPE_MASK) < 4) { chip->tea.dev_nr = tea575x_tuner >> 16; chip->tea.card = card; chip->tea.freq_fixup = 10700; chip->tea.private_data = chip; - chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & 0x000f) - 1]; + chip->tea.ops = &snd_fm801_tea_ops[(tea575x_tuner & TUNER_TYPE_MASK) - 1]; snd_tea575x_init(&chip->tea); } #endif @@ -1483,7 +1497,7 @@ static int __devinit snd_card_fm801_probe(struct pci_dev *pci, sprintf(card->longname, "%s at 0x%lx, irq %i", card->shortname, chip->port, chip->irq); - if (tea575x_tuner[dev] & 0x0010) + if (chip->tea575x_tuner & TUNER_ONLY) goto __fm801_tuner_only; if ((err = snd_fm801_pcm(chip, 0, NULL)) < 0) { -- cgit v1.2.3 From fbfecd3712f917ca210a55c157233d88b785896b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 28 Oct 2009 20:11:04 +0100 Subject: tree-wide: fix typos "couter" -> "counter" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch was generated by git grep -E -i -l 'couter' | xargs -r perl -p -i -e 's/couter/counter/' Signed-off-by: Uwe Kleine-König Signed-off-by: Jiri Kosina --- sound/synth/emux/soundfont.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/synth/emux/soundfont.c b/sound/synth/emux/soundfont.c index 63c8f45c0c22..67c91230c197 100644 --- a/sound/synth/emux/soundfont.c +++ b/sound/synth/emux/soundfont.c @@ -374,7 +374,7 @@ sf_zone_new(struct snd_sf_list *sflist, struct snd_soundfont *sf) /* - * increment sample couter + * increment sample counter */ static void set_sample_counter(struct snd_sf_list *sflist, struct snd_soundfont *sf, -- cgit v1.2.3 From af901ca181d92aac3a7dc265144a9081a86d8f39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Goddard=20Rosa?= Date: Sat, 14 Nov 2009 13:09:05 -0200 Subject: tree-wide: fix assorted typos all over the place MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit That is "success", "unknown", "through", "performance", "[re|un]mapping" , "access", "default", "reasonable", "[con]currently", "temperature" , "channel", "[un]used", "application", "example","hierarchy", "therefore" , "[over|under]flow", "contiguous", "threshold", "enough" and others. Signed-off-by: André Goddard Rosa Signed-off-by: Jiri Kosina --- sound/Kconfig | 2 +- sound/isa/cs423x/cs4236.c | 2 +- sound/isa/opti9xx/miro.c | 2 +- sound/isa/opti9xx/opti92x-ad1848.c | 2 +- sound/oss/dmasound/dmasound_paula.c | 2 +- sound/pci/ca0106/ca0106_proc.c | 2 +- sound/pci/cs46xx/imgs/cwcdma.asp | 9 +++++---- sound/pci/emu10k1/emu10k1x.c | 2 +- sound/pci/hda/patch_cmedia.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- sound/pci/rme9652/hdspm.c | 4 ++-- sound/soc/codecs/uda134x.c | 4 ++-- sound/soc/codecs/wm8903.c | 6 +++--- sound/soc/codecs/wm8993.c | 4 ++-- sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +- sound/soc/s6000/s6000-pcm.c | 2 +- sound/sound_core.c | 2 +- 17 files changed, 26 insertions(+), 25 deletions(-) (limited to 'sound') diff --git a/sound/Kconfig b/sound/Kconfig index 4b5365ad6b46..fcad760f5691 100644 --- a/sound/Kconfig +++ b/sound/Kconfig @@ -55,7 +55,7 @@ config SOUND_OSS_CORE_PRECLAIM Please read Documentation/feature-removal-schedule.txt for details. - If unusre, say Y. + If unsure, say Y. source "sound/oss/dmasound/Kconfig" diff --git a/sound/isa/cs423x/cs4236.c b/sound/isa/cs423x/cs4236.c index a076a6ce8071..a828baaab636 100644 --- a/sound/isa/cs423x/cs4236.c +++ b/sound/isa/cs423x/cs4236.c @@ -177,7 +177,7 @@ static struct pnp_card_device_id snd_cs423x_pnpids[] = { { .id = "CSC0437", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* Digital PC 5000 Onboard - CS4236B */ { .id = "CSC0735", .devs = { { "CSC0000" }, { "CSC0010" } } }, - /* some uknown CS4236B */ + /* some unknown CS4236B */ { .id = "CSC0b35", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, /* Intel PR440FX Onboard sound */ { .id = "CSC0b36", .devs = { { "CSC0000" }, { "CSC0010" }, { "CSC0003" } } }, diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index 02e30d7c6a93..ddad60ef3f37 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -137,7 +137,7 @@ struct snd_miro { static void snd_miro_proc_init(struct snd_miro * miro); static char * snd_opti9xx_names[] = { - "unkown", + "unknown", "82C928", "82C929", "82C924", "82C925", "82C930", "82C931", "82C933" diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 5cd555325b9d..848007508ffd 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -185,7 +185,7 @@ MODULE_DEVICE_TABLE(pnp_card, snd_opti9xx_pnpids); #endif static char * snd_opti9xx_names[] = { - "unkown", + "unknown", "82C928", "82C929", "82C924", "82C925", "82C930", "82C931", "82C933" diff --git a/sound/oss/dmasound/dmasound_paula.c b/sound/oss/dmasound/dmasound_paula.c index 06e9e88e4c05..bb14e4c67e89 100644 --- a/sound/oss/dmasound/dmasound_paula.c +++ b/sound/oss/dmasound/dmasound_paula.c @@ -657,7 +657,7 @@ static int AmiStateInfo(char *buffer, size_t space) len += sprintf(buffer+len, "\tsound.volume_right = %d [0...64]\n", dmasound.volume_right); if (len >= space) { - printk(KERN_ERR "dmasound_paula: overlowed state buffer alloc.\n") ; + printk(KERN_ERR "dmasound_paula: overflowed state buffer alloc.\n") ; len = space ; } return len; diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index c62b7d10ec61..8d13092300da 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c @@ -233,7 +233,7 @@ static void snd_ca0106_proc_dump_iec958( struct snd_info_buffer *buffer, u32 val snd_iprintf(buffer, "user-defined\n"); break; default: - snd_iprintf(buffer, "unkown\n"); + snd_iprintf(buffer, "unknown\n"); break; } snd_iprintf(buffer, "Sample Bits: "); diff --git a/sound/pci/cs46xx/imgs/cwcdma.asp b/sound/pci/cs46xx/imgs/cwcdma.asp index 09d24c76f034..a65e1193c89a 100644 --- a/sound/pci/cs46xx/imgs/cwcdma.asp +++ b/sound/pci/cs46xx/imgs/cwcdma.asp @@ -26,10 +26,11 @@ // // // 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 throug SPDIF. SRC (source rate converters) -// task always alters the samples in some how, however it's from 48khz -> 48khz. The -// alterations are not audible, but AC3 wont work. +// 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. // // ... // | diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 36e08bd2b3cc..360e3809a60b 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c @@ -184,7 +184,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard."); * The hardware has 3 channels for playback and 1 for capture. * - channel 0 is the front channel * - channel 1 is the rear channel - * - channel 2 is the center/lfe chanel + * - channel 2 is the center/lfe channel * Volume is controlled by the AC97 for the front and rear channels by * the PCM Playback Volume, Sigmatel Surround Playback Volume and * Surround Playback Volume. The Sigmatel 4-Speaker Stereo switch affects diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index 780e1a72114a..8917071d5b6a 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c @@ -66,7 +66,7 @@ struct cmi_spec { struct hda_pcm pcm_rec[2]; /* PCM information */ - /* pin deafault configuration */ + /* pin default configuration */ hda_nid_t pin_nid[NUM_PINS]; unsigned int def_conf[NUM_PINS]; unsigned int pin_def_confs; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index ff20048504b6..872731eb49e8 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6619,7 +6619,7 @@ static struct hda_input_mux alc889A_mb31_capture_source = { /* Front Mic (0x01) unused */ { "Line", 0x2 }, /* Line 2 (0x03) unused */ - /* CD (0x04) unsused? */ + /* CD (0x04) unused? */ }, }; diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 0dce331a2a3b..a1b10d1a384d 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -3017,7 +3017,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, insel = "Coaxial"; break; default: - insel = "Unkown"; + insel = "Unknown"; } switch (hdspm->control_register & HDSPM_SyncRefMask) { @@ -3028,7 +3028,7 @@ snd_hdspm_proc_read_madi(struct snd_info_entry * entry, syncref = "MADI"; break; default: - syncref = "Unkown"; + syncref = "Unknown"; } snd_iprintf(buffer, "Inputsel = %s, SyncRef = %s\n", insel, syncref); diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c index c33b92edbded..8ce1c9b2e5b8 100644 --- a/sound/soc/codecs/uda134x.c +++ b/sound/soc/codecs/uda134x.c @@ -101,7 +101,7 @@ static int uda134x_write(struct snd_soc_codec *codec, unsigned int reg, pr_debug("%s reg: %02X, value:%02X\n", __func__, reg, value); if (reg >= UDA134X_REGS_NUM) { - printk(KERN_ERR "%s unkown register: reg: %u", + printk(KERN_ERR "%s unknown register: reg: %u", __func__, reg); return -EINVAL; } @@ -552,7 +552,7 @@ static int uda134x_soc_probe(struct platform_device *pdev) ARRAY_SIZE(uda1341_snd_controls)); break; default: - printk(KERN_ERR "%s unkown codec type: %d", + printk(KERN_ERR "%s unknown codec type: %d", __func__, pd->model); return -EINVAL; } diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c index fe1307b500cf..d72347d90b70 100644 --- a/sound/soc/codecs/wm8903.c +++ b/sound/soc/codecs/wm8903.c @@ -607,7 +607,7 @@ SOC_SINGLE("Right Input PGA Common Mode Switch", WM8903_ANALOGUE_RIGHT_INPUT_1, SOC_SINGLE("DRC Switch", WM8903_DRC_0, 15, 1, 0), SOC_ENUM("DRC Compressor Slope R0", drc_slope_r0), SOC_ENUM("DRC Compressor Slope R1", drc_slope_r1), -SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8903_DRC_3, 5, 124, 1, +SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8903_DRC_3, 5, 124, 1, drc_tlv_thresh), SOC_SINGLE_TLV("DRC Volume", WM8903_DRC_3, 0, 30, 1, drc_tlv_amp), SOC_SINGLE_TLV("DRC Minimum Gain Volume", WM8903_DRC_1, 2, 3, 1, drc_tlv_min), @@ -617,11 +617,11 @@ SOC_ENUM("DRC Decay Rate", drc_decay), SOC_ENUM("DRC FF Delay", drc_ff_delay), SOC_SINGLE("DRC Anticlip Switch", WM8903_DRC_0, 1, 1, 0), SOC_SINGLE("DRC QR Switch", WM8903_DRC_0, 2, 1, 0), -SOC_SINGLE_TLV("DRC QR Threashold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), +SOC_SINGLE_TLV("DRC QR Threshold Volume", WM8903_DRC_0, 6, 3, 0, drc_tlv_max), SOC_ENUM("DRC QR Decay Rate", drc_qr_decay), SOC_SINGLE("DRC Smoothing Switch", WM8903_DRC_0, 3, 1, 0), SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8903_DRC_0, 0, 1, 0), -SOC_ENUM("DRC Smoothing Threashold", drc_smoothing), +SOC_ENUM("DRC Smoothing Threshold", drc_smoothing), SOC_SINGLE_TLV("DRC Startup Volume", WM8903_DRC_0, 6, 18, 0, drc_tlv_startup), SOC_DOUBLE_R_TLV("Digital Capture Volume", WM8903_ADC_DIGITAL_VOLUME_LEFT, diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c index d9987999e92c..bc033687b220 100644 --- a/sound/soc/codecs/wm8993.c +++ b/sound/soc/codecs/wm8993.c @@ -689,7 +689,7 @@ SOC_DOUBLE_TLV("Digital Sidetone Volume", WM8993_DIGITAL_SIDE_TONE, SOC_SINGLE("DRC Switch", WM8993_DRC_CONTROL_1, 15, 1, 0), SOC_ENUM("DRC Path", drc_path), -SOC_SINGLE_TLV("DRC Compressor Threashold Volume", WM8993_DRC_CONTROL_2, +SOC_SINGLE_TLV("DRC Compressor Threshold Volume", WM8993_DRC_CONTROL_2, 2, 60, 1, drc_comp_threash), SOC_SINGLE_TLV("DRC Compressor Amplitude Volume", WM8993_DRC_CONTROL_3, 11, 30, 1, drc_comp_amp), @@ -709,7 +709,7 @@ SOC_SINGLE_TLV("DRC Quick Release Volume", WM8993_DRC_CONTROL_3, 2, 3, 0, SOC_ENUM("DRC Quick Release Rate", drc_qr_rate), SOC_SINGLE("DRC Smoothing Switch", WM8993_DRC_CONTROL_1, 11, 1, 0), SOC_SINGLE("DRC Smoothing Hysteresis Switch", WM8993_DRC_CONTROL_1, 8, 1, 0), -SOC_ENUM("DRC Smoothing Hysteresis Threashold", drc_smooth), +SOC_ENUM("DRC Smoothing Hysteresis Threshold", drc_smooth), SOC_SINGLE_TLV("DRC Startup Volume", WM8993_DRC_CONTROL_4, 8, 18, 0, drc_startup_tlv), diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c index 1966e0d5652d..3c7ccb78b6ab 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -270,7 +270,7 @@ static int attach_gpio_amp(struct device *dev, gpio_direction_output(pd->amp_gain[1], 0); } - /* note, curently we assume GPA0 isn't valid amp */ + /* note, currently we assume GPA0 isn't valid amp */ if (pdata->amp_gpio > 0) { ret = gpio_request(pd->amp_gpio, "gpio-amp"); if (ret) { diff --git a/sound/soc/s6000/s6000-pcm.c b/sound/soc/s6000/s6000-pcm.c index 83b8028e209d..81d6f983f51e 100644 --- a/sound/soc/s6000/s6000-pcm.c +++ b/sound/soc/s6000/s6000-pcm.c @@ -196,7 +196,7 @@ static int s6000_pcm_start(struct snd_pcm_substream *substream) 0 /* destination skip after chunk (impossible) */, 4 /* 16 byte burst size */, -1 /* don't conserve bandwidth */, - 0 /* low watermark irq descriptor theshold */, + 0 /* low watermark irq descriptor threshold */, 0 /* disable hardware timestamps */, 1 /* enable channel */); diff --git a/sound/sound_core.c b/sound/sound_core.c index 49c998186592..dbca7c909a31 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c @@ -353,7 +353,7 @@ static struct sound_unit *chains[SOUND_STEP]; * @dev: device pointer * * Allocate a special sound device by minor number from the sound - * subsystem. The allocated number is returned on succes. On failure + * subsystem. The allocated number is returned on success. On failure * a negative error code is returned. */ -- cgit v1.2.3 From e15c1c1f3f903f679c9782b540f9d52c80c99610 Mon Sep 17 00:00:00 2001 From: Dominik Brodowski Date: Sat, 28 Nov 2009 18:12:06 +0100 Subject: pcmcia: remove unused IRQ_FIRST_SHARED Komuro pointed out that IRQ_FIRST_SHARED is not used at all in the PCMCIA subsystem, so remove it. Also, remove two bogus assignments. CC: Karsten Keil CC: netdev@vger.kernel.org CC: alsa-devel@alsa-project.org CC: Komuro Signed-off-by: Dominik Brodowski --- sound/pcmcia/pdaudiocf/pdaudiocf.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf.c b/sound/pcmcia/pdaudiocf/pdaudiocf.c index 7717e01fc071..edaa729126bb 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf.c @@ -143,7 +143,8 @@ static int snd_pdacf_probe(struct pcmcia_device *link) link->io.NumPorts1 = 16; link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_FORCED_PULSE; - // link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED; + /* FIXME: This driver should be updated to allow for dynamic IRQ sharing */ + /* link->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_FORCED_PULSE; */ link->irq.Handler = pdacf_interrupt; link->conf.Attributes = CONF_ENABLE_IRQ; -- cgit v1.2.3 From e6960e194a7dfb8197822225e04eca95fbd61a7f Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Fri, 4 Dec 2009 18:30:18 +0100 Subject: ALSA: opti93x: set MC indirect registers base from PnP data The PnP data on the OPTI931 and OPTI933 contains io port range for the MC indirect registers. Use the PnP range instead of hardwired value 0xE0E. Also, request region of MC indirect registers so it is marked as used to other drivers (this was missing previously). Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 112 ++++++++++++++++++++++--------------- 1 file changed, 67 insertions(+), 45 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index d08c38906449..8c88401c79bc 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -135,6 +135,8 @@ struct snd_opti9xx { unsigned long mc_base_size; #ifdef OPTi93X unsigned long mc_indir_index; + unsigned long mc_indir_size; + struct resource *res_mc_indir; struct snd_wss *codec; #endif /* OPTi93X */ unsigned long pwd_reg; @@ -231,7 +233,10 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, case OPTi9XX_HW_82C931: case OPTi9XX_HW_82C933: chip->mc_base = (hardware == OPTi9XX_HW_82C930) ? 0xf8f : 0xf8d; - chip->mc_indir_index = 0xe0e; + if (!chip->mc_indir_index) { + chip->mc_indir_index = 0xe0e; + chip->mc_indir_size = 2; + } chip->password = 0xe4; chip->pwd_reg = 0; break; @@ -560,57 +565,69 @@ static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) #endif /* OPTi93X */ -static int __devinit snd_card_opti9xx_detect(struct snd_card *card, - struct snd_opti9xx *chip) +static int __devinit snd_opti9xx_read_check(struct snd_opti9xx *chip) { - int i, err; + unsigned char value; +#ifdef OPTi93X + unsigned long flags; +#endif + chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, + "OPTi9xx MC"); + if (chip->res_mc_base == NULL) + return -EBUSY; #ifndef OPTi93X - for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { - unsigned char value; + value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); + if (value != 0xff && value != inb(chip->mc_base + OPTi9XX_MC_REG(1))) + if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) + return 0; +#else /* OPTi93X */ + chip->res_mc_indir = request_region(chip->mc_indir_index, + chip->mc_indir_size, + "OPTi93x MC"); + if (chip->res_mc_indir == NULL) + return -EBUSY; - if ((err = snd_opti9xx_init(chip, i)) < 0) - return err; + spin_lock_irqsave(&chip->lock, flags); + outb(chip->password, chip->mc_base + chip->pwd_reg); + outb(((chip->mc_indir_index & 0x1f0) >> 4), chip->mc_base); + spin_unlock_irqrestore(&chip->lock, flags); - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; + value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); + snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); + if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) + return 0; - value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(1)); - if ((value != 0xff) && (value != inb(chip->mc_base + 1))) - if (value == snd_opti9xx_read(chip, OPTi9XX_MC_REG(1))) - return 1; + release_and_free_resource(chip->res_mc_indir); + chip->res_mc_indir = NULL; +#endif /* OPTi93X */ + release_and_free_resource(chip->res_mc_base); + chip->res_mc_base = NULL; - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; + return -ENODEV; +} - } -#else /* OPTi93X */ - for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { - unsigned long flags; - unsigned char value; +static int __devinit snd_card_opti9xx_detect(struct snd_card *card, + struct snd_opti9xx *chip) +{ + int i, err; - if ((err = snd_opti9xx_init(chip, i)) < 0) +#ifndef OPTi93X + for (i = OPTi9XX_HW_82C928; i < OPTi9XX_HW_82C930; i++) { +#else + for (i = OPTi9XX_HW_82C931; i >= OPTi9XX_HW_82C930; i--) { +#endif + err = snd_opti9xx_init(chip, i); + if (err < 0) return err; - if ((chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, "OPTi9xx MC")) == NULL) - continue; - - spin_lock_irqsave(&chip->lock, flags); - outb(chip->password, chip->mc_base + chip->pwd_reg); - outb(((chip->mc_indir_index & (1 << 8)) >> 4) | - ((chip->mc_indir_index & 0xf0) >> 4), chip->mc_base); - spin_unlock_irqrestore(&chip->lock, flags); - - value = snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)); - snd_opti9xx_write(chip, OPTi9XX_MC_REG(7), 0xff - value); - if (snd_opti9xx_read(chip, OPTi9XX_MC_REG(7)) == 0xff - value) + err = snd_opti9xx_read_check(chip); + if (err == 0) return 1; - - release_and_free_resource(chip->res_mc_base); - chip->res_mc_base = NULL; +#ifdef OPTi93X + chip->mc_indir_index = 0; +#endif } -#endif /* OPTi93X */ - return -ENODEV; } @@ -639,6 +656,8 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, #ifdef OPTi93X port = pnp_port_start(pdev, 0) - 4; fm_port = pnp_port_start(pdev, 1) + 8; + chip->mc_indir_index = pnp_port_start(pdev, 3) + 2; + chip->mc_indir_size = pnp_port_len(pdev, 3) - 2; #else if (pid->driver_data != 0x0924) port = pnp_port_start(pdev, 1); @@ -669,7 +688,7 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, static void snd_card_opti9xx_free(struct snd_card *card) { struct snd_opti9xx *chip = card->private_data; - + if (chip) { #ifdef OPTi93X struct snd_wss *codec = chip->codec; @@ -677,6 +696,7 @@ static void snd_card_opti9xx_free(struct snd_card *card) disable_irq(codec->irq); free_irq(codec->irq, codec); } + release_and_free_resource(chip->res_mc_indir); #endif release_and_free_resource(chip->res_mc_base); } @@ -696,11 +716,6 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) struct snd_rawmidi *rmidi; struct snd_hwdep *synth; - if (! chip->res_mc_base && - (chip->res_mc_base = request_region(chip->mc_base, chip->mc_base_size, - "OPTi9xx MC")) == NULL) - return -ENOMEM; - #if defined(CS4231) || defined(OPTi93X) xdma2 = dma2; #else @@ -954,6 +969,13 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, } if (hw <= OPTi9XX_HW_82C930) chip->mc_base -= 0x80; + + error = snd_opti9xx_read_check(chip); + if (error) { + snd_printk(KERN_ERR "OPTI chip not found\n"); + snd_card_free(card); + return error; + } snd_card_set_dev(card, &pcard->card->dev); if ((error = snd_opti9xx_probe(card)) < 0) { snd_card_free(card); -- cgit v1.2.3 From 4b7e180335d23296170a5fa8c1f074722f94b253 Mon Sep 17 00:00:00 2001 From: "Justin P. Mattock" Date: Mon, 7 Dec 2009 15:07:46 -0800 Subject: ALSA: hda - iMac 9,1 sound patch. This is an updated patch for the Apple iMac 9,1 model to add sound. Original patch posted here: http://article.gmane.org/gmane.linux.alsa.devel/61361/match= I have been using this patch for a while now and have to say it works vary well, except for a few minor things: With the iMac 24-inch 3.06GHz Intel Core 2 Duo everything seems to be working as it should, although I have not looked into the microphone (never really use one, nor have any apps to test, my guess is it doesn't work, or I never figured out how to get it to work). With the iMac 24-inch 2.66GHz Intel Core 2 Duo everything is the same as with the above machine except I'm hearing a light scratchy/distortion noise come out of the speakers when using headphones(above machine does not do this). Other than that the sound level is great(especially with good Dj headphones). Signed-off-by: Justin P. Mattock Tested-by: Justin P. Mattock Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 111 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d967836f36bb..d0d14ed7ce81 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -208,6 +208,7 @@ enum { ALC885_MBP3, ALC885_MB5, ALC885_IMAC24, + ALC885_IMAC91, ALC883_3ST_2ch_DIG, ALC883_3ST_6ch_DIG, ALC883_3ST_6ch, @@ -7050,6 +7051,20 @@ static struct snd_kcontrol_new alc885_mb5_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc885_imac91_mixer[] = { + HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x0c, 0x00, HDA_OUTPUT), + HDA_BIND_MUTE ("Line-Out Playback Switch", 0x0c, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Speaker Playback Switch", 0x14, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0d, 0x00, HDA_OUTPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), + { } /* end */ +}; + + static struct snd_kcontrol_new alc882_w2jc_mixer[] = { HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), @@ -7505,6 +7520,66 @@ static struct hda_verb alc885_mbp3_init_verbs[] = { { } }; +/* iMac 9,1 */ +static struct hda_verb alc885_imac91_init_verbs[] = { + /* Line-Out mixer: unmute input/output amp left and right (volume = 0) */ + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* Rear mixer */ + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, + /* HP Pin: output 0 (0x0c) */ + {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, + {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, + /* Internal Speakers: output 0 (0x0d) */ + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* Mic (rear) pin: input vref at 80% */ + {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Front Mic pin: input vref at 80% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + /* Line In pin: use output 1 when in LineOut mode */ + {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, + + /* FIXME: use matrix-type input source selection */ + /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ + /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer2 */ + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x23, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* Input mixer3 */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, + /* ADC1: mute amp left and right */ + {0x07, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x07, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC2: mute amp left and right */ + {0x08, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x08, AC_VERB_SET_CONNECT_SEL, 0x00}, + /* ADC3: mute amp left and right */ + {0x09, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x09, AC_VERB_SET_CONNECT_SEL, 0x00}, + + { } +}; + /* iMac 24 mixer. */ static struct snd_kcontrol_new alc885_imac24_mixer[] = { HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x00, HDA_OUTPUT), @@ -7551,6 +7626,26 @@ static void alc885_mbp3_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[0] = 0x14; } +static void alc885_imac91_automute(struct hda_codec *codec) +{ + unsigned int present; + + present = snd_hda_codec_read(codec, 0x14, 0, + AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; + snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, + HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); + +} + +static void alc885_imac91_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + /* Headphone insertion or removal. */ + if ((res >> 26) == ALC880_HP_EVENT) + alc885_imac91_automute(codec); +} static struct hda_verb alc882_targa_verbs[] = { {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, @@ -8718,6 +8813,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { [ALC885_MB5] = "mb5", [ALC885_MBP3] = "mbp3", [ALC885_IMAC24] = "imac24", + [ALC885_IMAC91] = "imac91", [ALC883_3ST_2ch_DIG] = "3stack-2ch-dig", [ALC883_3ST_6ch_DIG] = "3stack-6ch-dig", [ALC883_3ST_6ch] = "3stack-6ch", @@ -8891,6 +8987,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), + SND_PCI_QUIRK(0x106b, 0x4900, "iMac 9,1 Aluminum", ALC885_IMAC91), SND_PCI_QUIRK(0x106b, 0x3f00, "Macbook 5,1", ALC885_MB5), /* FIXME: HP jack sense seems not working for MBP 5,1 or 5,2, * so apparently no perfect solution yet @@ -9002,6 +9099,20 @@ static struct alc_config_preset alc882_presets[] = { .setup = alc885_imac24_setup, .init_hook = alc885_imac24_init_hook, }, + [ALC885_IMAC91] = { + .mixers = { alc885_imac91_mixer, alc882_chmode_mixer }, + .init_verbs = { alc885_imac91_init_verbs, + alc880_gpio1_init_verbs }, + .num_dacs = ARRAY_SIZE(alc882_dac_nids), + .dac_nids = alc882_dac_nids, + .channel_mode = alc885_mbp_4ch_modes, + .num_channel_mode = ARRAY_SIZE(alc885_mbp_4ch_modes), + .input_mux = &alc882_capture_source, + .dig_out_nid = ALC882_DIGOUT_NID, + .dig_in_nid = ALC882_DIGIN_NID, + .unsol_event = alc885_imac91_unsol_event, + .init_hook = alc885_imac91_automute, + }, [ALC882_TARGA] = { .mixers = { alc882_targa_mixer, alc882_chmode_mixer }, .init_verbs = { alc882_base_init_verbs, alc882_adc1_init_verbs, -- cgit v1.2.3 From 23033b2bce4361f2859ee0331f97c9056dae7091 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2009 12:36:52 +0100 Subject: ALSA: hda - Add missing Line-Out and PCM switches as slave Realtek codecs may have "PCM" and "Line-Out" playback switches, and they can be slaves for vmaster. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d0d14ed7ce81..0fbcbeef1418 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -2401,6 +2401,8 @@ static const char *alc_slave_sws[] = { "Speaker Playback Switch", "Mono Playback Switch", "IEC958 Playback Switch", + "Line-Out Playback Switch", + "PCM Playback Switch", NULL, }; -- cgit v1.2.3 From d11f74c62fb4a1fefd39085570fb6dfa7b9ab2bb Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2009 12:52:47 +0100 Subject: ALSA: hda - Exclude unusable ADCs for ALC88x On Realtek codecs, a digital mic pin is connected often only to a single ADC. But the parser tries to set up all ADCs no matter whether the digital mic is available, and results in non-selectable input source. This patch adds a check of input-source availability of each ADC, and excludes ones that don't support all input sources. Reference: Novell bnc#561235 http://bugzilla.novell.com/show_bug.cgi?id=561235 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 0fbcbeef1418..2a96bc78964d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10021,10 +10021,12 @@ static int patch_alc882(struct hda_codec *codec) spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ if (!spec->adc_nids && spec->input_mux) { - int i; + int i, j; spec->num_adc_nids = 0; for (i = 0; i < ARRAY_SIZE(alc882_adc_nids); i++) { + const struct hda_input_mux *imux = spec->input_mux; hda_nid_t cap; + hda_nid_t items[16]; hda_nid_t nid = alc882_adc_nids[i]; unsigned int wcap = get_wcaps(codec, nid); /* get type */ @@ -10035,6 +10037,15 @@ static int patch_alc882(struct hda_codec *codec) err = snd_hda_get_connections(codec, nid, &cap, 1); if (err < 0) continue; + err = snd_hda_get_connections(codec, cap, items, + ARRAY_SIZE(items)); + if (err < 0) + continue; + for (j = 0; j < imux->num_items; j++) + if (imux->items[j].index >= err) + break; + if (j < imux->num_items) + continue; spec->private_capsrc_nids[spec->num_adc_nids] = cap; spec->num_adc_nids++; } -- cgit v1.2.3 From 2b6f6c0d11fcf6244b98d2b7490164d92d3e409f Mon Sep 17 00:00:00 2001 From: Tobias Hansen Date: Mon, 7 Dec 2009 19:08:19 +0100 Subject: ALSA: snd-usb-us122l: add product IDs of US-122MKII and US-144MKII I added the product IDs of the new revisions of the devices, so owners can test whether this suffices to make them work. Patched against ALSA snapshot 20091207. Signed-off-by: Tobias Hansen Signed-off-by: Takashi Iwai --- sound/usb/usx2y/us122l.c | 28 ++++++++++++++++++++++------ sound/usb/usx2y/us122l.h | 2 ++ 2 files changed, 24 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index f71cd28eca6b..91bb29666d26 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c @@ -194,7 +194,8 @@ static int usb_stream_hwdep_open(struct snd_hwdep *hw, struct file *file) if (!us122l->first) us122l->first = file; - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_get_interface(iface); } @@ -209,7 +210,8 @@ static int usb_stream_hwdep_release(struct snd_hwdep *hw, struct file *file) struct usb_interface *iface; snd_printdd(KERN_DEBUG "%p %p\n", hw, file); - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { iface = usb_ifnum_to_if(us122l->dev, 0); usb_autopm_put_interface(iface); } @@ -476,7 +478,8 @@ static bool us122l_create_card(struct snd_card *card) int err; struct us122l *us122l = US122L(card); - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -495,7 +498,8 @@ static bool us122l_create_card(struct snd_card *card) if (!us122l_start(us122l, 44100, 256)) return false; - if (us122l->dev->descriptor.idProduct == USB_ID_US144) + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) err = us144_create_usbmidi(card); else err = us122l_create_usbmidi(card); @@ -597,7 +601,8 @@ static int snd_us122l_probe(struct usb_interface *intf, struct snd_card *card; int err; - if (device->descriptor.idProduct == USB_ID_US144 + if ((device->descriptor.idProduct == USB_ID_US144 || + device->descriptor.idProduct == USB_ID_US144MKII) && device->speed == USB_SPEED_HIGH) { snd_printk(KERN_ERR "disable ehci-hcd to run US-144 \n"); return -ENODEV; @@ -692,7 +697,8 @@ static int snd_us122l_resume(struct usb_interface *intf) mutex_lock(&us122l->mutex); /* needed, doesn't restart without: */ - if (us122l->dev->descriptor.idProduct == USB_ID_US144) { + if (us122l->dev->descriptor.idProduct == USB_ID_US144 || + us122l->dev->descriptor.idProduct == USB_ID_US144MKII) { err = usb_set_interface(us122l->dev, 0, 1); if (err) { snd_printk(KERN_ERR "usb_set_interface error \n"); @@ -737,6 +743,16 @@ static struct usb_device_id snd_us122l_usb_id_table[] = { .idVendor = 0x0644, .idProduct = USB_ID_US144 }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US122MKII + }, + { + .match_flags = USB_DEVICE_ID_MATCH_DEVICE, + .idVendor = 0x0644, + .idProduct = USB_ID_US144MKII + }, { /* terminator */ } }; diff --git a/sound/usb/usx2y/us122l.h b/sound/usb/usx2y/us122l.h index 4daf1982e821..f263b3f96c86 100644 --- a/sound/usb/usx2y/us122l.h +++ b/sound/usb/usx2y/us122l.h @@ -25,5 +25,7 @@ struct us122l { #define USB_ID_US122L 0x800E #define USB_ID_US144 0x800F +#define USB_ID_US122MKII 0x8021 +#define USB_ID_US144MKII 0x8020 #endif -- cgit v1.2.3 From ee6e365e30f7ee89bd214ff1215aaf90e93d4c40 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 8 Dec 2009 17:23:33 +0100 Subject: ALSA: hda - Generalize EAPD inversion check in patch_analog.c Add a flag to spec field so that the EAPD inversion can be checked outside the relevant control callbacks. Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 455a0494f907..447eda1f6770 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -72,7 +72,8 @@ struct ad198x_spec { hda_nid_t private_dac_nids[AUTO_CFG_MAX_OUTS]; unsigned int jack_present :1; - unsigned int inv_jack_detect:1; + unsigned int inv_jack_detect:1; /* inverted jack-detection */ + unsigned int inv_eapd:1; /* inverted EAPD implementation */ #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_loopback_check loopback; @@ -458,7 +459,7 @@ static struct hda_codec_ops ad198x_patch_ops = { /* * EAPD control - * the private value = nid | (invert << 8) + * the private value = nid */ #define ad198x_eapd_info snd_ctl_boolean_mono_info @@ -467,8 +468,7 @@ static int ad198x_eapd_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; - if (invert) + if (spec->inv_eapd) ucontrol->value.integer.value[0] = ! spec->cur_eapd; else ucontrol->value.integer.value[0] = spec->cur_eapd; @@ -480,11 +480,10 @@ static int ad198x_eapd_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); struct ad198x_spec *spec = codec->spec; - int invert = (kcontrol->private_value >> 8) & 1; hda_nid_t nid = kcontrol->private_value & 0xff; unsigned int eapd; eapd = !!ucontrol->value.integer.value[0]; - if (invert) + if (spec->inv_eapd) eapd = !eapd; if (eapd == spec->cur_eapd) return 0; @@ -705,7 +704,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { .info = ad198x_eapd_info, .get = ad198x_eapd_get, .put = ad198x_eapd_put, - .private_value = 0x1b | (1 << 8), /* port-D, inversed */ + .private_value = 0x1b, /* port-D */ }, { } /* end */ }; @@ -1074,6 +1073,7 @@ static int patch_ad1986a(struct hda_codec *codec) 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; @@ -2124,7 +2124,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { .info = ad198x_eapd_info, .get = ad198x_eapd_get, .put = ad198x_eapd_put, - .private_value = 0x12 | (1 << 8), /* port-D, inversed */ + .private_value = 0x12, /* port-D */ }, { } /* end */ @@ -3065,6 +3065,7 @@ static int patch_ad1988(struct hda_codec *codec) 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) -- cgit v1.2.3 From 396087eaead95fcb29eb36f1e59517aeb58c545e Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 9 Dec 2009 10:44:47 +0100 Subject: ALSA: hda - Terradici HDA controllers does not support 64-bit mode Confirmed from vendor and tests in RedHat bugzilla #536782 . Signed-off-by: Jaroslav Kysela Cc: Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d822bfc6cad6..efcc4f7c57f2 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2450,6 +2450,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, } } + /* disable 64bit DMA address for Teradici */ + /* it does not work with device 6549:1200 subsys e4a2:040b */ + if (chip->driver_type == AZX_DRIVER_TERA) + gcap &= ~ICH6_GCAP_64OK; + /* allow 64bit DMA address if supported by H/W */ if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); -- cgit v1.2.3 From 7aee67466536bbf8bb44a95712c848a61c5a0acd Mon Sep 17 00:00:00 2001 From: David Santinoli Date: Wed, 9 Dec 2009 12:34:26 +0100 Subject: ALSA: hda/realtek: quirk for D945GCLF2 mainboard Quirk for the ALC662 found on the Intel D945GCLF2 (and possibly other) mainboards. Signed-off-by: David Santinoli Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 2a96bc78964d..deecdd2d5d37 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -16970,6 +16970,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { ALC662_3ST_6ch_DIG), SND_PCI_QUIRK_MASK(0x1854, 0xf000, 0x2000, "ASUS H13-200x", ALC663_ASUS_H13), + SND_PCI_QUIRK(0x8086, 0xd604, "Intel mobo", ALC662_3ST_2ch_DIG), {} }; -- cgit v1.2.3 From 482e46d4b7c9bfbb2edc047fafa85cee1b0fc1e1 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Wed, 9 Dec 2009 12:43:44 +0100 Subject: ALSA: ice1724 - aureon - modify WM8770 Master & DAC volume The volume levels in original implementation are incorrect and does not match the dB scale. The real range is linear (in the sense of the dB scale) from 0dB to -100dB. Remove logaritmic table and make all volumes from range 0dB..100dB. The tests are in RedHat's bugzilla #540817. Signed-off-by: Jaroslav Kysela Signed-off-by: Takashi Iwai --- sound/pci/ice1712/aureon.c | 31 +++++++------------------------ 1 file changed, 7 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c index 110d16e52733..765d7bd4c3d4 100644 --- a/sound/pci/ice1712/aureon.c +++ b/sound/pci/ice1712/aureon.c @@ -689,32 +689,14 @@ static int aureon_ac97_mmute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_e return change; } -static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -12700, 100, 1); +static const DECLARE_TLV_DB_SCALE(db_scale_wm_dac, -10000, 100, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_pcm, -6400, 50, 1); static const DECLARE_TLV_DB_SCALE(db_scale_wm_adc, -1200, 100, 0); static const DECLARE_TLV_DB_SCALE(db_scale_ac97_master, -4650, 150, 0); static const DECLARE_TLV_DB_SCALE(db_scale_ac97_gain, -3450, 150, 0); -/* - * Logarithmic volume values for WM8770 - * Computed as 20 * Log10(255 / x) - */ -static const unsigned char wm_vol[256] = { - 127, 48, 42, 39, 36, 34, 33, 31, 30, 29, 28, 27, 27, 26, 25, 25, 24, 24, 23, - 23, 22, 22, 21, 21, 21, 20, 20, 20, 19, 19, 19, 18, 18, 18, 18, 17, 17, 17, - 17, 16, 16, 16, 16, 15, 15, 15, 15, 15, 15, 14, 14, 14, 14, 14, 13, 13, 13, - 13, 13, 13, 13, 12, 12, 12, 12, 12, 12, 12, 11, 11, 11, 11, 11, 11, 11, 11, - 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0 -}; - -#define WM_VOL_MAX (sizeof(wm_vol) - 1) +#define WM_VOL_MAX 100 +#define WM_VOL_CNT 101 /* 0dB .. -100dB */ #define WM_VOL_MUTE 0x8000 static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned short vol, unsigned short master) @@ -724,7 +706,8 @@ static void wm_set_vol(struct snd_ice1712 *ice, unsigned int index, unsigned sho if ((master & WM_VOL_MUTE) || (vol & WM_VOL_MUTE)) nvol = 0; else - nvol = 127 - wm_vol[(((vol & ~WM_VOL_MUTE) * (master & ~WM_VOL_MUTE)) / 127) & WM_VOL_MAX]; + nvol = ((vol % WM_VOL_CNT) * (master % WM_VOL_CNT)) / + WM_VOL_MAX; wm_put(ice, index, nvol); wm_put_nocache(ice, index, 0x180 | nvol); @@ -820,7 +803,7 @@ static int wm_vol_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info * uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->count = voices; uinfo->value.integer.min = 0; /* mute (-101dB) */ - uinfo->value.integer.max = 0x7F; /* 0dB */ + uinfo->value.integer.max = WM_VOL_MAX; /* 0dB */ return 0; } @@ -850,7 +833,7 @@ static int wm_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value * snd_ice1712_save_gpio_status(ice); for (i = 0; i < voices; i++) { unsigned int vol = ucontrol->value.integer.value[i]; - if (vol > 0x7f) + if (vol > WM_VOL_MAX) continue; vol |= spec->vol[ofs+i]; if (vol != spec->vol[ofs+i]) { -- cgit v1.2.3 From 5f60e496083efb01893a899b6885828330db971f Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Wed, 9 Dec 2009 20:12:43 +0100 Subject: ALSA: opti93x: fix irq releasing if the irq cannot be allocated Use the chip->irq to check if the irq should be released so the irq is not released if it has not been allocated. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/opti9xx/opti92x-ad1848.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) (limited to 'sound') diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index 8c88401c79bc..d8eac3f28947 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -548,10 +548,13 @@ __skip_mpu: static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) { - struct snd_wss *codec = dev_id; - struct snd_opti9xx *chip = codec->card->private_data; + struct snd_opti9xx *chip = dev_id; + struct snd_wss *codec = chip->codec; unsigned char status; + if (!codec) + return IRQ_HANDLED; + status = snd_opti9xx_read(chip, OPTi9XX_MC_REG(11)); if ((status & OPTi93X_IRQ_PLAYBACK) && codec->playback_substream) snd_pcm_period_elapsed(codec->playback_substream); @@ -691,10 +694,9 @@ static void snd_card_opti9xx_free(struct snd_card *card) if (chip) { #ifdef OPTi93X - struct snd_wss *codec = chip->codec; - if (codec && codec->irq > 0) { - disable_irq(codec->irq); - free_irq(codec->irq, codec); + if (chip->irq > 0) { + disable_irq(chip->irq); + free_irq(chip->irq, chip); } release_and_free_resource(chip->res_mc_indir); #endif @@ -759,9 +761,9 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) #endif #ifdef OPTi93X error = request_irq(irq, snd_opti93x_interrupt, - IRQF_DISABLED, DEV_NAME" - WSS", codec); + IRQF_DISABLED, DEV_NAME" - WSS", chip); if (error < 0) { - snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", chip->irq); + snd_printk(KERN_ERR "opti9xx: can't grab IRQ %d\n", irq); return error; } #endif -- cgit v1.2.3 From 6b2f3d1f769be5779b479c37800229d9a4809fc3 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 27 Oct 2009 11:05:28 +0100 Subject: vfs: Implement proper O_SYNC semantics While Linux provided an O_SYNC flag basically since day 1, it took until Linux 2.4.0-test12pre2 to actually get it implemented for filesystems, since that day we had generic_osync_around with only minor changes and the great "For now, when the user asks for O_SYNC, we'll actually give O_DSYNC" comment. This patch intends to actually give us real O_SYNC semantics in addition to the O_DSYNC semantics. After Jan's O_SYNC patches which are required before this patch it's actually surprisingly simple, we just need to figure out when to set the datasync flag to vfs_fsync_range and when not. This patch renames the existing O_SYNC flag to O_DSYNC while keeping it's numerical value to keep binary compatibility, and adds a new real O_SYNC flag. To guarantee backwards compatiblity it is defined as expanding to both the O_DSYNC and the new additional binary flag (__O_SYNC) to make sure we are backwards-compatible when compiled against the new headers. This also means that all places that don't care about the differences can just check O_DSYNC and get the right behaviour for O_SYNC, too - only places that actuall care need to check __O_SYNC in addition. Drivers and network filesystems have been updated in a fail safe way to always do the full sync magic if O_DSYNC is set. The few places setting O_SYNC for lower layers are kept that way for now to stay failsafe. We enforce that O_DSYNC is set when __O_SYNC is set early in the open path to make sure we always get these sane options. Note that parisc really screwed up their headers as they already define a O_DSYNC that has always been a no-op. We try to repair it by using it for the new O_DSYNC and redefinining O_SYNC to send both the traditional O_SYNC numerical value _and_ the O_DSYNC one. Cc: Richard Henderson Cc: Ivan Kokshaysky Cc: Grant Grundler Cc: "David S. Miller" Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Thomas Gleixner Cc: Al Viro Cc: Andreas Dilger Acked-by: Trond Myklebust Acked-by: Kyle McMartin Acked-by: Ulrich Drepper Signed-off-by: Christoph Hellwig Signed-off-by: Andrew Morton Signed-off-by: Jan Kara --- sound/core/rawmidi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/core/rawmidi.c b/sound/core/rawmidi.c index 2f766123b158..0f5a194695d9 100644 --- a/sound/core/rawmidi.c +++ b/sound/core/rawmidi.c @@ -1257,7 +1257,7 @@ static ssize_t snd_rawmidi_write(struct file *file, const char __user *buf, break; count -= count1; } - if (file->f_flags & O_SYNC) { + if (file->f_flags & O_DSYNC) { spin_lock_irq(&runtime->lock); while (runtime->avail != runtime->buffer_size) { wait_queue_t wait; -- cgit v1.2.3 From c357aab02ee8de1f833579861ebd1e5683d2e806 Mon Sep 17 00:00:00 2001 From: Vitaliy Kulikov Date: Fri, 11 Dec 2009 07:51:54 +0100 Subject: ALSA: hda - Fix LED GPIO setup for HP laptops with IDT codecs This patch fixes an error in processing of the HP BIOS configuration to enable GPIO based mute LED indicator control. That error causes driver to enable such control on all HP systems with the 92HD75 IDT codecs and results in unnecessary toggling of the GPIO on mute control manipulation. It also adds support of the future HP BIOS configuration extension for the named control. New configuration string has a format HP_Mute_LED_P_G 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 (0..9) Lastly, it adds more systems to the support of the audio implementation as found on HP B-series systems Signed-off-by: Vitaliy Kulikov Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 95 ++++++++++++++++++++++++++++++------------ 1 file changed, 68 insertions(+), 27 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 6b0bc040c3b1..e66672317e57 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -209,6 +209,7 @@ struct sigmatel_spec { unsigned int gpio_data; unsigned int gpio_mute; unsigned int gpio_led; + unsigned int gpio_led_polarity; /* stream */ unsigned int stream_delay; @@ -4724,13 +4725,61 @@ static void stac92xx_unsol_event(struct hda_codec *codec, unsigned int res) } } -static int hp_bseries_system(u32 subsystem_id) +/* + * 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 + */ +static int find_mute_led_gpio(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + const struct dmi_device *dev = NULL; + + 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_%d", + &spec->gpio_led_polarity, + &spec->gpio_led) == 2) { + spec->gpio_led = 1 << spec->gpio_led; + return 1; + } + if (sscanf(dev->name, "HP_Mute_LED_%d", + &spec->gpio_led_polarity) == 1) { + switch (codec->vendor_id) { + case 0x111d7608: + /* GPIO 0 */ + spec->gpio_led = 0x01; + return 1; + case 0x111d7600: + case 0x111d7601: + case 0x111d7602: + case 0x111d7603: + /* GPIO 3 */ + spec->gpio_led = 0x08; + return 1; + } + } + } + } + return 0; +} + +static int hp_blike_system(u32 subsystem_id) { switch (subsystem_id) { - case 0x103c307e: - case 0x103c307f: - case 0x103c3080: - case 0x103c3081: + case 0x103c1520: + case 0x103c1521: + case 0x103c1523: + case 0x103c1524: + case 0x103c1525: case 0x103c1722: case 0x103c1723: case 0x103c1724: @@ -4739,6 +4788,14 @@ static int hp_bseries_system(u32 subsystem_id) 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; @@ -4833,7 +4890,7 @@ static int stac92xx_hp_check_power_status(struct hda_codec *codec, else spec->gpio_data |= spec->gpio_led; /* white */ - if (hp_bseries_system(codec->subsystem_id)) { + if (!spec->gpio_led_polarity) { /* LED state is inverted on these systems */ spec->gpio_data ^= spec->gpio_led; } @@ -5526,7 +5583,7 @@ again: break; } - if (hp_bseries_system(codec->subsystem_id)) { + 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 || @@ -5544,26 +5601,10 @@ again: } } - if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { - const struct dmi_device *dev = NULL; - while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, - NULL, dev))) { - if (strcmp(dev->name, "HP_Mute_LED_1")) { - switch (codec->vendor_id) { - case 0x111d7608: - spec->gpio_led = 0x01; - break; - case 0x111d7600: - case 0x111d7601: - case 0x111d7602: - case 0x111d7603: - spec->gpio_led = 0x08; - break; - } - break; - } - } - } + if (find_mute_led_gpio(codec)) + snd_printd("mute LED gpio %d polarity %d\n", + spec->gpio_led, + spec->gpio_led_polarity); #ifdef CONFIG_SND_HDA_POWER_SAVE if (spec->gpio_led) { -- cgit v1.2.3 From b923528ed29dc2d12832f76b1b9e05848d9de853 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 11 Dec 2009 12:28:33 +0800 Subject: ALSA: hda - show HBR(High Bit Rate) pin cap in procfs Note that the HBR capability only applies to HDMI pin. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_proc.c | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2d627613aea3..f9a084a1378e 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -258,6 +258,7 @@ enum { #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% */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 09476fc1ab64..8d381c891001 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -240,8 +240,11 @@ static void print_pin_caps(struct snd_info_buffer *buffer, /* Realtek uses this bit as a different meaning */ if ((codec->vendor_id >> 16) == 0x10ec) snd_iprintf(buffer, " R/L"); - else + else { + if (caps & AC_PINCAP_HBR) + snd_iprintf(buffer, " HBR"); snd_iprintf(buffer, " HDMI"); + } } if (caps & AC_PINCAP_TRIG_REQ) snd_iprintf(buffer, " Trigger"); -- cgit v1.2.3 From 728765b30a052317b6cb6111d4c4e66aba5c0099 Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 11 Dec 2009 12:28:34 +0800 Subject: ALSA: intelhdmi - accept DisplayPort pin HDA036 spec states: DP (Display Port) indicates whether the Pin Complex Widget supports connection to a Display Port sink. Supported if set to 1. Note that it is possible for the pin widget to support more than one digital display connection type, e.g. HDMI and DP bit are both set to 1. Also export the DP pin cap in procfs. Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 3 +++ sound/pci/hda/hda_proc.c | 2 ++ sound/pci/hda/patch_intelhdmi.c | 2 +- 3 files changed, 6 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index f9a084a1378e..9000d52fccca 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -255,6 +255,9 @@ enum { * 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 */ diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 8d381c891001..c9afc04adac8 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c @@ -246,6 +246,8 @@ static void print_pin_caps(struct snd_info_buffer *buffer, snd_iprintf(buffer, " HDMI"); } } + if (caps & AC_PINCAP_DP) + snd_iprintf(buffer, " DP"); if (caps & AC_PINCAP_TRIG_REQ) snd_iprintf(buffer, " Trigger"); if (caps & AC_PINCAP_IMP_SENSE) diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 928df59be5d8..742f15eb3331 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -344,7 +344,7 @@ static int intel_hdmi_parse_codec(struct hda_codec *codec) break; case AC_WID_PIN: caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); - if (!(caps & AC_PINCAP_HDMI)) + if (!(caps & (AC_PINCAP_HDMI | AC_PINCAP_DP))) continue; if (intel_hdmi_add_pin(codec, nid) < 0) return -EINVAL; -- cgit v1.2.3 From 1ffc69a6e86aa9458046d1719957e091c8e95f7a Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 11 Dec 2009 12:28:35 +0800 Subject: ALSA: intelhdmi - channel mapping applies to Pin HDA036-A specifies that the Audio Sample Packet (ASP) Channel Mapping verbs apply to Digital Display Pin Complex instead of Converter. With this fix, channel mapping is working as expected for IbexPeak. Thanks to Marcin for pointing this out! Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 742f15eb3331..0d5dd1ba8205 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -436,14 +436,15 @@ static void hdmi_set_channel_count(struct hda_codec *codec, AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); } -static void hdmi_debug_channel_mapping(struct hda_codec *codec, hda_nid_t nid) +static void hdmi_debug_channel_mapping(struct hda_codec *codec, + hda_nid_t pin_nid) { #ifdef CONFIG_SND_DEBUG_VERBOSE int i; int slot; for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, nid, 0, + 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); @@ -619,7 +620,8 @@ static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, return ai->CA; } -static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, +static void hdmi_setup_channel_mapping(struct hda_codec *codec, + hda_nid_t pin_nid, struct hdmi_audio_infoframe *ai) { int i; @@ -633,11 +635,11 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, hda_nid_t nid, */ for (i = 0; i < 8; i++) - snd_hda_codec_write(codec, nid, 0, + snd_hda_codec_write(codec, pin_nid, 0, AC_VERB_SET_HDMI_CHAN_SLOT, (i << 4) | i); - hdmi_debug_channel_mapping(codec, nid); + hdmi_debug_channel_mapping(codec, pin_nid); } static bool hdmi_infoframe_uptodate(struct hda_codec *codec, hda_nid_t pin_nid, @@ -676,7 +678,6 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, }; hdmi_setup_channel_allocation(codec, nid, &ai); - hdmi_setup_channel_mapping(codec, nid, &ai); for (i = 0; i < spec->num_pins; i++) { if (spec->pin_cvt[i] != nid) @@ -686,6 +687,7 @@ static void hdmi_setup_audio_infoframe(struct hda_codec *codec, hda_nid_t nid, pin_nid = spec->pin[i]; if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { + hdmi_setup_channel_mapping(codec, pin_nid, &ai); hdmi_stop_infoframe_trans(codec, pin_nid); hdmi_fill_audio_infoframe(codec, pin_nid, &ai); hdmi_start_infoframe_trans(codec, pin_nid); -- cgit v1.2.3 From b14224bb74e19072c34617c501bceab94ebf579f Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 11 Dec 2009 12:28:36 +0800 Subject: ALSA: intelhdmi - add channel mapping for typical configurations IbexPeak is the first Intel HDMI audio codec to support channel mapping. Currently the outstanding problem is, the HDMI channel order do not agree with that of ALSA. This patch presents workaround for some typical use cases. It gives priority to the typical ALSA surround configurations, and defines channel mapping for them. We may need better kernel+userspace interactive channel mapping scheme. For example, in current scheme if user plays with the surround50 device, the kernel is unaware of this and will still select the surround41 channel allocation and channel mapping.. Thanks to Marcin for offering good tips! Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_intelhdmi.c | 89 +++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 22 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 0d5dd1ba8205..3990182777ee 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -145,6 +145,42 @@ struct cea_channel_speaker_allocation { int spk_mask; }; +/* + * ALSA sequence is: + * + * surround40 surround41 surround50 surround51 surround71 + * ch0 front left = = = = + * ch1 front right = = = = + * ch2 rear left = = = = + * ch3 rear right = = = = + * ch4 LFE center center center + * ch5 LFE LFE + * ch6 side left + * ch7 side right + * + * surround71 = {FL, FR, RLC, RRC, FC, LFE, RL, RR} + */ +static int hdmi_channel_mapping[0x32][8] = { + /* stereo */ + [0x00] = { 0x00, 0x11, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* 2.1 */ + [0x01] = { 0x00, 0x11, 0x22, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* Dolby Surround */ + [0x02] = { 0x00, 0x11, 0x23, 0xf2, 0xf4, 0xf5, 0xf6, 0xf7 }, + /* surround40 */ + [0x08] = { 0x00, 0x11, 0x24, 0x35, 0xf3, 0xf2, 0xf6, 0xf7 }, + /* 4ch */ + [0x03] = { 0x00, 0x11, 0x23, 0x32, 0x44, 0xf5, 0xf6, 0xf7 }, + /* surround41 */ + [0x09] = { 0x00, 0x11, 0x24, 0x34, 0x43, 0xf2, 0xf6, 0xf7 }, + /* surround50 */ + [0x0a] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0xf2, 0xf6, 0xf7 }, + /* surround51 */ + [0x0b] = { 0x00, 0x11, 0x24, 0x35, 0x43, 0x52, 0xf6, 0xf7 }, + /* 7.1 */ + [0x13] = { 0x00, 0x11, 0x26, 0x37, 0x43, 0x52, 0x64, 0x75 }, +}; + /* * This is an ordered list! * @@ -152,32 +188,36 @@ struct cea_channel_speaker_allocation { * hdmi_setup_channel_allocation(). */ static struct cea_channel_speaker_allocation channel_allocations[] = { -/* channel: 8 7 6 5 4 3 2 1 */ +/* channel: 7 6 5 4 3 2 1 0 */ { .ca_index = 0x00, .speakers = { 0, 0, 0, 0, 0, 0, FR, FL } }, /* 2.1 */ { .ca_index = 0x01, .speakers = { 0, 0, 0, 0, 0, LFE, FR, FL } }, /* Dolby Surround */ { .ca_index = 0x02, .speakers = { 0, 0, 0, 0, FC, 0, FR, FL } }, + /* surround40 */ +{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, + /* surround41 */ +{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, + /* surround50 */ +{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, + /* surround51 */ +{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, + /* 6.1 */ +{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, + /* surround71 */ +{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, + { .ca_index = 0x03, .speakers = { 0, 0, 0, 0, FC, LFE, FR, FL } }, { .ca_index = 0x04, .speakers = { 0, 0, 0, RC, 0, 0, FR, FL } }, { .ca_index = 0x05, .speakers = { 0, 0, 0, RC, 0, LFE, FR, FL } }, { .ca_index = 0x06, .speakers = { 0, 0, 0, RC, FC, 0, FR, FL } }, { .ca_index = 0x07, .speakers = { 0, 0, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x08, .speakers = { 0, 0, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x09, .speakers = { 0, 0, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x0a, .speakers = { 0, 0, RR, RL, FC, 0, FR, FL } }, - /* 5.1 */ -{ .ca_index = 0x0b, .speakers = { 0, 0, RR, RL, FC, LFE, FR, FL } }, { .ca_index = 0x0c, .speakers = { 0, RC, RR, RL, 0, 0, FR, FL } }, { .ca_index = 0x0d, .speakers = { 0, RC, RR, RL, 0, LFE, FR, FL } }, { .ca_index = 0x0e, .speakers = { 0, RC, RR, RL, FC, 0, FR, FL } }, - /* 6.1 */ -{ .ca_index = 0x0f, .speakers = { 0, RC, RR, RL, FC, LFE, FR, FL } }, { .ca_index = 0x10, .speakers = { RRC, RLC, RR, RL, 0, 0, FR, FL } }, { .ca_index = 0x11, .speakers = { RRC, RLC, RR, RL, 0, LFE, FR, FL } }, { .ca_index = 0x12, .speakers = { RRC, RLC, RR, RL, FC, 0, FR, FL } }, - /* 7.1 */ -{ .ca_index = 0x13, .speakers = { RRC, RLC, RR, RL, FC, LFE, FR, FL } }, { .ca_index = 0x14, .speakers = { FRC, FLC, 0, 0, 0, 0, FR, FL } }, { .ca_index = 0x15, .speakers = { FRC, FLC, 0, 0, 0, LFE, FR, FL } }, { .ca_index = 0x16, .speakers = { FRC, FLC, 0, 0, FC, 0, FR, FL } }, @@ -210,7 +250,6 @@ static struct cea_channel_speaker_allocation channel_allocations[] = { { .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, }; - /* * HDA/HDMI auto parsing */ @@ -625,19 +664,25 @@ static void hdmi_setup_channel_mapping(struct hda_codec *codec, struct hdmi_audio_infoframe *ai) { int i; + int ca = ai->CA; + int err; - if (!ai->CA) - return; - - /* - * TODO: adjust channel mapping if necessary - * ALSA sequence is front/surr/clfe/side? - */ + if (hdmi_channel_mapping[ca][1] == 0) { + for (i = 0; i < channel_allocations[ca].channels; i++) + hdmi_channel_mapping[ca][i] = i | (i << 4); + for (; i < 8; i++) + hdmi_channel_mapping[ca][i] = 0xf | (i << 4); + } - for (i = 0; i < 8; i++) - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_HDMI_CHAN_SLOT, - (i << 4) | i); + for (i = 0; i < 8; i++) { + err = snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_HDMI_CHAN_SLOT, + hdmi_channel_mapping[ca][i]); + if (err) { + snd_printdd(KERN_INFO "HDMI: channel mapping failed\n"); + break; + } + } hdmi_debug_channel_mapping(codec, pin_nid); } -- cgit v1.2.3 From fcfdebe70759c74e2e701f69aaa7f0e5e32cf5a6 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 11 Dec 2009 12:51:05 +0100 Subject: ALSA: hrtimer - Fix lock-up The timer stop callback can be called from snd_timer_interrupt(), which is called from the hrtimer callback. Since hrtimer_cancel() waits for the callback completion, this eventually results in a lock-up. This patch fixes the problem by just toggling a flag at stop callback and call hrtimer_cancel() later. Reported-and-tested-by: Wojtek Zabolotny Cc: Signed-off-by: Takashi Iwai --- sound/core/hrtimer.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/hrtimer.c b/sound/core/hrtimer.c index 34c7d48f5061..7f4d744ae40a 100644 --- a/sound/core/hrtimer.c +++ b/sound/core/hrtimer.c @@ -37,14 +37,22 @@ static unsigned int resolution; struct snd_hrtimer { struct snd_timer *timer; struct hrtimer hrt; + atomic_t running; }; static enum hrtimer_restart snd_hrtimer_callback(struct hrtimer *hrt) { struct snd_hrtimer *stime = container_of(hrt, struct snd_hrtimer, hrt); struct snd_timer *t = stime->timer; + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; + hrtimer_forward_now(hrt, ns_to_ktime(t->sticks * resolution)); snd_timer_interrupt(stime->timer, t->sticks); + + if (!atomic_read(&stime->running)) + return HRTIMER_NORESTART; return HRTIMER_RESTART; } @@ -58,6 +66,7 @@ static int snd_hrtimer_open(struct snd_timer *t) hrtimer_init(&stime->hrt, CLOCK_MONOTONIC, HRTIMER_MODE_REL); stime->timer = t; stime->hrt.function = snd_hrtimer_callback; + atomic_set(&stime->running, 0); t->private_data = stime; return 0; } @@ -78,16 +87,18 @@ static int snd_hrtimer_start(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; + atomic_set(&stime->running, 0); + hrtimer_cancel(&stime->hrt); hrtimer_start(&stime->hrt, ns_to_ktime(t->sticks * resolution), HRTIMER_MODE_REL); + atomic_set(&stime->running, 1); return 0; } static int snd_hrtimer_stop(struct snd_timer *t) { struct snd_hrtimer *stime = t->private_data; - - hrtimer_cancel(&stime->hrt); + atomic_set(&stime->running, 0); return 0; } -- cgit v1.2.3 From 0287d970652027d5e299e0215578f228660a0e4e Mon Sep 17 00:00:00 2001 From: Wu Fengguang Date: Fri, 11 Dec 2009 20:15:11 +0800 Subject: intelhdmi - dont power off HDA link For codecs without EPSS support (G45/IbexPeak), the hotplug event will be lost if the HDA is powered off during the time. After that the pin presence detection verb returns inaccurate info. So always power-on HDA link for !EPSS codecs. KarL offers the fact and Takashi recommends to flag hda_bus. Thanks! Signed-off-by: Wu Fengguang Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.h | 1 + sound/pci/hda/hda_intel.c | 3 ++- sound/pci/hda/patch_intelhdmi.c | 11 +++++++++++ 3 files changed, 14 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 9000d52fccca..1d541b7f5547 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h @@ -639,6 +639,7 @@ struct hda_bus { unsigned int rirb_error:1; /* error in codec communication */ 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 */ }; /* diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index efcc4f7c57f2..e54420e691ae 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2082,7 +2082,8 @@ static void azx_power_notify(struct hda_bus *bus) } if (power_on) azx_init_chip(chip); - else if (chip->running && power_save_controller) + else if (chip->running && power_save_controller && + !bus->power_keep_link_on) azx_stop_chip(chip); } #endif /* CONFIG_SND_HDA_POWER_SAVE */ diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 3990182777ee..918f40378d52 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -391,6 +391,17 @@ static int intel_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_SND_HDA_POWER_SAVE + 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; } -- cgit v1.2.3 From 52dc438606d1ef78b96f56cc04dbea9242005730 Mon Sep 17 00:00:00 2001 From: Alexey Fisher Date: Sat, 12 Dec 2009 11:16:41 +0200 Subject: ALSA: hda - Overwrite pin config on intel DG45ID board. The pin config provided by BIOS have some problems: 0x0221401f: [Jack] HP Out at Ext Front <-- other association and sequence 0x02a19020: [Jack] Mic at Ext Front <-- other association 0x01113014: [Jack] Speaker at Ext Rear <-- line out (not speaker) 0x01114010: [Jack] Speaker at Ext Rear <-- line out 0x01a19030: [Jack] Mic at Ext Rear <-- other association 0x01111012: [Jack] Speaker at Ext Rear <-- line out 0x01116011: [Jack] Speaker at Ext Rear <-- line out 0x40f000f0: [N/A] Other at Ext N/A 0x40f000f0: [N/A] Other at Ext N/A 0x40f000f0: [N/A] Other at Ext N/A 0x40f000f0: [N/A] Other at Ext N/A 0x40f000f0: [N/A] Other at Ext N/A 0x01451140: [Jack] SPDIF Out at Ext Rear 0x40f000f0: [N/A] Other at Ext N/A just overwrite it. Signed-off-by: Alexey Fisher Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index e66672317e57..3d59f8325848 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1539,6 +1539,13 @@ static unsigned int alienware_m17x_pin_configs[13] = { 0x904601b0, }; +static unsigned int intel_dg45id_pin_configs[14] = { + 0x02214230, 0x02A19240, 0x01013214, 0x01014210, + 0x01A19250, 0x01011212, 0x01016211, 0x40f000f0, + 0x40f000f0, 0x40f000f0, 0x40f000f0, 0x014510A0, + 0x074510B0, 0x40f000f0 +}; + static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [STAC_92HD73XX_REF] = ref92hd73xx_pin_configs, [STAC_DELL_M6_AMIC] = dell_m6_pin_configs, @@ -1546,6 +1553,7 @@ static unsigned int *stac92hd73xx_brd_tbl[STAC_92HD73XX_MODELS] = { [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 const char *stac92hd73xx_models[STAC_92HD73XX_MODELS] = { -- cgit v1.2.3 From 5a65edbc12b6b34ef912114f1fc8215786f85b25 Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Nov 2009 16:10:51 +0000 Subject: mfd: Convert wm8350 IRQ handlers to irq_handler_t This is done as simple code transformation, the semantics of the IRQ API provided by the core are are still very different to those of genirq (mainly with regard to masking). Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- sound/soc/codecs/wm8350.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index f82125d9e85a..17a327d67fd5 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1340,9 +1340,10 @@ static int wm8350_resume(struct platform_device *pdev) return 0; } -static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) +static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) { struct wm8350_data *priv = data; + struct wm8350 *wm8350 = priv->codec.control_data; u16 reg; int report; int mask; @@ -1365,7 +1366,7 @@ static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) if (!jack->jack) { dev_warn(wm8350->dev, "Jack interrupt called with no jack\n"); - return; + return IRQ_NONE; } /* Debounce */ @@ -1378,6 +1379,8 @@ static void wm8350_hp_jack_handler(struct wm8350 *wm8350, int irq, void *data) report = 0; snd_soc_jack_report(jack->jack, report, jack->report); + + return IRQ_HANDLED; } /** @@ -1421,7 +1424,7 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, wm8350_set_bits(wm8350, WM8350_JACK_DETECT, ena); /* Sync status */ - wm8350_hp_jack_handler(wm8350, irq, priv); + wm8350_hp_jack_handler(irq, priv); wm8350_unmask_irq(wm8350, irq); @@ -1485,9 +1488,11 @@ static int wm8350_probe(struct platform_device *pdev) wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, - wm8350_hp_jack_handler, priv); + wm8350_hp_jack_handler, 0, "Left jack detect", + priv); wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, - wm8350_hp_jack_handler, priv); + wm8350_hp_jack_handler, 0, "Right jack detect", + priv); ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); if (ret < 0) { -- cgit v1.2.3 From 6a6127462eb9096419fd4b3115ec5971d83a600f Mon Sep 17 00:00:00 2001 From: Mark Brown Date: Wed, 4 Nov 2009 16:10:52 +0000 Subject: mfd: Mask and unmask wm8350 IRQs on request and free Bring the WM8350 IRQ API more in line with the generic IRQ API by masking and unmasking interrupts as they are requested and freed. This is mostly just a case of deleting the mask and unmask calls from the individual drivers. The RTC driver is changed to mask the periodic IRQ after requesting it rather than only unmasking the alarm IRQ. If the periodic IRQ fires in the period where it is reqested then there will be a spurious notification but there should be no serious consequences from this. The CODEC drive is changed to explicitly disable headphone jack detection prior to requesting the IRQs. This will avoid the IRQ firing with no jack set up. Signed-off-by: Mark Brown Signed-off-by: Samuel Ortiz --- sound/soc/codecs/wm8350.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 17a327d67fd5..ebbf11b653a4 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1426,8 +1426,6 @@ int wm8350_hp_jack_detect(struct snd_soc_codec *codec, enum wm8350_jack which, /* Sync status */ wm8350_hp_jack_handler(irq, priv); - wm8350_unmask_irq(wm8350, irq); - return 0; } EXPORT_SYMBOL_GPL(wm8350_hp_jack_detect); @@ -1485,8 +1483,10 @@ static int wm8350_probe(struct platform_device *pdev) wm8350_set_bits(wm8350, WM8350_ROUT2_VOLUME, WM8350_OUT2_VU | WM8350_OUT2R_MUTE); - wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); - wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); + /* Make sure jack detect is disabled to start off with */ + wm8350_clear_bits(wm8350, WM8350_JACK_DETECT, + WM8350_JDL_ENA | WM8350_JDR_ENA); + wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, wm8350_hp_jack_handler, 0, "Left jack detect", priv); @@ -1521,8 +1521,6 @@ static int wm8350_remove(struct platform_device *pdev) WM8350_JDL_ENA | WM8350_JDR_ENA); wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_4, WM8350_TOCLK_ENA); - wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); - wm8350_mask_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); -- cgit v1.2.3 From b07682b6056eb6701f8cb86aa5800e6f2ea7919b Mon Sep 17 00:00:00 2001 From: Santosh Shilimkar Date: Sun, 13 Dec 2009 20:05:51 +0100 Subject: mfd: Rename twl4030* driver files to enable re-use The upcoming TWL6030 is companion chip for OMAP4 like the current TWL4030 for OMAP3. The common modules like RTC, Regulator creates opportunity to re-use the most of the code from twl4030. This patch renames few common drivers twl4030* files to twl* to enable the code re-use. Signed-off-by: Rajendra Nayak Signed-off-by: Balaji T K Signed-off-by: Santosh Shilimkar Acked-by: Kevin Hilman Signed-off-by: Samuel Ortiz --- sound/soc/codecs/twl4030.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index 5f1681f6ca76..c3a6ceb542cb 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -26,7 +26,7 @@ #include #include #include -#include +#include #include #include #include -- cgit v1.2.3 From fc7b92fca4e546184557f1c53f84ad57c66b7695 Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Sun, 13 Dec 2009 21:23:33 +0100 Subject: mfd: Rename all twl4030_i2c* This patch renames function names like twl4030_i2c_write_u8, twl4030_i2c_read_u8 to twl_i2c_write_u8, twl_i2c_read_u8 and also common variable in twl-core.c Signed-off-by: Rajendra Nayak Signed-off-by: Balaji T K Signed-off-by: Santosh Shilimkar Acked-by: Kevin Hilman Signed-off-by: Samuel Ortiz --- sound/soc/codecs/twl4030.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c index c3a6ceb542cb..2a27f7b56726 100644 --- a/sound/soc/codecs/twl4030.c +++ b/sound/soc/codecs/twl4030.c @@ -175,7 +175,7 @@ static int twl4030_write(struct snd_soc_codec *codec, { twl4030_write_reg_cache(codec, reg, value); if (likely(reg < TWL4030_REG_SW_SHADOW)) - return twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, + return twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, value, reg); else return 0; @@ -261,7 +261,7 @@ static void twl4030_power_up(struct snd_soc_codec *codec) do { /* this takes a little while, so don't slam i2c */ udelay(2000); - twl4030_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, + twl_i2c_read_u8(TWL4030_MODULE_AUDIO_VOICE, &byte, TWL4030_REG_ANAMICL); } while ((i++ < 100) && ((byte & TWL4030_CNCL_OFFSET_START) == @@ -542,7 +542,7 @@ static int pin_name##pga_event(struct snd_soc_dapm_widget *w, \ break; \ case SND_SOC_DAPM_POST_PMD: \ reg_val = twl4030_read_reg_cache(w->codec, reg); \ - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, \ reg_val & (~mask), \ reg); \ break; \ @@ -679,7 +679,7 @@ static void headset_ramp(struct snd_soc_codec *codec, int ramp) mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] / twl4030->sysclk) + 1); /* Bypass the reg_cache to mute the headset */ - twl4030_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, + twl_i2c_write_u8(TWL4030_MODULE_AUDIO_VOICE, hs_gain & (~0x0f), TWL4030_REG_HS_GAIN_SET); -- cgit v1.2.3 From 950200e2ff11daae1c5d9426703bdd494603f38b Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 13 Dec 2009 14:11:02 -0500 Subject: ALSA: hda: Use ALC260_WILL quirk for another Acer model (0x1025007f) BugLink: https://bugs.launchpad.net/bugs/418627 The original reporter states that this quirk is necessary to obtain reasonable gain for playback. Without it, sound is inaudible. Tested with playback (spkr and hp) and capture. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index deecdd2d5d37..c9e860709747 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -6248,6 +6248,7 @@ static const char *alc260_models[ALC260_MODEL_LAST] = { static struct snd_pci_quirk alc260_cfg_tbl[] = { SND_PCI_QUIRK(0x1025, 0x007b, "Acer C20x", ALC260_ACER), + SND_PCI_QUIRK(0x1025, 0x007f, "Acer", ALC260_WILL), SND_PCI_QUIRK(0x1025, 0x008f, "Acer", ALC260_ACER), SND_PCI_QUIRK(0x1509, 0x4540, "Favorit 100XS", ALC260_FAVORIT100), SND_PCI_QUIRK(0x103c, 0x2808, "HP d5700", ALC260_HP_3013), -- cgit v1.2.3 From 01f5966d2f36f08eb6604665eade69c9f38ffaed Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sun, 13 Dec 2009 16:22:58 -0500 Subject: ALSA: hda: Fix max PCM level to 0 dB for AD1981_HP BugLink: https://bugs.launchpad.net/bugs/461062 The original reporter states that PCM maxes at +12 dB and results in very bad distortion. Cap PCM at 0 dB to resolve this symptom. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_analog.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 447eda1f6770..1a36137e13ec 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c @@ -1789,6 +1789,14 @@ static int patch_ad1981(struct hda_codec *codec) 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; -- cgit v1.2.3 From 0d64b568fcd48b133721c1d322e7c51d85eb12df Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Dec 2009 12:42:56 +0100 Subject: ALSA: sound/isa/gus: Correct code taking the size of a pointer sizeof(share_id) is just the size of the pointer. On the other hand, block->share_id is an array, so its size seems more appropriate. A simplified version of the semantic patch that finds this problem is as follows: (http://coccinelle.lip6.fr/) // @@ expression *x; expression f; type T; @@ *f(...,(T)x,...) // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/isa/gus/gus_mem.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/isa/gus/gus_mem.c b/sound/isa/gus/gus_mem.c index 661205c4dcea..af888a022fc0 100644 --- a/sound/isa/gus/gus_mem.c +++ b/sound/isa/gus/gus_mem.c @@ -127,7 +127,8 @@ static struct snd_gf1_mem_block *snd_gf1_mem_share(struct snd_gf1_mem * alloc, !share_id[2] && !share_id[3]) return NULL; for (block = alloc->first; block; block = block->next) - if (!memcmp(share_id, block->share_id, sizeof(share_id))) + if (!memcmp(share_id, block->share_id, + sizeof(block->share_id))) return block; return NULL; } -- cgit v1.2.3 From 6dd7dc767e35cfbb38f8c63a50b1c27acad25920 Mon Sep 17 00:00:00 2001 From: Stefan Ringel Date: Mon, 14 Dec 2009 11:27:11 +0100 Subject: ALSA: hda - Add PCI IDs for Nvidia G2xx-series Signed-off-by: Stefan Ringel Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index e54420e691ae..9b56f937913e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2713,6 +2713,9 @@ static struct pci_device_id azx_ids[] = { { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, + { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, -- cgit v1.2.3 From f74890277a196949e4004fe2955e1d4fb3930f98 Mon Sep 17 00:00:00 2001 From: Steve Soule Date: Mon, 14 Dec 2009 11:06:03 -0700 Subject: ALSA: ac97_codec - increase timeout for analog sections to 5 second I have a Soundblaster 16PCI. For many years, alsa has had a bug where not all of the card's controls are detected (many alsa versions, many kernel versions). In particular, Master Playback Volume is usually not detected, and so I get no sound or extremely faint sound. The problem has always been inconsistent: sometimes all of the controls are detected correctly, and sometimes a partial set is detected. It works correctly about 10% of the time. Finally, I got around to tracking down the problem. When the driver fails, it prints the kernel message "AC'97 0 analog subsections not ready". This message is generated from the function snd_ac97_mixer() in ac97_codec.c. The message indicates that the card failed to come back after reset within the time limit. The time limit is 120 milliseconds. I tried increasing the time limit to 1 second, and found that this made the driver work about 70% of the time. I tried increasing it to 5 seconds, and it now seems to work 100% of the time. I expect that this change would be completely harmless for existing cards that work, and would only introduce additional delay for cards that do not work. ALSA bug#4032. Signed-off-by: Steve Soule Signed-off-by: Jaroslav Kysela --- sound/pci/ac97/ac97_codec.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c index 20cb60afb200..c11920623009 100644 --- a/sound/pci/ac97/ac97_codec.c +++ b/sound/pci/ac97/ac97_codec.c @@ -2122,7 +2122,7 @@ int snd_ac97_mixer(struct snd_ac97_bus *bus, struct snd_ac97_template *template, } /* nothing should be in powerdown mode */ snd_ac97_write_cache(ac97, AC97_GENERAL_PURPOSE, 0); - end_time = jiffies + msecs_to_jiffies(120); + end_time = jiffies + msecs_to_jiffies(5000); do { if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f) goto __ready_ok; -- cgit v1.2.3 From 471452104b8520337ae2fb48c4e61cd4896e025d Mon Sep 17 00:00:00 2001 From: Alexey Dobriyan Date: Mon, 14 Dec 2009 18:00:08 -0800 Subject: const: constify remaining dev_pm_ops Signed-off-by: Alexey Dobriyan Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/arm/pxa2xx-ac97.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec.c | 2 +- sound/soc/s3c24xx/s3c24xx_simtec.h | 2 +- sound/soc/soc-core.c | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/arm/pxa2xx-ac97.c b/sound/arm/pxa2xx-ac97.c index b4b48afb6de6..5d9411839cd7 100644 --- a/sound/arm/pxa2xx-ac97.c +++ b/sound/arm/pxa2xx-ac97.c @@ -159,7 +159,7 @@ static int pxa2xx_ac97_resume(struct device *dev) return ret; } -static struct dev_pm_ops pxa2xx_ac97_pm_ops = { +static const struct dev_pm_ops pxa2xx_ac97_pm_ops = { .suspend = pxa2xx_ac97_suspend, .resume = pxa2xx_ac97_resume, }; diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.c b/sound/soc/s3c24xx/s3c24xx_simtec.c index d441c3b64631..4984754f3298 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.c +++ b/sound/soc/s3c24xx/s3c24xx_simtec.c @@ -312,7 +312,7 @@ int simtec_audio_resume(struct device *dev) return 0; } -struct dev_pm_ops simtec_audio_pmops = { +const struct dev_pm_ops simtec_audio_pmops = { .resume = simtec_audio_resume, }; EXPORT_SYMBOL_GPL(simtec_audio_pmops); diff --git a/sound/soc/s3c24xx/s3c24xx_simtec.h b/sound/soc/s3c24xx/s3c24xx_simtec.h index 2714203af161..e18faee30cce 100644 --- a/sound/soc/s3c24xx/s3c24xx_simtec.h +++ b/sound/soc/s3c24xx/s3c24xx_simtec.h @@ -15,7 +15,7 @@ extern int simtec_audio_core_probe(struct platform_device *pdev, extern int simtec_audio_remove(struct platform_device *pdev); #ifdef CONFIG_PM -extern struct dev_pm_ops simtec_audio_pmops; +extern const struct dev_pm_ops simtec_audio_pmops; #define simtec_audio_pm &simtec_audio_pmops #else #define simtec_audio_pm NULL diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index ef8f28284cb9..0a6440c6f54a 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -1236,7 +1236,7 @@ static int soc_poweroff(struct device *dev) return 0; } -static struct dev_pm_ops soc_pm_ops = { +static const struct dev_pm_ops soc_pm_ops = { .suspend = soc_suspend, .resume = soc_resume, .poweroff = soc_poweroff, -- cgit v1.2.3 From 3c55494670745e523f69b56edb66ca0b50a470c2 Mon Sep 17 00:00:00 2001 From: Andres Salomon Date: Mon, 14 Dec 2009 18:00:36 -0800 Subject: ALSA: cs5535audio: free OLPC quirks from reliance on MGEODE_LX cpu optimization Previously, OLPC support for the mic extensions was only enabled in the ALSA driver if CONFIG_OLPC and CONFIG_MGEODE_LX were both set. This was because the old geode GPIO code was written in a manner that assumed CONFIG_MGEODE_LX. With the new cs553x-gpio driver, this is no longer the case; as such, we can drop the requirement on CONFIG_MGEODE_LX and instead include a requirement on GPIOLIB. We use the generic GPIO API rather than the cs553x-specific API. Signed-off-by: Andres Salomon Cc: Takashi Iwai Cc: Jordan Crouse Cc: David Brownell Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/pci/cs5535audio/Makefile | 2 -- sound/pci/cs5535audio/cs5535audio.c | 1 + sound/pci/cs5535audio/cs5535audio.h | 4 +++- sound/pci/cs5535audio/cs5535audio_olpc.c | 26 +++++++++++++++++++------- 4 files changed, 23 insertions(+), 10 deletions(-) (limited to 'sound') diff --git a/sound/pci/cs5535audio/Makefile b/sound/pci/cs5535audio/Makefile index fda7a94c992f..ccc642269b9e 100644 --- a/sound/pci/cs5535audio/Makefile +++ b/sound/pci/cs5535audio/Makefile @@ -4,9 +4,7 @@ snd-cs5535audio-y := cs5535audio.o cs5535audio_pcm.o snd-cs5535audio-$(CONFIG_PM) += cs5535audio_pm.o -ifdef CONFIG_MGEODE_LX snd-cs5535audio-$(CONFIG_OLPC) += cs5535audio_olpc.o -endif # Toplevel Module Dependency obj-$(CONFIG_SND_CS5535AUDIO) += snd-cs5535audio.o diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 05f56e04849b..91e7faf69bbb 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c @@ -389,6 +389,7 @@ probefail_out: static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) { + olpc_quirks_cleanup(); snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); } diff --git a/sound/pci/cs5535audio/cs5535audio.h b/sound/pci/cs5535audio/cs5535audio.h index 7a298ac662e3..51966d782a3c 100644 --- a/sound/pci/cs5535audio/cs5535audio.h +++ b/sound/pci/cs5535audio/cs5535audio.h @@ -99,10 +99,11 @@ int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state); int snd_cs5535audio_resume(struct pci_dev *pci); #endif -#if defined(CONFIG_OLPC) && defined(CONFIG_MGEODE_LX) +#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_analog_input(struct snd_ac97 *ac97, int on); void olpc_mic_bias(struct snd_ac97 *ac97, int on); @@ -128,6 +129,7 @@ static inline int olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) { return 0; } +static inline void olpc_quirks_cleanup(void) { } static inline void olpc_analog_input(struct snd_ac97 *ac97, int on) { } static inline void olpc_mic_bias(struct snd_ac97 *ac97, int on) { } static inline void olpc_capture_open(struct snd_ac97 *ac97) { } diff --git a/sound/pci/cs5535audio/cs5535audio_olpc.c b/sound/pci/cs5535audio/cs5535audio_olpc.c index 5c6814335cd7..50da49be9ae5 100644 --- a/sound/pci/cs5535audio/cs5535audio_olpc.c +++ b/sound/pci/cs5535audio/cs5535audio_olpc.c @@ -13,10 +13,13 @@ #include #include #include +#include #include #include "cs5535audio.h" +#define DRV_NAME "cs5535audio-olpc" + /* * OLPC has an additional feature on top of the regular AD1888 codec features. * It has an Analog Input mode that is switched into (after disabling the @@ -38,10 +41,7 @@ void olpc_analog_input(struct snd_ac97 *ac97, int on) } /* set Analog Input through GPIO */ - if (on) - geode_gpio_set(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); - else - geode_gpio_clear(OLPC_GPIO_MIC_AC, GPIO_OUTPUT_VAL); + gpio_set_value(OLPC_GPIO_MIC_AC, on); } /* @@ -73,8 +73,7 @@ static int olpc_dc_info(struct snd_kcontrol *kctl, static int olpc_dc_get(struct snd_kcontrol *kctl, struct snd_ctl_elem_value *v) { - v->value.integer.value[0] = geode_gpio_isset(OLPC_GPIO_MIC_AC, - GPIO_OUTPUT_VAL); + v->value.integer.value[0] = gpio_get_value(OLPC_GPIO_MIC_AC); return 0; } @@ -153,6 +152,12 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) if (!machine_is_olpc()) return 0; + if (gpio_request(OLPC_GPIO_MIC_AC, DRV_NAME)) { + printk(KERN_ERR DRV_NAME ": unable to allocate MIC GPIO\n"); + return -EIO; + } + gpio_direction_output(OLPC_GPIO_MIC_AC, 0); + /* drop the original AD1888 HPF control */ memset(&elem, 0, sizeof(elem)); elem.iface = SNDRV_CTL_ELEM_IFACE_MIXER; @@ -169,11 +174,18 @@ int __devinit olpc_quirks(struct snd_card *card, struct snd_ac97 *ac97) for (i = 0; i < ARRAY_SIZE(olpc_cs5535audio_ctls); i++) { err = snd_ctl_add(card, snd_ctl_new1(&olpc_cs5535audio_ctls[i], ac97->private_data)); - if (err < 0) + if (err < 0) { + gpio_free(OLPC_GPIO_MIC_AC); return err; + } } /* turn off the mic by default */ olpc_mic_bias(ac97, 0); return 0; } + +void __devexit olpc_quirks_cleanup(void) +{ + gpio_free(OLPC_GPIO_MIC_AC); +} -- cgit v1.2.3 From e7d2860b690d4f3bed6824757c540579638e3d1e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Goddard=20Rosa?= Date: Mon, 14 Dec 2009 18:01:06 -0800 Subject: tree-wide: convert open calls to remove spaces to skip_spaces() lib function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes use of skip_spaces() defined in lib/string.c for removing leading spaces from strings all over the tree. It decreases lib.a code size by 47 bytes and reuses the function tree-wide: text data bss dec hex filename 64688 584 592 65864 10148 (TOTALS-BEFORE) 64641 584 592 65817 10119 (TOTALS-AFTER) Also, while at it, if we see (*str && isspace(*str)), we can be sure to remove the first condition (*str) as the second one (isspace(*str)) also evaluates to 0 whenever *str == 0, making it redundant. In other words, "a char equals zero is never a space". Julia Lawall tried the semantic patch (http://coccinelle.lip6.fr) below, and found occurrences of this pattern on 3 more files: drivers/leds/led-class.c drivers/leds/ledtrig-timer.c drivers/video/output.c @@ expression str; @@ ( // ignore skip_spaces cases while (*str && isspace(*str)) { \(str++;\|++str;\) } | - *str && isspace(*str) ) Signed-off-by: André Goddard Rosa Cc: Julia Lawall Cc: Martin Schwidefsky Cc: Jeff Dike Cc: Ingo Molnar Cc: Thomas Gleixner Cc: "H. Peter Anvin" Cc: Richard Purdie Cc: Neil Brown Cc: Kyle McMartin Cc: Henrique de Moraes Holschuh Cc: David Howells Cc: Cc: Samuel Ortiz Cc: Patrick McHardy Cc: Takashi Iwai Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- sound/pci/hda/hda_hwdep.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index d24328661c6a..40ccb419b6e9 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include "hda_codec.h" @@ -428,8 +429,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf) char *key, *val; struct hda_hint *hint; - while (isspace(*buf)) - buf++; + buf = skip_spaces(buf); if (!*buf || *buf == '#' || *buf == '\n') return 0; if (*buf == '=') @@ -444,8 +444,7 @@ static int parse_hints(struct hda_codec *codec, const char *buf) return -EINVAL; } *val++ = 0; - while (isspace(*val)) - val++; + val = skip_spaces(val); remove_trail_spaces(key); remove_trail_spaces(val); hint = get_hint(codec, key); -- cgit v1.2.3 From ebeb53e1e1f11a51d8a93843a437f516e3528bfa Mon Sep 17 00:00:00 2001 From: Balaji T K Date: Tue, 15 Dec 2009 20:09:02 +0530 Subject: mfd: twl: fix twl4030 rename for remaining driver, board files Recent drivers/mfd/twl4030* renames to twl broke compile for various boards as the series was missing a patch to change the board-*.c files. This patch renames include twl4030.h to include twl.h and also renames twl4030_i2c_ routines. Signed-off-by: Balaji T K Acked-by: Mark Brown Reviewed-by: Felipe Balbi Cc: Samuel Ortiz Signed-off-by: Tony Lindgren --- sound/soc/omap/sdp3430.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/soc/omap/sdp3430.c b/sound/soc/omap/sdp3430.c index c071f9603a38..3c85c0f92823 100644 --- a/sound/soc/omap/sdp3430.c +++ b/sound/soc/omap/sdp3430.c @@ -24,7 +24,7 @@ #include #include -#include +#include #include #include #include @@ -321,11 +321,11 @@ static int __init sdp3430_soc_init(void) *(unsigned int *)sdp3430_dai[1].cpu_dai->private_data = 2; /* McBSP3 */ /* Set TWL4030 GPIO6 as EXTMUTE signal */ - twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, + twl_i2c_read_u8(TWL4030_MODULE_INTBR, &pin_mux, TWL4030_INTBR_PMBR1); pin_mux &= ~TWL4030_GPIO6_PWM0_MUTE(0x03); pin_mux |= TWL4030_GPIO6_PWM0_MUTE(0x02); - twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, + twl_i2c_write_u8(TWL4030_MODULE_INTBR, pin_mux, TWL4030_INTBR_PMBR1); ret = platform_device_add(sdp3430_snd_device); -- cgit v1.2.3 From 2fbe74b90bafebce615466b4c20f96b0465df1ae Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Wed, 16 Dec 2009 16:54:43 +0100 Subject: sound/oss/pss: Fix test of unsigned in pss_reset_dsp() and pss_download_boot() limit and jiffies are unsigned so the test did not work. Signed-off-by: Roel Kluin Signed-off-by: Takashi Iwai --- sound/oss/pss.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 83f5ee236b12..e19dd5dcc2de 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -269,7 +269,7 @@ static int pss_reset_dsp(pss_confdata * devc) unsigned long i, limit = jiffies + HZ/10; outw(0x2000, REG(PSS_CONTROL)); - for (i = 0; i < 32768 && (limit-jiffies >= 0); i++) + for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) inw(REG(PSS_CONTROL)); outw(0x0000, REG(PSS_CONTROL)); return 1; @@ -369,11 +369,11 @@ static int pss_download_boot(pss_confdata * devc, unsigned char *block, int size outw(0, REG(PSS_DATA)); limit = jiffies + HZ/10; - for (i = 0; i < 32768 && (limit - jiffies >= 0); i++) + for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) val = inw(REG(PSS_STATUS)); limit = jiffies + HZ/10; - for (i = 0; i < 32768 && (limit-jiffies >= 0); i++) + for (i = 0; i < 32768 && time_after_eq(limit, jiffies); i++) { val = inw(REG(PSS_STATUS)); if (val & 0x4000) -- cgit v1.2.3 From ebb83eeb6469bedda83b4dc6f23ddf93eb32b347 Mon Sep 17 00:00:00 2001 From: Kailang Yang Date: Thu, 17 Dec 2009 12:23:00 +0100 Subject: ALSA: hda - More ALC663 fixes and support of compatible chips 1. Add more ASUS NB model. 2. Fixed alc663_m51va_setup M51VA has Digital Mic that NID is 0x12. The record source index is 0x9 for ALC663. So, to modify the alc663_m51va_setup function to index 0x9 and add analog Mic aupport function alc663_mode1_setup. 3. Add ASUS mode7 and mode8 modules for ALC663 Signed-off-by: Kailang Yang Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 306 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 282 insertions(+), 24 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index c9e860709747..287bb6019df9 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -131,8 +131,8 @@ enum { enum { ALC269_BASIC, ALC269_QUANTA_FL1, - ALC269_ASUS_EEEPC_P703, - ALC269_ASUS_EEEPC_P901, + ALC269_ASUS_AMIC, + ALC269_ASUS_DMIC, ALC269_FUJITSU, ALC269_LIFEBOOK, ALC269_AUTO, @@ -188,6 +188,8 @@ enum { ALC663_ASUS_MODE4, ALC663_ASUS_MODE5, ALC663_ASUS_MODE6, + ALC663_ASUS_MODE7, + ALC663_ASUS_MODE8, ALC272_DELL, ALC272_DELL_ZM1, ALC272_SAMSUNG_NC10, @@ -13232,10 +13234,12 @@ static struct hda_verb alc269_eeepc_amic_init_verbs[] = { /* toggle speaker-output according to the hp-jack state */ static void alc269_speaker_automute(struct hda_codec *codec) { + struct alc_spec *spec = codec->spec; + unsigned int nid = spec->autocfg.hp_pins[0]; unsigned int present; unsigned char bits; - present = snd_hda_jack_detect(codec, 0x15); + present = snd_hda_jack_detect(codec, nid); bits = present ? AMP_IN_MUTE(0) : 0; snd_hda_codec_amp_stereo(codec, 0x0c, HDA_INPUT, 0, AMP_IN_MUTE(0), bits); @@ -13460,8 +13464,8 @@ static void alc269_auto_init(struct hda_codec *codec) static const char *alc269_models[ALC269_MODEL_LAST] = { [ALC269_BASIC] = "basic", [ALC269_QUANTA_FL1] = "quanta", - [ALC269_ASUS_EEEPC_P703] = "eeepc-p703", - [ALC269_ASUS_EEEPC_P901] = "eeepc-p901", + [ALC269_ASUS_AMIC] = "asus-amic", + [ALC269_ASUS_DMIC] = "asus-dmic", [ALC269_FUJITSU] = "fujitsu", [ALC269_LIFEBOOK] = "lifebook", [ALC269_AUTO] = "auto", @@ -13470,18 +13474,41 @@ static const char *alc269_models[ALC269_MODEL_LAST] = { static struct snd_pci_quirk alc269_cfg_tbl[] = { SND_PCI_QUIRK(0x17aa, 0x3bf8, "Quanta FL1", ALC269_QUANTA_FL1), SND_PCI_QUIRK(0x1043, 0x8330, "ASUS Eeepc P703 P900A", - ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_EEEPC_P703), - SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_EEEPC_P703), + ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1133, "ASUS UJ20ft", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1273, "ASUS UL80JT", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1283, "ASUS U53Jc", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x12b3, "ASUS N82Jv", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x13a3, "ASUS UL30Vt", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1373, "ASUS G73JX", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1383, "ASUS UJ30Jc", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x13d3, "ASUS N61JA", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1413, "ASUS UL50", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1443, "ASUS UL30", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1453, "ASUS M60Jv", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1483, "ASUS UL80", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x14f3, "ASUS F83Vf", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x14e3, "ASUS UL20", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1513, "ASUS UX30", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x15a3, "ASUS N60Jv", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x15b3, "ASUS N60Dp", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x15c3, "ASUS N70De", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x15e3, "ASUS F83T", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1643, "ASUS M60J", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1653, "ASUS U50", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1693, "ASUS F50N", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x16a3, "ASUS F5Q", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_DMIC), + SND_PCI_QUIRK(0x1043, 0x1723, "ASUS P80", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1743, "ASUS U80", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1773, "ASUS U20A", ALC269_ASUS_AMIC), + SND_PCI_QUIRK(0x1043, 0x1883, "ASUS F81Se", ALC269_ASUS_AMIC), SND_PCI_QUIRK(0x1043, 0x831a, "ASUS Eeepc P901", - ALC269_ASUS_EEEPC_P901), + ALC269_ASUS_DMIC), SND_PCI_QUIRK(0x1043, 0x834a, "ASUS Eeepc S101", - ALC269_ASUS_EEEPC_P901), - SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_ASUS_EEEPC_P901), + ALC269_ASUS_DMIC), + SND_PCI_QUIRK(0x1043, 0x8398, "ASUS P1005HA", ALC269_ASUS_DMIC), + SND_PCI_QUIRK(0x1043, 0x83ce, "ASUS P1005HA", ALC269_ASUS_DMIC), SND_PCI_QUIRK(0x1734, 0x115d, "FSC Amilo", ALC269_FUJITSU), SND_PCI_QUIRK(0x10cf, 0x1475, "Lifebook ICH9M-based", ALC269_LIFEBOOK), {} @@ -13511,7 +13538,7 @@ static struct alc_config_preset alc269_presets[] = { .setup = alc269_quanta_fl1_setup, .init_hook = alc269_quanta_fl1_init_hook, }, - [ALC269_ASUS_EEEPC_P703] = { + [ALC269_ASUS_AMIC] = { .mixers = { alc269_eeepc_mixer }, .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, @@ -13525,7 +13552,7 @@ static struct alc_config_preset alc269_presets[] = { .setup = alc269_eeepc_amic_setup, .init_hook = alc269_eeepc_inithook, }, - [ALC269_ASUS_EEEPC_P901] = { + [ALC269_ASUS_DMIC] = { .mixers = { alc269_eeepc_mixer }, .cap_mixer = alc269_epc_capture_mixer, .init_verbs = { alc269_init_verbs, @@ -16160,6 +16187,52 @@ static struct snd_kcontrol_new alc663_g50v_mixer[] = { { } /* end */ }; +static struct hda_bind_ctls alc663_asus_mode7_8_all_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x21, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static struct hda_bind_ctls alc663_asus_mode7_8_sp_bind_switch = { + .ops = &snd_hda_bind_sw, + .values = { + HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), + HDA_COMPOSE_AMP_VAL(0x17, 3, 0, HDA_OUTPUT), + 0 + }, +}; + +static struct snd_kcontrol_new alc663_mode7_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x1b, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("IntMic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("IntMic Playback Switch", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), + { } /* end */ +}; + +static struct snd_kcontrol_new alc663_mode8_mixer[] = { + HDA_BIND_SW("Master Playback Switch", &alc663_asus_mode7_8_all_bind_switch), + HDA_BIND_VOL("Speaker Playback Volume", &alc663_asus_bind_master_vol), + HDA_BIND_SW("Speaker Playback Switch", &alc663_asus_mode7_8_sp_bind_switch), + HDA_CODEC_MUTE("Headphone1 Playback Switch", 0x15, 0x0, HDA_OUTPUT), + HDA_CODEC_MUTE("Headphone2 Playback Switch", 0x21, 0x0, HDA_OUTPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + static struct snd_kcontrol_new alc662_chmode_mixer[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, @@ -16447,6 +16520,45 @@ static struct hda_verb alc272_dell_init_verbs[] = { {} }; +static struct hda_verb alc663_mode7_init_verbs[] = { + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x19, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + +static struct hda_verb alc663_mode8_init_verbs[] = { + {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, + {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, + {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, + {0x21, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, + {0x21, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, + {0x21, AC_VERB_SET_CONNECT_SEL, 0x01}, /* Headphone */ + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, + {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(9)}, + {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {0x18, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_MIC_EVENT}, + {0x21, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, + {} +}; + static struct snd_kcontrol_new alc662_auto_capture_mixer[] = { HDA_CODEC_VOLUME("Capture Volume", 0x09, 0x0, HDA_INPUT), HDA_CODEC_MUTE("Capture Switch", 0x09, 0x0, HDA_INPUT), @@ -16626,6 +16738,54 @@ static void alc663_two_hp_m2_speaker_automute(struct hda_codec *codec) } } +static void alc663_two_hp_m7_speaker_automute(struct hda_codec *codec) +{ + unsigned int present1, present2; + + present1 = snd_hda_codec_read(codec, 0x1b, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + present2 = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + + if (present1 || present2) { + snd_hda_codec_write_cache(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } else { + snd_hda_codec_write_cache(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + } +} + +static void alc663_two_hp_m8_speaker_automute(struct hda_codec *codec) +{ + unsigned int present1, present2; + + present1 = snd_hda_codec_read(codec, 0x21, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + present2 = snd_hda_codec_read(codec, 0x15, 0, + AC_VERB_GET_PIN_SENSE, 0) + & AC_PINSENSE_PRESENCE; + + if (present1 || present2) { + snd_hda_codec_write_cache(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); + } else { + snd_hda_codec_write_cache(codec, 0x14, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + snd_hda_codec_write_cache(codec, 0x17, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); + } +} + static void alc663_m51va_unsol_event(struct hda_codec *codec, unsigned int res) { @@ -16645,7 +16805,7 @@ static void alc663_m51va_setup(struct hda_codec *codec) spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; - spec->int_mic.mux_idx = 1; + spec->int_mic.mux_idx = 9; spec->auto_mic = 1; } @@ -16657,7 +16817,17 @@ static void alc663_m51va_inithook(struct hda_codec *codec) /* ***************** Mode1 ******************************/ #define alc663_mode1_unsol_event alc663_m51va_unsol_event -#define alc663_mode1_setup alc663_m51va_setup + +static void alc663_mode1_setup(struct hda_codec *codec) +{ + struct alc_spec *spec = codec->spec; + spec->ext_mic.pin = 0x18; + spec->ext_mic.mux_idx = 0; + spec->int_mic.pin = 0x19; + spec->int_mic.mux_idx = 1; + spec->auto_mic = 1; +} + #define alc663_mode1_inithook alc663_m51va_inithook /* ***************** Mode2 ******************************/ @@ -16674,7 +16844,7 @@ static void alc662_mode2_unsol_event(struct hda_codec *codec, } } -#define alc662_mode2_setup alc663_m51va_setup +#define alc662_mode2_setup alc663_mode1_setup static void alc662_mode2_inithook(struct hda_codec *codec) { @@ -16695,7 +16865,7 @@ static void alc663_mode3_unsol_event(struct hda_codec *codec, } } -#define alc663_mode3_setup alc663_m51va_setup +#define alc663_mode3_setup alc663_mode1_setup static void alc663_mode3_inithook(struct hda_codec *codec) { @@ -16716,7 +16886,7 @@ static void alc663_mode4_unsol_event(struct hda_codec *codec, } } -#define alc663_mode4_setup alc663_m51va_setup +#define alc663_mode4_setup alc663_mode1_setup static void alc663_mode4_inithook(struct hda_codec *codec) { @@ -16737,7 +16907,7 @@ static void alc663_mode5_unsol_event(struct hda_codec *codec, } } -#define alc663_mode5_setup alc663_m51va_setup +#define alc663_mode5_setup alc663_mode1_setup static void alc663_mode5_inithook(struct hda_codec *codec) { @@ -16758,7 +16928,7 @@ static void alc663_mode6_unsol_event(struct hda_codec *codec, } } -#define alc663_mode6_setup alc663_m51va_setup +#define alc663_mode6_setup alc663_mode1_setup static void alc663_mode6_inithook(struct hda_codec *codec) { @@ -16766,6 +16936,50 @@ static void alc663_mode6_inithook(struct hda_codec *codec) alc_mic_automute(codec); } +/* ***************** Mode7 ******************************/ +static void alc663_mode7_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc663_two_hp_m7_speaker_automute(codec); + break; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); + break; + } +} + +#define alc663_mode7_setup alc663_mode1_setup + +static void alc663_mode7_inithook(struct hda_codec *codec) +{ + alc663_two_hp_m7_speaker_automute(codec); + alc_mic_automute(codec); +} + +/* ***************** Mode8 ******************************/ +static void alc663_mode8_unsol_event(struct hda_codec *codec, + unsigned int res) +{ + switch (res >> 26) { + case ALC880_HP_EVENT: + alc663_two_hp_m8_speaker_automute(codec); + break; + case ALC880_MIC_EVENT: + alc_mic_automute(codec); + break; + } +} + +#define alc663_mode8_setup alc663_m51va_setup + +static void alc663_mode8_inithook(struct hda_codec *codec) +{ + alc663_two_hp_m8_speaker_automute(codec); + alc_mic_automute(codec); +} + static void alc663_g71v_hp_automute(struct hda_codec *codec) { unsigned int present; @@ -16900,6 +17114,8 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { [ALC663_ASUS_MODE4] = "asus-mode4", [ALC663_ASUS_MODE5] = "asus-mode5", [ALC663_ASUS_MODE6] = "asus-mode6", + [ALC663_ASUS_MODE7] = "asus-mode7", + [ALC663_ASUS_MODE8] = "asus-mode8", [ALC272_DELL] = "dell", [ALC272_DELL_ZM1] = "dell-zm1", [ALC272_SAMSUNG_NC10] = "samsung-nc10", @@ -16916,12 +17132,22 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { SND_PCI_QUIRK(0x1043, 0x11d3, "ASUS NB", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x11f3, "ASUS NB", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1203, "ASUS NB", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1303, "ASUS G60J", ALC663_ASUS_MODE1), + SND_PCI_QUIRK(0x1043, 0x1333, "ASUS G60Jx", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x1339, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x13e3, "ASUS N71JA", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x1463, "ASUS N71", ALC663_ASUS_MODE7), + SND_PCI_QUIRK(0x1043, 0x14d3, "ASUS G72", ALC663_ASUS_MODE8), + SND_PCI_QUIRK(0x1043, 0x1563, "ASUS N90", ALC663_ASUS_MODE3), + SND_PCI_QUIRK(0x1043, 0x15d3, "ASUS N50SF F50SF", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x16c3, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x16f3, "ASUS K40C K50C", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1733, "ASUS N81De", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x1753, "ASUS NB", ALC662_ASUS_MODE2), SND_PCI_QUIRK(0x1043, 0x1763, "ASUS NB", ALC663_ASUS_MODE6), SND_PCI_QUIRK(0x1043, 0x1765, "ASUS NB", ALC663_ASUS_MODE6), SND_PCI_QUIRK(0x1043, 0x1783, "ASUS NB", ALC662_ASUS_MODE2), + SND_PCI_QUIRK(0x1043, 0x1793, "ASUS F50GX", ALC663_ASUS_MODE1), SND_PCI_QUIRK(0x1043, 0x17b3, "ASUS F70SL", ALC663_ASUS_MODE3), SND_PCI_QUIRK(0x1043, 0x17c3, "ASUS UX20", ALC663_ASUS_M51VA), SND_PCI_QUIRK(0x1043, 0x17f3, "ASUS X58LE", ALC662_ASUS_MODE2), @@ -17205,6 +17431,36 @@ static struct alc_config_preset alc662_presets[] = { .setup = alc663_mode6_setup, .init_hook = alc663_mode6_inithook, }, + [ALC663_ASUS_MODE7] = { + .mixers = { alc663_mode7_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc663_mode7_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc663_mode7_unsol_event, + .setup = alc663_mode7_setup, + .init_hook = alc663_mode7_inithook, + }, + [ALC663_ASUS_MODE8] = { + .mixers = { alc663_mode8_mixer }, + .cap_mixer = alc662_auto_capture_mixer, + .init_verbs = { alc662_init_verbs, + alc663_mode8_init_verbs }, + .num_dacs = ARRAY_SIZE(alc662_dac_nids), + .hp_nid = 0x03, + .dac_nids = alc662_dac_nids, + .dig_out_nid = ALC662_DIGOUT_NID, + .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), + .channel_mode = alc662_3ST_2ch_modes, + .unsol_event = alc663_mode8_unsol_event, + .setup = alc663_mode8_setup, + .init_hook = alc663_mode8_inithook, + }, [ALC272_DELL] = { .mixers = { alc663_m51va_mixer }, .cap_mixer = alc272_auto_capture_mixer, @@ -17688,7 +17944,9 @@ static struct hda_codec_preset snd_hda_preset_realtek[] = { { .id = 0x10ec0267, .name = "ALC267", .patch = patch_alc268 }, { .id = 0x10ec0268, .name = "ALC268", .patch = patch_alc268 }, { .id = 0x10ec0269, .name = "ALC269", .patch = patch_alc269 }, + { .id = 0x10ec0270, .name = "ALC270", .patch = patch_alc269 }, { .id = 0x10ec0272, .name = "ALC272", .patch = patch_alc662 }, + { .id = 0x10ec0275, .name = "ALC275", .patch = patch_alc269 }, { .id = 0x10ec0861, .rev = 0x100340, .name = "ALC660", .patch = patch_alc861 }, { .id = 0x10ec0660, .name = "ALC660-VD", .patch = patch_alc861vd }, -- cgit v1.2.3 From 254bba6a7e28c77d8b32d9eaeba02d4943ee844e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Einar=20R=C3=BCnkaru?= Date: Wed, 16 Dec 2009 22:16:13 +0200 Subject: ALSA: hda - Fixed internal mic initialization for Dell Vostro 1015 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed initialization of internal mic and added internal mic boost control Renamed analog mic boost control to ext mic boost contol. Name pair analog/digital seems too confusing for a normal user. Signed-off-by: Einar Rünkaru Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 39 +++++++++++++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 6 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index a09c03c3f62b..ca9ad9fddbf2 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -111,6 +111,7 @@ struct conexant_spec { unsigned int dell_automute; unsigned int port_d_mode; unsigned char ext_mic_bias; + unsigned int dell_vostro; }; static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, @@ -2109,9 +2110,12 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); int val; + hda_nid_t nid = kcontrol->private_value & 0xff; + int inout = (kcontrol->private_value & 0x100) ? + AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; - val = snd_hda_codec_read(codec, 0x17, 0, - AC_VERB_GET_AMP_GAIN_MUTE, AC_AMP_GET_OUTPUT); + val = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_AMP_GAIN_MUTE, inout); ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; return 0; @@ -2123,6 +2127,9 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, struct hda_codec *codec = snd_kcontrol_chip(kcontrol); const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; unsigned int idx; + hda_nid_t nid = kcontrol->private_value & 0xff; + int inout = (kcontrol->private_value & 0x100) ? + AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; if (!imux->num_items) return 0; @@ -2130,9 +2137,9 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, if (idx >= imux->num_items) idx = imux->num_items - 1; - snd_hda_codec_write_cache(codec, 0x17, 0, + snd_hda_codec_write_cache(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, - AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | + AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | imux->items[idx].index); return 1; @@ -2201,10 +2208,11 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Analog Mic Boost Capture Enum", + .name = "Ext Mic Boost Capture Enum", .info = cxt5066_mic_boost_mux_enum_info, .get = cxt5066_mic_boost_mux_enum_get, .put = cxt5066_mic_boost_mux_enum_put, + .private_value = 0x17, }, HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), @@ -2212,6 +2220,18 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { {} }; +static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { + { + .iface = SNDRV_CTL_ELEM_IFACE_MIXER, + .name = "Int Mic Boost Capture Enum", + .info = cxt5066_mic_boost_mux_enum_info, + .get = cxt5066_mic_boost_mux_enum_get, + .put = cxt5066_mic_boost_mux_enum_put, + .private_value = 0x23 | 0x100, + }, + {} +}; + static struct hda_verb cxt5066_init_verbs[] = { {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port B */ {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, /* Port C */ @@ -2397,11 +2417,16 @@ static struct hda_verb cxt5066_init_verbs_portd_lo[] = { /* initialize jack-sensing, too */ static int cxt5066_init(struct hda_codec *codec) { + struct conexant_spec *spec = codec->spec; + snd_printdd("CXT5066: init\n"); conexant_init(codec); if (codec->patch_ops.unsol_event) { cxt5066_hp_automute(codec); - cxt5066_automic(codec); + if (spec->dell_vostro) + cxt5066_vostro_automic(codec); + else + cxt5066_automic(codec); } return 0; } @@ -2500,7 +2525,9 @@ static int patch_cxt5066(struct hda_codec *codec) spec->init_verbs[0] = cxt5066_init_verbs_vostro; spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; spec->mixers[spec->num_mixers++] = cxt5066_mixers; + spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; spec->port_d_mode = 0; + spec->dell_vostro = 1; /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; -- cgit v1.2.3 From c0f8faf0c7cd497ec7c1d61e1e9424f4384c1f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Einar=20R=C3=BCnkaru?= Date: Wed, 16 Dec 2009 22:41:36 +0200 Subject: ALSA: hda - Make use of beep device found in Dell Vostro 1015n MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Conexant CX20583-10Z has digital beep device with volume control. Making use of them. Signed-off-by: Einar Rünkaru Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_conexant.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index ca9ad9fddbf2..c578c28f368e 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -29,6 +29,7 @@ #include "hda_codec.h" #include "hda_local.h" +#include "hda_beep.h" #define CXT_PIN_DIR_IN 0x00 #define CXT_PIN_DIR_OUT 0x01 @@ -477,6 +478,7 @@ static void conexant_free(struct hda_codec *codec) snd_array_free(&spec->jacks); } #endif + snd_hda_detach_beep_device(codec); kfree(codec->spec); } @@ -2229,6 +2231,7 @@ static struct snd_kcontrol_new cxt5066_vostro_mixers[] = { .put = cxt5066_mic_boost_mux_enum_put, .private_value = 0x23 | 0x100, }, + HDA_CODEC_VOLUME_MONO("Beep Playback Volume", 0x13, 1, 0x0, HDA_OUTPUT), {} }; @@ -2528,6 +2531,7 @@ static int patch_cxt5066(struct hda_codec *codec) spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; spec->port_d_mode = 0; spec->dell_vostro = 1; + snd_hda_attach_beep_device(codec, 0x13); /* no S/PDIF out */ spec->multiout.dig_out_nid = 0; -- cgit v1.2.3 From 035eb0cff0671ada49ba9f3e5c9e7b0cb950efea Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 17 Dec 2009 15:00:26 +0100 Subject: ALSA: hda - Fix missing capsrc_nids for ALC88x Some model quirks missed the corresponding capsrc_nids. This resulted in non-working capture source selection. Signed-off-by: Takashi Iwai Cc: --- sound/pci/hda/patch_realtek.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 287bb6019df9..d9a9f0c7cf5b 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9238,6 +9238,8 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), .adc_nids = alc889_adc_nids, + .capsrc_nids = alc889_capsrc_nids, + .capsrc_nids = alc889_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .dig_in_nid = ALC883_DIGIN_NID, .slave_dig_outs = alc883_slave_dig_outs, @@ -9284,6 +9286,7 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, @@ -9430,6 +9433,7 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), .channel_mode = alc883_sixstack_modes, .input_mux = &alc883_capture_source, @@ -9491,6 +9495,7 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .adc_nids = alc883_adc_nids_alt, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_alt), + .capsrc_nids = alc883_capsrc_nids, .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), .channel_mode = alc883_3ST_2ch_modes, .input_mux = &alc883_lenovo_101e_capture_source, @@ -9670,6 +9675,7 @@ static struct alc_config_preset alc882_presets[] = { alc880_gpio1_init_verbs }, .adc_nids = alc883_adc_nids, .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), + .capsrc_nids = alc883_capsrc_nids, .dac_nids = alc883_dac_nids, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .channel_mode = alc889A_mb31_6ch_modes, -- cgit v1.2.3 From 2fef62c825f09e29d2f52dc187ddf6f99e28c7f1 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Dec 2009 08:48:42 +0100 Subject: ALSA: hda - Fix quirk for Maxdata obook4-1 Works fine with the auto-parser. Reference: Novell bnc#564940 https://bugzilla.novell.com/show_bug.cgi?id=564940 Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index d9a9f0c7cf5b..84bc2c7c4421 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -8921,7 +8921,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x040d, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x0579, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0x28fb, "Targa T8", ALC882_TARGA), /* MSI-1049 T8 */ - SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC883_TARGA_2ch_DIG), + SND_PCI_QUIRK(0x1462, 0x2fb3, "MSI", ALC882_AUTO), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC882_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x3729, "MSI S420", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x3783, "NEC S970", ALC883_TARGA_DIG), -- cgit v1.2.3 From 3e85fd614c7b6bb7f33bb04a0dcb5a3bfca4c0fe Mon Sep 17 00:00:00 2001 From: Clemens Ladisch Date: Fri, 18 Dec 2009 09:27:24 +0100 Subject: sound: sgio2audio/pdaudiocf/usb-audio: initialize PCM buffer When allocating the PCM buffer, use vmalloc_user() instead of vmalloc(). Otherwise, it would be possible for applications to play the previous contents of the kernel memory to the speakers, or to read it directly if the buffer is exported to userspace. Signed-off-by: Clemens Ladisch Cc: Signed-off-by: Takashi Iwai --- sound/mips/sgio2audio.c | 2 +- sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | 2 +- sound/usb/usbaudio.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index 8691f4cf6191..f1d9d16b5486 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c @@ -609,7 +609,7 @@ static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, /* alloc virtual 'dma' area */ if (runtime->dma_area) vfree(runtime->dma_area); - runtime->dma_area = vmalloc(size); + runtime->dma_area = vmalloc_user(size); if (runtime->dma_area == NULL) return -ENOMEM; runtime->dma_bytes = size; diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index d057e6489643..5cfa608823f7 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c @@ -51,7 +51,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t s return 0; /* already enough large */ vfree(runtime->dma_area); } - runtime->dma_area = vmalloc_32(size); + runtime->dma_area = vmalloc_32_user(size); if (! runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index b074a594c595..4963defee18a 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -752,7 +752,7 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t s return 0; /* already large enough */ vfree(runtime->dma_area); } - runtime->dma_area = vmalloc(size); + runtime->dma_area = vmalloc_user(size); if (!runtime->dma_area) return -ENOMEM; runtime->dma_bytes = size; -- cgit v1.2.3 From d49464318a7c51676c44cbd1e2480f651cc43807 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Fri, 18 Dec 2009 20:25:30 +0100 Subject: ALSA: aaci - Fix a typo Fixed a typo of the max buffer size specified for buffer allocation changed in the commit d6797322231af98b9bb4afb175dd614cf511e5f7. Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 1497dce1b04a..ae38f2c342cc 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -1028,7 +1028,7 @@ static int __devinit aaci_init_pcm(struct aaci *aaci) snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &aaci_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &aaci_capture_ops); snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, - NULL, 0, 64 * 104); + NULL, 0, 64 * 1024); } return ret; -- cgit v1.2.3 From 6ca867c827c84d21316e9dc4035abe9480f8347c Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 17:48:35 +0000 Subject: ALSA: AACI: simplify codec rate information There's no need for a specific rule; ALSA's generic AC'97 support calculates the necessary rate constraint information itself, and we can use this directly. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 75 +++----------------------------------------------------- 1 file changed, 3 insertions(+), 72 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index ae38f2c342cc..ea3be874c84f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -330,63 +330,6 @@ static irqreturn_t aaci_irq(int irq, void *devid) /* * ALSA support. */ - -struct aaci_stream { - unsigned char codec_idx; - unsigned char rate_idx; -}; - -static struct aaci_stream aaci_streams[] = { - [ACSTREAM_FRONT] = { - .codec_idx = 0, - .rate_idx = AC97_RATES_FRONT_DAC, - }, - [ACSTREAM_SURROUND] = { - .codec_idx = 0, - .rate_idx = AC97_RATES_SURR_DAC, - }, - [ACSTREAM_LFE] = { - .codec_idx = 0, - .rate_idx = AC97_RATES_LFE_DAC, - }, -}; - -static inline unsigned int aaci_rate_mask(struct aaci *aaci, int streamid) -{ - struct aaci_stream *s = aaci_streams + streamid; - return aaci->ac97_bus->codec[s->codec_idx]->rates[s->rate_idx]; -} - -static unsigned int rate_list[] = { - 5512, 8000, 11025, 16000, 22050, 32000, 44100, - 48000, 64000, 88200, 96000, 176400, 192000 -}; - -/* - * Double-rate rule: we can support double rate iff channels == 2 - * (unimplemented) - */ -static int -aaci_rule_rate_by_channels(struct snd_pcm_hw_params *p, struct snd_pcm_hw_rule *rule) -{ - struct aaci *aaci = rule->private; - unsigned int rate_mask = SNDRV_PCM_RATE_8000_48000|SNDRV_PCM_RATE_5512; - struct snd_interval *c = hw_param_interval(p, SNDRV_PCM_HW_PARAM_CHANNELS); - - switch (c->max) { - case 6: - rate_mask &= aaci_rate_mask(aaci, ACSTREAM_LFE); - case 4: - rate_mask &= aaci_rate_mask(aaci, ACSTREAM_SURROUND); - case 2: - rate_mask &= aaci_rate_mask(aaci, ACSTREAM_FRONT); - } - - return snd_interval_list(hw_param_interval(p, rule->var), - ARRAY_SIZE(rate_list), rate_list, - rate_mask); -} - static struct snd_pcm_hardware aaci_hw_info = { .info = SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID | @@ -400,10 +343,7 @@ static struct snd_pcm_hardware aaci_hw_info = { */ .formats = SNDRV_PCM_FMTBIT_S16_LE, - /* should this be continuous or knot? */ - .rates = SNDRV_PCM_RATE_CONTINUOUS, - .rate_max = 48000, - .rate_min = 4000, + /* rates are setup from the AC'97 codec */ .channels_min = 2, .channels_max = 6, .buffer_bytes_max = 64 * 1024, @@ -423,6 +363,8 @@ static int __aaci_pcm_open(struct aaci *aaci, aacirun->substream = substream; runtime->private_data = aacirun; runtime->hw = aaci_hw_info; + runtime->hw.rates = aacirun->pcm->rates; + snd_pcm_limit_hw_rates(runtime); /* * FIXME: ALSA specifies fifo_size in bytes. If we're in normal @@ -433,17 +375,6 @@ static int __aaci_pcm_open(struct aaci *aaci, */ runtime->hw.fifo_size = aaci->fifosize * 2; - /* - * Add rule describing hardware rate dependency - * on the number of channels. - */ - ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, - aaci_rule_rate_by_channels, aaci, - SNDRV_PCM_HW_PARAM_CHANNELS, - SNDRV_PCM_HW_PARAM_RATE, -1); - if (ret) - goto out; - ret = request_irq(aaci->dev->irq[0], aaci_irq, IRQF_SHARED|IRQF_DISABLED, DRIVER_NAME, aaci); if (ret) -- cgit v1.2.3 From 4e30b69108b20eca80f1a323f969bf7629c7795f Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 17:48:37 +0000 Subject: ALSA: AACI: cleanup aaci_pcm_hw_params Since the recording and playback paths are now the same, eliminate the needless conditionals. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index ea3be874c84f..2e28748a3d8d 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -438,18 +438,14 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); - if (err < 0) - goto out; - - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), - params_channels(params), - aacirun->pcm->r[0].slots); - if (err) - goto out; + if (err >= 0) { + err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + params_channels(params), + aacirun->pcm->r[0].slots); - aacirun->pcm_open = 1; + aacirun->pcm_open = err == 0; + } - out: return err; } @@ -458,7 +454,7 @@ static int aaci_pcm_prepare(struct snd_pcm_substream *substream) struct snd_pcm_runtime *runtime = substream->runtime; struct aaci_runtime *aacirun = runtime->private_data; - aacirun->start = (void *)runtime->dma_area; + aacirun->start = runtime->dma_area; aacirun->end = aacirun->start + snd_pcm_lib_buffer_bytes(substream); aacirun->ptr = aacirun->start; aacirun->period = -- cgit v1.2.3 From d3aee7996c30f928bbbbfd0994148e35d2e83084 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 17:48:40 +0000 Subject: ALSA: AACI: factor common hw_params logic into aaci_pcm_hw_params Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index 2e28748a3d8d..b88bbded2f4f 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -444,6 +444,11 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, aacirun->pcm->r[0].slots); aacirun->pcm_open = err == 0; + aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; + aacirun->fifosz = aaci->fifosize * 4; + + if (aacirun->cr & CR_COMPACT) + aacirun->fifosz >>= 1; } return err; @@ -554,14 +559,9 @@ static int aaci_pcm_playback_hw_params(struct snd_pcm_substream *substream, * Enable FIFO, compact mode, 16 bits per sample. * FIXME: double rate slots? */ - if (ret >= 0) { - aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; + if (ret >= 0) aacirun->cr |= channels_to_txmask[channels]; - aacirun->fifosz = aaci->fifosize * 4; - if (aacirun->cr & CR_COMPACT) - aacirun->fifosz >>= 1; - } return ret; } @@ -648,18 +648,10 @@ static int aaci_pcm_capture_hw_params(struct snd_pcm_substream *substream, int ret; ret = aaci_pcm_hw_params(substream, aacirun, params); - - if (ret >= 0) { - aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; - + if (ret >= 0) /* Line in record: slot 3 and 4 */ aacirun->cr |= CR_SL3 | CR_SL4; - aacirun->fifosz = aaci->fifosize * 4; - - if (aacirun->cr & CR_COMPACT) - aacirun->fifosz >>= 1; - } return ret; } -- cgit v1.2.3 From a08d56583f6b87e2981d1b6e9ee891bdc741cc44 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 17:48:45 +0000 Subject: ALSA: AACI: add double-rate support Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b88bbded2f4f..b377370af2d7 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -366,6 +366,10 @@ static int __aaci_pcm_open(struct aaci *aaci, runtime->hw.rates = aacirun->pcm->rates; snd_pcm_limit_hw_rates(runtime); + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && + aacirun->pcm->r[1].slots) + snd_ac97_pcm_double_rate_rules(runtime); + /* * FIXME: ALSA specifies fifo_size in bytes. If we're in normal * mode, each 32-bit word contains one sample. If we're in @@ -439,9 +443,12 @@ static int aaci_pcm_hw_params(struct snd_pcm_substream *substream, err = snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); if (err >= 0) { - err = snd_ac97_pcm_open(aacirun->pcm, params_rate(params), + unsigned int rate = params_rate(params); + int dbl = rate > 48000; + + err = snd_ac97_pcm_open(aacirun->pcm, rate, params_channels(params), - aacirun->pcm->r[0].slots); + aacirun->pcm->r[dbl].slots); aacirun->pcm_open = err == 0; aacirun->cr = CR_FEN | CR_COMPACT | CR_SZ16; @@ -808,6 +815,12 @@ static struct ac97_pcm ac97_defs[] __devinitdata = { (1 << AC97_SLOT_PCM_SRIGHT) | (1 << AC97_SLOT_LFE), }, + [1] = { + .slots = (1 << AC97_SLOT_PCM_LEFT) | + (1 << AC97_SLOT_PCM_RIGHT) | + (1 << AC97_SLOT_PCM_LEFT_0) | + (1 << AC97_SLOT_PCM_RIGHT_0), + }, }, }, [1] = { /* PCM in */ -- cgit v1.2.3 From d6a89fefa50feda5516cd5210ad0008a44632b52 Mon Sep 17 00:00:00 2001 From: Russell King Date: Fri, 18 Dec 2009 17:48:50 +0000 Subject: ALSA: AACI: switch to per-pcm locking We can use finer-grained locking, which makes things easier when we gain DMA support. Signed-off-by: Russell King Signed-off-by: Takashi Iwai --- sound/arm/aaci.c | 49 +++++++++++++++++++++++++++++-------------------- sound/arm/aaci.h | 2 +- 2 files changed, 30 insertions(+), 21 deletions(-) (limited to 'sound') diff --git a/sound/arm/aaci.c b/sound/arm/aaci.c index b377370af2d7..c5699863643b 100644 --- a/sound/arm/aaci.c +++ b/sound/arm/aaci.c @@ -172,14 +172,15 @@ static unsigned short aaci_ac97_read(struct snd_ac97 *ac97, unsigned short reg) return v; } -static inline void aaci_chan_wait_ready(struct aaci_runtime *aacirun) +static inline void +aaci_chan_wait_ready(struct aaci_runtime *aacirun, unsigned long mask) { u32 val; int timeout = 5000; do { val = readl(aacirun->base + AACI_SR); - } while (val & (SR_TXB|SR_RXB) && timeout--); + } while (val & mask && timeout--); } @@ -208,8 +209,10 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) writel(0, aacirun->base + AACI_IE); return; } - ptr = aacirun->ptr; + spin_lock(&aacirun->lock); + + ptr = aacirun->ptr; do { unsigned int len = aacirun->fifosz; u32 val; @@ -217,9 +220,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) if (aacirun->bytes <= 0) { aacirun->bytes += aacirun->period; aacirun->ptr = ptr; - spin_unlock(&aaci->lock); + spin_unlock(&aacirun->lock); snd_pcm_period_elapsed(aacirun->substream); - spin_lock(&aaci->lock); + spin_lock(&aacirun->lock); } if (!(aacirun->cr & CR_EN)) break; @@ -245,7 +248,10 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) ptr = aacirun->start; } } while(1); + aacirun->ptr = ptr; + + spin_unlock(&aacirun->lock); } if (mask & ISR_URINTR) { @@ -263,6 +269,8 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) return; } + spin_lock(&aacirun->lock); + ptr = aacirun->ptr; do { unsigned int len = aacirun->fifosz; @@ -271,9 +279,9 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) if (aacirun->bytes <= 0) { aacirun->bytes += aacirun->period; aacirun->ptr = ptr; - spin_unlock(&aaci->lock); + spin_unlock(&aacirun->lock); snd_pcm_period_elapsed(aacirun->substream); - spin_lock(&aaci->lock); + spin_lock(&aacirun->lock); } if (!(aacirun->cr & CR_EN)) break; @@ -301,6 +309,8 @@ static void aaci_fifo_irq(struct aaci *aaci, int channel, u32 mask) } while (1); aacirun->ptr = ptr; + + spin_unlock(&aacirun->lock); } } @@ -310,7 +320,6 @@ static irqreturn_t aaci_irq(int irq, void *devid) u32 mask; int i; - spin_lock(&aaci->lock); mask = readl(aaci->base + AACI_ALLINTS); if (mask) { u32 m = mask; @@ -320,7 +329,6 @@ static irqreturn_t aaci_irq(int irq, void *devid) } } } - spin_unlock(&aaci->lock); return mask ? IRQ_HANDLED : IRQ_NONE; } @@ -580,7 +588,7 @@ static void aaci_pcm_playback_stop(struct aaci_runtime *aacirun) ie &= ~(IE_URIE|IE_TXIE); writel(ie, aacirun->base + AACI_IE); aacirun->cr &= ~CR_EN; - aaci_chan_wait_ready(aacirun); + aaci_chan_wait_ready(aacirun, SR_TXB); writel(aacirun->cr, aacirun->base + AACI_TXCR); } @@ -588,7 +596,7 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) { u32 ie; - aaci_chan_wait_ready(aacirun); + aaci_chan_wait_ready(aacirun, SR_TXB); aacirun->cr |= CR_EN; ie = readl(aacirun->base + AACI_IE); @@ -599,12 +607,12 @@ static void aaci_pcm_playback_start(struct aaci_runtime *aacirun) static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) { - struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; unsigned long flags; int ret = 0; - spin_lock_irqsave(&aaci->lock, flags); + spin_lock_irqsave(&aacirun->lock, flags); + switch (cmd) { case SNDRV_PCM_TRIGGER_START: aaci_pcm_playback_start(aacirun); @@ -631,7 +639,8 @@ static int aaci_pcm_playback_trigger(struct snd_pcm_substream *substream, int cm default: ret = -EINVAL; } - spin_unlock_irqrestore(&aaci->lock, flags); + + spin_unlock_irqrestore(&aacirun->lock, flags); return ret; } @@ -666,7 +675,7 @@ static void aaci_pcm_capture_stop(struct aaci_runtime *aacirun) { u32 ie; - aaci_chan_wait_ready(aacirun); + aaci_chan_wait_ready(aacirun, SR_RXB); ie = readl(aacirun->base + AACI_IE); ie &= ~(IE_ORIE | IE_RXIE); @@ -681,7 +690,7 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) { u32 ie; - aaci_chan_wait_ready(aacirun); + aaci_chan_wait_ready(aacirun, SR_RXB); #ifdef DEBUG /* RX Timeout value: bits 28:17 in RXCR */ @@ -698,12 +707,11 @@ static void aaci_pcm_capture_start(struct aaci_runtime *aacirun) static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) { - struct aaci *aaci = substream->private_data; struct aaci_runtime *aacirun = substream->runtime->private_data; unsigned long flags; int ret = 0; - spin_lock_irqsave(&aaci->lock, flags); + spin_lock_irqsave(&aacirun->lock, flags); switch (cmd) { case SNDRV_PCM_TRIGGER_START: @@ -732,7 +740,7 @@ static int aaci_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd ret = -EINVAL; } - spin_unlock_irqrestore(&aaci->lock, flags); + spin_unlock_irqrestore(&aacirun->lock, flags); return ret; } @@ -933,7 +941,6 @@ static struct aaci * __devinit aaci_init_card(struct amba_device *dev) aaci = card->private_data; mutex_init(&aaci->ac97_sem); - spin_lock_init(&aaci->lock); aaci->card = card; aaci->dev = dev; @@ -1020,12 +1027,14 @@ static int __devinit aaci_probe(struct amba_device *dev, struct amba_id *id) /* * Playback uses AACI channel 0 */ + spin_lock_init(&aaci->playback.lock); aaci->playback.base = aaci->base + AACI_CSCH1; aaci->playback.fifo = aaci->base + AACI_DR1; /* * Capture uses AACI channel 0 */ + spin_lock_init(&aaci->capture.lock); aaci->capture.base = aaci->base + AACI_CSCH1; aaci->capture.fifo = aaci->base + AACI_DR1; diff --git a/sound/arm/aaci.h b/sound/arm/aaci.h index 924f69c1c44c..6a4a2eebdda1 100644 --- a/sound/arm/aaci.h +++ b/sound/arm/aaci.h @@ -202,6 +202,7 @@ struct aaci_runtime { void __iomem *base; void __iomem *fifo; + spinlock_t lock; struct ac97_pcm *pcm; int pcm_open; @@ -232,7 +233,6 @@ struct aaci { struct snd_ac97 *ac97; u32 maincr; - spinlock_t lock; struct aaci_runtime playback; struct aaci_runtime capture; -- cgit v1.2.3 From ef86f581f7e8b29cb58d7f4e892e1a91b3805124 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sat, 19 Dec 2009 08:18:03 +0100 Subject: ALSA: Use kzalloc for allocating only one thing Use kzalloc rather than kcalloc(1,...) The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ @@ - kcalloc(1, + kzalloc( ...) // Signed-off-by: Julia Lawall Signed-off-by: Takashi Iwai --- sound/isa/msnd/msnd_midi.c | 2 +- sound/pci/hda/patch_realtek.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/isa/msnd/msnd_midi.c b/sound/isa/msnd/msnd_midi.c index cb9aa4c4edd0..4be562b2cf21 100644 --- a/sound/isa/msnd/msnd_midi.c +++ b/sound/isa/msnd/msnd_midi.c @@ -162,7 +162,7 @@ int snd_msndmidi_new(struct snd_card *card, int device) err = snd_rawmidi_new(card, "MSND-MIDI", device, 1, 1, &rmidi); if (err < 0) return err; - mpu = kcalloc(1, sizeof(*mpu), GFP_KERNEL); + mpu = kzalloc(sizeof(*mpu), GFP_KERNEL); if (mpu == NULL) { snd_device_free(card, rmidi); return -ENOMEM; diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index aeed4cc5aa79..20c1828e4bac 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -12857,7 +12857,7 @@ static int patch_alc268(struct hda_codec *codec) int board_config; int i, has_beep, err; - spec = kcalloc(1, sizeof(*spec), GFP_KERNEL); + spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) return -ENOMEM; -- cgit v1.2.3 From 440b004cf953bec2bc8cd91c64ae707fd7e25327 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sun, 20 Dec 2009 12:04:08 +0100 Subject: ALSA: hda/realtek: Remove extra .capsrc_nids initialization for ALC889_INTEL Signed-off-by: Jaroslav Kysela --- sound/pci/hda/patch_realtek.c | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 8b375771b3ab..2d3f4f893ef3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -9238,8 +9238,6 @@ static struct alc_config_preset alc882_presets[] = { .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), .adc_nids = alc889_adc_nids, - .capsrc_nids = alc889_capsrc_nids, - .capsrc_nids = alc889_capsrc_nids, .dig_out_nid = ALC883_DIGOUT_NID, .dig_in_nid = ALC883_DIGIN_NID, .slave_dig_outs = alc883_slave_dig_outs, -- cgit v1.2.3 From e2595322a3a353a59cecd7f57e7aa421ecb02d12 Mon Sep 17 00:00:00 2001 From: Daniel T Chen Date: Sat, 19 Dec 2009 18:19:02 -0500 Subject: ALSA: hda: Set Front Mic to input vref 50% for Lenovo 3000 Y410 BugLink: https://bugs.launchpad.net/bugs/479373 The OR has verified with hda-verb that the internal microphone needs VREF50 set for audible capture. Signed-off-by: Daniel T Chen Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 84bc2c7c4421..1554c3a6fd2e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -10686,6 +10686,13 @@ static struct hda_verb alc262_lenovo_3000_unsol_verbs[] = { {} }; +static struct hda_verb alc262_lenovo_3000_init_verbs[] = { + /* Front Mic pin: input vref at 50% */ + {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF50}, + {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, + {} +}; + static struct hda_input_mux alc262_fujitsu_capture_source = { .num_items = 3, .items = { @@ -11728,7 +11735,8 @@ static struct alc_config_preset alc262_presets[] = { [ALC262_LENOVO_3000] = { .mixers = { alc262_lenovo_3000_mixer }, .init_verbs = { alc262_init_verbs, alc262_EAPD_verbs, - alc262_lenovo_3000_unsol_verbs }, + alc262_lenovo_3000_unsol_verbs, + alc262_lenovo_3000_init_verbs }, .num_dacs = ARRAY_SIZE(alc262_dac_nids), .dac_nids = alc262_dac_nids, .hp_nid = 0x03, -- cgit v1.2.3 From 0f86a228f4a4639b3142ce0dad208433b2db377a Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 20 Dec 2009 22:51:18 +0100 Subject: ALSA: HDA: simplify Aspire 8930G verb array This patch just simplifies the 8930G verb array a bit. Just use the common ALC889 EAPD verb array to make things more consistent. The file is already huge enough already. Signed-off-by: Hector Martin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 1554c3a6fd2e..cb97323acc17 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1665,9 +1665,6 @@ static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { /* some bit here disables the other DACs. Init=0x4900 */ {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, -/* Enable amplifiers */ - {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, - {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, /* DMIC fix * This laptop has a stereo digital microphone. The mics are only 1cm apart * which makes the stereo useless. However, either the mic or the ALC889 @@ -9386,7 +9383,8 @@ static struct alc_config_preset alc882_presets[] = { .mixers = { alc888_base_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, - alc889_acer_aspire_8930g_verbs }, + alc889_acer_aspire_8930g_verbs, + alc889_eapd_verbs}, .num_dacs = ARRAY_SIZE(alc883_dac_nids), .dac_nids = alc883_dac_nids, .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), -- cgit v1.2.3 From 556eea9a926bff8f014b4f80522b4de97ae84213 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 20 Dec 2009 22:51:23 +0100 Subject: ALSA: HDA: remove useless mixers on Aspire 8930G This patch removes some extra mixers that do nothing on the Acer Aspire 8930G. The CD mixer is useless because the SATA DVD/Blu-Ray drive has no analog audio output, and the Side mixer is useless because we max out at 6ch anyway. Signed-off-by: Hector Martin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index cb97323acc17..faeb74f28207 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -1777,6 +1777,25 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { { } /* end */ }; +static struct snd_kcontrol_new alc889_acer_aspire_8930g_mixer[] = { + HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 2, HDA_INPUT), + HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x0, + HDA_OUTPUT), + HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x0, HDA_OUTPUT), + HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 2, HDA_INPUT), + HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 2, HDA_INPUT), + HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), + HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), + HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), + { } /* end */ +}; + + static void alc888_acer_aspire_4930g_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; @@ -9380,7 +9399,7 @@ static struct alc_config_preset alc882_presets[] = { .init_hook = alc_automute_amp, }, [ALC888_ACER_ASPIRE_8930G] = { - .mixers = { alc888_base_mixer, + .mixers = { alc889_acer_aspire_8930g_mixer, alc883_chmode_mixer }, .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, alc889_acer_aspire_8930g_verbs, -- cgit v1.2.3 From f5de24b06aa46427500d0fdbe8616b73a71d8c28 Mon Sep 17 00:00:00 2001 From: Hector Martin Date: Sun, 20 Dec 2009 22:51:31 +0100 Subject: ALSA: HDA: add powersaving hook for Realtek The current Realtek code makes no specific provision for turning stuff off. The codec chip is placed into low-power mode generically, but this doesn't turn off any external hardware connected to it, in particular external amplifiers. This patch creates a hook function that is called by the codec suspend/resume functions. It ought to disable any external hardware in a device-specific way. I've implemented a generic ALC889 function that sets the EAPD pin properly, and used it for the Acer Aspire 8930G which can benefit from this feature. On my laptop, this results in ~0.5W extra savings. Signed-off-by: Hector Martin Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_realtek.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index faeb74f28207..b3abe9ca826d 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -337,6 +337,9 @@ struct alc_spec { /* hooks */ void (*init_hook)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); +#ifdef CONFIG_SND_HDA_POWER_SAVE + void (*power_hook)(struct hda_codec *codec, int power); +#endif /* for pin sensing */ unsigned int sense_updated: 1; @@ -388,6 +391,7 @@ struct alc_config_preset { void (*init_hook)(struct hda_codec *); #ifdef CONFIG_SND_HDA_POWER_SAVE struct hda_amp_list *loopbacks; + void (*power_hook)(struct hda_codec *codec, int power); #endif }; @@ -900,6 +904,7 @@ static void setup_preset(struct hda_codec *codec, spec->unsol_event = preset->unsol_event; spec->init_hook = preset->init_hook; #ifdef CONFIG_SND_HDA_POWER_SAVE + spec->power_hook = preset->power_hook; spec->loopback.amplist = preset->loopbacks; #endif @@ -1826,6 +1831,16 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) spec->autocfg.speaker_pins[2] = 0x1b; } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static void alc889_power_eapd(struct hda_codec *codec, int power) +{ + snd_hda_codec_write(codec, 0x14, 0, + AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); + snd_hda_codec_write(codec, 0x15, 0, + AC_VERB_SET_EAPD_BTLENABLE, power ? 2 : 0); +} +#endif + /* * ALC880 3-stack model * @@ -3619,12 +3634,29 @@ static void alc_free(struct hda_codec *codec) snd_hda_detach_beep_device(codec); } +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int alc_suspend(struct hda_codec *codec, pm_message_t state) +{ + struct alc_spec *spec = codec->spec; + if (spec && spec->power_hook) + spec->power_hook(codec, 0); + return 0; +} +#endif + #ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { +#ifdef CONFIG_SND_HDA_POWER_SAVE + struct alc_spec *spec = codec->spec; +#endif codec->patch_ops.init(codec); snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (spec && spec->power_hook) + spec->power_hook(codec, 1); +#endif return 0; } #endif @@ -3641,6 +3673,7 @@ static struct hda_codec_ops alc_patch_ops = { .resume = alc_resume, #endif #ifdef CONFIG_SND_HDA_POWER_SAVE + .suspend = alc_suspend, .check_power_status = alc_check_power_status, #endif }; @@ -9420,6 +9453,9 @@ static struct alc_config_preset alc882_presets[] = { .unsol_event = alc_automute_amp_unsol_event, .setup = alc889_acer_aspire_8930g_setup, .init_hook = alc_automute_amp, +#ifdef CONFIG_SND_HDA_POWER_SAVE + .power_hook = alc889_power_eapd, +#endif }, [ALC888_ACER_ASPIRE_7730G] = { .mixers = { alc883_3ST_6ch_mixer, -- cgit v1.2.3 From 40962d7c741de1c21b6ce8516c1d9f8836fb383e Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sat, 19 Dec 2009 18:31:04 +0100 Subject: ALSA: fix incorrect rounding direction in snd_interval_ratnum() The direction of rounding is incorrect in the snd_interval_ratnum() It was detected with following parameters (sb8 driver playing 8kHz stereo file): - num is always 1000000 - requested frequency rate is from 7999 to 7999 (single frequency) The first loop calculates div_down(num, freq->min) which is 125. Thus, a frequency range's minimum value is 1000000 / 125 = 8000 Hz. The second loop calculates div_up(num, freq->max) which is 126 The frequency range's maximum value is 1000000 / 126 = 7936 Hz. The range maximum is lower than the range minimum so the function fails due to empty result range. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/core/pcm_lib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'sound') diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index 30f410832a25..a27545b23ee9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -758,7 +758,7 @@ int snd_interval_ratnum(struct snd_interval *i, int diff; if (q == 0) q = 1; - den = div_down(num, q); + den = div_up(num, q); if (den < rats[k].den_min) continue; if (den > rats[k].den_max) @@ -794,7 +794,7 @@ int snd_interval_ratnum(struct snd_interval *i, i->empty = 1; return -EINVAL; } - den = div_up(num, q); + den = div_down(num, q); if (den > rats[k].den_max) continue; if (den < rats[k].den_min) -- cgit v1.2.3 From db8cf334f66bdf1ba2b3d2f7128095fc9b7a6e2b Mon Sep 17 00:00:00 2001 From: Krzysztof Helt Date: Sun, 20 Dec 2009 20:15:19 +0100 Subject: ALSA: sbawe: fix memory detection Memory amount is increased before a successful write-read sequence is done. Thus, 512 kB of onboard memory is detected on memoryless cards like SB32. Move the increasing of memory counter after successful read is done. Signed-off-by: Krzysztof Helt Signed-off-by: Takashi Iwai --- sound/isa/sb/emu8000.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'sound') diff --git a/sound/isa/sb/emu8000.c b/sound/isa/sb/emu8000.c index 96678d5d3834..751762f1c59a 100644 --- a/sound/isa/sb/emu8000.c +++ b/sound/isa/sb/emu8000.c @@ -393,8 +393,6 @@ size_dram(struct snd_emu8000 *emu) while (size < EMU8000_MAX_DRAM) { - size += 512 * 1024; /* increment 512kbytes */ - /* Write a unique data on the test address. * if the address is out of range, the data is written on * 0x200000(=EMU8000_DRAM_OFFSET). Then the id word is @@ -414,7 +412,9 @@ size_dram(struct snd_emu8000 *emu) /*snd_emu8000_read_wait(emu);*/ EMU8000_SMLD_READ(emu); /* discard stale data */ if (EMU8000_SMLD_READ(emu) != UNIQUE_ID2) - break; /* we must have wrapped around */ + break; /* no memory at this address */ + + size += 512 * 1024; /* increment 512kbytes */ snd_emu8000_read_wait(emu); -- cgit v1.2.3 From d8d881dd2c814e1500558889d800cf78d11cf898 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Dec 2009 07:52:49 +0100 Subject: ALSA: hda - Fix NULL dereference with enable_beep=0 option Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 3d59f8325848..417fb22ae83c 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -3779,15 +3779,16 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out err = snd_hda_attach_beep_device(codec, nid); if (err < 0) return err; - /* IDT/STAC codecs have linear beep tone parameter */ - codec->beep->linear_tone = 1; - /* if no beep switch is available, make its own one */ - caps = query_amp_caps(codec, nid, HDA_OUTPUT); - if (codec->beep && - !((caps & AC_AMPCAP_MUTE) >> AC_AMPCAP_MUTE_SHIFT)) { - err = stac92xx_beep_switch_ctl(codec); - if (err < 0) - return err; + if (codec->beep) { + /* IDT/STAC codecs have linear beep tone parameter */ + codec->beep->linear_tone = 1; + /* 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); + if (err < 0) + return err; + } } } #endif -- cgit v1.2.3 From 1a5ba2e9fc7999b8de2a71c7e7b9f58d752c05e4 Mon Sep 17 00:00:00 2001 From: Rafael Avila de Espindola Date: Tue, 22 Dec 2009 07:59:37 +0100 Subject: ALSA: hda - Add support for the new 27 inch IMacs With the attached patch I am able to use the sound on a new IMac 27. What works: *) Internal speakers *) Internal microphone *) Headphone I don't have an external mic or a SPDIF device to test the rest. Signed-off-by: Rafael Avila de Espindola Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_cirrus.c | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) (limited to 'sound') diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index 4b200da1bd18..fe0423c39598 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c @@ -66,6 +66,7 @@ struct cs_spec { /* available models */ enum { CS420X_MBP55, + CS420X_IMAC27, CS420X_AUTO, CS420X_MODELS }; @@ -827,7 +828,8 @@ static void cs_automute(struct hda_codec *codec) AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); } - if (spec->board_config == CS420X_MBP55) { + if (spec->board_config == CS420X_MBP55 || + spec->board_config == CS420X_IMAC27) { unsigned int gpio = hp_present ? 0x02 : 0x08; snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); @@ -1069,12 +1071,14 @@ static int cs_parse_auto_config(struct hda_codec *codec) static const char *cs420x_models[CS420X_MODELS] = { [CS420X_MBP55] = "mbp55", + [CS420X_IMAC27] = "imac27", [CS420X_AUTO] = "auto", }; static struct snd_pci_quirk cs420x_cfg_tbl[] = { SND_PCI_QUIRK(0x10de, 0xcb79, "MacBookPro 5,5", CS420X_MBP55), + SND_PCI_QUIRK(0x8086, 0x7270, "IMac 27 Inch", CS420X_IMAC27), {} /* terminator */ }; @@ -1097,8 +1101,23 @@ static struct cs_pincfg mbp55_pincfgs[] = { {} /* terminator */ }; +static struct cs_pincfg imac27_pincfgs[] = { + { 0x09, 0x012b4050 }, + { 0x0a, 0x90100140 }, + { 0x0b, 0x90100142 }, + { 0x0c, 0x018b3020 }, + { 0x0d, 0x90a00110 }, + { 0x0e, 0x400000f0 }, + { 0x0f, 0x01cbe030 }, + { 0x10, 0x014be060 }, + { 0x12, 0x01ab9070 }, + { 0x15, 0x400000f0 }, + {} /* terminator */ +}; + static struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { [CS420X_MBP55] = mbp55_pincfgs, + [CS420X_IMAC27] = imac27_pincfgs, }; static void fix_pincfg(struct hda_codec *codec, int model) @@ -1128,6 +1147,7 @@ static int patch_cs420x(struct hda_codec *codec) fix_pincfg(codec, spec->board_config); switch (spec->board_config) { + case CS420X_IMAC27: case CS420X_MBP55: /* GPIO1 = headphones */ /* GPIO3 = speakers */ -- cgit v1.2.3 From 9dc8398bab52931435fce403ce2eaf5822f28e58 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 22 Dec 2009 08:15:01 +0100 Subject: ALSA: hda - Add MSI blacklist A machine with AMD CPU with Nvidia board doesn't work with MSI. Reported-by: Robert J. King Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_intel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'sound') diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 9b56f937913e..ff8ad46cc50e 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -2322,6 +2322,7 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) * white/black-list for enable_msi */ static struct snd_pci_quirk msi_black_list[] __devinitdata = { + SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ {} }; -- cgit v1.2.3 From a9605391cfab2bf9a73e51faac5147622f73c6d5 Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Mon, 21 Dec 2009 16:36:10 -0800 Subject: ALSA: sound/core/pcm_timer.c: use lib/gcd.c Make sound/core/pcm_timer.c use lib/gcd.c Signed-off-by: Florian Fainelli Signed-off-by: Andrew Morton Signed-off-by: Takashi Iwai --- sound/core/Kconfig | 1 + sound/core/pcm_timer.c | 17 +---------------- 2 files changed, 2 insertions(+), 16 deletions(-) (limited to 'sound') diff --git a/sound/core/Kconfig b/sound/core/Kconfig index c15682a2f9db..475455c76610 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -5,6 +5,7 @@ config SND_TIMER config SND_PCM tristate select SND_TIMER + select GCD config SND_HWDEP tristate diff --git a/sound/core/pcm_timer.c b/sound/core/pcm_timer.c index ca8068b63d6c..b01d9481d632 100644 --- a/sound/core/pcm_timer.c +++ b/sound/core/pcm_timer.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include @@ -28,22 +29,6 @@ * Timer functions */ -/* Greatest common divisor */ -static unsigned long gcd(unsigned long a, unsigned long b) -{ - unsigned long r; - if (a < b) { - r = a; - a = b; - b = r; - } - while ((r = a % b) != 0) { - a = b; - b = r; - } - return b; -} - void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream) { unsigned long rate, mult, fsize, l, post; -- cgit v1.2.3 From f62faedbed546f4e0c1ba204999e7c206059f305 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Wed, 23 Dec 2009 09:27:51 +0100 Subject: ALSA: hda - Set mixer name after codec patch Postpone the mixer name setup after the codec patch since the codec patch may change the codec name string in itself. Signed-off-by: Takashi Iwai --- sound/pci/hda/hda_codec.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'sound') diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 9cfdb771928c..950ee5cfcacf 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -1086,11 +1086,6 @@ int snd_hda_codec_configure(struct hda_codec *codec) if (err < 0) return err; } - /* audio codec should override the mixer name */ - 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); if (is_generic_config(codec)) { err = snd_hda_parse_generic_codec(codec); @@ -1109,6 +1104,11 @@ int snd_hda_codec_configure(struct hda_codec *codec) patched: if (!err && codec->patch_ops.unsol_event) err = init_unsol_queue(codec->bus); + /* audio codec should override the mixer name */ + if (!err && (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; } EXPORT_SYMBOL_HDA(snd_hda_codec_configure); -- cgit v1.2.3 From 95e70e87533f9d117d369495ee633cb7d18dc802 Mon Sep 17 00:00:00 2001 From: Anisse Astier Date: Wed, 23 Dec 2009 17:28:45 +0100 Subject: ALSA: hda - Add STAC9205 PCI_QUIRK for Dell Vostro 1700 Signed-off-by: Anisse Astier Signed-off-by: Takashi Iwai --- sound/pci/hda/patch_sigmatel.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sound') diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 417fb22ae83c..eeda7beeb57a 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -2104,6 +2104,7 @@ static unsigned int ref9205_pin_configs[12] = { 10280204 1028021F 10280228 (Dell Vostro 1500) + 10280229 (Dell Vostro 1700) */ static unsigned int dell_9205_m42_pin_configs[12] = { 0x0321101F, 0x03A11020, 0x400003FA, 0x90170310, @@ -2189,6 +2190,8 @@ static struct snd_pci_quirk stac9205_cfg_tbl[] = { "Dell Inspiron", STAC_9205_DELL_M44), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0228, "Dell Vostro 1500", STAC_9205_DELL_M42), + SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0229, + "Dell Vostro 1700", STAC_9205_DELL_M42), /* Gateway */ SND_PCI_QUIRK(0x107b, 0x0560, "Gateway T6834c", STAC_9205_EAPD), SND_PCI_QUIRK(0x107b, 0x0565, "Gateway T1616", STAC_9205_EAPD), -- cgit v1.2.3