1
0
Fork 0

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
  ...
wifi-calibration
Linus Torvalds 2010-03-08 07:34:26 -08:00
commit 56b78921c3
28 changed files with 1285 additions and 1126 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
@ -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)
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");

View File

@ -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>

View File

@ -12,4 +12,3 @@ typedef struct vmidi_devc {
int intr_active;
void (*midi_input_intr) (int dev, unsigned char data);
} vmidi_devc;

View File

@ -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"

View File

@ -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

View File

@ -978,7 +978,8 @@ 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,
int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus,
unsigned int codec_addr,
struct hda_codec **codecp)
{
struct hda_codec *codec;
@ -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);
@ -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,
},
@ -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;
}
@ -4089,7 +4096,7 @@ 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;
@ -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;

View File

@ -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 */

View File

@ -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 */
{}
};

View 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;
}

View File

@ -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;

View File

@ -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 ((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,

View File

@ -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;

View File

@ -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;
}

View File

@ -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");
}

View File

@ -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;

View File

@ -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);

View File

@ -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.

View File

@ -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 */

View File

@ -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);

View File

@ -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
};

View File

@ -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 */

View File

@ -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),