forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6: (26 commits) ALSA: hdmi - show debug message on changing audio infoframe ALSA: hdmi - merge common code for intelhdmi and nvhdmi ALSA: hda - Add ASRock mobo to MSI blacklist ALSA: hda: uninitialized variable fix ALSA: hda: Use LPIB for a Biostar Microtech board ALSA: usb/audio.h: Fix field order ALSA: fix jazz16 compile (udelay) ALSA: hda: Use LPIB for Dell Latitude 131L ALSA: hda - Build hda_eld into snd-hda-codec module ALSA: hda - Support NVIDIA MCP89 and GT21x hdmi audio ALSA: hda - Support max codecs to 8 for nvidia hda controller ALSA: riptide: clean up while loop ALSA: usbaudio - remove debug "SAMPLE BYTES" printk line ALSA: timer - pass real event in snd_timer_notify1() to instance callback ALSA: oxygen: change || to && ALSA: opti92x: use PnP data to select Master Control port ASoC: fix ak4104 register array access ASoC: soc_pcm_open: Add missing bailout tag ALSA: usbaudio: Fix wrong bitrate for Creative Creative VF0470 Live Cam ALSA: ua101: removing debugging code ...
This commit is contained in:
commit
56b78921c3
@ -1812,7 +1812,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed.
|
||||
Module snd-ua101
|
||||
----------------
|
||||
|
||||
Module for the Edirol UA-101 audio/MIDI interface.
|
||||
Module for the Edirol UA-101/UA-1000 audio/MIDI interfaces.
|
||||
|
||||
This module supports multiple devices, autoprobe and hotplugging.
|
||||
|
||||
|
@ -269,8 +269,8 @@ struct uac_format_type_i_ext_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u8 bSubslotSize;
|
||||
__u8 bFormatType;
|
||||
__u8 bSubslotSize;
|
||||
__u8 bBitResolution;
|
||||
__u8 bHeaderLength;
|
||||
__u8 bControlSize;
|
||||
|
@ -544,7 +544,7 @@ struct snd_rawmidi_status {
|
||||
* Timer section - /dev/snd/timer
|
||||
*/
|
||||
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 5)
|
||||
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 6)
|
||||
|
||||
enum {
|
||||
SNDRV_TIMER_CLASS_NONE = -1,
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,34 @@ 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;
|
||||
#endif /* CONFIG_PNP */
|
||||
else {
|
||||
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 +303,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 +352,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 +365,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 +429,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 +510,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 +752,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 +773,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 +798,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 +862,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 +903,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 +1101,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");
|
||||
|
@ -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>
|
||||
|
@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* Coprocessor access types
|
||||
* Coprocessor access types
|
||||
*/
|
||||
#define COPR_CUSTOM 0x0001 /* Custom applications */
|
||||
#define COPR_MIDI 0x0002 /* MIDI (MPU-401) emulation */
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
||||
@ -1952,7 +1954,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 +2441,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 +2612,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 +2620,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,
|
||||
},
|
||||
@ -2883,7 +2885,7 @@ int /*__devinit*/ snd_hda_build_controls(struct hda_bus *bus)
|
||||
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);
|
||||
"for #%d (error %d)\n", codec->addr, err);
|
||||
err = snd_hda_codec_reset(codec);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR
|
||||
@ -2979,8 +2981,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 +3304,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 +3343,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 +3473,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 +3614,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 +3643,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 +3669,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 +3837,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 +4096,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 +4130,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 +4193,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 +4293,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 +4443,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.
|
||||
*
|
||||
|
@ -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 */
|
||||
|
@ -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,12 @@ 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(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
|
||||
SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
|
||||
{}
|
||||
};
|
||||
|
||||
@ -2354,6 +2358,7 @@ 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(0x1849, 0x0888, "ASRock", 0), /* Athlon64 X2 + nvidia */
|
||||
{}
|
||||
};
|
||||
|
||||
|
849
sound/pci/hda/patch_hdmi.c
Normal file
849
sound/pci/hda/patch_hdmi.c
Normal file
@ -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;
|
||||
}
|
||||
|
@ -40,814 +40,19 @@
|
||||
*
|
||||
* 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.
|
||||
* HDMI callbacks
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
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,
|
||||
@ -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;
|
||||
|
@ -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 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;
|
||||
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 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 = {
|
||||
static struct hda_codec_ops nvhdmi_patch_ops_8ch_89 = {
|
||||
.build_controls = nvhdmi_build_controls,
|
||||
.build_pcms = nvhdmi_build_pcms_8ch,
|
||||
.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_7x = {
|
||||
.build_controls = nvhdmi_build_controls,
|
||||
.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 nvhdmi_spec *spec;
|
||||
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 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,13 +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 = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{ .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch },
|
||||
{ .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 = 0x10de000c, .name = "MCP89 HDMI",
|
||||
.patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000b, .name = "GT21x HDMI",
|
||||
.patch = patch_nvhdmi_8ch_89 },
|
||||
{ .id = 0x10de000d, .name = "GT240 HDMI",
|
||||
.patch = patch_nvhdmi_8ch_89 },
|
||||
{} /* terminator */
|
||||
};
|
||||
|
||||
@ -412,9 +566,12 @@ MODULE_ALIAS("snd-hda-codec-id:10de0006");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0007");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de0067");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de8001");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000c");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000b");
|
||||
MODULE_ALIAS("snd-hda-codec-id:10de000d");
|
||||
|
||||
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,
|
||||
|
@ -4915,7 +4915,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 */
|
||||
@ -13561,6 +13561,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 +13658,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 +13670,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 +13682,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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -1015,36 +1015,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),
|
||||
|
Loading…
Reference in New Issue
Block a user