diff options
author | Ingo Molnar <mingo@elte.hu> | 2010-04-02 20:02:55 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-04-02 20:03:08 +0200 |
commit | c9494727cf293ae2ec66af57547a3e79c724fec2 (patch) | |
tree | 44ae197b64fa7530ee695a90ad31326dda06f1e1 /sound | |
parent | 6427462bfa50f50dc6c088c07037264fcc73eca1 (diff) | |
parent | 42be79e37e264557f12860fa4cc84b4de3685954 (diff) | |
download | kernel_samsung_tuna-c9494727cf293ae2ec66af57547a3e79c724fec2.zip kernel_samsung_tuna-c9494727cf293ae2ec66af57547a3e79c724fec2.tar.gz kernel_samsung_tuna-c9494727cf293ae2ec66af57547a3e79c724fec2.tar.bz2 |
Merge branch 'linus' into sched/core
Merge reason: update to latest upstream
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'sound')
48 files changed, 1583 insertions, 1255 deletions
diff --git a/sound/arm/pxa2xx-ac97-lib.c b/sound/arm/pxa2xx-ac97-lib.c index 6fdca97..88eec38 100644 --- a/sound/arm/pxa2xx-ac97-lib.c +++ b/sound/arm/pxa2xx-ac97-lib.c @@ -22,7 +22,6 @@ #include <asm/irq.h> #include <mach/regs-ac97.h> -#include <mach/pxa2xx-gpio.h> #include <mach/audio.h> static DEFINE_MUTEX(car_mutex); @@ -32,6 +31,8 @@ static struct clk *ac97_clk; static struct clk *ac97conf_clk; static int reset_gpio; +extern void pxa27x_assert_ac97reset(int reset_gpio, int on); + /* * Beware PXA27x bugs: * @@ -42,45 +43,6 @@ static int reset_gpio; * 1 jiffy timeout if interrupt never comes). */ -enum { - RESETGPIO_FORCE_HIGH, - RESETGPIO_FORCE_LOW, - RESETGPIO_NORMAL_ALTFUNC -}; - -/** - * set_resetgpio_mode - computes and sets the AC97_RESET gpio mode on PXA - * @mode: chosen action - * - * As the PXA27x CPUs suffer from a AC97 bug, a manual control of the reset line - * must be done to insure proper work of AC97 reset line. This function - * computes the correct gpio_mode for further use by reset functions, and - * applied the change through pxa_gpio_mode. - */ -static void set_resetgpio_mode(int resetgpio_action) -{ - int mode = 0; - - if (reset_gpio) - switch (resetgpio_action) { - case RESETGPIO_NORMAL_ALTFUNC: - if (reset_gpio == 113) - mode = 113 | GPIO_ALT_FN_2_OUT; - if (reset_gpio == 95) - mode = 95 | GPIO_ALT_FN_1_OUT; - break; - case RESETGPIO_FORCE_LOW: - mode = reset_gpio | GPIO_OUT | GPIO_DFLT_LOW; - break; - case RESETGPIO_FORCE_HIGH: - mode = reset_gpio | GPIO_OUT | GPIO_DFLT_HIGH; - break; - }; - - if (mode) - pxa_gpio_mode(mode); -} - unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short reg) { unsigned short val = -1; @@ -174,12 +136,11 @@ static inline void pxa_ac97_warm_pxa27x(void) { gsr_bits = 0; - /* warm reset broken on Bulverde, - so manually keep AC97 reset high */ - set_resetgpio_mode(RESETGPIO_FORCE_HIGH); + /* warm reset broken on Bulverde, so manually keep AC97 reset high */ + pxa27x_assert_ac97reset(reset_gpio, 1); udelay(10); GCR |= GCR_WARM_RST; - set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); + pxa27x_assert_ac97reset(reset_gpio, 0); udelay(500); } @@ -345,16 +306,6 @@ EXPORT_SYMBOL_GPL(pxa2xx_ac97_hw_suspend); int pxa2xx_ac97_hw_resume(void) { - if (cpu_is_pxa25x() || cpu_is_pxa27x()) { - pxa_gpio_mode(GPIO31_SYNC_AC97_MD); - pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); - pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); - pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); - } - if (cpu_is_pxa27x()) { - /* Use GPIO 113 or 95 as AC97 Reset on Bulverde */ - set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); - } clk_enable(ac97_clk); return 0; } @@ -386,16 +337,9 @@ int __devinit pxa2xx_ac97_hw_probe(struct platform_device *dev) reset_gpio = 113; } - if (cpu_is_pxa25x() || cpu_is_pxa27x()) { - pxa_gpio_mode(GPIO31_SYNC_AC97_MD); - pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD); - pxa_gpio_mode(GPIO28_BITCLK_AC97_MD); - pxa_gpio_mode(GPIO29_SDATA_IN_AC97_MD); - } - if (cpu_is_pxa27x()) { /* Use GPIO 113 as AC97 Reset on Bulverde */ - set_resetgpio_mode(RESETGPIO_NORMAL_ALTFUNC); + pxa27x_assert_ac97reset(reset_gpio, 0); ac97conf_clk = clk_get(&dev->dev, "AC97CONFCLK"); if (IS_ERR(ac97conf_clk)) { ret = PTR_ERR(ac97conf_clk); diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c index 743ac6a..fd51fa8 100644 --- a/sound/arm/pxa2xx-pcm-lib.c +++ b/sound/arm/pxa2xx-pcm-lib.c @@ -205,6 +205,7 @@ int __pxa2xx_pcm_open(struct snd_pcm_substream *substream) if (!rtd->dma_desc_array) goto err1; + rtd->dma_ch = -1; runtime->private_data = rtd; return 0; diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index b546ac2..a2ff861 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c @@ -148,6 +148,9 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, #define xrun_debug(substream, mask) \ ((substream)->pstr->xrun_debug & (mask)) +#else +#define xrun_debug(substream, mask) 0 +#endif #define dump_stack_on_xrun(substream) do { \ if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ @@ -169,6 +172,7 @@ static void xrun(struct snd_pcm_substream *substream) } } +#ifdef CONFIG_SND_PCM_XRUN_DEBUG #define hw_ptr_error(substream, fmt, args...) \ do { \ if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ @@ -255,8 +259,6 @@ static void xrun_log_show(struct snd_pcm_substream *substream) #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ -#define xrun_debug(substream, mask) 0 -#define xrun(substream) do { } while (0) #define hw_ptr_error(substream, fmt, args...) do { } while (0) #define xrun_log(substream, pos) do { } while (0) #define xrun_log_show(substream) do { } while (0) diff --git a/sound/core/timer.c b/sound/core/timer.c index 8f8b17a..7394365 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c @@ -393,7 +393,7 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) event == SNDRV_TIMER_EVENT_CONTINUE) resolution = snd_timer_resolution(ti); if (ti->ccallback) - ti->ccallback(ti, SNDRV_TIMER_EVENT_START, &tstamp, resolution); + ti->ccallback(ti, event, &tstamp, resolution); if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) return; timer = ti->timer; diff --git a/sound/isa/opti9xx/miro.c b/sound/isa/opti9xx/miro.c index b865e45..5913717 100644 --- a/sound/isa/opti9xx/miro.c +++ b/sound/isa/opti9xx/miro.c @@ -1558,7 +1558,7 @@ static int __devinit snd_card_miro_pnp(struct snd_miro *chip, err = pnp_activate_dev(devmc); if (err < 0) { - snd_printk(KERN_ERR "OPL syntg pnp configure failure: %d\n", + snd_printk(KERN_ERR "MC pnp configure failure: %d\n", err); return err; } diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index a4af53b..4d2d040 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c @@ -144,12 +144,8 @@ struct snd_opti9xx { spinlock_t lock; + long wss_base; int irq; - -#ifdef CONFIG_PNP - struct pnp_dev *dev; - struct pnp_dev *devmpu; -#endif /* CONFIG_PNP */ }; static int snd_opti9xx_pnp_is_probed; @@ -159,12 +155,17 @@ static int snd_opti9xx_pnp_is_probed; static struct pnp_card_device_id snd_opti9xx_pnpids[] = { #ifndef OPTi93X /* OPTi 82C924 */ - { .id = "OPT0924", .devs = { { "OPT0000" }, { "OPT0002" } }, .driver_data = 0x0924 }, + { .id = "OPT0924", + .devs = { { "OPT0000" }, { "OPT0002" }, { "OPT0005" } }, + .driver_data = 0x0924 }, /* OPTi 82C925 */ - { .id = "OPT0925", .devs = { { "OPT9250" }, { "OPT0002" } }, .driver_data = 0x0925 }, + { .id = "OPT0925", + .devs = { { "OPT9250" }, { "OPT0002" }, { "OPT0005" } }, + .driver_data = 0x0925 }, #else /* OPTi 82C931/3 */ - { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, .driver_data = 0x0931 }, + { .id = "OPT0931", .devs = { { "OPT9310" }, { "OPT0002" } }, + .driver_data = 0x0931 }, #endif /* OPTi93X */ { .id = "" } }; @@ -207,24 +208,35 @@ static int __devinit snd_opti9xx_init(struct snd_opti9xx *chip, chip->hardware = hardware; strcpy(chip->name, snd_opti9xx_names[hardware]); - chip->mc_base_size = opti9xx_mc_size[hardware]; - spin_lock_init(&chip->lock); chip->irq = -1; +#ifndef OPTi93X +#ifdef CONFIG_PNP + if (isapnp && chip->mc_base) + /* PnP resource gives the least 10 bits */ + chip->mc_base |= 0xc00; + else +#endif /* CONFIG_PNP */ + { + chip->mc_base = 0xf8c; + chip->mc_base_size = opti9xx_mc_size[hardware]; + } +#else + chip->mc_base_size = opti9xx_mc_size[hardware]; +#endif + switch (hardware) { #ifndef OPTi93X case OPTi9XX_HW_82C928: case OPTi9XX_HW_82C929: - chip->mc_base = 0xf8c; chip->password = (hardware == OPTi9XX_HW_82C928) ? 0xe2 : 0xe3; chip->pwd_reg = 3; break; case OPTi9XX_HW_82C924: case OPTi9XX_HW_82C925: - chip->mc_base = 0xf8c; chip->password = 0xe5; chip->pwd_reg = 3; break; @@ -292,7 +304,7 @@ static unsigned char snd_opti9xx_read(struct snd_opti9xx *chip, spin_unlock_irqrestore(&chip->lock, flags); return retval; } - + static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, unsigned char value) { @@ -341,7 +353,7 @@ static void snd_opti9xx_write(struct snd_opti9xx *chip, unsigned char reg, static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, - long wss_base, + long port, int irq, int dma1, int dma2, long mpu_port, int mpu_irq) { @@ -354,16 +366,23 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, switch (chip->hardware) { #ifndef OPTi93X case OPTi9XX_HW_82C924: + /* opti 929 mode (?), OPL3 clock output, audio enable */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(4), 0xf0, 0xfc); + /* enable wave audio */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(6), 0x02, 0x02); case OPTi9XX_HW_82C925: + /* enable WSS mode */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), 0x80, 0x80); + /* OPL3 FM synthesis */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(2), 0x00, 0x20); + /* disable Sound Blaster IRQ and DMA */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(3), 0xf0, 0xff); #ifdef CS4231 + /* cs4231/4248 fix enabled */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x02, 0x02); #else + /* cs4231/4248 fix disabled */ snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(5), 0x00, 0x02); #endif /* CS4231 */ break; @@ -411,21 +430,26 @@ static int __devinit snd_opti9xx_configure(struct snd_opti9xx *chip, return -EINVAL; } - switch (wss_base) { - case 0x530: + /* PnP resource says it decodes only 10 bits of address */ + switch (port & 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: - snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", wss_base); + snd_printk(KERN_WARNING "WSS port 0x%lx not valid\n", port); goto __skip_base; } snd_opti9xx_write_mask(chip, OPTi9XX_MC_REG(1), wss_base_bits << 4, 0x30); @@ -487,7 +511,7 @@ __skip_base: #endif /* CS4231 || OPTi93X */ #ifndef OPTi93X - outb(irq_bits << 3 | dma_bits, wss_base); + outb(irq_bits << 3 | dma_bits, chip->wss_base); #else /* OPTi93X */ snd_opti9xx_write(chip, OPTi9XX_MC_REG(3), (irq_bits << 3 | dma_bits)); #endif /* OPTi93X */ @@ -729,15 +753,15 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, { struct pnp_dev *pdev; int err; + struct pnp_dev *devmpu; +#ifndef OPTi93X + struct pnp_dev *devmc; +#endif - chip->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); - if (chip->dev == NULL) + pdev = pnp_request_card_device(card, pid->devs[0].id, NULL); + if (pdev == NULL) return -EBUSY; - chip->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); - - pdev = chip->dev; - err = pnp_activate_dev(pdev); if (err < 0) { snd_printk(KERN_ERR "AUDIO pnp configure failure: %d\n", err); @@ -750,9 +774,24 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, 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); + devmc = pnp_request_card_device(card, pid->devs[2].id, NULL); + if (devmc == NULL) + return -EBUSY; + + err = pnp_activate_dev(devmc); + if (err < 0) { + snd_printk(KERN_ERR "MC 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 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; #endif /* OPTi93X */ irq = pnp_irq(pdev, 0); dma1 = pnp_dma(pdev, 0); @@ -760,16 +799,16 @@ static int __devinit snd_card_opti9xx_pnp(struct snd_opti9xx *chip, dma2 = pnp_dma(pdev, 1); #endif /* CS4231 || OPTi93X */ - pdev = chip->devmpu; - if (pdev && mpu_port > 0) { - err = pnp_activate_dev(pdev); + devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); + + if (devmpu && mpu_port > 0) { + err = pnp_activate_dev(devmpu); if (err < 0) { - snd_printk(KERN_ERR "AUDIO pnp configure failure\n"); + snd_printk(KERN_ERR "MPU401 pnp configure failure\n"); mpu_port = -1; - chip->devmpu = NULL; } else { - mpu_port = pnp_port_start(pdev, 0); - mpu_irq = pnp_irq(pdev, 0); + mpu_port = pnp_port_start(devmpu, 0); + mpu_irq = pnp_irq(devmpu, 0); } } return pid->driver_data; @@ -824,7 +863,7 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) if (error) return error; - error = snd_wss_create(card, port + 4, -1, irq, dma1, xdma2, + error = snd_wss_create(card, chip->wss_base + 4, -1, irq, dma1, xdma2, #ifdef OPTi93X WSS_HW_OPTI93X, WSS_HWSHARE_IRQ, #else @@ -865,10 +904,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) 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, port + 4, irq, dma1, xdma2); + card->shortname, pcm->name, + chip->wss_base + 4, irq, dma1, xdma2); #else sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", - card->shortname, pcm->name, port + 4, irq, dma1); + card->shortname, pcm->name, chip->wss_base + 4, irq, dma1); #endif /* CS4231 || OPTi93X */ if (mpu_port <= 0 || mpu_port == SNDRV_AUTO_PORT) @@ -1062,9 +1102,6 @@ static int __devinit snd_opti9xx_pnp_probe(struct pnp_card_link *pcard, snd_card_free(card); return error; } - 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"); diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c index 8d21a3f..8ccbcdd 100644 --- a/sound/isa/sb/jazz16.c +++ b/sound/isa/sb/jazz16.c @@ -14,6 +14,7 @@ #include <linux/init.h> #include <linux/module.h> #include <linux/io.h> +#include <linux/delay.h> #include <asm/dma.h> #include <linux/isa.h> #include <sound/core.h> diff --git a/sound/oss/coproc.h b/sound/oss/coproc.h index 7306346..7bec21b 100644 --- a/sound/oss/coproc.h +++ b/sound/oss/coproc.h @@ -4,7 +4,7 @@ */ /* - * Coprocessor access types + * Coprocessor access types */ #define COPR_CUSTOM 0x0001 /* Custom applications */ #define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */ diff --git a/sound/oss/sequencer.c b/sound/oss/sequencer.c index c798746..e85789e 100644 --- a/sound/oss/sequencer.c +++ b/sound/oss/sequencer.c @@ -1631,8 +1631,6 @@ unsigned long compute_finetune(unsigned long base_freq, int bend, int range, } semitones = bend / 100; - if (semitones > 99) - semitones = 99; cents = bend % 100; amount = (int) (semitone_tuning[semitones] * multiplier * cent_tuning[cents]) / 10000; diff --git a/sound/oss/v_midi.h b/sound/oss/v_midi.h index 1b86cb4..08e2185 100644 --- a/sound/oss/v_midi.h +++ b/sound/oss/v_midi.h @@ -2,9 +2,9 @@ typedef struct vmidi_devc { int dev; /* State variables */ - int opened; + int opened; spinlock_t lock; - + /* MIDI fields */ int my_mididev; int pair_mididev; @@ -12,4 +12,3 @@ typedef struct vmidi_devc { int intr_active; void (*midi_input_intr) (int dev, unsigned char data); } vmidi_devc; - diff --git a/sound/oss/vidc.c b/sound/oss/vidc.c index 725fef0..a4127ba 100644 --- a/sound/oss/vidc.c +++ b/sound/oss/vidc.c @@ -363,13 +363,13 @@ static void vidc_audio_trigger(int dev, int enable_bits) struct audio_operations *adev = audio_devs[dev]; if (enable_bits & PCM_ENABLE_OUTPUT) { - if (!(adev->flags & DMA_ACTIVE)) { + if (!(adev->dmap_out->flags & DMA_ACTIVE)) { unsigned long flags; local_irq_save(flags); /* prevent recusion */ - adev->flags |= DMA_ACTIVE; + adev->dmap_out->flags |= DMA_ACTIVE; dma_interrupt = vidc_audio_dma_interrupt; vidc_sound_dma_irq(0, NULL); diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 1caf5e3..e68c98e 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c @@ -1852,12 +1852,14 @@ static unsigned int ad1981_jacks_blacklist[] = { 0x10140523, /* Thinkpad R40 */ 0x10140534, /* Thinkpad X31 */ 0x10140537, /* Thinkpad T41p */ + 0x1014053e, /* Thinkpad R40e */ 0x10140554, /* Thinkpad T42p/R50p */ 0x10140567, /* Thinkpad T43p 2668-G7U */ 0x10140581, /* Thinkpad X41-2527 */ 0x10280160, /* Dell Dimension 2400 */ 0x104380b0, /* Asus A7V8X-MX */ 0x11790241, /* Toshiba Satellite A-15 S127 */ + 0x1179ff10, /* Toshiba P500 */ 0x144dc01a, /* Samsung NP-X20C004/SEG */ 0 /* end */ }; diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 1ded64e..329968e 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c @@ -941,13 +941,21 @@ static snd_pcm_uframes_t snd_cmipci_pcm_pointer(struct cmipci *cm, struct cmipci struct snd_pcm_substream *substream) { size_t ptr; - unsigned int reg; + unsigned int reg, rem, tries; + if (!rec->running) return 0; #if 1 // this seems better.. reg = rec->ch ? CM_REG_CH1_FRAME2 : CM_REG_CH0_FRAME2; - ptr = rec->dma_size - (snd_cmipci_read_w(cm, reg) + 1); - ptr >>= rec->shift; + for (tries = 0; tries < 3; tries++) { + rem = snd_cmipci_read_w(cm, reg); + if (rem < rec->dma_size) + goto ok; + } + printk(KERN_ERR "cmipci: invalid PCM pointer: %#x\n", rem); + return SNDRV_PCM_POS_XRUN; +ok: + ptr = (rec->dma_size - (rem + 1)) >> rec->shift; #else reg = rec->ch ? CM_REG_CH1_FRAME1 : CM_REG_CH0_FRAME1; ptr = snd_cmipci_read(cm, reg) - rec->offset; diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index 556cff9..567348b 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig @@ -157,7 +157,7 @@ config SND_HDA_CODEC_INTELHDMI config SND_HDA_ELD def_bool y - depends on SND_HDA_CODEC_INTELHDMI + depends on SND_HDA_CODEC_INTELHDMI || SND_HDA_CODEC_NVHDMI config SND_HDA_CODEC_CIRRUS bool "Build Cirrus Logic codec support" diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 315a1c4..24bc195 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile @@ -3,7 +3,7 @@ snd-hda-intel-objs := hda_intel.o snd-hda-codec-y := hda_codec.o snd-hda-codec-$(CONFIG_SND_HDA_GENERIC) += hda_generic.o snd-hda-codec-$(CONFIG_PROC_FS) += hda_proc.o -# snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o +snd-hda-codec-$(CONFIG_SND_HDA_ELD) += hda_eld.o snd-hda-codec-$(CONFIG_SND_HDA_HWDEP) += hda_hwdep.o snd-hda-codec-$(CONFIG_SND_HDA_INPUT_BEEP) += hda_beep.o @@ -18,7 +18,7 @@ snd-hda-codec-ca0110-objs := patch_ca0110.o snd-hda-codec-conexant-objs := patch_conexant.o snd-hda-codec-via-objs := patch_via.o snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o -snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o hda_eld.o +snd-hda-codec-intelhdmi-objs := patch_intelhdmi.o # common driver obj-$(CONFIG_SND_HDA_INTEL) := snd-hda-codec.o diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 76d3c4c..0e76ac2 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c @@ -978,8 +978,9 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, * * Returns 0 if successful, or a negative error code. */ -int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr, - struct hda_codec **codecp) +int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, + unsigned int codec_addr, + struct hda_codec **codecp) { struct hda_codec *codec; char component[31]; @@ -1186,7 +1187,7 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); */ /* FIXME: more better hash key? */ -#define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) +#define HDA_HASH_KEY(nid, dir, idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) @@ -1356,7 +1357,8 @@ u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid) if (!codec->no_trigger_sense) { 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); + 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); @@ -1372,8 +1374,8 @@ EXPORT_SYMBOL_HDA(snd_hda_pin_sense); */ 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); + u32 sense = snd_hda_pin_sense(codec, nid); + return !!(sense & AC_PINSENSE_PRESENCE); } EXPORT_SYMBOL_HDA(snd_hda_jack_detect); @@ -1804,6 +1806,8 @@ int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, item->nid = nid; return 0; } + printk(KERN_ERR "hda-codec: no NID for mapping control %s:%d:%d\n", + kctl->id.name, kctl->id.index, index); return -EINVAL; } EXPORT_SYMBOL_HDA(snd_hda_add_nid); @@ -1952,7 +1956,7 @@ int snd_hda_add_vmaster(struct hda_codec *codec, char *name, err = snd_hda_ctl_add(codec, 0, kctl); if (err < 0) return err; - + for (s = slaves; *s; s++) { struct snd_kcontrol *sctl; int i = 0; @@ -2439,27 +2443,27 @@ static struct snd_kcontrol_new dig_mixes[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,CON_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, CON_MASK), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_cmask_get, }, { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,PRO_MASK), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PRO_MASK), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_pmask_get, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_default_get, .put = snd_hda_spdif_default_put, }, { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",PLAYBACK,SWITCH), + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, SWITCH), .info = snd_hda_spdif_out_switch_info, .get = snd_hda_spdif_out_switch_get, .put = snd_hda_spdif_out_switch_put, @@ -2610,7 +2614,7 @@ static int snd_hda_spdif_in_status_get(struct snd_kcontrol *kcontrol, static struct snd_kcontrol_new dig_in_ctls[] = { { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,SWITCH), + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, SWITCH), .info = snd_hda_spdif_in_switch_info, .get = snd_hda_spdif_in_switch_get, .put = snd_hda_spdif_in_switch_put, @@ -2618,7 +2622,7 @@ static struct snd_kcontrol_new dig_in_ctls[] = { { .access = SNDRV_CTL_ELEM_ACCESS_READ, .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = SNDRV_CTL_NAME_IEC958("",CAPTURE,DEFAULT), + .name = SNDRV_CTL_NAME_IEC958("", CAPTURE, DEFAULT), .info = snd_hda_spdif_mask_info, .get = snd_hda_spdif_in_status_get, }, @@ -2882,8 +2886,8 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { int err = snd_hda_codec_build_controls(codec); if (err < 0) { - printk(KERN_ERR "hda_codec: cannot build controls" - "for #%d (error %d)\n", codec->addr, err); + printk(KERN_ERR "hda_codec: cannot build controls " + "for #%d (error %d)\n", codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { printk(KERN_ERR @@ -2979,8 +2983,12 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, val |= channels - 1; switch (snd_pcm_format_width(format)) { - case 8: val |= 0x00; break; - case 16: val |= 0x10; break; + case 8: + val |= 0x00; + break; + case 16: + val |= 0x10; + break; case 20: case 24: case 32: @@ -3298,7 +3306,8 @@ 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", snd_hda_pcm_type_name[type]); + snd_printk(KERN_WARNING "Too many %s devices\n", + snd_hda_pcm_type_name[type]); return -EAGAIN; } @@ -3336,7 +3345,7 @@ int snd_hda_codec_build_pcms(struct hda_codec *codec) err = codec->patch_ops.build_pcms(codec); if (err < 0) { printk(KERN_ERR "hda_codec: cannot build PCMs" - "for #%d (error %d)\n", codec->addr, err); + "for #%d (error %d)\n", codec->addr, err); err = snd_hda_codec_reset(codec); if (err < 0) { printk(KERN_ERR @@ -3466,8 +3475,8 @@ EXPORT_SYMBOL_HDA(snd_hda_check_board_config); /** * snd_hda_check_board_codec_sid_config - compare the current codec - subsystem ID with the - config table + subsystem ID with the + config table This is important for Gateway notebooks with SB450 HDA Audio where the vendor ID of the PCI device is: @@ -3607,7 +3616,7 @@ void snd_hda_update_power_acct(struct hda_codec *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; @@ -3636,7 +3645,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up); * * 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; @@ -3662,7 +3671,7 @@ EXPORT_SYMBOL_HDA(snd_hda_power_down); * * 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) @@ -3830,7 +3839,7 @@ static void setup_dig_out_stream(struct hda_codec *codec, hda_nid_t nid, { /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) - set_dig_out_convert(codec, nid, + set_dig_out_convert(codec, nid, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff, -1); snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); @@ -4089,13 +4098,13 @@ static int is_in_nid_list(hda_nid_t nid, hda_nid_t *list) /* * Sort an associated group of pins according to their sequence numbers. */ -static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, +static void sort_pins_by_sequence(hda_nid_t *pins, short *sequences, int num_pins) { int i, j; short seq; hda_nid_t nid; - + for (i = 0; i < num_pins; i++) { for (j = i + 1; j < num_pins; j++) { if (sequences[i] > sequences[j]) { @@ -4123,7 +4132,7 @@ static void sort_pins_by_sequence(hda_nid_t * pins, short * sequences, * is detected, one of speaker of HP pins is assigned as the primary * output, i.e. to line_out_pins[0]. So, line_outs is always positive * if any analog output exists. - * + * * The analog input pins are assigned to input_pins array. * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, * respectively. @@ -4186,9 +4195,9 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, case AC_JACK_SPEAKER: seq = get_defcfg_sequence(def_conf); assoc = get_defcfg_association(def_conf); - if (! assoc) + if (!assoc) continue; - if (! assoc_speaker) + if (!assoc_speaker) assoc_speaker = assoc; else if (assoc_speaker != assoc) continue; @@ -4286,7 +4295,7 @@ int snd_hda_parse_pin_def_config(struct hda_codec *codec, cfg->speaker_outs); sort_pins_by_sequence(cfg->hp_pins, sequences_hp, cfg->hp_outs); - + /* if we have only one mic, make it AUTO_PIN_MIC */ if (!cfg->input_pins[AUTO_PIN_MIC] && cfg->input_pins[AUTO_PIN_FRONT_MIC]) { @@ -4436,7 +4445,7 @@ EXPORT_SYMBOL_HDA(snd_hda_resume); /** * 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. * diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c index 4228f2f..dcd2244 100644 --- a/sound/pci/hda/hda_eld.c +++ b/sound/pci/hda/hda_eld.c @@ -331,6 +331,7 @@ int snd_hdmi_get_eld_size(struct hda_codec *codec, hda_nid_t nid) return snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_HDMI_DIP_SIZE, AC_DIPSIZE_ELD_BUF); } +EXPORT_SYMBOL_HDA(snd_hdmi_get_eld_size); int snd_hdmi_get_eld(struct hdmi_eld *eld, struct hda_codec *codec, hda_nid_t nid) @@ -366,6 +367,7 @@ int snd_hdmi_get_eld(struct hdmi_eld *eld, kfree(buf); return ret; } +EXPORT_SYMBOL_HDA(snd_hdmi_get_eld); static void hdmi_show_short_audio_desc(struct cea_sad *a) { @@ -404,6 +406,7 @@ void snd_print_channel_allocation(int spk_alloc, char *buf, int buflen) } buf[j] = '\0'; /* necessary when j == 0 */ } +EXPORT_SYMBOL_HDA(snd_print_channel_allocation); void snd_hdmi_show_eld(struct hdmi_eld *e) { @@ -422,6 +425,7 @@ void snd_hdmi_show_eld(struct hdmi_eld *e) for (i = 0; i < e->sad_count; i++) hdmi_show_short_audio_desc(e->sad + i); } +EXPORT_SYMBOL_HDA(snd_hdmi_show_eld); #ifdef CONFIG_PROC_FS @@ -580,6 +584,7 @@ int snd_hda_eld_proc_new(struct hda_codec *codec, struct hdmi_eld *eld, return 0; } +EXPORT_SYMBOL_HDA(snd_hda_eld_proc_new); void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) { @@ -588,5 +593,6 @@ void snd_hda_eld_proc_free(struct hda_codec *codec, struct hdmi_eld *eld) eld->proc_entry = NULL; } } +EXPORT_SYMBOL_HDA(snd_hda_eld_proc_free); #endif /* CONFIG_PROC_FS */ diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index d5c93ad..4bb9067 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c @@ -267,7 +267,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; #define RIRB_INT_MASK 0x05 /* STATESTS int mask: S3,SD2,SD1,SD0 */ -#define AZX_MAX_CODECS 4 +#define AZX_MAX_CODECS 8 +#define AZX_DEFAULT_CODECS 4 #define STATESTS_INT_MASK ((1 << AZX_MAX_CODECS) - 1) /* SD_CTL bits */ @@ -1367,6 +1368,7 @@ static void azx_bus_reset(struct hda_bus *bus) /* number of codec slots for each chipset: 0 = default slots (i.e. 4) */ static unsigned int azx_max_codecs[AZX_NUM_DRIVERS] __devinitdata = { + [AZX_DRIVER_NVIDIA] = 8, [AZX_DRIVER_TERA] = 1, }; @@ -1399,7 +1401,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model) codecs = 0; max_slots = azx_max_codecs[chip->driver_type]; if (!max_slots) - max_slots = AZX_MAX_CODECS; + max_slots = AZX_DEFAULT_CODECS; /* First try to probe all given codec slots */ for (c = 0; c < max_slots; c++) { @@ -2263,10 +2265,14 @@ 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(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1458, 0xa022, "ga-ma770-ud3", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), + SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), + SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), {} }; @@ -2354,6 +2360,8 @@ static void __devinit check_probe_mask(struct azx *chip, int dev) static struct snd_pci_quirk msi_black_list[] __devinitdata = { SND_PCI_QUIRK(0x1043, 0x81f2, "ASUS", 0), /* Athlon64 X2 + nvidia */ SND_PCI_QUIRK(0x1043, 0x81f6, "ASUS", 0), /* nvidia */ + SND_PCI_QUIRK(0x1043, 0x822d, "ASUS", 0), /* Athlon64 X2 + nvidia MCP55 */ + SND_PCI_QUIRK(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */ {} }; @@ -2372,6 +2380,13 @@ static void __devinit check_msi(struct azx *chip) "hda_intel: msi for device %04x:%04x set to %d\n", q->subvendor, q->subdevice, q->value); chip->msi = q->value; + return; + } + + /* NVidia chipsets seem to cause troubles with MSI */ + if (chip->driver_type == AZX_DRIVER_NVIDIA) { + printk(KERN_INFO "hda_intel: Disable MSI for Nvidia chipset\n"); + chip->msi = 0; } } @@ -2700,6 +2715,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { { PCI_DEVICE(0x8086, 0x3a6e), .driver_data = AZX_DRIVER_ICH }, /* PCH */ { PCI_DEVICE(0x8086, 0x3b56), .driver_data = AZX_DRIVER_ICH }, + { PCI_DEVICE(0x8086, 0x3b57), .driver_data = AZX_DRIVER_ICH }, /* CPT */ { PCI_DEVICE(0x8086, 0x1c20), .driver_data = AZX_DRIVER_PCH }, /* SCH */ diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 194a28c..61682e1 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c @@ -1591,6 +1591,21 @@ static int patch_cxt5047(struct hda_codec *codec) #endif } spec->vmaster_nid = 0x13; + + switch (codec->subsystem_id >> 16) { + case 0x103c: + /* HP laptops have really bad sound over 0 dB on NID 0x10. + * Fix max PCM level to 0 dB (originally it has 0x1e steps + * with 0 dB offset 0x17) + */ + snd_hda_override_amp_caps(codec, 0x10, HDA_INPUT, + (0x17 << AC_AMPCAP_OFFSET_SHIFT) | + (0x17 << AC_AMPCAP_NUM_STEPS_SHIFT) | + (0x05 << AC_AMPCAP_STEP_SIZE_SHIFT) | + (1 << AC_AMPCAP_MUTE_SHIFT)); + break; + } + return 0; } diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c new file mode 100644 index 0000000..2c2bafb --- /dev/null +++ b/sound/pci/hda/patch_hdmi.c @@ -0,0 +1,849 @@ +/* + * + * patch_hdmi.c - routines for HDMI/DisplayPort codecs + * + * Copyright(c) 2008-2010 Intel Corporation. All rights reserved. + * + * Authors: + * Wu Fengguang <wfg@linux.intel.com> + * + * Maintained by: + * Wu Fengguang <wfg@linux.intel.com> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + +struct hdmi_spec { + int num_cvts; + int num_pins; + hda_nid_t cvt[MAX_HDMI_CVTS+1]; /* audio sources */ + hda_nid_t pin[MAX_HDMI_PINS+1]; /* audio sinks */ + + /* + * source connection for each pin + */ + hda_nid_t pin_cvt[MAX_HDMI_PINS+1]; + + /* + * HDMI sink attached to each pin + */ + struct hdmi_eld sink_eld[MAX_HDMI_PINS]; + + /* + * export one pcm per pipe + */ + struct hda_pcm pcm_rec[MAX_HDMI_CVTS]; + + /* + * nvhdmi specific + */ + struct hda_multi_out multiout; + unsigned int codec_type; +}; + + +struct hdmi_audio_infoframe { + u8 type; /* 0x84 */ + u8 ver; /* 0x01 */ + u8 len; /* 0x0a */ + + u8 checksum; /* PB0 */ + u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ + u8 SS01_SF24; + u8 CXT04; + u8 CA; + u8 LFEPBL01_LSV36_DM_INH7; + u8 reserved[5]; /* PB6 - PB10 */ +}; + +/* + * CEA speaker placement: + * + * FLH FCH FRH + * FLW FL FLC FC FRC FR FRW + * + * LFE + * TC + * + * RL RLC RC RRC RR + * + * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to + * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. + */ +enum cea_speaker_placement { + FL = (1 << 0), /* Front Left */ + FC = (1 << 1), /* Front Center */ + FR = (1 << 2), /* Front Right */ + FLC = (1 << 3), /* Front Left Center */ + FRC = (1 << 4), /* Front Right Center */ + RL = (1 << 5), /* Rear Left */ + RC = (1 << 6), /* Rear Center */ + RR = (1 << 7), /* Rear Right */ + RLC = (1 << 8), /* Rear Left Center */ + RRC = (1 << 9), /* Rear Right Center */ + LFE = (1 << 10), /* Low Frequency Effect */ + FLW = (1 << 11), /* Front Left Wide */ + FRW = (1 << 12), /* Front Right Wide */ + FLH = (1 << 13), /* Front Left High */ + FCH = (1 << 14), /* Front Center High */ + FRH = (1 << 15), /* Front Right High */ + TC = (1 << 16), /* Top Center */ +}; + +/* + * ELD SA bits in the CEA Speaker Allocation data block + */ +static int eld_speaker_allocation_bits[] = { + [0] = FL | FR, + [1] = LFE, + [2] = FC, + [3] = RL | RR, + [4] = RC, + [5] = FLC | FRC, + [6] = RLC | RRC, + /* the following are not defined in ELD yet */ + [7] = FLW | FRW, + [8] = FLH | FRH, + [9] = TC, + [10] = FCH, +}; + +struct cea_channel_speaker_allocation { + int ca_index; + int speakers[8]; + + /* derived values, just for convenience */ + int channels; + 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! + * + * The preceding ones have better chances to be selected by + * hdmi_setup_channel_allocation(). + */ +static struct cea_channel_speaker_allocation channel_allocations[] = { +/* 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 = 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 } }, +{ .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 } }, +{ .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 } }, +{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, +{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, +{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, +{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, +{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, +{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, +{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, +{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, +{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, +{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, +}; + + +/* + * HDMI routines + */ + +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; +} + +static void hdmi_get_show_eld(struct hda_codec *codec, hda_nid_t pin_nid, + struct hdmi_eld *eld) +{ + if (!snd_hdmi_get_eld(eld, codec, pin_nid)) + snd_hdmi_show_eld(eld); +} + +#ifdef BE_PARANOID +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, 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 pin_nid, + int packet_index, int byte_index) +{ + int val; + + val = (packet_index << 5) | (byte_index & 0x1f); + + 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 pin_nid, + unsigned char 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, hda_nid_t pin_nid) +{ + /* Unmute */ + if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); + /* Enable pin out */ + snd_hda_codec_write(codec, pin_nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); +} + +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); +} + +static void hdmi_set_channel_count(struct hda_codec *codec, + hda_nid_t nid, int chs) +{ + if (chs != hdmi_get_channel_count(codec, nid)) + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_CVT_CHAN_COUNT, chs - 1); +} + + +/* + * Channel mapping routines + */ + +/* + * Compute derived values in channel_allocations[]. + */ +static void init_channel_allocations(void) +{ + int i, j; + struct cea_channel_speaker_allocation *p; + + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + p = channel_allocations + i; + p->channels = 0; + p->spk_mask = 0; + for (j = 0; j < ARRAY_SIZE(p->speakers); j++) + if (p->speakers[j]) { + p->channels++; + p->spk_mask |= p->speakers[j]; + } + } +} + +/* + * The transformation takes two steps: + * + * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask + * spk_mask => (channel_allocations[]) => ai->CA + * + * TODO: it could select the wrong CA from multiple candidates. +*/ +static int hdmi_setup_channel_allocation(struct hda_codec *codec, hda_nid_t nid, + struct hdmi_audio_infoframe *ai) +{ + struct hdmi_spec *spec = codec->spec; + struct hdmi_eld *eld; + int i; + int spk_mask = 0; + int channels = 1 + (ai->CC02_CT47 & 0x7); + char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; + + /* + * CA defaults to 0 for basic stereo audio + */ + 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 + * configuration, to _not_ prohibit multi-channel audio playback. + */ + if (!eld->spk_alloc) + eld->spk_alloc = 0xffff; + + /* + * expand ELD's speaker allocation mask + * + * ELD tells the speaker mask in a compact(paired) form, + * expand ELD's notions to match the ones used by Audio InfoFrame. + */ + for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { + if (eld->spk_alloc & (1 << i)) + spk_mask |= eld_speaker_allocation_bits[i]; + } + + /* search for the first working match in the CA table */ + for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { + if (channels == channel_allocations[i].channels && + (spk_mask & channel_allocations[i].spk_mask) == + channel_allocations[i].spk_mask) { + ai->CA = channel_allocations[i].ca_index; + break; + } + } + + snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); + snd_printdd("HDMI: select CA 0x%x for %d-channel allocation: %s\n", + ai->CA, channels, buf); + + return ai->CA; +} + +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, pin_nid, 0, + AC_VERB_GET_HDMI_CHAN_SLOT, i); + printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", + slot >> 4, slot & 0xf); + } +#endif +} + + +static void hdmi_setup_channel_mapping(struct hda_codec *codec, + hda_nid_t pin_nid, + struct hdmi_audio_infoframe *ai) +{ + int i; + int ca = ai->CA; + int err; + + 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++) { + 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_NOTICE + "HDMI: channel mapping failed\n"); + break; + } + } + + hdmi_debug_channel_mapping(codec, pin_nid); +} + + +/* + * Audio InfoFrame routines + */ + +/* + * Enable Audio InfoFrame Transmission + */ +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, + AC_DIPXMIT_BEST); +} + +/* + * Disable Audio InfoFrame Transmission + */ +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 void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) +{ +#ifdef CONFIG_SND_DEBUG_VERBOSE + int i; + int size; + + size = snd_hdmi_get_eld_size(codec, pin_nid); + printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); + + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); + } +#endif +} + +static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) +{ +#ifdef BE_PARANOID + int i, j; + int size; + int pi, bi; + for (i = 0; i < 8; i++) { + size = snd_hda_codec_read(codec, pin_nid, 0, + AC_VERB_GET_HDMI_DIP_SIZE, i); + if (size == 0) + continue; + + hdmi_set_dip_index(codec, pin_nid, i, 0x0); + for (j = 1; j < 1000; j++) { + hdmi_write_dip_byte(codec, pin_nid, 0x0); + hdmi_get_dip_index(codec, pin_nid, &pi, &bi); + if (pi != i) + snd_printd(KERN_INFO "dip index %d: %d != %d\n", + bi, pi, i); + if (bi == 0) /* byte index wrapped around */ + break; + } + snd_printd(KERN_INFO + "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", + i, size, j); + } +#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 *bytes = (u8 *)ai; + int i; + + hdmi_debug_dip_size(codec, pin_nid); + hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ + + 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, bytes[i]); +} + +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) +{ + struct hdmi_spec *spec = codec->spec; + hda_nid_t pin_nid; + int i; + struct hdmi_audio_infoframe ai = { + .type = 0x84, + .ver = 0x01, + .len = 0x0a, + .CC02_CT47 = substream->runtime->channels - 1, + }; + + hdmi_setup_channel_allocation(codec, nid, &ai); + + for (i = 0; i < spec->num_pins; i++) { + if (spec->pin_cvt[i] != nid) + continue; + if (!spec->sink_eld[i].monitor_present) + continue; + + pin_nid = spec->pin[i]; + if (!hdmi_infoframe_uptodate(codec, pin_nid, &ai)) { + snd_printdd("hdmi_setup_audio_infoframe: " + "cvt=%d pin=%d channels=%d\n", + nid, pin_nid, + substream->runtime->channels); + 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); + } + } +} + + +/* + * Unsolicited events + */ + +static void hdmi_intrinsic_event(struct hda_codec *codec, unsigned int res) +{ + struct 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: 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_eld[index].monitor_present = pind; + spec->sink_eld[index].eld_valid = eldv; + + if (pind && eldv) { + hdmi_get_show_eld(codec, spec->pin[index], + &spec->sink_eld[index]); + /* TODO: do real things about ELD */ + } +} + +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 CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", + tag, + subtag, + cp_state, + cp_ready); + + /* TODO */ + if (cp_state) + ; + if (cp_ready) + ; +} + + +static void hdmi_unsol_event(struct hda_codec *codec, unsigned int res) +{ + struct 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 (hda_node_index(spec->pin, tag) < 0) { + snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); + return; + } + + if (subtag == 0) + hdmi_intrinsic_event(codec, res); + else + hdmi_non_intrinsic_event(codec, 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); +} + +/* + * HDA/HDMI auto parsing + */ + +static int hdmi_read_pin_conn(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct 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 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 hdmi_add_pin(struct hda_codec *codec, hda_nid_t pin_nid) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->num_pins >= MAX_HDMI_PINS) { + snd_printk(KERN_WARNING + "HDMI: no space for pin %d\n", 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++; + + /* + * It is assumed that converter nodes come first in the node list and + * hence have been registered and usable now. + */ + return hdmi_read_pin_conn(codec, pin_nid); +} + +static int hdmi_add_cvt(struct hda_codec *codec, hda_nid_t nid) +{ + struct hdmi_spec *spec = codec->spec; + + if (spec->num_cvts >= MAX_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 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 (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 | AC_PINCAP_DP))) + continue; + if (hdmi_add_pin(codec, nid) < 0) + return -EINVAL; + break; + } + } + + /* + * 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; +} + diff --git a/sound/pci/hda/patch_intelhdmi.c b/sound/pci/hda/patch_intelhdmi.c index 918f403..88d0351 100644 --- a/sound/pci/hda/patch_intelhdmi.c +++ b/sound/pci/hda/patch_intelhdmi.c @@ -40,815 +40,20 @@ * * The HDA correspondence of pipes/ports are converter/pin nodes. */ -#define INTEL_HDMI_CVTS 2 -#define INTEL_HDMI_PINS 3 +#define MAX_HDMI_CVTS 2 +#define MAX_HDMI_PINS 3 -static char *intel_hdmi_pcm_names[INTEL_HDMI_CVTS] = { +#include "patch_hdmi.c" + +static char *intel_hdmi_pcm_names[MAX_HDMI_CVTS] = { "INTEL HDMI 0", "INTEL HDMI 1", }; -struct intel_hdmi_spec { - 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 - */ - 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 { - u8 type; /* 0x84 */ - u8 ver; /* 0x01 */ - u8 len; /* 0x0a */ - - u8 checksum; /* PB0 */ - u8 CC02_CT47; /* CC in bits 0:2, CT in 4:7 */ - u8 SS01_SF24; - u8 CXT04; - u8 CA; - u8 LFEPBL01_LSV36_DM_INH7; - u8 reserved[5]; /* PB6 - PB10 */ -}; - -/* - * CEA speaker placement: - * - * FLH FCH FRH - * FLW FL FLC FC FRC FR FRW - * - * LFE - * TC - * - * RL RLC RC RRC RR - * - * The Left/Right Surround channel _notions_ LS/RS in SMPTE 320M corresponds to - * CEA RL/RR; The SMPTE channel _assignment_ C/LFE is swapped to CEA LFE/FC. - */ -enum cea_speaker_placement { - FL = (1 << 0), /* Front Left */ - FC = (1 << 1), /* Front Center */ - FR = (1 << 2), /* Front Right */ - FLC = (1 << 3), /* Front Left Center */ - FRC = (1 << 4), /* Front Right Center */ - RL = (1 << 5), /* Rear Left */ - RC = (1 << 6), /* Rear Center */ - RR = (1 << 7), /* Rear Right */ - RLC = (1 << 8), /* Rear Left Center */ - RRC = (1 << 9), /* Rear Right Center */ - LFE = (1 << 10), /* Low Frequency Effect */ - FLW = (1 << 11), /* Front Left Wide */ - FRW = (1 << 12), /* Front Right Wide */ - FLH = (1 << 13), /* Front Left High */ - FCH = (1 << 14), /* Front Center High */ - FRH = (1 << 15), /* Front Right High */ - TC = (1 << 16), /* Top Center */ -}; - -/* - * ELD SA bits in the CEA Speaker Allocation data block - */ -static int eld_speaker_allocation_bits[] = { - [0] = FL | FR, - [1] = LFE, - [2] = FC, - [3] = RL | RR, - [4] = RC, - [5] = FLC | FRC, - [6] = RLC | RRC, - /* the following are not defined in ELD yet */ - [7] = FLW | FRW, - [8] = FLH | FRH, - [9] = TC, - [10] = FCH, -}; - -struct cea_channel_speaker_allocation { - int ca_index; - int speakers[8]; - - /* derived values, just for convenience */ - int channels; - 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! - * - * The preceding ones have better chances to be selected by - * hdmi_setup_channel_allocation(). - */ -static struct cea_channel_speaker_allocation channel_allocations[] = { -/* 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 = 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 } }, -{ .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 } }, -{ .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 } }, -{ .ca_index = 0x17, .speakers = { FRC, FLC, 0, 0, FC, LFE, FR, FL } }, -{ .ca_index = 0x18, .speakers = { FRC, FLC, 0, RC, 0, 0, FR, FL } }, -{ .ca_index = 0x19, .speakers = { FRC, FLC, 0, RC, 0, LFE, FR, FL } }, -{ .ca_index = 0x1a, .speakers = { FRC, FLC, 0, RC, FC, 0, FR, FL } }, -{ .ca_index = 0x1b, .speakers = { FRC, FLC, 0, RC, FC, LFE, FR, FL } }, -{ .ca_index = 0x1c, .speakers = { FRC, FLC, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x1d, .speakers = { FRC, FLC, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x1e, .speakers = { FRC, FLC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x1f, .speakers = { FRC, FLC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x20, .speakers = { 0, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x21, .speakers = { 0, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x22, .speakers = { TC, 0, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x23, .speakers = { TC, 0, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x24, .speakers = { FRH, FLH, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x25, .speakers = { FRH, FLH, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x26, .speakers = { FRW, FLW, RR, RL, 0, 0, FR, FL } }, -{ .ca_index = 0x27, .speakers = { FRW, FLW, RR, RL, 0, LFE, FR, FL } }, -{ .ca_index = 0x28, .speakers = { TC, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x29, .speakers = { TC, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2a, .speakers = { FCH, RC, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2b, .speakers = { FCH, RC, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2c, .speakers = { TC, FCH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2d, .speakers = { TC, FCH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x2e, .speakers = { FRH, FLH, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x2f, .speakers = { FRH, FLH, RR, RL, FC, LFE, FR, FL } }, -{ .ca_index = 0x30, .speakers = { FRW, FLW, RR, RL, FC, 0, FR, FL } }, -{ .ca_index = 0x31, .speakers = { FRW, FLW, RR, RL, FC, LFE, FR, FL } }, -}; - -/* - * HDA/HDMI auto parsing - */ - -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; -} - -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 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; - - if (spec->num_pins >= INTEL_HDMI_PINS) { - snd_printk(KERN_WARNING - "HDMI: no space for pin %d \n", 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++; - - /* - * 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 | AC_PINCAP_DP))) - continue; - if (intel_hdmi_add_pin(codec, nid) < 0) - return -EINVAL; - break; - } - } - - /* - * 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; -} - -/* - * HDMI routines - */ - -#ifdef BE_PARANOID -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, 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 pin_nid, - int packet_index, int byte_index) -{ - int val; - - val = (packet_index << 5) | (byte_index & 0x1f); - - 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 pin_nid, - unsigned char 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, hda_nid_t pin_nid) -{ - /* Unmute */ - if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP) - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); - /* Enable pin out */ - snd_hda_codec_write(codec, pin_nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); -} - -/* - * Enable Audio InfoFrame Transmission - */ -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, - AC_DIPXMIT_BEST); -} - -/* - * Disable Audio InfoFrame Transmission - */ -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, hda_nid_t nid) -{ - 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, - hda_nid_t nid, int chs) -{ - if (chs != hdmi_get_channel_count(codec, nid)) - 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 pin_nid) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int slot; - - for (i = 0; i < 8; i++) { - slot = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_CHAN_SLOT, i); - printk(KERN_DEBUG "HDMI: ASP channel %d => slot %d\n", - slot >> 4, slot & 0xf); - } -#endif -} - - -/* - * Audio InfoFrame routines - */ - -static void hdmi_debug_dip_size(struct hda_codec *codec, hda_nid_t pin_nid) -{ -#ifdef CONFIG_SND_DEBUG_VERBOSE - int i; - int size; - - size = snd_hdmi_get_eld_size(codec, pin_nid); - printk(KERN_DEBUG "HDMI: ELD buf size is %d\n", size); - - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - printk(KERN_DEBUG "HDMI: DIP GP[%d] buf size is %d\n", i, size); - } -#endif -} - -static void hdmi_clear_dip_buffers(struct hda_codec *codec, hda_nid_t pin_nid) -{ -#ifdef BE_PARANOID - int i, j; - int size; - int pi, bi; - for (i = 0; i < 8; i++) { - size = snd_hda_codec_read(codec, pin_nid, 0, - AC_VERB_GET_HDMI_DIP_SIZE, i); - if (size == 0) - continue; - - hdmi_set_dip_index(codec, pin_nid, i, 0x0); - for (j = 1; j < 1000; j++) { - hdmi_write_dip_byte(codec, pin_nid, 0x0); - hdmi_get_dip_index(codec, pin_nid, &pi, &bi); - if (pi != i) - snd_printd(KERN_INFO "dip index %d: %d != %d\n", - bi, pi, i); - if (bi == 0) /* byte index wrapped around */ - break; - } - snd_printd(KERN_INFO - "HDMI: DIP GP[%d] buf reported size=%d, written=%d\n", - i, size, j); - } -#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 *bytes = (u8 *)ai; - int i; - - hdmi_debug_dip_size(codec, pin_nid); - hdmi_clear_dip_buffers(codec, pin_nid); /* be paranoid */ - - 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, bytes[i]); -} - -/* - * Compute derived values in channel_allocations[]. - */ -static void init_channel_allocations(void) -{ - int i, j; - struct cea_channel_speaker_allocation *p; - - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - p = channel_allocations + i; - p->channels = 0; - p->spk_mask = 0; - for (j = 0; j < ARRAY_SIZE(p->speakers); j++) - if (p->speakers[j]) { - p->channels++; - p->spk_mask |= p->speakers[j]; - } - } -} - -/* - * The transformation takes two steps: - * - * eld->spk_alloc => (eld_speaker_allocation_bits[]) => spk_mask - * spk_mask => (channel_allocations[]) => ai->CA - * - * TODO: it could select the wrong CA from multiple candidates. -*/ -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; - int i; - int spk_mask = 0; - int channels = 1 + (ai->CC02_CT47 & 0x7); - char buf[SND_PRINT_CHANNEL_ALLOCATION_ADVISED_BUFSIZE]; - - /* - * CA defaults to 0 for basic stereo audio - */ - 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 - * configuration, to _not_ prohibit multi-channel audio playback. - */ - if (!eld->spk_alloc) - eld->spk_alloc = 0xffff; - - /* - * expand ELD's speaker allocation mask - * - * ELD tells the speaker mask in a compact(paired) form, - * expand ELD's notions to match the ones used by Audio InfoFrame. - */ - for (i = 0; i < ARRAY_SIZE(eld_speaker_allocation_bits); i++) { - if (eld->spk_alloc & (1 << i)) - spk_mask |= eld_speaker_allocation_bits[i]; - } - - /* search for the first working match in the CA table */ - for (i = 0; i < ARRAY_SIZE(channel_allocations); i++) { - if (channels == channel_allocations[i].channels && - (spk_mask & channel_allocations[i].spk_mask) == - channel_allocations[i].spk_mask) { - ai->CA = channel_allocations[i].ca_index; - break; - } - } - - snd_print_channel_allocation(eld->spk_alloc, buf, sizeof(buf)); - snd_printdd(KERN_INFO - "HDMI: select CA 0x%x for %d-channel allocation: %s\n", - ai->CA, channels, buf); - - return ai->CA; -} - -static void hdmi_setup_channel_mapping(struct hda_codec *codec, - hda_nid_t pin_nid, - struct hdmi_audio_infoframe *ai) -{ - int i; - int ca = ai->CA; - int err; - - 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++) { - 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); -} - -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) -{ - struct intel_hdmi_spec *spec = codec->spec; - hda_nid_t pin_nid; - int i; - struct hdmi_audio_infoframe ai = { - .type = 0x84, - .ver = 0x01, - .len = 0x0a, - .CC02_CT47 = substream->runtime->channels - 1, - }; - - hdmi_setup_channel_allocation(codec, nid, &ai); - - for (i = 0; i < spec->num_pins; i++) { - if (spec->pin_cvt[i] != nid) - continue; - if (!spec->sink_eld[i].monitor_present) - continue; - - 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); - } - } -} - - /* - * Unsolicited events + * HDMI callbacks */ -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: 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_eld[index].monitor_present = pind; - spec->sink_eld[index].eld_valid = eldv; - - if (pind && eldv) { - hdmi_get_show_eld(codec, spec->pin[index], &spec->sink_eld[index]); - /* TODO: do real things about ELD */ - } -} - -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 CP event: PIN=%d SUBTAG=0x%x CP_STATE=%d CP_READY=%d\n", - tag, - subtag, - cp_state, - cp_ready); - - /* TODO */ - if (cp_state) - ; - if (cp_ready) - ; -} - - -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 (hda_node_index(spec->pin, tag) < 0) { - snd_printd(KERN_INFO "Unexpected HDMI event tag 0x%x\n", tag); - return; - } - - if (subtag == 0) - hdmi_intrinsic_event(codec, res); - else - hdmi_non_intrinsic_event(codec, 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, @@ -882,7 +87,7 @@ 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 hdmi_spec *spec = codec->spec; struct hda_pcm *info = spec->pcm_rec; int i; @@ -908,7 +113,7 @@ static int intel_hdmi_build_pcms(struct hda_codec *codec) static int intel_hdmi_build_controls(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int err; int i; @@ -923,7 +128,7 @@ static int intel_hdmi_build_controls(struct hda_codec *codec) static int intel_hdmi_init(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; for (i = 0; spec->pin[i]; i++) { @@ -937,7 +142,7 @@ static int intel_hdmi_init(struct hda_codec *codec) static void intel_hdmi_free(struct hda_codec *codec) { - struct intel_hdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; for (i = 0; i < spec->num_pins; i++) @@ -951,12 +156,12 @@ static struct hda_codec_ops intel_hdmi_patch_ops = { .free = intel_hdmi_free, .build_pcms = intel_hdmi_build_pcms, .build_controls = intel_hdmi_build_controls, - .unsol_event = intel_hdmi_unsol_event, + .unsol_event = hdmi_unsol_event, }; static int patch_intel_hdmi(struct hda_codec *codec) { - struct intel_hdmi_spec *spec; + struct hdmi_spec *spec; int i; spec = kzalloc(sizeof(*spec), GFP_KERNEL); @@ -964,7 +169,7 @@ static int patch_intel_hdmi(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; - if (intel_hdmi_parse_codec(codec) < 0) { + if (hdmi_parse_codec(codec) < 0) { codec->spec = NULL; kfree(spec); return -EINVAL; diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index 6afdab0..3c10c0b 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c @@ -29,13 +29,23 @@ #include "hda_codec.h" #include "hda_local.h" +#define MAX_HDMI_CVTS 1 +#define MAX_HDMI_PINS 1 + +#include "patch_hdmi.c" + +static char *nvhdmi_pcm_names[MAX_HDMI_CVTS] = { + "NVIDIA HDMI", +}; + /* define below to restrict the supported rates and formats */ /* #define LIMITED_RATE_FMT_SUPPORT */ -struct nvhdmi_spec { - struct hda_multi_out multiout; - - struct hda_pcm pcm_rec; +enum HDACodec { + HDA_CODEC_NVIDIA_MCP7X, + HDA_CODEC_NVIDIA_MCP89, + HDA_CODEC_NVIDIA_GT21X, + HDA_CODEC_INVALID }; #define Nv_VERB_SET_Channel_Allocation 0xF79 @@ -43,15 +53,18 @@ struct nvhdmi_spec { #define Nv_VERB_SET_Audio_Protection_On 0xF98 #define Nv_VERB_SET_Audio_Protection_Off 0xF99 -#define Nv_Master_Convert_nid 0x04 -#define Nv_Master_Pin_nid 0x05 +#define nvhdmi_master_con_nid_7x 0x04 +#define nvhdmi_master_pin_nid_7x 0x05 -static hda_nid_t nvhdmi_convert_nids[4] = { +#define nvhdmi_master_con_nid_89 0x04 +#define nvhdmi_master_pin_nid_89 0x05 + +static hda_nid_t nvhdmi_con_nids_7x[4] = { /*front, rear, clfe, rear_surr */ 0x6, 0x8, 0xa, 0xc, }; -static struct hda_verb nvhdmi_basic_init[] = { +static struct hda_verb nvhdmi_basic_init_7x[] = { /* set audio protect on */ { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, /* enable digital output on pin widget */ @@ -84,22 +97,60 @@ static struct hda_verb nvhdmi_basic_init[] = { */ static int nvhdmi_build_controls(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int err; + int i; - err = snd_hda_create_spdif_out_ctls(codec, spec->multiout.dig_out_nid); - if (err < 0) - return err; + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + for (i = 0; i < codec->num_pcms; i++) { + err = snd_hda_create_spdif_out_ctls(codec, + spec->cvt[i]); + if (err < 0) + return err; + } + } else { + err = snd_hda_create_spdif_out_ctls(codec, + spec->multiout.dig_out_nid); + if (err < 0) + return err; + } return 0; } static int nvhdmi_init(struct hda_codec *codec) { - snd_hda_sequence_write(codec, nvhdmi_basic_init); + struct hdmi_spec *spec = codec->spec; + int i; + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + 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]); + } + } else { + snd_hda_sequence_write(codec, nvhdmi_basic_init_7x); + } return 0; } +static void nvhdmi_free(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + int i; + + if ((spec->codec_type == HDA_CODEC_NVIDIA_MCP89) + || (spec->codec_type == HDA_CODEC_NVIDIA_GT21X)) { + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_free(codec, &spec->sink_eld[i]); + } + + kfree(spec); +} + /* * Digital out */ @@ -107,25 +158,25 @@ static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_open(codec, &spec->multiout); } -static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo, +static int nvhdmi_dig_playback_pcm_close_8ch_7x(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; int i; - snd_hda_codec_write(codec, Nv_Master_Convert_nid, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_CHANNEL_STREAMID, 0); for (i = 0; i < 4; i++) { /* set the stream id */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_CHANNEL_STREAMID, 0); /* set the stream format */ - snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, + snd_hda_codec_write(codec, nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_STREAM_FORMAT, 0); } @@ -136,10 +187,25 @@ static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_close(codec, &spec->multiout); } +static int nvhdmi_dig_playback_pcm_prepare_8ch_89(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, hinfo->nid, + substream->runtime->channels); + + hdmi_setup_audio_infoframe(codec, hinfo->nid, substream); + + hdmi_setup_stream(codec, hinfo->nid, stream_tag, format); + return 0; +} + static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, @@ -181,29 +247,29 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); /* set the stream format */ - snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, + snd_hda_codec_write(codec, nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_STREAM_FORMAT, format); /* turn on again (if needed) */ /* enable and set the channel status audio/data flag */ if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, - Nv_Master_Convert_nid, + nvhdmi_master_con_nid_7x, 0, AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); } @@ -220,19 +286,19 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); /* set the stream id */ snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | channel_id); /* set the stream format */ snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_STREAM_FORMAT, format); @@ -241,12 +307,12 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_1, codec->spdif_ctls & 0xff); snd_hda_codec_write(codec, - nvhdmi_convert_nids[i], + nvhdmi_con_nids_7x[i], 0, AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); } @@ -261,28 +327,47 @@ static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, return 0; } +static int nvhdmi_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, + struct hda_codec *codec, + struct snd_pcm_substream *substream) +{ + return 0; +} + static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, struct hda_codec *codec, unsigned int stream_tag, unsigned int format, struct snd_pcm_substream *substream) { - struct nvhdmi_spec *spec = codec->spec; + struct hdmi_spec *spec = codec->spec; return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, format, substream); } -static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = { +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_89 = { + .substreams = 1, + .channels_min = 2, + .rates = SUPPORTED_RATES, + .maxbps = SUPPORTED_MAXBPS, + .formats = SUPPORTED_FORMATS, + .ops = { + .prepare = nvhdmi_dig_playback_pcm_prepare_8ch_89, + .cleanup = nvhdmi_playback_pcm_cleanup, + }, +}; + +static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch_7x = { .substreams = 1, .channels_min = 2, .channels_max = 8, - .nid = Nv_Master_Convert_nid, + .nid = nvhdmi_master_con_nid_7x, .rates = SUPPORTED_RATES, .maxbps = SUPPORTED_MAXBPS, .formats = SUPPORTED_FORMATS, .ops = { .open = nvhdmi_dig_playback_pcm_open, - .close = nvhdmi_dig_playback_pcm_close_8ch, + .close = nvhdmi_dig_playback_pcm_close_8ch_7x, .prepare = nvhdmi_dig_playback_pcm_prepare_8ch }, }; @@ -291,7 +376,7 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { .substreams = 1, .channels_min = 2, .channels_max = 2, - .nid = Nv_Master_Convert_nid, + .nid = nvhdmi_master_con_nid_7x, .rates = SUPPORTED_RATES, .maxbps = SUPPORTED_MAXBPS, .formats = SUPPORTED_FORMATS, @@ -302,10 +387,36 @@ static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { }, }; -static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) +static int nvhdmi_build_pcms_8ch_89(struct hda_codec *codec) +{ + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; + int i; + + codec->num_pcms = spec->num_cvts; + 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 = nvhdmi_pcm_names[i]; + info->pcm_type = HDA_PCM_TYPE_HDMI; + info->stream[SNDRV_PCM_STREAM_PLAYBACK] + = nvhdmi_pcm_digital_playback_8ch_89; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->cvt[i]; + info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = chans; + } + + return 0; +} + +static int nvhdmi_build_pcms_8ch_7x(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; codec->num_pcms = 1; codec->pcm_info = info; @@ -313,15 +424,15 @@ static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) info->name = "NVIDIA HDMI"; info->pcm_type = HDA_PCM_TYPE_HDMI; info->stream[SNDRV_PCM_STREAM_PLAYBACK] - = nvhdmi_pcm_digital_playback_8ch; + = nvhdmi_pcm_digital_playback_8ch_7x; return 0; } static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) { - struct nvhdmi_spec *spec = codec->spec; - struct hda_pcm *info = &spec->pcm_rec; + struct hdmi_spec *spec = codec->spec; + struct hda_pcm *info = spec->pcm_rec; codec->num_pcms = 1; codec->pcm_info = info; @@ -334,14 +445,17 @@ static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) return 0; } -static void nvhdmi_free(struct hda_codec *codec) -{ - kfree(codec->spec); -} +static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = { + .build_controls = nvhdmi_build_controls, + .build_pcms = nvhdmi_build_pcms_8ch_89, + .init = nvhdmi_init, + .free = nvhdmi_free, + .unsol_event = hdmi_unsol_event, +}; -static struct hda_codec_ops nvhdmi_patch_ops_8ch = { +static struct hda_codec_ops nvhdmi_patch_ops_8ch_7x = { .build_controls = nvhdmi_build_controls, - .build_pcms = nvhdmi_build_pcms_8ch, + .build_pcms = nvhdmi_build_pcms_8ch_7x, .init = nvhdmi_init, .free = nvhdmi_free, }; @@ -353,9 +467,36 @@ static struct hda_codec_ops nvhdmi_patch_ops_2ch = { .free = nvhdmi_free, }; -static int patch_nvhdmi_8ch(struct hda_codec *codec) +static int patch_nvhdmi_8ch_89(struct hda_codec *codec) +{ + struct hdmi_spec *spec; + int i; + + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + spec->codec_type = HDA_CODEC_NVIDIA_MCP89; + + if (hdmi_parse_codec(codec) < 0) { + codec->spec = NULL; + kfree(spec); + return -EINVAL; + } + codec->patch_ops = nvhdmi_patch_ops_8ch_89; + + for (i = 0; i < spec->num_pins; i++) + snd_hda_eld_proc_new(codec, &spec->sink_eld[i], i); + + init_channel_allocations(); + + return 0; +} + +static int patch_nvhdmi_8ch_7x(struct hda_codec *codec) { - struct nvhdmi_spec *spec; + struct hdmi_spec *spec; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -365,16 +506,17 @@ static int patch_nvhdmi_8ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 8; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; + spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; - codec->patch_ops = nvhdmi_patch_ops_8ch; + codec->patch_ops = nvhdmi_patch_ops_8ch_7x; return 0; } static int patch_nvhdmi_2ch(struct hda_codec *codec) { - struct nvhdmi_spec *spec; + struct hdmi_spec *spec; spec = kzalloc(sizeof(*spec), GFP_KERNEL); if (spec == NULL) @@ -384,7 +526,8 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) spec->multiout.num_dacs = 0; /* no analog */ spec->multiout.max_channels = 2; - spec->multiout.dig_out_nid = Nv_Master_Convert_nid; + spec->multiout.dig_out_nid = nvhdmi_master_con_nid_7x; + spec->codec_type = HDA_CODEC_NVIDIA_MCP7X; codec->patch_ops = nvhdmi_patch_ops_2ch; @@ -395,11 +538,24 @@ static int patch_nvhdmi_2ch(struct hda_codec *codec) * patch entries */ 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 = 0x10de0002, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0003, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0005, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0006, .name = "MCP77/78 HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de0007, .name = "MCP79/7A HDMI", + .patch = patch_nvhdmi_8ch_7x }, + { .id = 0x10de000a, .name = "GT220 HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000b, .name = "GT21x HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000c, .name = "MCP89 HDMI", + .patch = patch_nvhdmi_8ch_89 }, + { .id = 0x10de000d, .name = "GT240 HDMI", + .patch = patch_nvhdmi_8ch_89 }, { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, {} /* terminator */ @@ -410,11 +566,15 @@ 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:10de000a"); +MODULE_ALIAS("snd-hda-codec-id:10de000b"); +MODULE_ALIAS("snd-hda-codec-id:10de000c"); +MODULE_ALIAS("snd-hda-codec-id:10de000d"); MODULE_ALIAS("snd-hda-codec-id:10de0067"); MODULE_ALIAS("snd-hda-codec-id:10de8001"); MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("Nvidia HDMI HD-audio codec"); +MODULE_DESCRIPTION("NVIDIA HDMI HD-audio codec"); static struct hda_codec_preset_list nvhdmi_list = { .preset = snd_hda_preset_nvhdmi, diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index e8cbe21..9a23444 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c @@ -411,6 +411,8 @@ static int alc_mux_enum_info(struct snd_kcontrol *kcontrol, unsigned int mux_idx = snd_ctl_get_ioffidx(kcontrol, &uinfo->id); if (mux_idx >= spec->num_mux_defs) mux_idx = 0; + if (!spec->input_mux[mux_idx].num_items && mux_idx > 0) + mux_idx = 0; return snd_hda_input_mux_info(&spec->input_mux[mux_idx], uinfo); } @@ -439,6 +441,8 @@ static int alc_mux_enum_put(struct snd_kcontrol *kcontrol, mux_idx = adc_idx >= spec->num_mux_defs ? 0 : adc_idx; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; type = get_wcaps_type(get_wcaps(codec, nid)); if (type == AC_WID_AUD_MIX) { @@ -2528,8 +2532,6 @@ static int alc_build_controls(struct hda_codec *codec) return err; } - alc_free_kctls(codec); /* no longer needed */ - /* assign Capture Source enums to NID */ kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); if (!kctl) @@ -2598,6 +2600,9 @@ static int alc_build_controls(struct hda_codec *codec) } } } + + alc_free_kctls(codec); /* no longer needed */ + return 0; } @@ -4915,7 +4920,7 @@ static void fixup_automic_adc(struct hda_codec *codec) static void fixup_single_adc(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; - hda_nid_t pin; + hda_nid_t pin = 0; int i; /* search for the input pin; there must be only one */ @@ -6473,7 +6478,7 @@ static struct alc_config_preset alc260_presets[] = { .num_dacs = ARRAY_SIZE(alc260_dac_nids), .dac_nids = alc260_dac_nids, .num_adc_nids = ARRAY_SIZE(alc260_dual_adc_nids), - .adc_nids = alc260_adc_nids, + .adc_nids = alc260_dual_adc_nids, .num_channel_mode = ARRAY_SIZE(alc260_modes), .channel_mode = alc260_modes, .input_mux = &alc260_capture_source, @@ -9191,6 +9196,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), + SND_PCI_QUIRK(0x1462, 0x4570, "MSI Wind Top AE2220", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), @@ -9200,6 +9206,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x1462, 0x7280, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7327, "MSI", ALC883_6ST_DIG), SND_PCI_QUIRK(0x1462, 0x7350, "MSI", ALC883_6ST_DIG), + SND_PCI_QUIRK(0x1462, 0x7437, "MSI NetOn AP1900", ALC883_TARGA_DIG), SND_PCI_QUIRK(0x1462, 0xa422, "MSI", ALC883_TARGA_2ch_DIG), SND_PCI_QUIRK(0x1462, 0xaa08, "MSI", ALC883_TARGA_2ch_DIG), @@ -9231,7 +9238,7 @@ static struct snd_pci_quirk alc882_cfg_tbl[] = { SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC889_INTEL), SND_PCI_QUIRK(0x8086, 0x0021, "Intel IbexPeak", ALC889A_INTEL), SND_PCI_QUIRK(0x8086, 0x3b56, "Intel IbexPeak", ALC889A_INTEL), - SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), + SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC882_6ST_DIG), {} }; @@ -10036,8 +10043,11 @@ static void alc882_auto_set_output_and_unmute(struct hda_codec *codec, alc_set_pin_output(codec, nid, pin_type); if (spec->multiout.dac_nids[dac_idx] == 0x25) idx = 4; - else + else { + if (spec->multiout.num_dacs >= dac_idx) + return; idx = spec->multiout.dac_nids[dac_idx] - 2; + } snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, idx); } @@ -10105,6 +10115,8 @@ static void alc882_auto_init_input_src(struct hda_codec *codec) continue; mux_idx = c >= spec->num_mux_defs ? 0 : c; imux = &spec->input_mux[mux_idx]; + if (!imux->num_items && mux_idx > 0) + imux = &spec->input_mux[0]; for (idx = 0; idx < conns; idx++) { /* if the current connection is the selected one, * unmute it as default - otherwise mute it @@ -13201,7 +13213,7 @@ static int patch_alc268(struct hda_codec *codec) if (board_config < 0 || board_config >= ALC268_MODEL_LAST) board_config = snd_hda_check_board_codec_sid_config(codec, - ALC882_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); + ALC268_MODEL_LAST, alc268_models, alc268_ssid_cfg_tbl); if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { printk(KERN_INFO "hda_codec: %s: BIOS auto-probing.\n", @@ -13561,6 +13573,8 @@ static void alc269_lifebook_unsol_event(struct hda_codec *codec, static void alc269_quanta_fl1_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; @@ -13656,6 +13670,8 @@ static void alc269_laptop_unsol_event(struct hda_codec *codec, static void alc269_laptop_dmic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -13666,6 +13682,8 @@ static void alc269_laptop_dmic_setup(struct hda_codec *codec) static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x12; @@ -13676,6 +13694,8 @@ static void alc269vb_laptop_dmic_setup(struct hda_codec *codec) static void alc269_laptop_amic_setup(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + spec->autocfg.hp_pins[0] = 0x15; + spec->autocfg.speaker_pins[0] = 0x14; spec->ext_mic.pin = 0x18; spec->ext_mic.mux_idx = 0; spec->int_mic.pin = 0x19; diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 8c416bb..c4be3fa 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c @@ -1730,6 +1730,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { "HP HDX", STAC_HP_HDX), /* HDX16 */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3620, "HP dv6", STAC_HP_DV5), + SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3061, + "HP dv6", STAC_HP_DV5), /* HP dv6-1110ax */ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x7010, "HP", STAC_HP_DV5), SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x0233, diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c index 7754db1..dbc4b89 100644 --- a/sound/pci/oxygen/xonar_wm87x6.c +++ b/sound/pci/oxygen/xonar_wm87x6.c @@ -68,7 +68,7 @@ static void wm8776_write(struct oxygen *chip, OXYGEN_SPI_CEN_LATCH_CLOCK_LO, (reg << 9) | value); if (reg < ARRAY_SIZE(data->wm8776_regs)) { - if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) + if (reg >= WM8776_HPLVOL && reg <= WM8776_DACMASTER) value &= ~WM8776_UPDATE; data->wm8776_regs[reg] = value; } diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 960a227..ad44626 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c @@ -1974,9 +1974,9 @@ snd_riptide_proc_read(struct snd_info_entry *entry, } snd_iprintf(buffer, "Paths:\n"); i = getpaths(cif, p); - while (i--) { - snd_iprintf(buffer, "%x->%x ", p[i - 1], p[i]); - i--; + while (i >= 2) { + i -= 2; + snd_iprintf(buffer, "%x->%x ", p[i], p[i + 1]); } snd_iprintf(buffer, "\n"); } diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index 3d72c1e..547b713 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c @@ -2479,7 +2479,7 @@ static int snd_hdspm_put_qs_wire(struct snd_kcontrol *kcontrol, on MADICARD - playback mixer matrix: [channelout+64] [output] [value] - input(thru) mixer matrix: [channelin] [output] [value] - (better do 2 kontrols for seperation ?) + (better do 2 kontrols for separation ?) */ #define HDSPM_MIXER(xname, xindex) \ diff --git a/sound/soc/codecs/ak4104.c b/sound/soc/codecs/ak4104.c index b9ef7e4..b68d99f 100644 --- a/sound/soc/codecs/ak4104.c +++ b/sound/soc/codecs/ak4104.c @@ -90,12 +90,10 @@ static int ak4104_spi_write(struct snd_soc_codec *codec, unsigned int reg, if (reg >= codec->reg_cache_size) return -EINVAL; - reg &= AK4104_REG_MASK; - reg |= AK4104_WRITE; - /* only write to the hardware if value has changed */ if (cache[reg] != value) { - u8 tmp[2] = { reg, value }; + u8 tmp[2] = { (reg & AK4104_REG_MASK) | AK4104_WRITE, value }; + if (spi_write(spi, tmp, sizeof(tmp))) { dev_err(&spi->dev, "SPI write failed\n"); return -EIO; diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c index f9f367d..d50f169 100644 --- a/sound/soc/codecs/tlv320dac33.c +++ b/sound/soc/codecs/tlv320dac33.c @@ -778,7 +778,7 @@ static int dac33_prepare_chip(struct snd_pcm_substream *substream) if (dac33->fifo_mode) { /* Generic for all FIFO modes */ /* 50-51 : ASRC Control registers */ - dac33_write(codec, DAC33_ASRC_CTRL_A, (1 << 4)); /* div=2 */ + dac33_write(codec, DAC33_ASRC_CTRL_A, DAC33_SRCLKDIV(1)); dac33_write(codec, DAC33_ASRC_CTRL_B, 1); /* ??? */ /* Write registers 0x34 and 0x35 (MSB, LSB) */ @@ -1038,11 +1038,7 @@ static int dac33_set_dai_fmt(struct snd_soc_dai *codec_dai, case SND_SOC_DAIFMT_DSP_A: aictrl_a |= DAC33_AFMT_DSP; aictrl_b &= ~DAC33_DATA_DELAY_MASK; - aictrl_b |= DAC33_DATA_DELAY(1); /* 1 bit delay */ - break; - case SND_SOC_DAIFMT_DSP_B: - aictrl_a |= DAC33_AFMT_DSP; - aictrl_b &= ~DAC33_DATA_DELAY_MASK; /* No delay */ + aictrl_b |= DAC33_DATA_DELAY(0); break; case SND_SOC_DAIFMT_RIGHT_J: aictrl_a |= DAC33_AFMT_RIGHT_J; @@ -1066,7 +1062,7 @@ static void dac33_init_chip(struct snd_soc_codec *codec) { /* 44-46: DAC Control Registers */ /* A : DAC sample rate Fsref/1.5 */ - dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(1)); + dac33_write(codec, DAC33_DAC_CTRL_A, DAC33_DACRATE(0)); /* B : DAC src=normal, not muted */ dac33_write(codec, DAC33_DAC_CTRL_B, DAC33_DACSRCR_RIGHT | DAC33_DACSRCL_LEFT); diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c index a2763c2..9cd0a66 100644 --- a/sound/soc/codecs/uda1380.c +++ b/sound/soc/codecs/uda1380.c @@ -137,7 +137,7 @@ static void uda1380_flush_work(struct work_struct *work) { int bit, reg; - for_each_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { + for_each_set_bit(bit, &uda1380_cache_dirty, UDA1380_CACHEREGNUM - 0x10) { reg = 0x10 + bit; pr_debug("uda1380: flush reg %x val %x:\n", reg, uda1380_read_reg_cache(uda1380_codec, reg)); diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c index 718ef91..df2c6d9 100644 --- a/sound/soc/codecs/wm8350.c +++ b/sound/soc/codecs/wm8350.c @@ -1349,7 +1349,7 @@ static irqreturn_t wm8350_hp_jack_handler(int irq, void *data) int mask; struct wm8350_jack_data *jack = NULL; - switch (irq) { + switch (irq - wm8350->irq_base) { case WM8350_IRQ_CODEC_JCK_DET_L: jack = &priv->hpl; mask = WM8350_JACK_L_LVL; @@ -1424,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(irq, priv); + wm8350_hp_jack_handler(irq + wm8350->irq_base, priv); return 0; } @@ -1521,8 +1521,8 @@ 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_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L); - wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_L, priv); + wm8350_free_irq(wm8350, WM8350_IRQ_CODEC_JCK_DET_R, priv); priv->hpl.jack = NULL; priv->hpr.jack = NULL; diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c index a54dc77..056b787 100644 --- a/sound/soc/codecs/wm8990.c +++ b/sound/soc/codecs/wm8990.c @@ -990,7 +990,7 @@ static int wm8990_set_dai_pll(struct snd_soc_dai *codec_dai, int pll_id, reg = snd_soc_read(codec, WM8990_CLOCKING_2); snd_soc_write(codec, WM8990_CLOCKING_2, reg | WM8990_SYSCLK_SRC); - /* set up N , fractional mode and pre-divisor if neccessary */ + /* set up N , fractional mode and pre-divisor if necessary */ snd_soc_write(codec, WM8990_PLL1, pll_div.n | WM8990_SDM | (pll_div.div2?WM8990_PRESCALE:0)); snd_soc_write(codec, WM8990_PLL2, (u8)(pll_div.k>>8)); diff --git a/sound/soc/codecs/wm_hubs.c b/sound/soc/codecs/wm_hubs.c index 0ad9f5d..486bdd2 100644 --- a/sound/soc/codecs/wm_hubs.c +++ b/sound/soc/codecs/wm_hubs.c @@ -74,7 +74,7 @@ static void wait_for_dc_servo(struct snd_soc_codec *codec) msleep(1); reg = snd_soc_read(codec, WM8993_DC_SERVO_READBACK_0); dev_dbg(codec->dev, "DC servo: %x\n", reg); - } while (reg & WM8993_DCS_DATAPATH_BUSY); + } while (reg & WM8993_DCS_DATAPATH_BUSY && count < 400); if (reg & WM8993_DCS_DATAPATH_BUSY) dev_err(codec->dev, "Timed out waiting for DC Servo\n"); diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index c7d0fd9..7174b4c 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig @@ -1,6 +1,6 @@ config SND_IMX_SOC tristate "SoC Audio for Freescale i.MX CPUs" - depends on ARCH_MXC && BROKEN + depends on ARCH_MXC select SND_PCM select FIQ select SND_SOC_AC97_BUS diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c index d297256..e814a95 100644 --- a/sound/soc/omap/omap-mcbsp.c +++ b/sound/soc/omap/omap-mcbsp.c @@ -39,6 +39,14 @@ #define OMAP_MCBSP_RATES (SNDRV_PCM_RATE_8000_96000) +#define OMAP_MCBSP_SOC_SINGLE_S16_EXT(xname, xmin, xmax, \ + xhandler_get, xhandler_put) \ +{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ + .info = omap_mcbsp_st_info_volsw, \ + .get = xhandler_get, .put = xhandler_put, \ + .private_value = (unsigned long) &(struct soc_mixer_control) \ + {.min = xmin, .max = xmax} } + struct omap_mcbsp_data { unsigned int bus_id; struct omap_mcbsp_reg_cfg regs; @@ -82,11 +90,11 @@ static const int omap1_dma_reqs[][2] = {}; static const unsigned long omap1_mcbsp_port[][2] = {}; #endif -#if defined(CONFIG_ARCH_OMAP24XX) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) static const int omap24xx_dma_reqs[][2] = { { OMAP24XX_DMA_MCBSP1_TX, OMAP24XX_DMA_MCBSP1_RX }, { OMAP24XX_DMA_MCBSP2_TX, OMAP24XX_DMA_MCBSP2_RX }, -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) { OMAP24XX_DMA_MCBSP3_TX, OMAP24XX_DMA_MCBSP3_RX }, { OMAP24XX_DMA_MCBSP4_TX, OMAP24XX_DMA_MCBSP4_RX }, { OMAP24XX_DMA_MCBSP5_TX, OMAP24XX_DMA_MCBSP5_RX }, @@ -124,7 +132,7 @@ static const unsigned long omap2430_mcbsp_port[][2] = { static const unsigned long omap2430_mcbsp_port[][2] = {}; #endif -#if defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP3) static const unsigned long omap34xx_mcbsp_port[][2] = { { OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DXR, OMAP34XX_MCBSP1_BASE + OMAP_MCBSP_REG_DRR }, @@ -639,6 +647,136 @@ struct snd_soc_dai omap_mcbsp_dai[] = { EXPORT_SYMBOL_GPL(omap_mcbsp_dai); +int omap_mcbsp_st_info_volsw(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int max = mc->max; + int min = mc->min; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->count = 1; + uinfo->value.integer.min = min; + uinfo->value.integer.max = max; + return 0; +} + +#define OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(id, channel) \ +static int \ +omap_mcbsp##id##_set_st_ch##channel##_volume(struct snd_kcontrol *kc, \ + struct snd_ctl_elem_value *uc) \ +{ \ + struct soc_mixer_control *mc = \ + (struct soc_mixer_control *)kc->private_value; \ + int max = mc->max; \ + int min = mc->min; \ + int val = uc->value.integer.value[0]; \ + \ + if (val < min || val > max) \ + return -EINVAL; \ + \ + /* OMAP McBSP implementation uses index values 0..4 */ \ + return omap_st_set_chgain((id)-1, channel, val); \ +} + +#define OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(id, channel) \ +static int \ +omap_mcbsp##id##_get_st_ch##channel##_volume(struct snd_kcontrol *kc, \ + struct snd_ctl_elem_value *uc) \ +{ \ + s16 chgain; \ + \ + if (omap_st_get_chgain((id)-1, channel, &chgain)) \ + return -EAGAIN; \ + \ + uc->value.integer.value[0] = chgain; \ + return 0; \ +} + +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 0) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(2, 1) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 0) +OMAP_MCBSP_ST_SET_CHANNEL_VOLUME(3, 1) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 0) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(2, 1) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 0) +OMAP_MCBSP_ST_GET_CHANNEL_VOLUME(3, 1) + +static int omap_mcbsp_st_put_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + u8 value = ucontrol->value.integer.value[0]; + + if (value == omap_st_is_enabled(mc->reg)) + return 0; + + if (value) + omap_st_enable(mc->reg); + else + omap_st_disable(mc->reg); + + return 1; +} + +static int omap_mcbsp_st_get_mode(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + ucontrol->value.integer.value[0] = omap_st_is_enabled(mc->reg); + return 0; +} + +static const struct snd_kcontrol_new omap_mcbsp2_st_controls[] = { + SOC_SINGLE_EXT("McBSP2 Sidetone Switch", 1, 0, 1, 0, + omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), + OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 0 Volume", + -32768, 32767, + omap_mcbsp2_get_st_ch0_volume, + omap_mcbsp2_set_st_ch0_volume), + OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP2 Sidetone Channel 1 Volume", + -32768, 32767, + omap_mcbsp2_get_st_ch1_volume, + omap_mcbsp2_set_st_ch1_volume), +}; + +static const struct snd_kcontrol_new omap_mcbsp3_st_controls[] = { + SOC_SINGLE_EXT("McBSP3 Sidetone Switch", 2, 0, 1, 0, + omap_mcbsp_st_get_mode, omap_mcbsp_st_put_mode), + OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 0 Volume", + -32768, 32767, + omap_mcbsp3_get_st_ch0_volume, + omap_mcbsp3_set_st_ch0_volume), + OMAP_MCBSP_SOC_SINGLE_S16_EXT("McBSP3 Sidetone Channel 1 Volume", + -32768, 32767, + omap_mcbsp3_get_st_ch1_volume, + omap_mcbsp3_set_st_ch1_volume), +}; + +int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id) +{ + if (!cpu_is_omap34xx()) + return -ENODEV; + + switch (mcbsp_id) { + case 1: /* McBSP 2 */ + return snd_soc_add_controls(codec, omap_mcbsp2_st_controls, + ARRAY_SIZE(omap_mcbsp2_st_controls)); + case 2: /* McBSP 3 */ + return snd_soc_add_controls(codec, omap_mcbsp3_st_controls, + ARRAY_SIZE(omap_mcbsp3_st_controls)); + default: + break; + } + + return -EINVAL; +} +EXPORT_SYMBOL_GPL(omap_mcbsp_st_add_controls); + static int __init snd_omap_mcbsp_init(void) { return snd_soc_register_dais(omap_mcbsp_dai, diff --git a/sound/soc/omap/omap-mcbsp.h b/sound/soc/omap/omap-mcbsp.h index 647d2f9..6c363e5 100644 --- a/sound/soc/omap/omap-mcbsp.h +++ b/sound/soc/omap/omap-mcbsp.h @@ -50,11 +50,13 @@ enum omap_mcbsp_div { #undef NUM_LINKS #define NUM_LINKS 3 #endif -#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP34XX) +#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3) #undef NUM_LINKS #define NUM_LINKS 5 #endif extern struct snd_soc_dai omap_mcbsp_dai[NUM_LINKS]; +int omap_mcbsp_st_add_controls(struct snd_soc_codec *codec, int mcbsp_id); + #endif diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c index e69397f..9e95e51 100644 --- a/sound/soc/pxa/pxa-ssp.c +++ b/sound/soc/pxa/pxa-ssp.c @@ -42,11 +42,14 @@ * SSP audio private data */ struct ssp_priv { - struct ssp_dev dev; + struct ssp_device *ssp; unsigned int sysclk; int dai_fmt; #ifdef CONFIG_PM - struct ssp_state state; + uint32_t cr0; + uint32_t cr1; + uint32_t to; + uint32_t psp; #endif }; @@ -61,6 +64,22 @@ static void dump_registers(struct ssp_device *ssp) ssp_read_reg(ssp, SSACD)); } +static void ssp_enable(struct ssp_device *ssp) +{ + uint32_t sscr0; + + sscr0 = __raw_readl(ssp->mmio_base + SSCR0) | SSCR0_SSE; + __raw_writel(sscr0, ssp->mmio_base + SSCR0); +} + +static void ssp_disable(struct ssp_device *ssp) +{ + uint32_t sscr0; + + sscr0 = __raw_readl(ssp->mmio_base + SSCR0) & ~SSCR0_SSE; + __raw_writel(sscr0, ssp->mmio_base + SSCR0); +} + struct pxa2xx_pcm_dma_data { struct pxa2xx_pcm_dma_params params; char name[20]; @@ -94,13 +113,12 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->ssp; int ret = 0; if (!cpu_dai->active) { - priv->dev.port = cpu_dai->id + 1; - priv->dev.irq = NO_IRQ; - clk_enable(priv->dev.ssp->clk); - ssp_disable(&priv->dev); + clk_enable(ssp->clk); + ssp_disable(ssp); } if (cpu_dai->dma_data) { @@ -116,10 +134,11 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->ssp; if (!cpu_dai->active) { - ssp_disable(&priv->dev); - clk_disable(priv->dev.ssp->clk); + ssp_disable(ssp); + clk_disable(ssp->clk); } if (cpu_dai->dma_data) { @@ -133,27 +152,39 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream, static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->ssp; if (!cpu_dai->active) - clk_enable(priv->dev.ssp->clk); + clk_enable(ssp->clk); - ssp_save_state(&priv->dev, &priv->state); - clk_disable(priv->dev.ssp->clk); + priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0); + priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1); + priv->to = __raw_readl(ssp->mmio_base + SSTO); + priv->psp = __raw_readl(ssp->mmio_base + SSPSP); + ssp_disable(ssp); + clk_disable(ssp->clk); return 0; } static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai) { struct ssp_priv *priv = cpu_dai->private_data; + struct ssp_device *ssp = priv->ssp; + uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE; + + clk_enable(ssp->clk); - clk_enable(priv->dev.ssp->clk); - ssp_restore_state(&priv->dev, &priv->state); + __raw_writel(sssr, ssp->mmio_base + SSSR); + __raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0); + __raw_writel(priv->cr1, ssp->mmio_base + SSCR1); + __raw_writel(priv->to, ssp->mmio_base + SSTO); + __raw_writel(priv->psp, ssp->mmio_base + SSPSP); if (cpu_dai->active) - ssp_enable(&priv->dev); + ssp_enable(ssp); else - clk_disable(priv->dev.ssp->clk); + clk_disable(ssp->clk); return 0; } @@ -203,7 +234,7 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; int val; u32 sscr0 = ssp_read_reg(ssp, SSCR0) & @@ -244,11 +275,11 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai, /* The SSP clock must be disabled when changing SSP clock mode * on PXA2xx. On PXA3xx it must be enabled when doing so. */ if (!cpu_is_pxa3xx()) - clk_disable(priv->dev.ssp->clk); + clk_disable(ssp->clk); val = ssp_read_reg(ssp, SSCR0) | sscr0; ssp_write_reg(ssp, SSCR0, val); if (!cpu_is_pxa3xx()) - clk_enable(priv->dev.ssp->clk); + clk_enable(ssp->clk); return 0; } @@ -260,7 +291,7 @@ static int pxa_ssp_set_dai_clkdiv(struct snd_soc_dai *cpu_dai, int div_id, int div) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; int val; switch (div_id) { @@ -311,7 +342,7 @@ static int pxa_ssp_set_dai_pll(struct snd_soc_dai *cpu_dai, int pll_id, int source, unsigned int freq_in, unsigned int freq_out) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; u32 ssacd = ssp_read_reg(ssp, SSACD) & ~0x70; #if defined(CONFIG_PXA3xx) @@ -380,7 +411,7 @@ static int pxa_ssp_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, unsigned int tx_mask, unsigned int rx_mask, int slots, int slot_width) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; u32 sscr0; sscr0 = ssp_read_reg(ssp, SSCR0); @@ -415,7 +446,7 @@ static int pxa_ssp_set_dai_tristate(struct snd_soc_dai *cpu_dai, int tristate) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; u32 sscr1; sscr1 = ssp_read_reg(ssp, SSCR1); @@ -437,7 +468,7 @@ static int pxa_ssp_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; u32 sscr0; u32 sscr1; u32 sspsp; @@ -532,7 +563,7 @@ static int pxa_ssp_hw_params(struct snd_pcm_substream *substream, struct snd_soc_pcm_runtime *rtd = substream->private_data; struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; int chn = params_channels(params); u32 sscr0; u32 sspsp; @@ -642,12 +673,12 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai; int ret = 0; struct ssp_priv *priv = cpu_dai->private_data; - struct ssp_device *ssp = priv->dev.ssp; + struct ssp_device *ssp = priv->ssp; int val; switch (cmd) { case SNDRV_PCM_TRIGGER_RESUME: - ssp_enable(&priv->dev); + ssp_enable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: val = ssp_read_reg(ssp, SSCR1); @@ -666,7 +697,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, else val |= SSCR1_RSRE; ssp_write_reg(ssp, SSCR1, val); - ssp_enable(&priv->dev); + ssp_enable(ssp); break; case SNDRV_PCM_TRIGGER_STOP: val = ssp_read_reg(ssp, SSCR1); @@ -677,7 +708,7 @@ static int pxa_ssp_trigger(struct snd_pcm_substream *substream, int cmd, ssp_write_reg(ssp, SSCR1, val); break; case SNDRV_PCM_TRIGGER_SUSPEND: - ssp_disable(&priv->dev); + ssp_disable(ssp); break; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: val = ssp_read_reg(ssp, SSCR1); @@ -707,8 +738,8 @@ static int pxa_ssp_probe(struct platform_device *pdev, if (!priv) return -ENOMEM; - priv->dev.ssp = ssp_request(dai->id + 1, "SoC audio"); - if (priv->dev.ssp == NULL) { + priv->ssp = ssp_request(dai->id + 1, "SoC audio"); + if (priv->ssp == NULL) { ret = -ENODEV; goto err_priv; } @@ -727,7 +758,7 @@ static void pxa_ssp_remove(struct platform_device *pdev, struct snd_soc_dai *dai) { struct ssp_priv *priv = dai->private_data; - ssp_free(priv->dev.ssp); + ssp_free(priv->ssp); } #define PXA_SSP_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\ diff --git a/sound/soc/s3c24xx/s3c64xx-i2s.c b/sound/soc/s3c24xx/s3c64xx-i2s.c index 93ed3aa..a72c251 100644 --- a/sound/soc/s3c24xx/s3c64xx-i2s.c +++ b/sound/soc/s3c24xx/s3c64xx-i2s.c @@ -22,8 +22,8 @@ #include <sound/soc.h> #include <plat/regs-s3c2412-iis.h> -#include <plat/gpio-bank-d.h> -#include <plat/gpio-bank-e.h> +#include <mach/gpio-bank-d.h> +#include <mach/gpio-bank-e.h> #include <plat/gpio-cfg.h> #include <mach/map.h> diff --git a/sound/soc/sh/Kconfig b/sound/soc/sh/Kconfig index 1066749..f07f6d8 100644 --- a/sound/soc/sh/Kconfig +++ b/sound/soc/sh/Kconfig @@ -32,6 +32,7 @@ config SND_SOC_SH4_SIU select DMA_ENGINE select DMADEVICES select SH_DMAE + select FW_LOADER ## ## Boards diff --git a/sound/soc/sh/siu.h b/sound/soc/sh/siu.h index 9cc04ab..c0bfab8 100644 --- a/sound/soc/sh/siu.h +++ b/sound/soc/sh/siu.h @@ -72,7 +72,7 @@ struct siu_firmware { #include <linux/interrupt.h> #include <linux/io.h> -#include <asm/dma-sh.h> +#include <asm/dmaengine.h> #include <sound/core.h> #include <sound/pcm.h> diff --git a/sound/soc/sh/siu_pcm.c b/sound/soc/sh/siu_pcm.c index c5efc30..ba7f8d0 100644 --- a/sound/soc/sh/siu_pcm.c +++ b/sound/soc/sh/siu_pcm.c @@ -32,7 +32,7 @@ #include <sound/pcm_params.h> #include <sound/soc-dai.h> -#include <asm/dma-sh.h> +#include <asm/dmaengine.h> #include <asm/siu.h> #include "siu.h" diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index a03bac9..c8b0556 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -427,24 +427,24 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) if (!runtime->hw.rates) { printk(KERN_ERR "asoc: %s <-> %s No matching rates\n", codec_dai->name, cpu_dai->name); - goto machine_err; + goto config_err; } if (!runtime->hw.formats) { printk(KERN_ERR "asoc: %s <-> %s No matching formats\n", codec_dai->name, cpu_dai->name); - goto machine_err; + goto config_err; } if (!runtime->hw.channels_min || !runtime->hw.channels_max) { printk(KERN_ERR "asoc: %s <-> %s No matching channels\n", codec_dai->name, cpu_dai->name); - goto machine_err; + goto config_err; } /* Symmetry only applies if we've already got an active stream. */ if (cpu_dai->active || codec_dai->active) { ret = soc_pcm_apply_symmetry(substream); if (ret != 0) - goto machine_err; + goto config_err; } pr_debug("asoc: %s <-> %s info:\n", codec_dai->name, cpu_dai->name); @@ -464,10 +464,14 @@ static int soc_pcm_open(struct snd_pcm_substream *substream) mutex_unlock(&pcm_mutex); return 0; -machine_err: +config_err: if (machine->ops && machine->ops->shutdown) machine->ops->shutdown(substream); +machine_err: + if (codec_dai->ops->shutdown) + codec_dai->ops->shutdown(substream, codec_dai); + codec_dai_err: if (platform->pcm_ops->close) platform->pcm_ops->close(substream); diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 8c29258..c570ae3 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig @@ -22,13 +22,13 @@ config SND_USB_AUDIO will be called snd-usb-audio. config SND_USB_UA101 - tristate "Edirol UA-101 driver (EXPERIMENTAL)" + tristate "Edirol UA-101/UA-1000 driver (EXPERIMENTAL)" depends on EXPERIMENTAL select SND_PCM select SND_RAWMIDI help - Say Y here to include support for the Edirol UA-101 audio/MIDI - interface. + Say Y here to include support for the Edirol UA-101 and UA-1000 + audio/MIDI interfaces. To compile this driver as a module, choose M here: the module will be called snd-ua101. diff --git a/sound/usb/caiaq/midi.h b/sound/usb/caiaq/midi.h index 9d16db0..380f984 100644 --- a/sound/usb/caiaq/midi.h +++ b/sound/usb/caiaq/midi.h @@ -3,6 +3,6 @@ int snd_usb_caiaq_midi_init(struct snd_usb_caiaqdev *dev); void snd_usb_caiaq_midi_handle_input(struct snd_usb_caiaqdev *dev, int port, const char *buf, int len); -void snd_usb_caiaq_midi_output_done(struct urb* urb); +void snd_usb_caiaq_midi_output_done(struct urb *urb); #endif /* CAIAQ_MIDI_H */ diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c index 4f4ccdf..3d458d3 100644 --- a/sound/usb/ua101.c +++ b/sound/usb/ua101.c @@ -1,5 +1,5 @@ /* - * Edirol UA-101 driver + * Edirol UA-101/UA-1000 driver * Copyright (c) Clemens Ladisch <clemens@ladisch.de> * * This driver is free software: you can redistribute it and/or modify @@ -25,13 +25,10 @@ #include <sound/pcm_params.h> #include "usbaudio.h" -MODULE_DESCRIPTION("Edirol UA-101 driver"); +MODULE_DESCRIPTION("Edirol UA-101/1000 driver"); MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); MODULE_LICENSE("GPL v2"); -MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}"); - -/* I use my UA-1A for testing because I don't have a UA-101 ... */ -#define UA1A_HACK +MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101},{Edirol,UA-1000}}"); /* * Should not be lower than the minimum scheduling delay of the host @@ -132,9 +129,6 @@ struct ua101 { dma_addr_t dma; } buffers[MAX_MEMORY_BUFFERS]; } capture, playback; - - unsigned int fps[10]; - unsigned int frame_counter; }; static DEFINE_MUTEX(devices_mutex); @@ -424,16 +418,6 @@ static void capture_urb_complete(struct urb *urb) if (do_period_elapsed) snd_pcm_period_elapsed(stream->substream); - /* for debugging: measure the sample rate relative to the USB clock */ - ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames; - if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) { - printk(KERN_DEBUG "capture rate:"); - for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames) - printk(KERN_CONT " %u", ua->fps[frames]); - printk(KERN_CONT "\n"); - memset(ua->fps, 0, sizeof(ua->fps)); - ua->frame_counter = 0; - } return; stream_stopped: @@ -1200,13 +1184,30 @@ static int ua101_probe(struct usb_interface *interface, .type = QUIRK_MIDI_FIXED_ENDPOINT, .data = &midi_ep }; + static const int intf_numbers[2][3] = { + { /* UA-101 */ + [INTF_PLAYBACK] = 0, + [INTF_CAPTURE] = 1, + [INTF_MIDI] = 2, + }, + { /* UA-1000 */ + [INTF_CAPTURE] = 1, + [INTF_PLAYBACK] = 2, + [INTF_MIDI] = 3, + }, + }; struct snd_card *card; struct ua101 *ua; unsigned int card_index, i; + int is_ua1000; + const char *name; char usb_path[32]; int err; - if (interface->altsetting->desc.bInterfaceNumber != 0) + is_ua1000 = usb_id->idProduct == 0x0044; + + if (interface->altsetting->desc.bInterfaceNumber != + intf_numbers[is_ua1000][0]) return -ENODEV; mutex_lock(&devices_mutex); @@ -1239,20 +1240,13 @@ static int ua101_probe(struct usb_interface *interface, init_waitqueue_head(&ua->rate_feedback_wait); init_waitqueue_head(&ua->alsa_playback_wait); -#ifdef UA1A_HACK - if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { - ua->intf[2] = interface; - ua->intf[0] = usb_ifnum_to_if(ua->dev, 1); - ua->intf[1] = usb_ifnum_to_if(ua->dev, 2); - usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua); - usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua); - } else { -#endif ua->intf[0] = interface; for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) { - ua->intf[i] = usb_ifnum_to_if(ua->dev, i); + ua->intf[i] = usb_ifnum_to_if(ua->dev, + intf_numbers[is_ua1000][i]); if (!ua->intf[i]) { - dev_err(&ua->dev->dev, "interface %u not found\n", i); + dev_err(&ua->dev->dev, "interface %u not found\n", + intf_numbers[is_ua1000][i]); err = -ENXIO; goto probe_error; } @@ -1264,39 +1258,19 @@ static int ua101_probe(struct usb_interface *interface, goto probe_error; } } -#ifdef UA1A_HACK - } -#endif snd_card_set_dev(card, &interface->dev); -#ifdef UA1A_HACK - if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { - ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE; - ua->rate = 44100; - ua->packets_per_second = 1000; - ua->capture.channels = 2; - ua->playback.channels = 2; - ua->capture.frame_bytes = 4; - ua->playback.frame_bytes = 4; - ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2); - ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1); - ua->capture.max_packet_bytes = 192; - ua->playback.max_packet_bytes = 192; - } else { -#endif err = detect_usb_format(ua); if (err < 0) goto probe_error; -#ifdef UA1A_HACK - } -#endif + name = usb_id->idProduct == 0x0044 ? "UA-1000" : "UA-101"; strcpy(card->driver, "UA-101"); - strcpy(card->shortname, "UA-101"); + strcpy(card->shortname, name); usb_make_path(ua->dev, usb_path, sizeof(usb_path)); snprintf(ua->card->longname, sizeof(ua->card->longname), - "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed", + "EDIROL %s (serial %s), %u Hz at %s, %s speed", name, ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path, ua->dev->speed == USB_SPEED_HIGH ? "high" : "full"); @@ -1314,24 +1288,18 @@ static int ua101_probe(struct usb_interface *interface, if (err < 0) goto probe_error; - err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm); + err = snd_pcm_new(card, name, 0, 1, 1, &ua->pcm); if (err < 0) goto probe_error; ua->pcm->private_data = ua; - strcpy(ua->pcm->name, "UA-101"); + strcpy(ua->pcm->name, name); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); -#ifdef UA1A_HACK - if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) { -#endif err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], &ua->midi_list, &midi_quirk); if (err < 0) goto probe_error; -#ifdef UA1A_HACK - } -#endif err = snd_card_register(card); if (err < 0) @@ -1386,11 +1354,9 @@ static void ua101_disconnect(struct usb_interface *interface) } static struct usb_device_id ua101_ids[] = { -#ifdef UA1A_HACK - { USB_DEVICE(0x0582, 0x0018) }, -#endif - { USB_DEVICE(0x0582, 0x007d) }, - { USB_DEVICE(0x0582, 0x008d) }, + { USB_DEVICE(0x0582, 0x0044) }, /* UA-1000 high speed */ + { USB_DEVICE(0x0582, 0x007d) }, /* UA-101 high speed */ + { USB_DEVICE(0x0582, 0x008d) }, /* UA-101 full speed */ { } }; MODULE_DEVICE_TABLE(usb, ua101_ids); diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index c539f7f..11b0826 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c @@ -2483,7 +2483,6 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, sample_width, sample_bytes); } /* check the format byte size */ - printk(" XXXXX SAMPLE BYTES %d\n", sample_bytes); switch (sample_bytes) { case 1: pcm_format = SNDRV_PCM_FORMAT_S8; @@ -2581,6 +2580,9 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof chip->usb_id == USB_ID(0x0d8c, 0x0102)) && fp->altsetting == 5 && fp->maxpacksize == 392) rate = 96000; + /* Creative VF0470 Live Cam reports 16 kHz instead of 8kHz */ + if (rate == 16000 && chip->usb_id == USB_ID(0x041e, 0x4068)) + rate = 8000; fp->rate_table[fp->nr_rates] = rate; if (!fp->rate_min || rate < fp->rate_min) fp->rate_min = rate; @@ -3386,58 +3388,6 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, return 0; } -/* - * Create a stream for an Edirol UA-1000 interface. - */ -static int create_ua1000_quirk(struct snd_usb_audio *chip, - struct usb_interface *iface, - const struct snd_usb_audio_quirk *quirk) -{ - static const struct audioformat ua1000_format = { - .format = SNDRV_PCM_FORMAT_S32_LE, - .fmt_type = UAC_FORMAT_TYPE_I, - .altsetting = 1, - .altset_idx = 1, - .attributes = 0, - .rates = SNDRV_PCM_RATE_CONTINUOUS, - }; - struct usb_host_interface *alts; - struct usb_interface_descriptor *altsd; - struct audioformat *fp; - int stream, err; - - if (iface->num_altsetting != 2) - return -ENXIO; - alts = &iface->altsetting[1]; - altsd = get_iface_desc(alts); - if (alts->extralen != 11 || alts->extra[1] != USB_DT_CS_INTERFACE || - altsd->bNumEndpoints != 1) - return -ENXIO; - - fp = kmemdup(&ua1000_format, sizeof(*fp), GFP_KERNEL); - if (!fp) - return -ENOMEM; - - fp->channels = alts->extra[4]; - fp->iface = altsd->bInterfaceNumber; - fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; - fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; - fp->datainterval = parse_datainterval(chip, alts); - fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); - fp->rate_max = fp->rate_min = combine_triple(&alts->extra[8]); - - stream = (fp->endpoint & USB_DIR_IN) - ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; - err = add_audio_endpoint(chip, stream, fp); - if (err < 0) { - kfree(fp); - return err; - } - /* FIXME: playback must be synchronized to capture */ - usb_set_interface(chip->dev, fp->iface, 0); - return 0; -} - static int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, const struct snd_usb_audio_quirk *quirk); @@ -3686,7 +3636,6 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, [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, [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk }; diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 6b016d4..42c299c 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h @@ -75,7 +75,6 @@ enum quirk_type { QUIRK_MIDI_US122L, QUIRK_AUDIO_STANDARD_INTERFACE, QUIRK_AUDIO_FIXED_ENDPOINT, - QUIRK_AUDIO_EDIROL_UA1000, QUIRK_AUDIO_EDIROL_UAXX, QUIRK_AUDIO_ALIGN_TRANSFER, @@ -112,7 +111,7 @@ struct snd_usb_midi_endpoint_info { /* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */ -/* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */ +/* for QUIRK_AUDIO_EDIROL_UAXX, data is NULL */ /* for QUIRK_IGNORE_INTERFACE, data is NULL */ diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index f06faf7..2b426c1 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h @@ -1016,36 +1016,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, { - USB_DEVICE(0x0582, 0x0044), - .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { - .vendor_name = "Roland", - .product_name = "UA-1000", - .ifnum = QUIRK_ANY_INTERFACE, - .type = QUIRK_COMPOSITE, - .data = (const struct snd_usb_audio_quirk[]) { - { - .ifnum = 1, - .type = QUIRK_AUDIO_EDIROL_UA1000 - }, - { - .ifnum = 2, - .type = QUIRK_AUDIO_EDIROL_UA1000 - }, - { - .ifnum = 3, - .type = QUIRK_MIDI_FIXED_ENDPOINT, - .data = & (const struct snd_usb_midi_endpoint_info) { - .out_cables = 0x0003, - .in_cables = 0x0003 - } - }, - { - .ifnum = -1 - } - } - } -}, -{ /* has ID 0x0049 when not in "Advanced Driver" mode */ USB_DEVICE(0x0582, 0x0047), .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |