From b0b0c2c41b20b318923fe995668905debbdb09dc Mon Sep 17 00:00:00 2001 From: Ricardo Neri Date: Fri, 18 May 2012 01:42:33 -0500 Subject: [PATCH] --- yaml --- r: 305808 b: refs/heads/master c: 5452030c564686a3dafd355da5456fbeca1de111 h: refs/heads/master v: v3 --- [refs] | 2 +- .../sound/alsa/ALSA-Configuration.txt | 2 +- trunk/include/sound/asound.h | 14 - trunk/include/sound/asoundef.h | 41 - trunk/sound/atmel/ac97c.c | 2 - trunk/sound/core/jack.c | 5 +- trunk/sound/core/pcm_lib.c | 18 +- trunk/sound/core/pcm_native.c | 12 +- trunk/sound/core/sound_oss.c | 6 +- trunk/sound/drivers/aloop.c | 62 +- trunk/sound/firewire/amdtp.c | 49 +- trunk/sound/firewire/amdtp.h | 29 +- trunk/sound/pci/Kconfig | 2 +- trunk/sound/pci/ad1889.c | 15 +- trunk/sound/pci/ali5451/ali5451.c | 15 +- trunk/sound/pci/als300.c | 15 +- trunk/sound/pci/als4000.c | 15 +- trunk/sound/pci/atiixp.c | 16 +- trunk/sound/pci/atiixp_modem.c | 16 +- trunk/sound/pci/au88x0/au88x0.c | 17 +- trunk/sound/pci/aw2/aw2-alsa.c | 23 +- trunk/sound/pci/azt3328.c | 23 +- trunk/sound/pci/bt87x.c | 19 +- trunk/sound/pci/ca0106/ca0106_main.c | 17 +- trunk/sound/pci/cmipci.c | 15 +- trunk/sound/pci/cs4281.c | 15 +- trunk/sound/pci/cs46xx/cs46xx.c | 15 +- trunk/sound/pci/cs5530.c | 16 +- trunk/sound/pci/cs5535audio/cs5535audio.c | 15 +- trunk/sound/pci/ctxfi/xfi.c | 13 +- trunk/sound/pci/echoaudio/echoaudio.c | 22 +- trunk/sound/pci/emu10k1/emu10k1.c | 15 +- trunk/sound/pci/emu10k1/emu10k1x.c | 17 +- trunk/sound/pci/ens1370.c | 15 +- trunk/sound/pci/es1938.c | 15 +- trunk/sound/pci/es1968.c | 15 +- trunk/sound/pci/fm801.c | 15 +- trunk/sound/pci/hda/Makefile | 2 +- trunk/sound/pci/hda/hda_auto_parser.c | 760 -------- trunk/sound/pci/hda/hda_auto_parser.h | 160 -- trunk/sound/pci/hda/hda_codec.c | 1027 ++++++++--- trunk/sound/pci/hda/hda_codec.h | 15 +- trunk/sound/pci/hda/hda_intel.c | 57 +- trunk/sound/pci/hda/hda_jack.c | 1 - trunk/sound/pci/hda/hda_jack.h | 2 - trunk/sound/pci/hda/hda_local.h | 122 +- trunk/sound/pci/hda/patch_analog.c | 14 +- trunk/sound/pci/hda/patch_ca0110.c | 8 +- trunk/sound/pci/hda/patch_ca0132.c | 9 +- trunk/sound/pci/hda/patch_cirrus.c | 30 +- trunk/sound/pci/hda/patch_cmedia.c | 1 - trunk/sound/pci/hda/patch_conexant.c | 186 +- trunk/sound/pci/hda/patch_hdmi.c | 4 +- trunk/sound/pci/hda/patch_realtek.c | 465 +++-- trunk/sound/pci/hda/patch_sigmatel.c | 120 +- trunk/sound/pci/hda/patch_via.c | 33 +- trunk/sound/pci/ice1712/ice1712.c | 15 +- trunk/sound/pci/ice1712/ice1724.c | 15 +- trunk/sound/pci/intel8x0.c | 16 +- trunk/sound/pci/intel8x0m.c | 16 +- trunk/sound/pci/korg1212/korg1212.c | 15 +- trunk/sound/pci/lola/lola.c | 15 +- trunk/sound/pci/lx6464es/lx6464es.c | 17 +- trunk/sound/pci/maestro3.c | 15 +- trunk/sound/pci/mixart/mixart.c | 15 +- trunk/sound/pci/nm256/nm256.c | 16 +- trunk/sound/pci/oxygen/oxygen.c | 21 +- trunk/sound/pci/oxygen/virtuoso.c | 13 +- trunk/sound/pci/oxygen/xonar_dg.c | 7 +- trunk/sound/pci/pcxhr/pcxhr.c | 15 +- trunk/sound/pci/riptide/riptide.c | 3 +- trunk/sound/pci/rme32.c | 15 +- trunk/sound/pci/rme96.c | 15 +- trunk/sound/pci/rme9652/hdsp.c | 15 +- trunk/sound/pci/rme9652/hdspm.c | 16 +- trunk/sound/pci/rme9652/rme9652.c | 15 +- trunk/sound/pci/sis7019.c | 13 +- trunk/sound/pci/sonicvibes.c | 15 +- trunk/sound/pci/trident/trident.c | 15 +- trunk/sound/pci/via82xx.c | 15 +- trunk/sound/pci/via82xx_modem.c | 15 +- trunk/sound/pci/vx222/vx222.c | 15 +- trunk/sound/pci/ymfpci/ymfpci.c | 15 +- trunk/sound/sh/sh_dac_audio.c | 4 +- trunk/sound/soc/codecs/Kconfig | 4 + trunk/sound/soc/codecs/Makefile | 2 + trunk/sound/soc/codecs/cs42l73.c | 16 +- trunk/sound/soc/codecs/omap-hdmi.c | 69 + trunk/sound/soc/codecs/wm8994.c | 2 +- trunk/sound/soc/omap/Kconfig | 1 + trunk/sound/sound_core.c | 2 +- trunk/sound/usb/card.c | 10 +- trunk/sound/usb/card.h | 86 +- trunk/sound/usb/endpoint.c | 1609 ++++++++--------- trunk/sound/usb/endpoint.h | 32 +- trunk/sound/usb/mixer.c | 50 +- trunk/sound/usb/mixer.h | 3 - trunk/sound/usb/mixer_maps.c | 13 - trunk/sound/usb/mixer_quirks.c | 472 +---- trunk/sound/usb/pcm.c | 453 +---- trunk/sound/usb/proc.c | 38 +- trunk/sound/usb/stream.c | 31 +- trunk/sound/usb/usbaudio.h | 2 - 103 files changed, 3120 insertions(+), 3826 deletions(-) delete mode 100644 trunk/sound/pci/hda/hda_auto_parser.c delete mode 100644 trunk/sound/pci/hda/hda_auto_parser.h create mode 100644 trunk/sound/soc/codecs/omap-hdmi.c diff --git a/[refs] b/[refs] index 1a87d5cc8c0d..b3d98dbc27ff 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 382e6a859e6622de0aa62c01976ae8ebd90e986d +refs/heads/master: 5452030c564686a3dafd355da5456fbeca1de111 diff --git a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt index 221b81016dba..8c16d50f6cb6 100644 --- a/trunk/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/trunk/Documentation/sound/alsa/ALSA-Configuration.txt @@ -1545,7 +1545,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. Module for sound cards based on the C-Media CMI8786/8787/8788 chip: * Asound A-8788 - * Asus Xonar DG/DGX + * Asus Xonar DG * AuzenTech X-Meridian * AuzenTech X-Meridian 2G * Bgears b-Enspirer diff --git a/trunk/include/sound/asound.h b/trunk/include/sound/asound.h index 0876a1e76aef..a2e4ff5ba9e9 100644 --- a/trunk/include/sound/asound.h +++ b/trunk/include/sound/asound.h @@ -68,20 +68,6 @@ struct snd_aes_iec958 { unsigned char dig_subframe[4]; /* AES/IEC958 subframe bits */ }; -/**************************************************************************** - * * - * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort * - * * - ****************************************************************************/ - -struct snd_cea_861_aud_if { - unsigned char db1_ct_cc; /* coding type and channel count */ - unsigned char db2_sf_ss; /* sample frequency and size */ - unsigned char db3; /* not used, all zeros */ - unsigned char db4_ca; /* channel allocation code */ - unsigned char db5_dminh_lsv; /* downmix inhibit & level-shit values */ -}; - /**************************************************************************** * * * Section for driver hardware dependent interface - /dev/snd/hw? * diff --git a/trunk/include/sound/asoundef.h b/trunk/include/sound/asoundef.h index bb05c02f89b0..20ebf3298eba 100644 --- a/trunk/include/sound/asoundef.h +++ b/trunk/include/sound/asoundef.h @@ -170,47 +170,6 @@ #define IEC958_AES5_CON_CGMSA_COPYNOMORE (2<<0) /* condition not be used */ #define IEC958_AES5_CON_CGMSA_COPYNEVER (3<<0) /* no copying is permitted */ -/**************************************************************************** - * * - * CEA-861 Audio InfoFrame. Used in HDMI and DisplayPort * - * * - ****************************************************************************/ -#define CEA861_AUDIO_INFOFRAME_DB1CC (7<<0) /* mask - channel count */ -#define CEA861_AUDIO_INFOFRAME_DB1CT (0xf<<4) /* mask - coding type */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM (0<<4) /* refer to stream */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_IEC60958 (1<<4) /* IEC-60958 L-PCM */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_AC3 (2<<4) /* AC-3 */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG1 (3<<4) /* MPEG1 Layers 1 & 2 */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_MP3 (4<<4) /* MPEG1 Layer 3 */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_MPEG2_MULTICH (5<<4) /* MPEG2 Multichannel */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_AAC (6<<4) /* AAC */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS (7<<4) /* DTS */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_ATRAC (8<<4) /* ATRAC */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_ONEBIT (9<<4) /* One Bit Audio */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_DOLBY_DIG_PLUS (10<<4) /* Dolby Digital + */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_DTS_HD (11<<4) /* DTS-HD */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_MAT (12<<4) /* MAT (MLP) */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_DST (13<<4) /* DST */ -#define CEA861_AUDIO_INFOFRAME_DB1CT_WMA_PRO (14<<4) /* WMA Pro */ -#define CEA861_AUDIO_INFOFRAME_DB2SF (7<<2) /* mask - sample frequency */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM (0<<2) /* refer to stream */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_32000 (1<<2) /* 32kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_44100 (2<<2) /* 44.1kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_48000 (3<<2) /* 48kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_88200 (4<<2) /* 88.2kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_96000 (5<<2) /* 96kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_176400 (6<<2) /* 176.4kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SF_192000 (7<<2) /* 192kHz */ -#define CEA861_AUDIO_INFOFRAME_DB2SS (3<<0) /* mask - sample size */ -#define CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM (0<<0) /* refer to stream */ -#define CEA861_AUDIO_INFOFRAME_DB2SS_16BIT (1<<0) /* 16 bits */ -#define CEA861_AUDIO_INFOFRAME_DB2SS_20BIT (2<<0) /* 20 bits */ -#define CEA861_AUDIO_INFOFRAME_DB2SS_24BIT (3<<0) /* 24 bits */ -#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH (1<<7) /* mask - inhibit downmixing */ -#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PERMITTED (0<<7) /* stereo downmix permitted */ -#define CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED (1<<7) /* stereo downmis prohibited */ -#define CEA861_AUDIO_INFOFRAME_DB5_LSV (0xf<<3) /* mask - level-shift values */ - /***************************************************************************** * * * MIDI v1.0 interface * diff --git a/trunk/sound/atmel/ac97c.c b/trunk/sound/atmel/ac97c.c index f5ded640b395..115313ef54d6 100644 --- a/trunk/sound/atmel/ac97c.c +++ b/trunk/sound/atmel/ac97c.c @@ -991,8 +991,6 @@ static int __devinit atmel_ac97c_probe(struct platform_device *pdev) gpio_direction_output(pdata->reset_pin, 1); chip->reset_pin = pdata->reset_pin; } - } else { - chip->reset_pin = -EINVAL; } snd_card_set_dev(card, &pdev->dev); diff --git a/trunk/sound/core/jack.c b/trunk/sound/core/jack.c index a06b1651fcba..471e1e3b0a99 100644 --- a/trunk/sound/core/jack.c +++ b/trunk/sound/core/jack.c @@ -155,7 +155,7 @@ EXPORT_SYMBOL(snd_jack_new); * @jack: The jack to configure * @parent: The device to set as parent for the jack. * - * Set the parent for the jack devices in the device tree. This + * Set the parent for the jack input device in the device tree. This * function is only valid prior to registration of the jack. If no * parent is configured then the parent device will be the sound card. */ @@ -179,9 +179,6 @@ EXPORT_SYMBOL(snd_jack_set_parent); * mapping is provided but keys are enabled in the jack type then * BTN_n numeric buttons will be reported. * - * If jacks are not reporting via the input API this call will have no - * effect. - * * Note that this is intended to be use by simple devices with small * numbers of keys that can be reported. It is also possible to * access the input device directly - devices with complex input diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index faedb1481b24..4d18941178e6 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -1894,7 +1894,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; - snd_pcm_uframes_t avail; int err = 0; if (size == 0) @@ -1918,12 +1917,13 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, } runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_playback_avail(runtime); while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; + snd_pcm_uframes_t avail; snd_pcm_uframes_t cont; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + avail = snd_pcm_playback_avail(runtime); if (!avail) { if (nonblock) { err = -EAGAIN; @@ -1971,7 +1971,6 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, offset += frames; size -= frames; xfer += frames; - avail -= frames; if (runtime->status->state == SNDRV_PCM_STATE_PREPARED && snd_pcm_playback_hw_avail(runtime) >= (snd_pcm_sframes_t)runtime->start_threshold) { err = snd_pcm_start(substream); @@ -2112,7 +2111,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, struct snd_pcm_runtime *runtime = substream->runtime; snd_pcm_uframes_t xfer = 0; snd_pcm_uframes_t offset = 0; - snd_pcm_uframes_t avail; int err = 0; if (size == 0) @@ -2143,12 +2141,13 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, } runtime->twake = runtime->control->avail_min ? : 1; - if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) - snd_pcm_update_hw_ptr(substream); - avail = snd_pcm_capture_avail(runtime); while (size > 0) { snd_pcm_uframes_t frames, appl_ptr, appl_ofs; + snd_pcm_uframes_t avail; snd_pcm_uframes_t cont; + if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) + snd_pcm_update_hw_ptr(substream); + avail = snd_pcm_capture_avail(runtime); if (!avail) { if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { @@ -2203,7 +2202,6 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, offset += frames; size -= frames; xfer += frames; - avail -= frames; } _end_unlock: runtime->twake = 0; diff --git a/trunk/sound/core/pcm_native.c b/trunk/sound/core/pcm_native.c index 53b5ada8f7c3..3fe99e644eb8 100644 --- a/trunk/sound/core/pcm_native.c +++ b/trunk/sound/core/pcm_native.c @@ -1360,14 +1360,7 @@ static int snd_pcm_prepare(struct snd_pcm_substream *substream, static int snd_pcm_pre_drain_init(struct snd_pcm_substream *substream, int state) { - struct snd_pcm_runtime *runtime = substream->runtime; - switch (runtime->status->state) { - case SNDRV_PCM_STATE_OPEN: - case SNDRV_PCM_STATE_DISCONNECTED: - case SNDRV_PCM_STATE_SUSPENDED: - return -EBADFD; - } - runtime->trigger_master = substream; + substream->runtime->trigger_master = substream; return 0; } @@ -1386,9 +1379,6 @@ static int snd_pcm_do_drain_init(struct snd_pcm_substream *substream, int state) case SNDRV_PCM_STATE_RUNNING: runtime->status->state = SNDRV_PCM_STATE_DRAINING; break; - case SNDRV_PCM_STATE_XRUN: - runtime->status->state = SNDRV_PCM_STATE_SETUP; - break; default: break; } diff --git a/trunk/sound/core/sound_oss.c b/trunk/sound/core/sound_oss.c index e9528333e36d..c70092043061 100644 --- a/trunk/sound/core/sound_oss.c +++ b/trunk/sound/core/sound_oss.c @@ -35,7 +35,7 @@ #include #include -#define SNDRV_OSS_MINORS 256 +#define SNDRV_OSS_MINORS 128 static struct snd_minor *snd_oss_minors[SNDRV_OSS_MINORS]; static DEFINE_MUTEX(sound_oss_mutex); @@ -111,7 +111,7 @@ int snd_register_oss_device(int type, struct snd_card *card, int dev, int register1 = -1, register2 = -1; struct device *carddev = snd_card_get_device_link(card); - if (card && card->number >= SNDRV_MINOR_OSS_DEVICES) + if (card && card->number >= 8) return 0; /* ignore silently */ if (minor < 0) return minor; @@ -170,7 +170,7 @@ int snd_unregister_oss_device(int type, struct snd_card *card, int dev) int track2 = -1; struct snd_minor *mptr; - if (card && card->number >= SNDRV_MINOR_OSS_DEVICES) + if (card && card->number >= 8) return 0; if (minor < 0) return minor; diff --git a/trunk/sound/drivers/aloop.c b/trunk/sound/drivers/aloop.c index 8b5c36f4d303..ad079b63b8ba 100644 --- a/trunk/sound/drivers/aloop.c +++ b/trunk/sound/drivers/aloop.c @@ -117,7 +117,6 @@ struct loopback_pcm { /* timer stuff */ unsigned int irq_pos; /* fractional IRQ position */ unsigned int period_size_frac; - unsigned int last_drift; unsigned long last_jiffies; struct timer_list timer; }; @@ -265,7 +264,6 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd) return err; dpcm->last_jiffies = jiffies; dpcm->pcm_rate_shift = 0; - dpcm->last_drift = 0; spin_lock(&cable->lock); cable->running |= stream; cable->pause &= ~stream; @@ -446,30 +444,34 @@ static void copy_play_buf(struct loopback_pcm *play, } } -static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm, - unsigned int jiffies_delta) +#define BYTEPOS_UPDATE_POSONLY 0 +#define BYTEPOS_UPDATE_CLEAR 1 +#define BYTEPOS_UPDATE_COPY 2 + +static void loopback_bytepos_update(struct loopback_pcm *dpcm, + unsigned int delta, + unsigned int cmd) { + unsigned int count; unsigned long last_pos; - unsigned int delta; last_pos = byte_pos(dpcm, dpcm->irq_pos); - dpcm->irq_pos += jiffies_delta * dpcm->pcm_bps; - delta = byte_pos(dpcm, dpcm->irq_pos) - last_pos; - if (delta >= dpcm->last_drift) - delta -= dpcm->last_drift; - dpcm->last_drift = 0; + dpcm->irq_pos += delta * dpcm->pcm_bps; + count = byte_pos(dpcm, dpcm->irq_pos) - last_pos; + if (!count) + return; + if (cmd == BYTEPOS_UPDATE_CLEAR) + clear_capture_buf(dpcm, count); + else if (cmd == BYTEPOS_UPDATE_COPY) + copy_play_buf(dpcm->cable->streams[SNDRV_PCM_STREAM_PLAYBACK], + dpcm->cable->streams[SNDRV_PCM_STREAM_CAPTURE], + count); + dpcm->buf_pos += count; + dpcm->buf_pos %= dpcm->pcm_buffer_size; if (dpcm->irq_pos >= dpcm->period_size_frac) { dpcm->irq_pos %= dpcm->period_size_frac; dpcm->period_update_pending = 1; } - return delta; -} - -static inline void bytepos_finish(struct loopback_pcm *dpcm, - unsigned int delta) -{ - dpcm->buf_pos += delta; - dpcm->buf_pos %= dpcm->pcm_buffer_size; } static unsigned int loopback_pos_update(struct loopback_cable *cable) @@ -479,7 +481,7 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) struct loopback_pcm *dpcm_capt = cable->streams[SNDRV_PCM_STREAM_CAPTURE]; unsigned long delta_play = 0, delta_capt = 0; - unsigned int running, count1, count2; + unsigned int running; unsigned long flags; spin_lock_irqsave(&cable->lock, flags); @@ -498,13 +500,12 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) goto unlock; if (delta_play > delta_capt) { - count1 = bytepos_delta(dpcm_play, delta_play - delta_capt); - bytepos_finish(dpcm_play, count1); + loopback_bytepos_update(dpcm_play, delta_play - delta_capt, + BYTEPOS_UPDATE_POSONLY); delta_play = delta_capt; } else if (delta_play < delta_capt) { - count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play); - clear_capture_buf(dpcm_capt, count1); - bytepos_finish(dpcm_capt, count1); + loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, + BYTEPOS_UPDATE_CLEAR); delta_capt = delta_play; } @@ -512,17 +513,8 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable) goto unlock; /* note delta_capt == delta_play at this moment */ - count1 = bytepos_delta(dpcm_play, delta_play); - count2 = bytepos_delta(dpcm_capt, delta_capt); - if (count1 < count2) { - dpcm_capt->last_drift = count2 - count1; - count1 = count2; - } else if (count1 > count2) { - dpcm_play->last_drift = count1 - count2; - } - copy_play_buf(dpcm_play, dpcm_capt, count1); - bytepos_finish(dpcm_play, count1); - bytepos_finish(dpcm_capt, count1); + loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); + loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); unlock: spin_unlock_irqrestore(&cable->lock, flags); return running; diff --git a/trunk/sound/firewire/amdtp.c b/trunk/sound/firewire/amdtp.c index ea995af6d049..87657dd7714c 100644 --- a/trunk/sound/firewire/amdtp.c +++ b/trunk/sound/firewire/amdtp.c @@ -31,8 +31,6 @@ #define INTERRUPT_INTERVAL 16 #define QUEUE_LENGTH 48 -static void pcm_period_tasklet(unsigned long data); - /** * amdtp_out_stream_init - initialize an AMDTP output stream structure * @s: the AMDTP output stream to initialize @@ -49,7 +47,6 @@ int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, s->flags = flags; s->context = ERR_PTR(-1); mutex_init(&s->mutex); - tasklet_init(&s->period_tasklet, pcm_period_tasklet, (unsigned long)s); s->packet_index = 0; return 0; @@ -167,21 +164,6 @@ void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, } EXPORT_SYMBOL(amdtp_out_stream_set_pcm_format); -/** - * amdtp_out_stream_pcm_prepare - prepare PCM device for running - * @s: the AMDTP output stream - * - * This function should be called from the PCM device's .prepare callback. - */ -void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s) -{ - tasklet_kill(&s->period_tasklet); - s->pcm_buffer_pointer = 0; - s->pcm_period_pointer = 0; - s->pointer_flush = true; -} -EXPORT_SYMBOL(amdtp_out_stream_pcm_prepare); - static unsigned int calculate_data_blocks(struct amdtp_out_stream *s) { unsigned int phase, data_blocks; @@ -394,21 +376,11 @@ static void queue_out_packet(struct amdtp_out_stream *s, unsigned int cycle) s->pcm_period_pointer += data_blocks; if (s->pcm_period_pointer >= pcm->runtime->period_size) { s->pcm_period_pointer -= pcm->runtime->period_size; - s->pointer_flush = false; - tasklet_hi_schedule(&s->period_tasklet); + snd_pcm_period_elapsed(pcm); } } } -static void pcm_period_tasklet(unsigned long data) -{ - struct amdtp_out_stream *s = (void *)data; - struct snd_pcm_substream *pcm = ACCESS_ONCE(s->pcm); - - if (pcm) - snd_pcm_period_elapsed(pcm); -} - static void out_packet_callback(struct fw_iso_context *context, u32 cycle, size_t header_length, void *header, void *data) { @@ -533,24 +505,6 @@ int amdtp_out_stream_start(struct amdtp_out_stream *s, int channel, int speed) } EXPORT_SYMBOL(amdtp_out_stream_start); -/** - * amdtp_out_stream_pcm_pointer - get the PCM buffer position - * @s: the AMDTP output stream that transports the PCM data - * - * Returns the current buffer position, in frames. - */ -unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s) -{ - /* this optimization is allowed to be racy */ - if (s->pointer_flush) - fw_iso_context_flush_completions(s->context); - else - s->pointer_flush = true; - - return ACCESS_ONCE(s->pcm_buffer_pointer); -} -EXPORT_SYMBOL(amdtp_out_stream_pcm_pointer); - /** * amdtp_out_stream_update - update the stream after a bus reset * @s: the AMDTP output stream @@ -578,7 +532,6 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s) return; } - tasklet_kill(&s->period_tasklet); fw_iso_context_stop(s->context); fw_iso_context_destroy(s->context); s->context = ERR_PTR(-1); diff --git a/trunk/sound/firewire/amdtp.h b/trunk/sound/firewire/amdtp.h index b680c5ef01d6..537a9cb83581 100644 --- a/trunk/sound/firewire/amdtp.h +++ b/trunk/sound/firewire/amdtp.h @@ -1,7 +1,6 @@ #ifndef SOUND_FIREWIRE_AMDTP_H_INCLUDED #define SOUND_FIREWIRE_AMDTP_H_INCLUDED -#include #include #include #include "packets-buffer.h" @@ -56,7 +55,6 @@ struct amdtp_out_stream { struct iso_packets_buffer buffer; struct snd_pcm_substream *pcm; - struct tasklet_struct period_tasklet; int packet_index; unsigned int data_block_counter; @@ -68,7 +66,6 @@ struct amdtp_out_stream { unsigned int pcm_buffer_pointer; unsigned int pcm_period_pointer; - bool pointer_flush; }; int amdtp_out_stream_init(struct amdtp_out_stream *s, struct fw_unit *unit, @@ -84,8 +81,6 @@ void amdtp_out_stream_stop(struct amdtp_out_stream *s); void amdtp_out_stream_set_pcm_format(struct amdtp_out_stream *s, snd_pcm_format_t format); -void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s); -unsigned long amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s); void amdtp_out_stream_pcm_abort(struct amdtp_out_stream *s); /** @@ -127,6 +122,18 @@ static inline bool amdtp_out_streaming_error(struct amdtp_out_stream *s) return s->packet_index < 0; } +/** + * amdtp_out_stream_pcm_prepare - prepare PCM device for running + * @s: the AMDTP output stream + * + * This function should be called from the PCM device's .prepare callback. + */ +static inline void amdtp_out_stream_pcm_prepare(struct amdtp_out_stream *s) +{ + s->pcm_buffer_pointer = 0; + s->pcm_period_pointer = 0; +} + /** * amdtp_out_stream_pcm_trigger - start/stop playback from a PCM device * @s: the AMDTP output stream @@ -142,6 +149,18 @@ static inline void amdtp_out_stream_pcm_trigger(struct amdtp_out_stream *s, ACCESS_ONCE(s->pcm) = pcm; } +/** + * amdtp_out_stream_pcm_pointer - get the PCM buffer position + * @s: the AMDTP output stream that transports the PCM data + * + * Returns the current buffer position, in frames. + */ +static inline unsigned long +amdtp_out_stream_pcm_pointer(struct amdtp_out_stream *s) +{ + return ACCESS_ONCE(s->pcm_buffer_pointer); +} + static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc) { return sfc & 1; diff --git a/trunk/sound/pci/Kconfig b/trunk/sound/pci/Kconfig index ff3af6e77d61..5ca0939e4223 100644 --- a/trunk/sound/pci/Kconfig +++ b/trunk/sound/pci/Kconfig @@ -228,7 +228,7 @@ config SND_OXYGEN Say Y here to include support for sound cards based on the C-Media CMI8788 (Oxygen HD Audio) chip: * Asound A-8788 - * Asus Xonar DG/DGX + * Asus Xonar DG * AuzenTech X-Meridian * AuzenTech X-Meridian 2G * Bgears b-Enspirer diff --git a/trunk/sound/pci/ad1889.c b/trunk/sound/pci/ad1889.c index e672ff4df2da..9d91d61902b4 100644 --- a/trunk/sound/pci/ad1889.c +++ b/trunk/sound/pci/ad1889.c @@ -1062,4 +1062,17 @@ static struct pci_driver ad1889_pci_driver = { .remove = __devexit_p(snd_ad1889_remove), }; -module_pci_driver(ad1889_pci_driver); +static int __init +alsa_ad1889_init(void) +{ + return pci_register_driver(&ad1889_pci_driver); +} + +static void __exit +alsa_ad1889_fini(void) +{ + pci_unregister_driver(&ad1889_pci_driver); +} + +module_init(alsa_ad1889_init); +module_exit(alsa_ad1889_fini); diff --git a/trunk/sound/pci/ali5451/ali5451.c b/trunk/sound/pci/ali5451/ali5451.c index 9dfc27bf6cc6..bdd6164e9c7e 100644 --- a/trunk/sound/pci/ali5451/ali5451.c +++ b/trunk/sound/pci/ali5451/ali5451.c @@ -2294,7 +2294,7 @@ static void __devexit snd_ali_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver ali5451_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_ali_ids, .probe = snd_ali_probe, @@ -2305,4 +2305,15 @@ static struct pci_driver ali5451_driver = { #endif }; -module_pci_driver(ali5451_driver); +static int __init alsa_card_ali_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_ali_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ali_init) +module_exit(alsa_card_ali_exit) diff --git a/trunk/sound/pci/als300.c b/trunk/sound/pci/als300.c index 59d65388faf5..8196e229b2df 100644 --- a/trunk/sound/pci/als300.c +++ b/trunk/sound/pci/als300.c @@ -852,7 +852,7 @@ static int __devinit snd_als300_probe(struct pci_dev *pci, return 0; } -static struct pci_driver als300_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_als300_ids, .probe = snd_als300_probe, @@ -863,4 +863,15 @@ static struct pci_driver als300_driver = { #endif }; -module_pci_driver(als300_driver); +static int __init alsa_card_als300_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_als300_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_als300_init) +module_exit(alsa_card_als300_exit) diff --git a/trunk/sound/pci/als4000.c b/trunk/sound/pci/als4000.c index 7d7f2598c748..3269b8011ea9 100644 --- a/trunk/sound/pci/als4000.c +++ b/trunk/sound/pci/als4000.c @@ -1036,7 +1036,7 @@ static int snd_als4000_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ -static struct pci_driver als4000_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_als4000_ids, .probe = snd_card_als4000_probe, @@ -1047,4 +1047,15 @@ static struct pci_driver als4000_driver = { #endif }; -module_pci_driver(als4000_driver); +static int __init alsa_card_als4000_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_als4000_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_als4000_init) +module_exit(alsa_card_als4000_exit) diff --git a/trunk/sound/pci/atiixp.c b/trunk/sound/pci/atiixp.c index 156a94f8a123..590682f115ef 100644 --- a/trunk/sound/pci/atiixp.c +++ b/trunk/sound/pci/atiixp.c @@ -1700,7 +1700,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver atiixp_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, @@ -1711,4 +1711,16 @@ static struct pci_driver atiixp_driver = { #endif }; -module_pci_driver(atiixp_driver); + +static int __init alsa_card_atiixp_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_atiixp_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_atiixp_init) +module_exit(alsa_card_atiixp_exit) diff --git a/trunk/sound/pci/atiixp_modem.c b/trunk/sound/pci/atiixp_modem.c index 30a4fd96ce73..524d35f31232 100644 --- a/trunk/sound/pci/atiixp_modem.c +++ b/trunk/sound/pci/atiixp_modem.c @@ -1331,7 +1331,7 @@ static void __devexit snd_atiixp_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver atiixp_modem_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_atiixp_ids, .probe = snd_atiixp_probe, @@ -1342,4 +1342,16 @@ static struct pci_driver atiixp_modem_driver = { #endif }; -module_pci_driver(atiixp_modem_driver); + +static int __init alsa_card_atiixp_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_atiixp_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_atiixp_init) +module_exit(alsa_card_atiixp_exit) diff --git a/trunk/sound/pci/au88x0/au88x0.c b/trunk/sound/pci/au88x0/au88x0.c index ffc376f9f4e4..f13ad536b2d5 100644 --- a/trunk/sound/pci/au88x0/au88x0.c +++ b/trunk/sound/pci/au88x0/au88x0.c @@ -375,11 +375,24 @@ static void __devexit snd_vortex_remove(struct pci_dev *pci) } // pci_driver definition -static struct pci_driver vortex_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_vortex_ids, .probe = snd_vortex_probe, .remove = __devexit_p(snd_vortex_remove), }; -module_pci_driver(vortex_driver); +// initialization of the module +static int __init alsa_card_vortex_init(void) +{ + return pci_register_driver(&driver); +} + +// clean up the module +static void __exit alsa_card_vortex_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_vortex_init) +module_exit(alsa_card_vortex_exit) diff --git a/trunk/sound/pci/aw2/aw2-alsa.c b/trunk/sound/pci/aw2/aw2-alsa.c index 0f804741825f..1c5231931462 100644 --- a/trunk/sound/pci/aw2/aw2-alsa.c +++ b/trunk/sound/pci/aw2/aw2-alsa.c @@ -112,6 +112,8 @@ struct aw2 { /********************************* * FUNCTION DECLARATIONS ********************************/ +static int __init alsa_card_aw2_init(void); +static void __exit alsa_card_aw2_exit(void); static int snd_aw2_dev_free(struct snd_device *device); static int __devinit snd_aw2_create(struct snd_card *card, struct pci_dev *pci, struct aw2 **rchip); @@ -169,15 +171,13 @@ static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { MODULE_DEVICE_TABLE(pci, snd_aw2_ids); /* pci_driver definition */ -static struct pci_driver aw2_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_aw2_ids, .probe = snd_aw2_probe, .remove = __devexit_p(snd_aw2_remove), }; -module_pci_driver(aw2_driver); - /* operators for playback PCM alsa interface */ static struct snd_pcm_ops snd_aw2_playback_ops = { .open = snd_aw2_pcm_playback_open, @@ -217,6 +217,23 @@ static struct snd_kcontrol_new aw2_control __devinitdata = { * FUNCTION IMPLEMENTATIONS ********************************/ +/* initialization of the module */ +static int __init alsa_card_aw2_init(void) +{ + snd_printdd(KERN_DEBUG "aw2: Load aw2 module\n"); + return pci_register_driver(&driver); +} + +/* clean up the module */ +static void __exit alsa_card_aw2_exit(void) +{ + snd_printdd(KERN_DEBUG "aw2: Unload aw2 module\n"); + pci_unregister_driver(&driver); +} + +module_init(alsa_card_aw2_init); +module_exit(alsa_card_aw2_exit); + /* component-destructor */ static int snd_aw2_dev_free(struct snd_device *device) { diff --git a/trunk/sound/pci/azt3328.c b/trunk/sound/pci/azt3328.c index f0b4d7493af5..496f14c1a731 100644 --- a/trunk/sound/pci/azt3328.c +++ b/trunk/sound/pci/azt3328.c @@ -2862,7 +2862,7 @@ snd_azf3328_resume(struct pci_dev *pci) #endif /* CONFIG_PM */ -static struct pci_driver azf3328_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_azf3328_ids, .probe = snd_azf3328_probe, @@ -2873,4 +2873,23 @@ static struct pci_driver azf3328_driver = { #endif }; -module_pci_driver(azf3328_driver); +static int __init +alsa_card_azf3328_init(void) +{ + int err; + snd_azf3328_dbgcallenter(); + err = pci_register_driver(&driver); + snd_azf3328_dbgcallleave(); + return err; +} + +static void __exit +alsa_card_azf3328_exit(void) +{ + snd_azf3328_dbgcallenter(); + pci_unregister_driver(&driver); + snd_azf3328_dbgcallleave(); +} + +module_init(alsa_card_azf3328_init) +module_exit(alsa_card_azf3328_exit) diff --git a/trunk/sound/pci/bt87x.c b/trunk/sound/pci/bt87x.c index b6a95eeca095..62d6163fc9d9 100644 --- a/trunk/sound/pci/bt87x.c +++ b/trunk/sound/pci/bt87x.c @@ -836,6 +836,8 @@ static struct { {0x7063, 0x2000}, /* pcHDTV HD-2000 TV */ }; +static struct pci_driver driver; + /* return the id of the card, or a negative value if it's blacklisted */ static int __devinit snd_bt87x_detect_card(struct pci_dev *pci) { @@ -962,11 +964,24 @@ static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { { } }; -static struct pci_driver bt87x_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_bt87x_ids, .probe = snd_bt87x_probe, .remove = __devexit_p(snd_bt87x_remove), }; -module_pci_driver(bt87x_driver); +static int __init alsa_card_bt87x_init(void) +{ + if (load_all) + driver.id_table = snd_bt87x_default_ids; + return pci_register_driver(&driver); +} + +static void __exit alsa_card_bt87x_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_bt87x_init) +module_exit(alsa_card_bt87x_exit) diff --git a/trunk/sound/pci/ca0106/ca0106_main.c b/trunk/sound/pci/ca0106/ca0106_main.c index e76d68a7081f..08d6ebfe5a61 100644 --- a/trunk/sound/pci/ca0106/ca0106_main.c +++ b/trunk/sound/pci/ca0106/ca0106_main.c @@ -1932,7 +1932,7 @@ static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { MODULE_DEVICE_TABLE(pci, snd_ca0106_ids); // pci_driver definition -static struct pci_driver ca0106_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_ca0106_ids, .probe = snd_ca0106_probe, @@ -1943,4 +1943,17 @@ static struct pci_driver ca0106_driver = { #endif }; -module_pci_driver(ca0106_driver); +// initialization of the module +static int __init alsa_card_ca0106_init(void) +{ + return pci_register_driver(&driver); +} + +// clean up the module +static void __exit alsa_card_ca0106_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ca0106_init) +module_exit(alsa_card_ca0106_exit) diff --git a/trunk/sound/pci/cmipci.c b/trunk/sound/pci/cmipci.c index 3815bd4c6779..19b06269adc2 100644 --- a/trunk/sound/pci/cmipci.c +++ b/trunk/sound/pci/cmipci.c @@ -3398,7 +3398,7 @@ static int snd_cmipci_resume(struct pci_dev *pci) } #endif /* CONFIG_PM */ -static struct pci_driver cmipci_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_cmipci_ids, .probe = snd_cmipci_probe, @@ -3409,4 +3409,15 @@ static struct pci_driver cmipci_driver = { #endif }; -module_pci_driver(cmipci_driver); +static int __init alsa_card_cmipci_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_cmipci_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_cmipci_init) +module_exit(alsa_card_cmipci_exit) diff --git a/trunk/sound/pci/cs4281.c b/trunk/sound/pci/cs4281.c index 33506ee569bd..a9f368f60df6 100644 --- a/trunk/sound/pci/cs4281.c +++ b/trunk/sound/pci/cs4281.c @@ -2084,7 +2084,7 @@ static int cs4281_resume(struct pci_dev *pci) } #endif /* CONFIG_PM */ -static struct pci_driver cs4281_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_cs4281_ids, .probe = snd_cs4281_probe, @@ -2095,4 +2095,15 @@ static struct pci_driver cs4281_driver = { #endif }; -module_pci_driver(cs4281_driver); +static int __init alsa_card_cs4281_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_cs4281_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_cs4281_init) +module_exit(alsa_card_cs4281_exit) diff --git a/trunk/sound/pci/cs46xx/cs46xx.c b/trunk/sound/pci/cs46xx/cs46xx.c index 6cc7404e0e8f..819d79d0586d 100644 --- a/trunk/sound/pci/cs46xx/cs46xx.c +++ b/trunk/sound/pci/cs46xx/cs46xx.c @@ -161,7 +161,7 @@ static void __devexit snd_card_cs46xx_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver cs46xx_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_cs46xx_ids, .probe = snd_card_cs46xx_probe, @@ -172,4 +172,15 @@ static struct pci_driver cs46xx_driver = { #endif }; -module_pci_driver(cs46xx_driver); +static int __init alsa_card_cs46xx_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_cs46xx_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_cs46xx_init) +module_exit(alsa_card_cs46xx_exit) diff --git a/trunk/sound/pci/cs5530.c b/trunk/sound/pci/cs5530.c index f1e4229993af..c47cabff2bfa 100644 --- a/trunk/sound/pci/cs5530.c +++ b/trunk/sound/pci/cs5530.c @@ -291,11 +291,23 @@ static int __devinit snd_cs5530_probe(struct pci_dev *pci, return 0; } -static struct pci_driver cs5530_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5530_ids, .probe = snd_cs5530_probe, .remove = __devexit_p(snd_cs5530_remove), }; -module_pci_driver(cs5530_driver); +static int __init alsa_card_cs5530_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_cs5530_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_cs5530_init) +module_exit(alsa_card_cs5530_exit) + diff --git a/trunk/sound/pci/cs5535audio/cs5535audio.c b/trunk/sound/pci/cs5535audio/cs5535audio.c index 2c9697cf0a1a..a2fb2173e980 100644 --- a/trunk/sound/pci/cs5535audio/cs5535audio.c +++ b/trunk/sound/pci/cs5535audio/cs5535audio.c @@ -394,7 +394,7 @@ static void __devexit snd_cs5535audio_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver cs5535audio_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_cs5535audio_ids, .probe = snd_cs5535audio_probe, @@ -405,7 +405,18 @@ static struct pci_driver cs5535audio_driver = { #endif }; -module_pci_driver(cs5535audio_driver); +static int __init alsa_card_cs5535audio_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_cs5535audio_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_cs5535audio_init) +module_exit(alsa_card_cs5535audio_exit) MODULE_AUTHOR("Jaya Kumar"); MODULE_LICENSE("GPL"); diff --git a/trunk/sound/pci/ctxfi/xfi.c b/trunk/sound/pci/ctxfi/xfi.c index 75aa2c338410..15d95d2bacee 100644 --- a/trunk/sound/pci/ctxfi/xfi.c +++ b/trunk/sound/pci/ctxfi/xfi.c @@ -154,4 +154,15 @@ static struct pci_driver ct_driver = { #endif }; -module_pci_driver(ct_driver); +static int __init ct_card_init(void) +{ + return pci_register_driver(&ct_driver); +} + +static void __exit ct_card_exit(void) +{ + pci_unregister_driver(&ct_driver); +} + +module_init(ct_card_init) +module_exit(ct_card_exit) diff --git a/trunk/sound/pci/echoaudio/echoaudio.c b/trunk/sound/pci/echoaudio/echoaudio.c index 0f8eda1dafdb..595c11f904bb 100644 --- a/trunk/sound/pci/echoaudio/echoaudio.c +++ b/trunk/sound/pci/echoaudio/echoaudio.c @@ -2328,7 +2328,7 @@ static void __devexit snd_echo_remove(struct pci_dev *pci) ******************************************************************************/ /* pci_driver definition */ -static struct pci_driver echo_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_echo_ids, .probe = snd_echo_probe, @@ -2339,4 +2339,22 @@ static struct pci_driver echo_driver = { #endif /* CONFIG_PM */ }; -module_pci_driver(echo_driver); + + +/* initialization of the module */ +static int __init alsa_card_echo_init(void) +{ + return pci_register_driver(&driver); +} + + + +/* clean up the module */ +static void __exit alsa_card_echo_exit(void) +{ + pci_unregister_driver(&driver); +} + + +module_init(alsa_card_echo_init) +module_exit(alsa_card_echo_exit) diff --git a/trunk/sound/pci/emu10k1/emu10k1.c b/trunk/sound/pci/emu10k1/emu10k1.c index 7fdbbe4d9965..790c65d980c8 100644 --- a/trunk/sound/pci/emu10k1/emu10k1.c +++ b/trunk/sound/pci/emu10k1/emu10k1.c @@ -263,7 +263,7 @@ static int snd_emu10k1_resume(struct pci_dev *pci) } #endif -static struct pci_driver emu10k1_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1_ids, .probe = snd_card_emu10k1_probe, @@ -274,4 +274,15 @@ static struct pci_driver emu10k1_driver = { #endif }; -module_pci_driver(emu10k1_driver); +static int __init alsa_card_emu10k1_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_emu10k1_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_emu10k1_init) +module_exit(alsa_card_emu10k1_exit) diff --git a/trunk/sound/pci/emu10k1/emu10k1x.c b/trunk/sound/pci/emu10k1/emu10k1x.c index 5c8978b2c4d9..47a651cb6e84 100644 --- a/trunk/sound/pci/emu10k1/emu10k1x.c +++ b/trunk/sound/pci/emu10k1/emu10k1x.c @@ -1612,11 +1612,24 @@ static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { MODULE_DEVICE_TABLE(pci, snd_emu10k1x_ids); // pci_driver definition -static struct pci_driver emu10k1x_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_emu10k1x_ids, .probe = snd_emu10k1x_probe, .remove = __devexit_p(snd_emu10k1x_remove), }; -module_pci_driver(emu10k1x_driver); +// initialization of the module +static int __init alsa_card_emu10k1x_init(void) +{ + return pci_register_driver(&driver); +} + +// clean up the module +static void __exit alsa_card_emu10k1x_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_emu10k1x_init) +module_exit(alsa_card_emu10k1x_exit) diff --git a/trunk/sound/pci/ens1370.c b/trunk/sound/pci/ens1370.c index 3821c81d1c99..47a245e84190 100644 --- a/trunk/sound/pci/ens1370.c +++ b/trunk/sound/pci/ens1370.c @@ -2488,7 +2488,7 @@ static void __devexit snd_audiopci_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver ens137x_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_audiopci_ids, .probe = snd_audiopci_probe, @@ -2499,4 +2499,15 @@ static struct pci_driver ens137x_driver = { #endif }; -module_pci_driver(ens137x_driver); +static int __init alsa_card_ens137x_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_ens137x_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ens137x_init) +module_exit(alsa_card_ens137x_exit) diff --git a/trunk/sound/pci/es1938.c b/trunk/sound/pci/es1938.c index 82c8d8c5c52a..53eb76b41108 100644 --- a/trunk/sound/pci/es1938.c +++ b/trunk/sound/pci/es1938.c @@ -1882,7 +1882,7 @@ static void __devexit snd_es1938_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver es1938_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_es1938_ids, .probe = snd_es1938_probe, @@ -1893,4 +1893,15 @@ static struct pci_driver es1938_driver = { #endif }; -module_pci_driver(es1938_driver); +static int __init alsa_card_es1938_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_es1938_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_es1938_init) +module_exit(alsa_card_es1938_exit) diff --git a/trunk/sound/pci/es1968.c b/trunk/sound/pci/es1968.c index 67f47d891959..a8faae1c85e4 100644 --- a/trunk/sound/pci/es1968.c +++ b/trunk/sound/pci/es1968.c @@ -2898,7 +2898,7 @@ static void __devexit snd_es1968_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver es1968_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_es1968_ids, .probe = snd_es1968_probe, @@ -2909,4 +2909,15 @@ static struct pci_driver es1968_driver = { #endif }; -module_pci_driver(es1968_driver); +static int __init alsa_card_es1968_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_es1968_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_es1968_init) +module_exit(alsa_card_es1968_exit) diff --git a/trunk/sound/pci/fm801.c b/trunk/sound/pci/fm801.c index f69662322750..a416ea8af3e9 100644 --- a/trunk/sound/pci/fm801.c +++ b/trunk/sound/pci/fm801.c @@ -1416,7 +1416,7 @@ static int snd_fm801_resume(struct pci_dev *pci) } #endif -static struct pci_driver fm801_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_fm801_ids, .probe = snd_card_fm801_probe, @@ -1427,4 +1427,15 @@ static struct pci_driver fm801_driver = { #endif }; -module_pci_driver(fm801_driver); +static int __init alsa_card_fm801_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_fm801_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_fm801_init) +module_exit(alsa_card_fm801_exit) diff --git a/trunk/sound/pci/hda/Makefile b/trunk/sound/pci/hda/Makefile index bd4149f1aaf4..ace157cc3d15 100644 --- a/trunk/sound/pci/hda/Makefile +++ b/trunk/sound/pci/hda/Makefile @@ -1,6 +1,6 @@ snd-hda-intel-objs := hda_intel.o -snd-hda-codec-y := hda_codec.o hda_jack.o hda_auto_parser.o +snd-hda-codec-y := hda_codec.o hda_jack.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_HWDEP) += hda_hwdep.o diff --git a/trunk/sound/pci/hda/hda_auto_parser.c b/trunk/sound/pci/hda/hda_auto_parser.c deleted file mode 100644 index 6e9ef3e25093..000000000000 --- a/trunk/sound/pci/hda/hda_auto_parser.c +++ /dev/null @@ -1,760 +0,0 @@ -/* - * BIOS auto-parser helper functions for HD-audio - * - * Copyright (c) 2012 Takashi Iwai - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include "hda_codec.h" -#include "hda_local.h" -#include "hda_auto_parser.h" - -#define SFX "hda_codec: " - -/* - * Helper for automatic pin configuration - */ - -static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) -{ - for (; *list; list++) - if (*list == nid) - return 1; - return 0; -} - - -/* - * Sort an associated group of pins according to their sequence numbers. - */ -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]) { - seq = sequences[i]; - sequences[i] = sequences[j]; - sequences[j] = seq; - nid = pins[i]; - pins[i] = pins[j]; - pins[j] = nid; - } - } - } -} - - -/* add the found input-pin to the cfg->inputs[] table */ -static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, - int type) -{ - if (cfg->num_inputs < AUTO_CFG_MAX_INS) { - cfg->inputs[cfg->num_inputs].pin = nid; - cfg->inputs[cfg->num_inputs].type = type; - cfg->num_inputs++; - } -} - -/* sort inputs in the order of AUTO_PIN_* type */ -static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) -{ - int i, j; - - for (i = 0; i < cfg->num_inputs; i++) { - for (j = i + 1; j < cfg->num_inputs; j++) { - if (cfg->inputs[i].type > cfg->inputs[j].type) { - struct auto_pin_cfg_item tmp; - tmp = cfg->inputs[i]; - cfg->inputs[i] = cfg->inputs[j]; - cfg->inputs[j] = tmp; - } - } - } -} - -/* Reorder the surround channels - * ALSA sequence is front/surr/clfe/side - * HDA sequence is: - * 4-ch: front/surr => OK as it is - * 6-ch: front/clfe/surr - * 8-ch: front/clfe/rear/side|fc - */ -static void reorder_outputs(unsigned int nums, hda_nid_t *pins) -{ - hda_nid_t nid; - - switch (nums) { - case 3: - case 4: - nid = pins[1]; - pins[1] = pins[2]; - pins[2] = nid; - break; - } -} - -/* - * Parse all pin widgets and store the useful pin nids to cfg - * - * The number of line-outs or any primary output is stored in line_outs, - * and the corresponding output pins are assigned to line_out_pins[], - * in the order of front, rear, CLFE, side, ... - * - * If more extra outputs (speaker and headphone) are found, the pins are - * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack - * 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 inputs array. - * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, - * respectively. - */ -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags) -{ - hda_nid_t nid, end_nid; - short seq, assoc_line_out; - short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; - short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; - short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; - int i; - - memset(cfg, 0, sizeof(*cfg)); - - memset(sequences_line_out, 0, sizeof(sequences_line_out)); - memset(sequences_speaker, 0, sizeof(sequences_speaker)); - memset(sequences_hp, 0, sizeof(sequences_hp)); - assoc_line_out = 0; - - codec->ignore_misc_bit = true; - end_nid = codec->start_nid + codec->num_nodes; - for (nid = codec->start_nid; nid < end_nid; nid++) { - unsigned int wid_caps = get_wcaps(codec, nid); - unsigned int wid_type = get_wcaps_type(wid_caps); - unsigned int def_conf; - short assoc, loc, conn, dev; - - /* read all default configuration for pin complex */ - if (wid_type != AC_WID_PIN) - continue; - /* ignore the given nids (e.g. pc-beep returns error) */ - if (ignore_nids && is_in_nid_list(nid, ignore_nids)) - continue; - - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & - AC_DEFCFG_MISC_NO_PRESENCE)) - codec->ignore_misc_bit = false; - conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) - continue; - loc = get_defcfg_location(def_conf); - dev = get_defcfg_device(def_conf); - - /* workaround for buggy BIOS setups */ - if (dev == AC_JACK_LINE_OUT) { - if (conn == AC_JACK_PORT_FIXED) - dev = AC_JACK_SPEAKER; - } - - switch (dev) { - case AC_JACK_LINE_OUT: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - - if (!(wid_caps & AC_WCAP_STEREO)) - if (!cfg->mono_out_pin) - cfg->mono_out_pin = nid; - if (!assoc) - continue; - if (!assoc_line_out) - assoc_line_out = assoc; - else if (assoc_line_out != assoc) - continue; - if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) - continue; - cfg->line_out_pins[cfg->line_outs] = nid; - sequences_line_out[cfg->line_outs] = seq; - cfg->line_outs++; - break; - case AC_JACK_SPEAKER: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) - continue; - cfg->speaker_pins[cfg->speaker_outs] = nid; - sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; - cfg->speaker_outs++; - break; - case AC_JACK_HP_OUT: - seq = get_defcfg_sequence(def_conf); - assoc = get_defcfg_association(def_conf); - if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) - continue; - cfg->hp_pins[cfg->hp_outs] = nid; - sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; - cfg->hp_outs++; - break; - case AC_JACK_MIC_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); - break; - case AC_JACK_LINE_IN: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); - break; - case AC_JACK_CD: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); - break; - case AC_JACK_AUX: - add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); - break; - case AC_JACK_SPDIF_OUT: - case AC_JACK_DIG_OTHER_OUT: - if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) - continue; - cfg->dig_out_pins[cfg->dig_outs] = nid; - cfg->dig_out_type[cfg->dig_outs] = - (loc == AC_JACK_LOC_HDMI) ? - HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; - cfg->dig_outs++; - break; - case AC_JACK_SPDIF_IN: - case AC_JACK_DIG_OTHER_IN: - cfg->dig_in_pin = nid; - if (loc == AC_JACK_LOC_HDMI) - cfg->dig_in_type = HDA_PCM_TYPE_HDMI; - else - cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; - break; - } - } - - /* FIX-UP: - * If no line-out is defined but multiple HPs are found, - * some of them might be the real line-outs. - */ - if (!cfg->line_outs && cfg->hp_outs > 1 && - !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { - int i = 0; - while (i < cfg->hp_outs) { - /* The real HPs should have the sequence 0x0f */ - if ((sequences_hp[i] & 0x0f) == 0x0f) { - i++; - continue; - } - /* Move it to the line-out table */ - cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; - sequences_line_out[cfg->line_outs] = sequences_hp[i]; - cfg->line_outs++; - cfg->hp_outs--; - memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, - sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); - memmove(sequences_hp + i, sequences_hp + i + 1, - sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); - } - memset(cfg->hp_pins + cfg->hp_outs, 0, - sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); - if (!cfg->hp_outs) - cfg->line_out_type = AUTO_PIN_HP_OUT; - - } - - /* sort by sequence */ - sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, - cfg->line_outs); - sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, - cfg->speaker_outs); - sort_pins_by_sequence(cfg->hp_pins, sequences_hp, - cfg->hp_outs); - - /* - * FIX-UP: if no line-outs are detected, try to use speaker or HP pin - * as a primary output - */ - if (!cfg->line_outs && - !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { - if (cfg->speaker_outs) { - cfg->line_outs = cfg->speaker_outs; - memcpy(cfg->line_out_pins, cfg->speaker_pins, - sizeof(cfg->speaker_pins)); - cfg->speaker_outs = 0; - memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); - cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; - } else if (cfg->hp_outs) { - cfg->line_outs = cfg->hp_outs; - memcpy(cfg->line_out_pins, cfg->hp_pins, - sizeof(cfg->hp_pins)); - cfg->hp_outs = 0; - memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); - cfg->line_out_type = AUTO_PIN_HP_OUT; - } - } - - reorder_outputs(cfg->line_outs, cfg->line_out_pins); - reorder_outputs(cfg->hp_outs, cfg->hp_pins); - reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); - - sort_autocfg_input_pins(cfg); - - /* - * debug prints of the parsed results - */ - snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", - cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], - cfg->line_out_pins[2], cfg->line_out_pins[3], - cfg->line_out_pins[4], - cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : - (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? - "speaker" : "line")); - snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - cfg->speaker_outs, cfg->speaker_pins[0], - cfg->speaker_pins[1], cfg->speaker_pins[2], - cfg->speaker_pins[3], cfg->speaker_pins[4]); - snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", - cfg->hp_outs, cfg->hp_pins[0], - cfg->hp_pins[1], cfg->hp_pins[2], - cfg->hp_pins[3], cfg->hp_pins[4]); - snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); - if (cfg->dig_outs) - snd_printd(" dig-out=0x%x/0x%x\n", - cfg->dig_out_pins[0], cfg->dig_out_pins[1]); - snd_printd(" inputs:"); - for (i = 0; i < cfg->num_inputs; i++) { - snd_printd(" %s=0x%x", - hda_get_autocfg_input_label(codec, cfg, i), - cfg->inputs[i].pin); - } - snd_printd("\n"); - if (cfg->dig_in_pin) - snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); - - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); - -int snd_hda_get_input_pin_attr(unsigned int def_conf) -{ - unsigned int loc = get_defcfg_location(def_conf); - unsigned int conn = get_defcfg_connect(def_conf); - if (conn == AC_JACK_PORT_NONE) - return INPUT_PIN_ATTR_UNUSED; - /* Windows may claim the internal mic to be BOTH, too */ - if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) - return INPUT_PIN_ATTR_INT; - if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) - return INPUT_PIN_ATTR_INT; - if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) - return INPUT_PIN_ATTR_DOCK; - if (loc == AC_JACK_LOC_REAR) - return INPUT_PIN_ATTR_REAR; - if (loc == AC_JACK_LOC_FRONT) - return INPUT_PIN_ATTR_FRONT; - return INPUT_PIN_ATTR_NORMAL; -} -EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); - -/** - * hda_get_input_pin_label - Give a label for the given input pin - * - * When check_location is true, the function checks the pin location - * for mic and line-in pins, and set an appropriate prefix like "Front", - * "Rear", "Internal". - */ - -static const char *hda_get_input_pin_label(struct hda_codec *codec, - hda_nid_t pin, bool check_location) -{ - unsigned int def_conf; - static const char * const mic_names[] = { - "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", - }; - int attr; - - def_conf = snd_hda_codec_get_pincfg(codec, pin); - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_MIC_IN: - if (!check_location) - return "Mic"; - attr = snd_hda_get_input_pin_attr(def_conf); - if (!attr) - return "None"; - return mic_names[attr - 1]; - case AC_JACK_LINE_IN: - if (!check_location) - return "Line"; - attr = snd_hda_get_input_pin_attr(def_conf); - if (!attr) - return "None"; - if (attr == INPUT_PIN_ATTR_DOCK) - return "Dock Line"; - return "Line"; - case AC_JACK_AUX: - return "Aux"; - case AC_JACK_CD: - return "CD"; - case AC_JACK_SPDIF_IN: - return "SPDIF In"; - case AC_JACK_DIG_OTHER_IN: - return "Digital In"; - default: - return "Misc"; - } -} - -/* Check whether the location prefix needs to be added to the label. - * If all mic-jacks are in the same location (e.g. rear panel), we don't - * have to put "Front" prefix to each label. In such a case, returns false. - */ -static int check_mic_location_need(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input) -{ - unsigned int defc; - int i, attr, attr2; - - defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); - attr = snd_hda_get_input_pin_attr(defc); - /* for internal or docking mics, we need locations */ - if (attr <= INPUT_PIN_ATTR_NORMAL) - return 1; - - attr = 0; - for (i = 0; i < cfg->num_inputs; i++) { - defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); - attr2 = snd_hda_get_input_pin_attr(defc); - if (attr2 >= INPUT_PIN_ATTR_NORMAL) { - if (attr && attr != attr2) - return 1; /* different locations found */ - attr = attr2; - } - } - return 0; -} - -/** - * hda_get_autocfg_input_label - Get a label for the given input - * - * Get a label for the given input pin defined by the autocfg item. - * Unlike hda_get_input_pin_label(), this function checks all inputs - * defined in autocfg and avoids the redundant mic/line prefix as much as - * possible. - */ -const char *hda_get_autocfg_input_label(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input) -{ - int type = cfg->inputs[input].type; - int has_multiple_pins = 0; - - if ((input > 0 && cfg->inputs[input - 1].type == type) || - (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) - has_multiple_pins = 1; - if (has_multiple_pins && type == AUTO_PIN_MIC) - has_multiple_pins &= check_mic_location_need(codec, cfg, input); - return hda_get_input_pin_label(codec, cfg->inputs[input].pin, - has_multiple_pins); -} -EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); - -/* return the position of NID in the list, or -1 if not found */ -static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) -{ - int i; - for (i = 0; i < nums; i++) - if (list[i] == nid) - return i; - return -1; -} - -/* get a unique suffix or an index number */ -static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, - int num_pins, int *indexp) -{ - static const char * const channel_sfx[] = { - " Front", " Surround", " CLFE", " Side" - }; - int i; - - i = find_idx_in_nid_list(nid, pins, num_pins); - if (i < 0) - return NULL; - if (num_pins == 1) - return ""; - if (num_pins > ARRAY_SIZE(channel_sfx)) { - if (indexp) - *indexp = i; - return ""; - } - return channel_sfx[i]; -} - -static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, - const char *name, char *label, int maxlen, - int *indexp) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - int attr = snd_hda_get_input_pin_attr(def_conf); - const char *pfx = "", *sfx = ""; - - /* handle as a speaker if it's a fixed line-out */ - if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT) - name = "Speaker"; - /* check the location */ - switch (attr) { - case INPUT_PIN_ATTR_DOCK: - pfx = "Dock "; - break; - case INPUT_PIN_ATTR_FRONT: - pfx = "Front "; - break; - } - if (cfg) { - /* try to give a unique suffix if needed */ - sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, - indexp); - if (!sfx) - sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, - indexp); - if (!sfx) { - /* don't add channel suffix for Headphone controls */ - int idx = find_idx_in_nid_list(nid, cfg->hp_pins, - cfg->hp_outs); - if (idx >= 0) - *indexp = idx; - sfx = ""; - } - } - snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); - return 1; -} - -/** - * snd_hda_get_pin_label - Get a label for the given I/O pin - * - * Get a label for the given pin. This function works for both input and - * output pins. When @cfg is given as non-NULL, the function tries to get - * an optimized label using hda_get_autocfg_input_label(). - * - * This function tries to give a unique label string for the pin as much as - * possible. For example, when the multiple line-outs are present, it adds - * the channel suffix like "Front", "Surround", etc (only when @cfg is given). - * If no unique name with a suffix is available and @indexp is non-NULL, the - * index number is stored in the pointer. - */ -int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, - char *label, int maxlen, int *indexp) -{ - unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); - const char *name = NULL; - int i; - - if (indexp) - *indexp = 0; - if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) - return 0; - - switch (get_defcfg_device(def_conf)) { - case AC_JACK_LINE_OUT: - return fill_audio_out_name(codec, nid, cfg, "Line Out", - label, maxlen, indexp); - case AC_JACK_SPEAKER: - return fill_audio_out_name(codec, nid, cfg, "Speaker", - label, maxlen, indexp); - case AC_JACK_HP_OUT: - return fill_audio_out_name(codec, nid, cfg, "Headphone", - label, maxlen, indexp); - case AC_JACK_SPDIF_OUT: - case AC_JACK_DIG_OTHER_OUT: - if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) - name = "HDMI"; - else - name = "SPDIF"; - if (cfg && indexp) { - i = find_idx_in_nid_list(nid, cfg->dig_out_pins, - cfg->dig_outs); - if (i >= 0) - *indexp = i; - } - break; - default: - if (cfg) { - for (i = 0; i < cfg->num_inputs; i++) { - if (cfg->inputs[i].pin != nid) - continue; - name = hda_get_autocfg_input_label(codec, cfg, i); - if (name) - break; - } - } - if (!name) - name = hda_get_input_pin_label(codec, nid, true); - break; - } - if (!name) - return 0; - strlcpy(label, name, maxlen); - return 1; -} -EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); - -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list) -{ - const struct hda_verb **v; - snd_array_init(&spec->verbs, sizeof(struct hda_verb *), 8); - v = snd_array_new(&spec->verbs); - if (!v) - return -ENOMEM; - *v = list; - return 0; -} -EXPORT_SYMBOL_HDA(snd_hda_gen_add_verbs); - -void snd_hda_gen_apply_verbs(struct hda_codec *codec) -{ - struct hda_gen_spec *spec = codec->spec; - int i; - for (i = 0; i < spec->verbs.used; i++) { - struct hda_verb **v = snd_array_elem(&spec->verbs, i); - snd_hda_sequence_write(codec, *v); - } -} -EXPORT_SYMBOL_HDA(snd_hda_gen_apply_verbs); - -void snd_hda_apply_pincfgs(struct hda_codec *codec, - const struct hda_pintbl *cfg) -{ - for (; cfg->nid; cfg++) - snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); -} -EXPORT_SYMBOL_HDA(snd_hda_apply_pincfgs); - -void snd_hda_apply_fixup(struct hda_codec *codec, int action) -{ - struct hda_gen_spec *spec = codec->spec; - int id = spec->fixup_id; -#ifdef CONFIG_SND_DEBUG_VERBOSE - const char *modelname = spec->fixup_name; -#endif - int depth = 0; - - if (!spec->fixup_list) - return; - - while (id >= 0) { - const struct hda_fixup *fix = spec->fixup_list + id; - - switch (fix->type) { - case HDA_FIXUP_PINS: - if (action != HDA_FIXUP_ACT_PRE_PROBE || !fix->v.pins) - break; - snd_printdd(KERN_INFO SFX - "%s: Apply pincfg for %s\n", - codec->chip_name, modelname); - snd_hda_apply_pincfgs(codec, fix->v.pins); - break; - case HDA_FIXUP_VERBS: - if (action != HDA_FIXUP_ACT_PROBE || !fix->v.verbs) - break; - snd_printdd(KERN_INFO SFX - "%s: Apply fix-verbs for %s\n", - codec->chip_name, modelname); - snd_hda_gen_add_verbs(codec->spec, fix->v.verbs); - break; - case HDA_FIXUP_FUNC: - if (!fix->v.func) - break; - snd_printdd(KERN_INFO SFX - "%s: Apply fix-func for %s\n", - codec->chip_name, modelname); - fix->v.func(codec, fix, action); - break; - default: - snd_printk(KERN_ERR SFX - "%s: Invalid fixup type %d\n", - codec->chip_name, fix->type); - break; - } - if (!fix->chained) - break; - if (++depth > 10) - break; - id = fix->chain_id; - } -} -EXPORT_SYMBOL_HDA(snd_hda_apply_fixup); - -void snd_hda_pick_fixup(struct hda_codec *codec, - const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, - const struct hda_fixup *fixlist) -{ - struct hda_gen_spec *spec = codec->spec; - const struct snd_pci_quirk *q; - int id = -1; - const char *name = NULL; - - /* when model=nofixup is given, don't pick up any fixups */ - if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { - spec->fixup_list = NULL; - spec->fixup_id = -1; - return; - } - - if (codec->modelname && models) { - while (models->name) { - if (!strcmp(codec->modelname, models->name)) { - id = models->id; - name = models->name; - break; - } - models++; - } - } - if (id < 0) { - q = snd_pci_quirk_lookup(codec->bus->pci, quirk); - if (q) { - id = q->value; -#ifdef CONFIG_SND_DEBUG_VERBOSE - name = q->name; -#endif - } - } - if (id < 0) { - for (q = quirk; q->subvendor; q++) { - unsigned int vendorid = - q->subdevice | (q->subvendor << 16); - if (vendorid == codec->subsystem_id) { - id = q->value; -#ifdef CONFIG_SND_DEBUG_VERBOSE - name = q->name; -#endif - break; - } - } - } - - spec->fixup_id = id; - if (id >= 0) { - spec->fixup_list = fixlist; - spec->fixup_name = name; - } -} -EXPORT_SYMBOL_HDA(snd_hda_pick_fixup); diff --git a/trunk/sound/pci/hda/hda_auto_parser.h b/trunk/sound/pci/hda/hda_auto_parser.h deleted file mode 100644 index 2a7889dfbd1b..000000000000 --- a/trunk/sound/pci/hda/hda_auto_parser.h +++ /dev/null @@ -1,160 +0,0 @@ -/* - * BIOS auto-parser helper functions for HD-audio - * - * Copyright (c) 2012 Takashi Iwai - * - * This driver is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef __SOUND_HDA_AUTO_PARSER_H -#define __SOUND_HDA_AUTO_PARSER_H - -/* - * Helper for automatic pin configuration - */ - -enum { - AUTO_PIN_MIC, - AUTO_PIN_LINE_IN, - AUTO_PIN_CD, - AUTO_PIN_AUX, - AUTO_PIN_LAST -}; - -enum { - AUTO_PIN_LINE_OUT, - AUTO_PIN_SPEAKER_OUT, - AUTO_PIN_HP_OUT -}; - -#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS -#define AUTO_CFG_MAX_INS 8 - -struct auto_pin_cfg_item { - hda_nid_t pin; - int type; -}; - -struct auto_pin_cfg; -const char *hda_get_autocfg_input_label(struct hda_codec *codec, - const struct auto_pin_cfg *cfg, - int input); -int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, - const struct auto_pin_cfg *cfg, - char *label, int maxlen, int *indexp); - -enum { - INPUT_PIN_ATTR_UNUSED, /* pin not connected */ - INPUT_PIN_ATTR_INT, /* internal mic/line-in */ - INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ - INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ - INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ - INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ -}; - -int snd_hda_get_input_pin_attr(unsigned int def_conf); - -struct auto_pin_cfg { - int line_outs; - /* sorted in the order of Front/Surr/CLFE/Side */ - hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS]; - int speaker_outs; - hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS]; - int hp_outs; - int line_out_type; /* AUTO_PIN_XXX_OUT */ - hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; - int num_inputs; - struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; - int dig_outs; - hda_nid_t dig_out_pins[2]; - hda_nid_t dig_in_pin; - hda_nid_t mono_out_pin; - int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */ - int dig_in_type; /* HDA_PCM_TYPE_XXX */ -}; - -/* bit-flags for snd_hda_parse_pin_def_config() behavior */ -#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ -#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ - -int snd_hda_parse_pin_defcfg(struct hda_codec *codec, - struct auto_pin_cfg *cfg, - const hda_nid_t *ignore_nids, - unsigned int cond_flags); - -/* older function */ -#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ - snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) - -/* - */ - -struct hda_gen_spec { - /* fix-up list */ - int fixup_id; - const struct hda_fixup *fixup_list; - const char *fixup_name; - - /* additional init verbs */ - struct snd_array verbs; -}; - - -/* - * Fix-up pin default configurations and add default verbs - */ - -struct hda_pintbl { - hda_nid_t nid; - u32 val; -}; - -struct hda_model_fixup { - const int id; - const char *name; -}; - -struct hda_fixup { - int type; - bool chained; - int chain_id; - union { - const struct hda_pintbl *pins; - const struct hda_verb *verbs; - void (*func)(struct hda_codec *codec, - const struct hda_fixup *fix, - int action); - } v; -}; - -/* fixup types */ -enum { - HDA_FIXUP_INVALID, - HDA_FIXUP_PINS, - HDA_FIXUP_VERBS, - HDA_FIXUP_FUNC, -}; - -/* fixup action definitions */ -enum { - HDA_FIXUP_ACT_PRE_PROBE, - HDA_FIXUP_ACT_PROBE, - HDA_FIXUP_ACT_INIT, - HDA_FIXUP_ACT_BUILD, -}; - -int snd_hda_gen_add_verbs(struct hda_gen_spec *spec, - const struct hda_verb *list); -void snd_hda_gen_apply_verbs(struct hda_codec *codec); -void snd_hda_apply_pincfgs(struct hda_codec *codec, - const struct hda_pintbl *cfg); -void snd_hda_apply_fixup(struct hda_codec *codec, int action); -void snd_hda_pick_fixup(struct hda_codec *codec, - const struct hda_model_fixup *models, - const struct snd_pci_quirk *quirk, - const struct hda_fixup *fixlist); - -#endif /* __SOUND_HDA_AUTO_PARSER_H */ diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index eb09a3348325..841475cc13b6 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -334,67 +334,78 @@ static hda_nid_t *lookup_conn_list(struct snd_array *array, hda_nid_t nid) return NULL; } -/* read the connection and add to the cache */ -static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid) -{ - hda_nid_t list[HDA_MAX_CONNECTIONS]; - int len; - - len = snd_hda_get_raw_connections(codec, nid, list, ARRAY_SIZE(list)); - if (len < 0) - return len; - return snd_hda_override_conn_list(codec, nid, len, list); -} - /** - * snd_hda_get_connections - copy connection list + * snd_hda_get_conn_list - get connection list * @codec: the HDA codec * @nid: NID to parse - * @conn_list: connection list array; when NULL, checks only the size - * @max_conns: max. number of connections to store + * @listp: the pointer to store NID list * * Parses the connection list of the given widget and stores the list * of NIDs. * * Returns the number of connections, or a negative error code. */ -int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, - hda_nid_t *conn_list, int max_conns) +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp) { struct snd_array *array = &codec->conn_lists; - int len; + int len, err; + hda_nid_t list[HDA_MAX_CONNECTIONS]; hda_nid_t *p; bool added = false; again: - mutex_lock(&codec->hash_mutex); - len = -1; /* if the connection-list is already cached, read it */ p = lookup_conn_list(array, nid); if (p) { - len = p[1]; - if (conn_list && len > max_conns) { - snd_printk(KERN_ERR "hda_codec: " - "Too many connections %d for NID 0x%x\n", - len, nid); - mutex_unlock(&codec->hash_mutex); - return -EINVAL; - } - if (conn_list && len) - memcpy(conn_list, p + 2, len * sizeof(hda_nid_t)); + if (listp) + *listp = p + 2; + return p[1]; } - mutex_unlock(&codec->hash_mutex); - if (len >= 0) - return len; if (snd_BUG_ON(added)) return -EINVAL; - len = read_and_add_raw_conns(codec, nid); + /* read the connection and add to the cache */ + len = snd_hda_get_raw_connections(codec, nid, list, HDA_MAX_CONNECTIONS); if (len < 0) return len; + err = snd_hda_override_conn_list(codec, nid, len, list); + if (err < 0) + return err; added = true; goto again; } +EXPORT_SYMBOL_HDA(snd_hda_get_conn_list); + +/** + * snd_hda_get_connections - copy connection list + * @codec: the HDA codec + * @nid: NID to parse + * @conn_list: connection list array + * @max_conns: max. number of connections to store + * + * Parses the connection list of the given widget and stores the list + * of NIDs. + * + * Returns the number of connections, or a negative error code. + */ +int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, + hda_nid_t *conn_list, int max_conns) +{ + const hda_nid_t *list; + int len = snd_hda_get_conn_list(codec, nid, &list); + + if (len <= 0) + return len; + if (len > max_conns) { + snd_printk(KERN_ERR "hda_codec: " + "Too many connections %d for NID 0x%x\n", + len, nid); + return -EINVAL; + } + memcpy(conn_list, list, len * sizeof(hda_nid_t)); + return len; +} EXPORT_SYMBOL_HDA(snd_hda_get_connections); /** @@ -532,7 +543,6 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, hda_nid_t *p; int i, old_used; - mutex_lock(&codec->hash_mutex); p = lookup_conn_list(array, nid); if (p) *p = -1; /* invalidate the old entry */ @@ -543,12 +553,10 @@ int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int len, for (i = 0; i < len; i++) if (!add_conn_list(array, list[i])) goto error_add; - mutex_unlock(&codec->hash_mutex); return 0; error_add: array->used = old_used; - mutex_unlock(&codec->hash_mutex); return -ENOMEM; } EXPORT_SYMBOL_HDA(snd_hda_override_conn_list); @@ -1247,7 +1255,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, codec->addr = codec_addr; mutex_init(&codec->spdif_mutex); mutex_init(&codec->control_mutex); - mutex_init(&codec->hash_mutex); init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); @@ -1257,9 +1264,15 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, snd_array_init(&codec->cvt_setups, sizeof(struct hda_cvt_setup), 8); snd_array_init(&codec->conn_lists, sizeof(hda_nid_t), 64); snd_array_init(&codec->spdif_out, sizeof(struct hda_spdif_out), 16); + if (codec->bus->modelname) { + codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); + if (!codec->modelname) { + snd_hda_codec_free(codec); + return -ENODEV; + } + } #ifdef CONFIG_SND_HDA_POWER_SAVE - spin_lock_init(&codec->power_lock); INIT_DELAYED_WORK(&codec->power_work, hda_power_work); /* snd_hda_codec_new() marks the codec as power-up, and leave it as is. * the caller has to power down appropriatley after initialization @@ -1268,14 +1281,6 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, hda_keep_power_on(codec); #endif - if (codec->bus->modelname) { - codec->modelname = kstrdup(codec->bus->modelname, GFP_KERNEL); - if (!codec->modelname) { - snd_hda_codec_free(codec); - return -ENODEV; - } - } - list_add_tail(&codec->list, &bus->codec_list); bus->caddr_tbl[codec_addr] = codec; @@ -1598,60 +1603,6 @@ get_alloc_amp_hash(struct hda_codec *codec, u32 key) return (struct hda_amp_info *)get_alloc_hash(&codec->amp_cache, key); } -/* overwrite the value with the key in the caps hash */ -static int write_caps_hash(struct hda_codec *codec, u32 key, unsigned int val) -{ - struct hda_amp_info *info; - - mutex_lock(&codec->hash_mutex); - info = get_alloc_amp_hash(codec, key); - if (!info) { - mutex_unlock(&codec->hash_mutex); - return -EINVAL; - } - info->amp_caps = val; - info->head.val |= INFO_AMP_CAPS; - mutex_unlock(&codec->hash_mutex); - return 0; -} - -/* query the value from the caps hash; if not found, fetch the current - * value from the given function and store in the hash - */ -static unsigned int -query_caps_hash(struct hda_codec *codec, hda_nid_t nid, int dir, u32 key, - unsigned int (*func)(struct hda_codec *, hda_nid_t, int)) -{ - struct hda_amp_info *info; - unsigned int val; - - mutex_lock(&codec->hash_mutex); - info = get_alloc_amp_hash(codec, key); - if (!info) { - mutex_unlock(&codec->hash_mutex); - return 0; - } - if (!(info->head.val & INFO_AMP_CAPS)) { - mutex_unlock(&codec->hash_mutex); /* for reentrance */ - val = func(codec, nid, dir); - write_caps_hash(codec, key, val); - } else { - val = info->amp_caps; - mutex_unlock(&codec->hash_mutex); - } - return val; -} - -static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid, - int direction) -{ - if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) - nid = codec->afg; - return snd_hda_param_read(codec, nid, - direction == HDA_OUTPUT ? - AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP); -} - /** * query_amp_caps - query AMP capabilities * @codec: the HD-auio codec @@ -1666,9 +1617,22 @@ static unsigned int read_amp_cap(struct hda_codec *codec, hda_nid_t nid, */ u32 query_amp_caps(struct hda_codec *codec, hda_nid_t nid, int direction) { - return query_caps_hash(codec, nid, direction, - HDA_HASH_KEY(nid, direction, 0), - read_amp_cap); + struct hda_amp_info *info; + + info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, 0)); + if (!info) + return 0; + if (!(info->head.val & INFO_AMP_CAPS)) { + if (!(get_wcaps(codec, nid) & AC_WCAP_AMP_OVRD)) + nid = codec->afg; + info->amp_caps = snd_hda_param_read(codec, nid, + direction == HDA_OUTPUT ? + AC_PAR_AMP_OUT_CAP : + AC_PAR_AMP_IN_CAP); + if (info->amp_caps) + info->head.val |= INFO_AMP_CAPS; + } + return info->amp_caps; } EXPORT_SYMBOL_HDA(query_amp_caps); @@ -1688,12 +1652,34 @@ EXPORT_SYMBOL_HDA(query_amp_caps); int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int caps) { - return write_caps_hash(codec, HDA_HASH_KEY(nid, dir, 0), caps); + struct hda_amp_info *info; + + info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, dir, 0)); + if (!info) + return -EINVAL; + info->amp_caps = caps; + info->head.val |= INFO_AMP_CAPS; + return 0; } EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); -static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid, - int dir) +static unsigned int +query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, + unsigned int (*func)(struct hda_codec *, hda_nid_t)) +{ + struct hda_amp_info *info; + + info = get_alloc_amp_hash(codec, key); + if (!info) + return 0; + if (!info->head.val) { + info->head.val |= INFO_AMP_CAPS; + info->amp_caps = func(codec, nid); + } + return info->amp_caps; +} + +static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) { return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); } @@ -1711,7 +1697,7 @@ static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid, */ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) { - return query_caps_hash(codec, nid, 0, HDA_HASH_PINCAP_KEY(nid), + return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), read_pin_cap); } EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); @@ -1729,47 +1715,41 @@ EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); int snd_hda_override_pin_caps(struct hda_codec *codec, hda_nid_t nid, unsigned int caps) { - return write_caps_hash(codec, HDA_HASH_PINCAP_KEY(nid), caps); + struct hda_amp_info *info; + info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); + if (!info) + return -ENOMEM; + info->amp_caps = caps; + info->head.val |= INFO_AMP_CAPS; + return 0; } EXPORT_SYMBOL_HDA(snd_hda_override_pin_caps); -/* read or sync the hash value with the current value; - * call within hash_mutex +/* + * read the current volume to info + * if the cache exists, read the cache value. */ -static struct hda_amp_info * -update_amp_hash(struct hda_codec *codec, hda_nid_t nid, int ch, - int direction, int index) +static unsigned int get_vol_mute(struct hda_codec *codec, + struct hda_amp_info *info, hda_nid_t nid, + int ch, int direction, int index) { - struct hda_amp_info *info; - unsigned int parm, val = 0; - bool val_read = false; + u32 val, parm; - retry: - info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); - if (!info) - return NULL; - if (!(info->head.val & INFO_AMP_VOL(ch))) { - if (!val_read) { - mutex_unlock(&codec->hash_mutex); - parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; - parm |= direction == HDA_OUTPUT ? - AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; - parm |= index; - val = snd_hda_codec_read(codec, nid, 0, + if (info->head.val & INFO_AMP_VOL(ch)) + return info->vol[ch]; + + parm = ch ? AC_AMP_GET_RIGHT : AC_AMP_GET_LEFT; + parm |= direction == HDA_OUTPUT ? AC_AMP_GET_OUTPUT : AC_AMP_GET_INPUT; + parm |= index; + val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_AMP_GAIN_MUTE, parm); - val &= 0xff; - val_read = true; - mutex_lock(&codec->hash_mutex); - goto retry; - } - info->vol[ch] = val; - info->head.val |= INFO_AMP_VOL(ch); - } - return info; + info->vol[ch] = val & 0xff; + info->head.val |= INFO_AMP_VOL(ch); + return info->vol[ch]; } /* - * write the current volume in info to the h/w + * write the current volume in info to the h/w and update the cache */ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, hda_nid_t nid, int ch, int direction, int index, @@ -1786,6 +1766,7 @@ static void put_vol_mute(struct hda_codec *codec, struct hda_amp_info *info, else parm |= val; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, parm); + info->vol[ch] = val; } /** @@ -1802,14 +1783,10 @@ int snd_hda_codec_amp_read(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int index) { struct hda_amp_info *info; - unsigned int val = 0; - - mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, index); - if (info) - val = info->vol[ch]; - mutex_unlock(&codec->hash_mutex); - return val; + info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, index)); + if (!info) + return 0; + return get_vol_mute(codec, info, nid, ch, direction, index); } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_read); @@ -1831,23 +1808,15 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, { struct hda_amp_info *info; + info = get_alloc_amp_hash(codec, HDA_HASH_KEY(nid, direction, idx)); + if (!info) + return 0; if (snd_BUG_ON(mask & ~0xff)) mask &= 0xff; val &= mask; - - mutex_lock(&codec->hash_mutex); - info = update_amp_hash(codec, nid, ch, direction, idx); - if (!info) { - mutex_unlock(&codec->hash_mutex); - return 0; - } - val |= info->vol[ch] & ~mask; - if (info->vol[ch] == val) { - mutex_unlock(&codec->hash_mutex); + val |= get_vol_mute(codec, info, nid, ch, direction, idx) & ~mask; + if (info->vol[ch] == val) return 0; - } - info->vol[ch] = val; - mutex_unlock(&codec->hash_mutex); put_vol_mute(codec, info, nid, ch, direction, idx, val); return 1; } @@ -2294,10 +2263,7 @@ int snd_hda_codec_reset(struct hda_codec *codec) /* OK, let it free */ #ifdef CONFIG_SND_HDA_POWER_SAVE - cancel_delayed_work_sync(&codec->power_work); - codec->power_on = 0; - codec->power_transition = 0; - codec->power_jiffies = jiffies; + cancel_delayed_work(&codec->power_work); flush_workqueue(codec->bus->workq); #endif snd_hda_ctls_clear(codec); @@ -2893,15 +2859,12 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); ucontrol->value.iec958.status[0] = spdif->status & 0xff; ucontrol->value.iec958.status[1] = (spdif->status >> 8) & 0xff; ucontrol->value.iec958.status[2] = (spdif->status >> 16) & 0xff; ucontrol->value.iec958.status[3] = (spdif->status >> 24) & 0xff; - mutex_unlock(&codec->spdif_mutex); return 0; } @@ -2987,14 +2950,12 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - struct hda_spdif_out *spdif; - hda_nid_t nid; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); + hda_nid_t nid = spdif->nid; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); - nid = spdif->nid; spdif->status = ucontrol->value.iec958.status[0] | ((unsigned int)ucontrol->value.iec958.status[1] << 8) | ((unsigned int)ucontrol->value.iec958.status[2] << 16) | @@ -3016,12 +2977,9 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); - mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; - mutex_unlock(&codec->spdif_mutex); return 0; } @@ -3041,14 +2999,12 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, { struct hda_codec *codec = snd_kcontrol_chip(kcontrol); int idx = kcontrol->private_value; - struct hda_spdif_out *spdif; - hda_nid_t nid; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); + hda_nid_t nid = spdif->nid; unsigned short val; int change; mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); - nid = spdif->nid; val = spdif->ctls & ~AC_DIG1_ENABLE; if (ucontrol->value.integer.value[0]) val |= AC_DIG1_ENABLE; @@ -3136,9 +3092,6 @@ int snd_hda_create_spdif_out_ctls(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_out_ctls); -/* get the hda_spdif_out entry from the given NID - * call within spdif_mutex lock - */ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, hda_nid_t nid) { @@ -3155,10 +3108,9 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_out_of_nid); void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) { - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); spdif->nid = (u16)-1; mutex_unlock(&codec->spdif_mutex); } @@ -3166,11 +3118,10 @@ EXPORT_SYMBOL_HDA(snd_hda_spdif_ctls_unassign); void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) { - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = snd_array_elem(&codec->spdif_out, idx); unsigned short val; mutex_lock(&codec->spdif_mutex); - spdif = snd_array_elem(&codec->spdif_out, idx); if (spdif->nid != nid) { spdif->nid = nid; val = spdif->ctls; @@ -3535,14 +3486,11 @@ static void hda_call_codec_suspend(struct hda_codec *codec) codec->afg ? codec->afg : codec->mfg, AC_PWRST_D3); #ifdef CONFIG_SND_HDA_POWER_SAVE - cancel_delayed_work(&codec->power_work); - spin_lock(&codec->power_lock); snd_hda_update_power_acct(codec); - trace_hda_power_down(codec); + cancel_delayed_work(&codec->power_work); codec->power_on = 0; codec->power_transition = 0; codec->power_jiffies = jiffies; - spin_unlock(&codec->power_lock); #endif } @@ -3551,10 +3499,6 @@ static void hda_call_codec_suspend(struct hda_codec *codec) */ static void hda_call_codec_resume(struct hda_codec *codec) { - /* set as if powered on for avoiding re-entering the resume - * in the resume / power-save sequence - */ - hda_keep_power_on(codec); hda_set_power_state(codec, codec->afg ? codec->afg : codec->mfg, AC_PWRST_D0); @@ -3570,7 +3514,6 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_amp(codec); snd_hda_codec_resume_cache(codec); } - snd_hda_power_down(codec); /* flag down before returning */ } #endif /* CONFIG_PM */ @@ -3722,8 +3665,7 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, } EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); -static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid, - int dir) +static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) { unsigned int val = 0; if (nid != codec->afg && @@ -3738,12 +3680,11 @@ static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid, static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) { - return query_caps_hash(codec, nid, 0, HDA_HASH_PARPCM_KEY(nid), + return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), get_pcm_param); } -static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid, - int dir) +static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) { unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); if (!streams || streams == -1) @@ -3755,7 +3696,7 @@ static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid, static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) { - return query_caps_hash(codec, nid, 0, HDA_HASH_PARSTR_KEY(nid), + return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), get_stream_param); } @@ -3834,13 +3775,11 @@ int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, bps = 20; } } -#if 0 /* FIXME: CS4206 doesn't work, which is the only codec supporting float */ if (streams & AC_SUPFMT_FLOAT32) { formats |= SNDRV_PCM_FMTBIT_FLOAT_LE; if (!bps) bps = 32; } -#endif if (streams == AC_SUPFMT_AC3) { /* should be exclusive */ /* temporary hack: we have still no proper support @@ -4344,18 +4283,12 @@ static void hda_power_work(struct work_struct *work) container_of(work, struct hda_codec, power_work.work); struct hda_bus *bus = codec->bus; - spin_lock(&codec->power_lock); - if (codec->power_transition > 0) { /* during power-up sequence? */ - spin_unlock(&codec->power_lock); - return; - } if (!codec->power_on || codec->power_count) { codec->power_transition = 0; - spin_unlock(&codec->power_lock); return; } - spin_unlock(&codec->power_lock); + trace_hda_power_down(codec); hda_call_codec_suspend(codec); if (bus->ops.pm_notify) bus->ops.pm_notify(bus); @@ -4363,11 +4296,9 @@ static void hda_power_work(struct work_struct *work) static void hda_keep_power_on(struct hda_codec *codec) { - spin_lock(&codec->power_lock); codec->power_count++; codec->power_on = 1; codec->power_jiffies = jiffies; - spin_unlock(&codec->power_lock); } /* update the power on/off account with the current jiffies */ @@ -4392,31 +4323,19 @@ void snd_hda_power_up(struct hda_codec *codec) { struct hda_bus *bus = codec->bus; - spin_lock(&codec->power_lock); codec->power_count++; - if (codec->power_on || codec->power_transition > 0) { - spin_unlock(&codec->power_lock); + if (codec->power_on || codec->power_transition) return; - } - spin_unlock(&codec->power_lock); - cancel_delayed_work_sync(&codec->power_work); - - spin_lock(&codec->power_lock); trace_hda_power_up(codec); snd_hda_update_power_acct(codec); codec->power_on = 1; codec->power_jiffies = jiffies; - codec->power_transition = 1; /* avoid reentrance */ - spin_unlock(&codec->power_lock); - if (bus->ops.pm_notify) bus->ops.pm_notify(bus); hda_call_codec_resume(codec); - - spin_lock(&codec->power_lock); + cancel_delayed_work(&codec->power_work); codec->power_transition = 0; - spin_unlock(&codec->power_lock); } EXPORT_SYMBOL_HDA(snd_hda_power_up); @@ -4432,18 +4351,14 @@ EXPORT_SYMBOL_HDA(snd_hda_power_up); */ void snd_hda_power_down(struct hda_codec *codec) { - spin_lock(&codec->power_lock); --codec->power_count; - if (!codec->power_on || codec->power_count || codec->power_transition) { - spin_unlock(&codec->power_lock); + if (!codec->power_on || codec->power_count || codec->power_transition) return; - } if (power_save(codec)) { - codec->power_transition = -1; /* avoid reentrance */ + codec->power_transition = 1; /* avoid reentrance */ queue_delayed_work(codec->bus->workq, &codec->power_work, msecs_to_jiffies(power_save(codec) * 1000)); } - spin_unlock(&codec->power_lock); } EXPORT_SYMBOL_HDA(snd_hda_power_down); @@ -4795,11 +4710,11 @@ int snd_hda_multi_out_analog_prepare(struct hda_codec *codec, { const hda_nid_t *nids = mout->dac_nids; int chs = substream->runtime->channels; - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = + snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); int i; mutex_lock(&codec->spdif_mutex); - spdif = snd_hda_spdif_out_of_nid(codec, mout->dig_out_nid); if (mout->dig_out_nid && mout->share_spdif && mout->dig_out_used != HDA_DIG_EXCLUSIVE) { if (chs == 2 && @@ -4880,58 +4795,601 @@ int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec, } EXPORT_SYMBOL_HDA(snd_hda_multi_out_analog_cleanup); +/* + * Helper for automatic pin configuration + */ + +static int is_in_nid_list(hda_nid_t nid, const hda_nid_t *list) +{ + for (; *list; list++) + if (*list == nid) + return 1; + return 0; +} + + +/* + * Sort an associated group of pins according to their sequence numbers. + */ +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]) { + seq = sequences[i]; + sequences[i] = sequences[j]; + sequences[j] = seq; + nid = pins[i]; + pins[i] = pins[j]; + pins[j] = nid; + } + } + } +} + + +/* add the found input-pin to the cfg->inputs[] table */ +static void add_auto_cfg_input_pin(struct auto_pin_cfg *cfg, hda_nid_t nid, + int type) +{ + if (cfg->num_inputs < AUTO_CFG_MAX_INS) { + cfg->inputs[cfg->num_inputs].pin = nid; + cfg->inputs[cfg->num_inputs].type = type; + cfg->num_inputs++; + } +} + +/* sort inputs in the order of AUTO_PIN_* type */ +static void sort_autocfg_input_pins(struct auto_pin_cfg *cfg) +{ + int i, j; + + for (i = 0; i < cfg->num_inputs; i++) { + for (j = i + 1; j < cfg->num_inputs; j++) { + if (cfg->inputs[i].type > cfg->inputs[j].type) { + struct auto_pin_cfg_item tmp; + tmp = cfg->inputs[i]; + cfg->inputs[i] = cfg->inputs[j]; + cfg->inputs[j] = tmp; + } + } + } +} + +/* Reorder the surround channels + * ALSA sequence is front/surr/clfe/side + * HDA sequence is: + * 4-ch: front/surr => OK as it is + * 6-ch: front/clfe/surr + * 8-ch: front/clfe/rear/side|fc + */ +static void reorder_outputs(unsigned int nums, hda_nid_t *pins) +{ + hda_nid_t nid; + + switch (nums) { + case 3: + case 4: + nid = pins[1]; + pins[1] = pins[2]; + pins[2] = nid; + break; + } +} + +/* + * Parse all pin widgets and store the useful pin nids to cfg + * + * The number of line-outs or any primary output is stored in line_outs, + * and the corresponding output pins are assigned to line_out_pins[], + * in the order of front, rear, CLFE, side, ... + * + * If more extra outputs (speaker and headphone) are found, the pins are + * assisnged to hp_pins[] and speaker_pins[], respectively. If no line-out jack + * 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 inputs array. + * The digital input/output pins are assigned to dig_in_pin and dig_out_pin, + * respectively. + */ +int snd_hda_parse_pin_defcfg(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids, + unsigned int cond_flags) +{ + hda_nid_t nid, end_nid; + short seq, assoc_line_out; + short sequences_line_out[ARRAY_SIZE(cfg->line_out_pins)]; + short sequences_speaker[ARRAY_SIZE(cfg->speaker_pins)]; + short sequences_hp[ARRAY_SIZE(cfg->hp_pins)]; + int i; + + memset(cfg, 0, sizeof(*cfg)); + + memset(sequences_line_out, 0, sizeof(sequences_line_out)); + memset(sequences_speaker, 0, sizeof(sequences_speaker)); + memset(sequences_hp, 0, sizeof(sequences_hp)); + assoc_line_out = 0; + + codec->ignore_misc_bit = true; + end_nid = codec->start_nid + codec->num_nodes; + for (nid = codec->start_nid; nid < end_nid; nid++) { + unsigned int wid_caps = get_wcaps(codec, nid); + unsigned int wid_type = get_wcaps_type(wid_caps); + unsigned int def_conf; + short assoc, loc, conn, dev; + + /* read all default configuration for pin complex */ + if (wid_type != AC_WID_PIN) + continue; + /* ignore the given nids (e.g. pc-beep returns error) */ + if (ignore_nids && is_in_nid_list(nid, ignore_nids)) + continue; + + def_conf = snd_hda_codec_get_pincfg(codec, nid); + if (!(get_defcfg_misc(snd_hda_codec_get_pincfg(codec, nid)) & + AC_DEFCFG_MISC_NO_PRESENCE)) + codec->ignore_misc_bit = false; + conn = get_defcfg_connect(def_conf); + if (conn == AC_JACK_PORT_NONE) + continue; + loc = get_defcfg_location(def_conf); + dev = get_defcfg_device(def_conf); + + /* workaround for buggy BIOS setups */ + if (dev == AC_JACK_LINE_OUT) { + if (conn == AC_JACK_PORT_FIXED) + dev = AC_JACK_SPEAKER; + } + + switch (dev) { + case AC_JACK_LINE_OUT: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + + if (!(wid_caps & AC_WCAP_STEREO)) + if (!cfg->mono_out_pin) + cfg->mono_out_pin = nid; + if (!assoc) + continue; + if (!assoc_line_out) + assoc_line_out = assoc; + else if (assoc_line_out != assoc) + continue; + if (cfg->line_outs >= ARRAY_SIZE(cfg->line_out_pins)) + continue; + cfg->line_out_pins[cfg->line_outs] = nid; + sequences_line_out[cfg->line_outs] = seq; + cfg->line_outs++; + break; + case AC_JACK_SPEAKER: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (cfg->speaker_outs >= ARRAY_SIZE(cfg->speaker_pins)) + continue; + cfg->speaker_pins[cfg->speaker_outs] = nid; + sequences_speaker[cfg->speaker_outs] = (assoc << 4) | seq; + cfg->speaker_outs++; + break; + case AC_JACK_HP_OUT: + seq = get_defcfg_sequence(def_conf); + assoc = get_defcfg_association(def_conf); + if (cfg->hp_outs >= ARRAY_SIZE(cfg->hp_pins)) + continue; + cfg->hp_pins[cfg->hp_outs] = nid; + sequences_hp[cfg->hp_outs] = (assoc << 4) | seq; + cfg->hp_outs++; + break; + case AC_JACK_MIC_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_MIC); + break; + case AC_JACK_LINE_IN: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_LINE_IN); + break; + case AC_JACK_CD: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_CD); + break; + case AC_JACK_AUX: + add_auto_cfg_input_pin(cfg, nid, AUTO_PIN_AUX); + break; + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (cfg->dig_outs >= ARRAY_SIZE(cfg->dig_out_pins)) + continue; + cfg->dig_out_pins[cfg->dig_outs] = nid; + cfg->dig_out_type[cfg->dig_outs] = + (loc == AC_JACK_LOC_HDMI) ? + HDA_PCM_TYPE_HDMI : HDA_PCM_TYPE_SPDIF; + cfg->dig_outs++; + break; + case AC_JACK_SPDIF_IN: + case AC_JACK_DIG_OTHER_IN: + cfg->dig_in_pin = nid; + if (loc == AC_JACK_LOC_HDMI) + cfg->dig_in_type = HDA_PCM_TYPE_HDMI; + else + cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; + break; + } + } + + /* FIX-UP: + * If no line-out is defined but multiple HPs are found, + * some of them might be the real line-outs. + */ + if (!cfg->line_outs && cfg->hp_outs > 1 && + !(cond_flags & HDA_PINCFG_NO_HP_FIXUP)) { + int i = 0; + while (i < cfg->hp_outs) { + /* The real HPs should have the sequence 0x0f */ + if ((sequences_hp[i] & 0x0f) == 0x0f) { + i++; + continue; + } + /* Move it to the line-out table */ + cfg->line_out_pins[cfg->line_outs] = cfg->hp_pins[i]; + sequences_line_out[cfg->line_outs] = sequences_hp[i]; + cfg->line_outs++; + cfg->hp_outs--; + memmove(cfg->hp_pins + i, cfg->hp_pins + i + 1, + sizeof(cfg->hp_pins[0]) * (cfg->hp_outs - i)); + memmove(sequences_hp + i, sequences_hp + i + 1, + sizeof(sequences_hp[0]) * (cfg->hp_outs - i)); + } + memset(cfg->hp_pins + cfg->hp_outs, 0, + sizeof(hda_nid_t) * (AUTO_CFG_MAX_OUTS - cfg->hp_outs)); + if (!cfg->hp_outs) + cfg->line_out_type = AUTO_PIN_HP_OUT; + + } + + /* sort by sequence */ + sort_pins_by_sequence(cfg->line_out_pins, sequences_line_out, + cfg->line_outs); + sort_pins_by_sequence(cfg->speaker_pins, sequences_speaker, + cfg->speaker_outs); + sort_pins_by_sequence(cfg->hp_pins, sequences_hp, + cfg->hp_outs); + + /* + * FIX-UP: if no line-outs are detected, try to use speaker or HP pin + * as a primary output + */ + if (!cfg->line_outs && + !(cond_flags & HDA_PINCFG_NO_LO_FIXUP)) { + if (cfg->speaker_outs) { + cfg->line_outs = cfg->speaker_outs; + memcpy(cfg->line_out_pins, cfg->speaker_pins, + sizeof(cfg->speaker_pins)); + cfg->speaker_outs = 0; + memset(cfg->speaker_pins, 0, sizeof(cfg->speaker_pins)); + cfg->line_out_type = AUTO_PIN_SPEAKER_OUT; + } else if (cfg->hp_outs) { + cfg->line_outs = cfg->hp_outs; + memcpy(cfg->line_out_pins, cfg->hp_pins, + sizeof(cfg->hp_pins)); + cfg->hp_outs = 0; + memset(cfg->hp_pins, 0, sizeof(cfg->hp_pins)); + cfg->line_out_type = AUTO_PIN_HP_OUT; + } + } + + reorder_outputs(cfg->line_outs, cfg->line_out_pins); + reorder_outputs(cfg->hp_outs, cfg->hp_pins); + reorder_outputs(cfg->speaker_outs, cfg->speaker_pins); + + sort_autocfg_input_pins(cfg); + + /* + * debug prints of the parsed results + */ + snd_printd("autoconfig: line_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x) type:%s\n", + cfg->line_outs, cfg->line_out_pins[0], cfg->line_out_pins[1], + cfg->line_out_pins[2], cfg->line_out_pins[3], + cfg->line_out_pins[4], + cfg->line_out_type == AUTO_PIN_HP_OUT ? "hp" : + (cfg->line_out_type == AUTO_PIN_SPEAKER_OUT ? + "speaker" : "line")); + snd_printd(" speaker_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->speaker_outs, cfg->speaker_pins[0], + cfg->speaker_pins[1], cfg->speaker_pins[2], + cfg->speaker_pins[3], cfg->speaker_pins[4]); + snd_printd(" hp_outs=%d (0x%x/0x%x/0x%x/0x%x/0x%x)\n", + cfg->hp_outs, cfg->hp_pins[0], + cfg->hp_pins[1], cfg->hp_pins[2], + cfg->hp_pins[3], cfg->hp_pins[4]); + snd_printd(" mono: mono_out=0x%x\n", cfg->mono_out_pin); + if (cfg->dig_outs) + snd_printd(" dig-out=0x%x/0x%x\n", + cfg->dig_out_pins[0], cfg->dig_out_pins[1]); + snd_printd(" inputs:"); + for (i = 0; i < cfg->num_inputs; i++) { + snd_printd(" %s=0x%x", + hda_get_autocfg_input_label(codec, cfg, i), + cfg->inputs[i].pin); + } + snd_printd("\n"); + if (cfg->dig_in_pin) + snd_printd(" dig-in=0x%x\n", cfg->dig_in_pin); + + return 0; +} +EXPORT_SYMBOL_HDA(snd_hda_parse_pin_defcfg); + +int snd_hda_get_input_pin_attr(unsigned int def_conf) +{ + unsigned int loc = get_defcfg_location(def_conf); + unsigned int conn = get_defcfg_connect(def_conf); + if (conn == AC_JACK_PORT_NONE) + return INPUT_PIN_ATTR_UNUSED; + /* Windows may claim the internal mic to be BOTH, too */ + if (conn == AC_JACK_PORT_FIXED || conn == AC_JACK_PORT_BOTH) + return INPUT_PIN_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_INTERNAL) + return INPUT_PIN_ATTR_INT; + if ((loc & 0x30) == AC_JACK_LOC_SEPARATE) + return INPUT_PIN_ATTR_DOCK; + if (loc == AC_JACK_LOC_REAR) + return INPUT_PIN_ATTR_REAR; + if (loc == AC_JACK_LOC_FRONT) + return INPUT_PIN_ATTR_FRONT; + return INPUT_PIN_ATTR_NORMAL; +} +EXPORT_SYMBOL_HDA(snd_hda_get_input_pin_attr); + +/** + * hda_get_input_pin_label - Give a label for the given input pin + * + * When check_location is true, the function checks the pin location + * for mic and line-in pins, and set an appropriate prefix like "Front", + * "Rear", "Internal". + */ + +static const char *hda_get_input_pin_label(struct hda_codec *codec, + hda_nid_t pin, bool check_location) +{ + unsigned int def_conf; + static const char * const mic_names[] = { + "Internal Mic", "Dock Mic", "Mic", "Front Mic", "Rear Mic", + }; + int attr; + + def_conf = snd_hda_codec_get_pincfg(codec, pin); + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_MIC_IN: + if (!check_location) + return "Mic"; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + return mic_names[attr - 1]; + case AC_JACK_LINE_IN: + if (!check_location) + return "Line"; + attr = snd_hda_get_input_pin_attr(def_conf); + if (!attr) + return "None"; + if (attr == INPUT_PIN_ATTR_DOCK) + return "Dock Line"; + return "Line"; + case AC_JACK_AUX: + return "Aux"; + case AC_JACK_CD: + return "CD"; + case AC_JACK_SPDIF_IN: + return "SPDIF In"; + case AC_JACK_DIG_OTHER_IN: + return "Digital In"; + default: + return "Misc"; + } +} + +/* Check whether the location prefix needs to be added to the label. + * If all mic-jacks are in the same location (e.g. rear panel), we don't + * have to put "Front" prefix to each label. In such a case, returns false. + */ +static int check_mic_location_need(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) +{ + unsigned int defc; + int i, attr, attr2; + + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[input].pin); + attr = snd_hda_get_input_pin_attr(defc); + /* for internal or docking mics, we need locations */ + if (attr <= INPUT_PIN_ATTR_NORMAL) + return 1; + + attr = 0; + for (i = 0; i < cfg->num_inputs; i++) { + defc = snd_hda_codec_get_pincfg(codec, cfg->inputs[i].pin); + attr2 = snd_hda_get_input_pin_attr(defc); + if (attr2 >= INPUT_PIN_ATTR_NORMAL) { + if (attr && attr != attr2) + return 1; /* different locations found */ + attr = attr2; + } + } + return 0; +} + /** - * snd_hda_get_default_vref - Get the default (mic) VREF pin bits + * hda_get_autocfg_input_label - Get a label for the given input * - * Guess the suitable VREF pin bits to be set as the pin-control value. - * Note: the function doesn't set the AC_PINCTL_IN_EN bit. - */ -unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin) -{ - unsigned int pincap; - unsigned int oldval; - oldval = snd_hda_codec_read(codec, pin, 0, - AC_VERB_GET_PIN_WIDGET_CONTROL, 0); - pincap = snd_hda_query_pin_caps(codec, pin); - pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; - /* Exception: if the default pin setup is vref50, we give it priority */ - if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50) - return AC_PINCTL_VREF_80; - else if (pincap & AC_PINCAP_VREF_50) - return AC_PINCTL_VREF_50; - else if (pincap & AC_PINCAP_VREF_100) - return AC_PINCTL_VREF_100; - else if (pincap & AC_PINCAP_VREF_GRD) - return AC_PINCTL_VREF_GRD; - return AC_PINCTL_VREF_HIZ; -} -EXPORT_SYMBOL_HDA(snd_hda_get_default_vref); - -int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, - unsigned int val, bool cached) -{ - if (val) { - unsigned int cap = snd_hda_query_pin_caps(codec, pin); - if (cap && (val & AC_PINCTL_OUT_EN)) { - if (!(cap & AC_PINCAP_OUT)) - val &= ~(AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN); - else if ((val & AC_PINCTL_HP_EN) && - !(cap & AC_PINCAP_HP_DRV)) - val &= ~AC_PINCTL_HP_EN; + * Get a label for the given input pin defined by the autocfg item. + * Unlike hda_get_input_pin_label(), this function checks all inputs + * defined in autocfg and avoids the redundant mic/line prefix as much as + * possible. + */ +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input) +{ + int type = cfg->inputs[input].type; + int has_multiple_pins = 0; + + if ((input > 0 && cfg->inputs[input - 1].type == type) || + (input < cfg->num_inputs - 1 && cfg->inputs[input + 1].type == type)) + has_multiple_pins = 1; + if (has_multiple_pins && type == AUTO_PIN_MIC) + has_multiple_pins &= check_mic_location_need(codec, cfg, input); + return hda_get_input_pin_label(codec, cfg->inputs[input].pin, + has_multiple_pins); +} +EXPORT_SYMBOL_HDA(hda_get_autocfg_input_label); + +/* return the position of NID in the list, or -1 if not found */ +static int find_idx_in_nid_list(hda_nid_t nid, const hda_nid_t *list, int nums) +{ + int i; + for (i = 0; i < nums; i++) + if (list[i] == nid) + return i; + return -1; +} + +/* get a unique suffix or an index number */ +static const char *check_output_sfx(hda_nid_t nid, const hda_nid_t *pins, + int num_pins, int *indexp) +{ + static const char * const channel_sfx[] = { + " Front", " Surround", " CLFE", " Side" + }; + int i; + + i = find_idx_in_nid_list(nid, pins, num_pins); + if (i < 0) + return NULL; + if (num_pins == 1) + return ""; + if (num_pins > ARRAY_SIZE(channel_sfx)) { + if (indexp) + *indexp = i; + return ""; + } + return channel_sfx[i]; +} + +static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + const char *name, char *label, int maxlen, + int *indexp) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + int attr = snd_hda_get_input_pin_attr(def_conf); + const char *pfx = "", *sfx = ""; + + /* handle as a speaker if it's a fixed line-out */ + if (!strcmp(name, "Line Out") && attr == INPUT_PIN_ATTR_INT) + name = "Speaker"; + /* check the location */ + switch (attr) { + case INPUT_PIN_ATTR_DOCK: + pfx = "Dock "; + break; + case INPUT_PIN_ATTR_FRONT: + pfx = "Front "; + break; + } + if (cfg) { + /* try to give a unique suffix if needed */ + sfx = check_output_sfx(nid, cfg->line_out_pins, cfg->line_outs, + indexp); + if (!sfx) + sfx = check_output_sfx(nid, cfg->speaker_pins, cfg->speaker_outs, + indexp); + if (!sfx) { + /* don't add channel suffix for Headphone controls */ + int idx = find_idx_in_nid_list(nid, cfg->hp_pins, + cfg->hp_outs); + if (idx >= 0) + *indexp = idx; + sfx = ""; } - if (cap && (val & AC_PINCTL_IN_EN)) { - if (!(cap & AC_PINCAP_IN)) - val &= ~(AC_PINCTL_IN_EN | AC_PINCTL_VREFEN); + } + snprintf(label, maxlen, "%s%s%s", pfx, name, sfx); + return 1; +} + +/** + * snd_hda_get_pin_label - Get a label for the given I/O pin + * + * Get a label for the given pin. This function works for both input and + * output pins. When @cfg is given as non-NULL, the function tries to get + * an optimized label using hda_get_autocfg_input_label(). + * + * This function tries to give a unique label string for the pin as much as + * possible. For example, when the multiple line-outs are present, it adds + * the channel suffix like "Front", "Surround", etc (only when @cfg is given). + * If no unique name with a suffix is available and @indexp is non-NULL, the + * index number is stored in the pointer. + */ +int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + char *label, int maxlen, int *indexp) +{ + unsigned int def_conf = snd_hda_codec_get_pincfg(codec, nid); + const char *name = NULL; + int i; + + if (indexp) + *indexp = 0; + if (get_defcfg_connect(def_conf) == AC_JACK_PORT_NONE) + return 0; + + switch (get_defcfg_device(def_conf)) { + case AC_JACK_LINE_OUT: + return fill_audio_out_name(codec, nid, cfg, "Line Out", + label, maxlen, indexp); + case AC_JACK_SPEAKER: + return fill_audio_out_name(codec, nid, cfg, "Speaker", + label, maxlen, indexp); + case AC_JACK_HP_OUT: + return fill_audio_out_name(codec, nid, cfg, "Headphone", + label, maxlen, indexp); + case AC_JACK_SPDIF_OUT: + case AC_JACK_DIG_OTHER_OUT: + if (get_defcfg_location(def_conf) == AC_JACK_LOC_HDMI) + name = "HDMI"; + else + name = "SPDIF"; + if (cfg && indexp) { + i = find_idx_in_nid_list(nid, cfg->dig_out_pins, + cfg->dig_outs); + if (i >= 0) + *indexp = i; + } + break; + default: + if (cfg) { + for (i = 0; i < cfg->num_inputs; i++) { + if (cfg->inputs[i].pin != nid) + continue; + name = hda_get_autocfg_input_label(codec, cfg, i); + if (name) + break; + } } + if (!name) + name = hda_get_input_pin_label(codec, nid, true); + break; } - if (cached) - return snd_hda_codec_update_cache(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, val); - else - return snd_hda_codec_write(codec, pin, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, val); + if (!name) + return 0; + strlcpy(label, name, maxlen); + return 1; } -EXPORT_SYMBOL_HDA(_snd_hda_set_pin_ctl); +EXPORT_SYMBOL_HDA(snd_hda_get_pin_label); /** * snd_hda_add_imux_item - Add an item to input_mux @@ -4986,6 +5444,8 @@ int snd_hda_suspend(struct hda_bus *bus) list_for_each_entry(codec, &bus->codec_list, list) { if (hda_codec_is_power_on(codec)) hda_call_codec_suspend(codec); + if (codec->patch_ops.post_suspend) + codec->patch_ops.post_suspend(codec); } return 0; } @@ -5005,7 +5465,10 @@ int snd_hda_resume(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - hda_call_codec_resume(codec); + if (codec->patch_ops.pre_resume) + codec->patch_ops.pre_resume(codec); + if (snd_hda_codec_needs_resume(codec)) + hda_call_codec_resume(codec); } return 0; } diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index 54b52819fb47..56b4f74c0b13 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -704,6 +704,8 @@ struct hda_codec_ops { unsigned int power_state); #ifdef CONFIG_PM int (*suspend)(struct hda_codec *codec, pm_message_t state); + int (*post_suspend)(struct hda_codec *codec); + int (*pre_resume)(struct hda_codec *codec); int (*resume)(struct hda_codec *codec); #endif #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -827,7 +829,6 @@ struct hda_codec { struct mutex spdif_mutex; struct mutex control_mutex; - struct mutex hash_mutex; struct snd_array spdif_out; unsigned int spdif_in_enable; /* SPDIF input enable? */ const hda_nid_t *slave_dig_outs; /* optional digital out slave widgets */ @@ -860,13 +861,12 @@ struct hda_codec { unsigned int no_jack_detect:1; /* Machine has no jack-detection */ #ifdef CONFIG_SND_HDA_POWER_SAVE unsigned int power_on :1; /* current (global) power-state */ - int power_transition; /* power-state in transition */ + unsigned int power_transition :1; /* power-state in transition */ int power_count; /* current (global) power refcount */ struct delayed_work power_work; /* delayed task for powerdown */ unsigned long power_on_acct; unsigned long power_off_acct; unsigned long power_jiffies; - spinlock_t power_lock; #endif /* codec-specific additional proc output */ @@ -911,13 +911,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *start_id); int snd_hda_get_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); -static inline int -snd_hda_get_num_conns(struct hda_codec *codec, hda_nid_t nid) -{ - return snd_hda_get_connections(codec, nid, NULL, 0); -} int snd_hda_get_raw_connections(struct hda_codec *codec, hda_nid_t nid, hda_nid_t *conn_list, int max_conns); +int snd_hda_get_conn_list(struct hda_codec *codec, hda_nid_t nid, + const hda_nid_t **listp); int snd_hda_override_conn_list(struct hda_codec *codec, hda_nid_t nid, int nums, const hda_nid_t *list); int snd_hda_get_conn_index(struct hda_codec *codec, hda_nid_t mux, @@ -1054,10 +1051,12 @@ const char *snd_hda_get_jack_location(u32 cfg); #ifdef CONFIG_SND_HDA_POWER_SAVE void snd_hda_power_up(struct hda_codec *codec); void snd_hda_power_down(struct hda_codec *codec); +#define snd_hda_codec_needs_resume(codec) codec->power_count void snd_hda_update_power_acct(struct hda_codec *codec); #else static inline void snd_hda_power_up(struct hda_codec *codec) {} static inline void snd_hda_power_down(struct hda_codec *codec) {} +#define snd_hda_codec_needs_resume(codec) 1 #endif #ifdef CONFIG_SND_HDA_PATCH_LOADER diff --git a/trunk/sound/pci/hda/hda_intel.c b/trunk/sound/pci/hda/hda_intel.c index 4ab8102f87ea..1f350522bed4 100644 --- a/trunk/sound/pci/hda/hda_intel.c +++ b/trunk/sound/pci/hda/hda_intel.c @@ -497,7 +497,6 @@ enum { AZX_DRIVER_NVIDIA, AZX_DRIVER_TERA, AZX_DRIVER_CTX, - AZX_DRIVER_CTHDA, AZX_DRIVER_GENERIC, AZX_NUM_DRIVERS, /* keep this as last entry */ }; @@ -519,7 +518,6 @@ enum { #define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */ #define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */ #define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */ -#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */ /* quirks for ATI SB / AMD Hudson */ #define AZX_DCAPS_PRESET_ATI_SB \ @@ -535,9 +533,6 @@ enum { (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\ AZX_DCAPS_ALIGN_BUFSIZE) -#define AZX_DCAPS_PRESET_CTHDA \ - (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY) - static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_ICH] = "HDA Intel", [AZX_DRIVER_PCH] = "HDA Intel PCH", @@ -551,7 +546,6 @@ static char *driver_short_names[] __devinitdata = { [AZX_DRIVER_NVIDIA] = "HDA NVidia", [AZX_DRIVER_TERA] = "HDA Teradici", [AZX_DRIVER_CTX] = "HDA Creative", - [AZX_DRIVER_CTHDA] = "HDA Creative", [AZX_DRIVER_GENERIC] = "HD-Audio Generic", }; @@ -1291,8 +1285,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) /* * set up a BDL entry */ -static int setup_bdle(struct azx *chip, - struct snd_pcm_substream *substream, +static int setup_bdle(struct snd_pcm_substream *substream, struct azx_dev *azx_dev, u32 **bdlp, int ofs, int size, int with_ioc) { @@ -1311,12 +1304,6 @@ static int setup_bdle(struct azx *chip, bdl[1] = cpu_to_le32(upper_32_bits(addr)); /* program the size field of the BDL entry */ chunk = snd_pcm_sgbuf_get_chunk_size(substream, ofs, size); - /* one BDLE cannot cross 4K boundary on CTHDA chips */ - if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY) { - u32 remain = 0x1000 - (ofs & 0xfff); - if (chunk > remain) - chunk = remain; - } bdl[2] = cpu_to_le32(chunk); /* program the IOC to enable interrupt * only when the whole fragment is processed @@ -1369,7 +1356,7 @@ static int azx_setup_periods(struct azx *chip, bdl_pos_adj[chip->dev_index]); pos_adj = 0; } else { - ofs = setup_bdle(chip, substream, azx_dev, + ofs = setup_bdle(substream, azx_dev, &bdl, ofs, pos_adj, !substream->runtime->no_period_wakeup); if (ofs < 0) @@ -1379,10 +1366,10 @@ static int azx_setup_periods(struct azx *chip, pos_adj = 0; for (i = 0; i < periods; i++) { if (i == periods - 1 && pos_adj) - ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs, + ofs = setup_bdle(substream, azx_dev, &bdl, ofs, period_bytes - pos_adj, 0); else - ofs = setup_bdle(chip, substream, azx_dev, &bdl, ofs, + ofs = setup_bdle(substream, azx_dev, &bdl, ofs, period_bytes, !substream->runtime->no_period_wakeup); if (ofs < 0) @@ -2366,6 +2353,17 @@ static void azx_power_notify(struct hda_bus *bus) * power management */ +static int snd_hda_codecs_inuse(struct hda_bus *bus) +{ + struct hda_codec *codec; + + list_for_each_entry(codec, &bus->codec_list, list) { + if (snd_hda_codec_needs_resume(codec)) + return 1; + } + return 0; +} + static int azx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); @@ -2412,7 +2410,8 @@ static int azx_resume(struct pci_dev *pci) return -EIO; azx_init_pci(chip); - azx_init_chip(chip, 1); + if (snd_hda_codecs_inuse(chip->bus)) + azx_init_chip(chip, 1); snd_hda_resume(chip->bus); snd_power_change_state(card, SNDRV_CTL_POWER_D0); @@ -2566,8 +2565,6 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { /* forced codec slots */ SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103), SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), - /* WinFast VP200 H (Teradici) user reported broken communication */ - SND_PCI_QUIRK(0x3a21, 0x040d, "WinFast VP200 H", 0x101), {} }; @@ -3133,11 +3130,6 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { .driver_data = AZX_DRIVER_CTX | AZX_DCAPS_CTX_WORKAROUND | AZX_DCAPS_RIRB_PRE_DELAY | AZX_DCAPS_POSFIX_LPIB }, #endif - /* CTHDA chips */ - { PCI_DEVICE(0x1102, 0x0010), - .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, - { PCI_DEVICE(0x1102, 0x0012), - .driver_data = AZX_DRIVER_CTHDA | AZX_DCAPS_PRESET_CTHDA }, /* Vortex86MX */ { PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC }, /* VMware HDAudio */ @@ -3156,7 +3148,7 @@ static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { MODULE_DEVICE_TABLE(pci, azx_ids); /* pci_driver definition */ -static struct pci_driver azx_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = azx_ids, .probe = azx_probe, @@ -3167,4 +3159,15 @@ static struct pci_driver azx_driver = { #endif }; -module_pci_driver(azx_driver); +static int __init alsa_card_azx_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_azx_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_azx_init) +module_exit(alsa_card_azx_exit) diff --git a/trunk/sound/pci/hda/hda_jack.c b/trunk/sound/pci/hda/hda_jack.c index 2dd1c113a4c1..d68948499fbc 100644 --- a/trunk/sound/pci/hda/hda_jack.c +++ b/trunk/sound/pci/hda/hda_jack.c @@ -17,7 +17,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_jack.h" bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid) diff --git a/trunk/sound/pci/hda/hda_jack.h b/trunk/sound/pci/hda/hda_jack.h index 8ae52465ec5d..c66655cf413a 100644 --- a/trunk/sound/pci/hda/hda_jack.h +++ b/trunk/sound/pci/hda/hda_jack.h @@ -12,8 +12,6 @@ #ifndef __SOUND_HDA_JACK_H #define __SOUND_HDA_JACK_H -struct auto_pin_cfg; - struct hda_jack_tbl { hda_nid_t nid; unsigned char action; /* event action (0 = none) */ diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 9a096a8e0fc5..0ec9248165bc 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -262,8 +262,6 @@ int snd_hda_input_mux_put(struct hda_codec *codec, const struct hda_input_mux *imux, struct snd_ctl_elem_value *ucontrol, hda_nid_t nid, unsigned int *cur_val); -int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, - int index, int *type_index_ret); /* * Channel mode helper @@ -395,7 +393,72 @@ struct hda_bus_unsolicited { struct hda_bus *bus; }; -/* helper macros to retrieve pin default-config values */ +/* + * Helper for automatic pin configuration + */ + +enum { + AUTO_PIN_MIC, + AUTO_PIN_LINE_IN, + AUTO_PIN_CD, + AUTO_PIN_AUX, + AUTO_PIN_LAST +}; + +enum { + AUTO_PIN_LINE_OUT, + AUTO_PIN_SPEAKER_OUT, + AUTO_PIN_HP_OUT +}; + +#define AUTO_CFG_MAX_OUTS HDA_MAX_OUTS +#define AUTO_CFG_MAX_INS 8 + +struct auto_pin_cfg_item { + hda_nid_t pin; + int type; +}; + +struct auto_pin_cfg; +const char *hda_get_autocfg_input_label(struct hda_codec *codec, + const struct auto_pin_cfg *cfg, + int input); +int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid, + const struct auto_pin_cfg *cfg, + char *label, int maxlen, int *indexp); +int snd_hda_add_imux_item(struct hda_input_mux *imux, const char *label, + int index, int *type_index_ret); + +enum { + INPUT_PIN_ATTR_UNUSED, /* pin not connected */ + INPUT_PIN_ATTR_INT, /* internal mic/line-in */ + INPUT_PIN_ATTR_DOCK, /* docking mic/line-in */ + INPUT_PIN_ATTR_NORMAL, /* mic/line-in jack */ + INPUT_PIN_ATTR_FRONT, /* mic/line-in jack in front */ + INPUT_PIN_ATTR_REAR, /* mic/line-in jack in rear */ +}; + +int snd_hda_get_input_pin_attr(unsigned int def_conf); + +struct auto_pin_cfg { + int line_outs; + /* sorted in the order of Front/Surr/CLFE/Side */ + hda_nid_t line_out_pins[AUTO_CFG_MAX_OUTS]; + int speaker_outs; + hda_nid_t speaker_pins[AUTO_CFG_MAX_OUTS]; + int hp_outs; + int line_out_type; /* AUTO_PIN_XXX_OUT */ + hda_nid_t hp_pins[AUTO_CFG_MAX_OUTS]; + int num_inputs; + struct auto_pin_cfg_item inputs[AUTO_CFG_MAX_INS]; + int dig_outs; + hda_nid_t dig_out_pins[2]; + hda_nid_t dig_in_pin; + hda_nid_t mono_out_pin; + int dig_out_type[2]; /* HDA_PCM_TYPE_XXX */ + int dig_in_type; /* HDA_PCM_TYPE_XXX */ +}; + #define get_defcfg_connect(cfg) \ ((cfg & AC_DEFCFG_PORT_CONN) >> AC_DEFCFG_PORT_CONN_SHIFT) #define get_defcfg_association(cfg) \ @@ -409,6 +472,19 @@ struct hda_bus_unsolicited { #define get_defcfg_misc(cfg) \ ((cfg & AC_DEFCFG_MISC) >> AC_DEFCFG_MISC_SHIFT) +/* bit-flags for snd_hda_parse_pin_def_config() behavior */ +#define HDA_PINCFG_NO_HP_FIXUP (1 << 0) /* no HP-split */ +#define HDA_PINCFG_NO_LO_FIXUP (1 << 1) /* don't take other outs as LO */ + +int snd_hda_parse_pin_defcfg(struct hda_codec *codec, + struct auto_pin_cfg *cfg, + const hda_nid_t *ignore_nids, + unsigned int cond_flags); + +/* older function */ +#define snd_hda_parse_pin_def_config(codec, cfg, ignore) \ + snd_hda_parse_pin_defcfg(codec, cfg, ignore, 0) + /* amp values */ #define AMP_IN_MUTE(idx) (0x7080 | ((idx)<<8)) #define AMP_IN_UNMUTE(idx) (0x7000 | ((idx)<<8)) @@ -426,46 +502,6 @@ struct hda_bus_unsolicited { #define PIN_HP (AC_PINCTL_OUT_EN | AC_PINCTL_HP_EN) #define PIN_HP_AMP (AC_PINCTL_HP_EN) -unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin); -int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, - unsigned int val, bool cached); - -/** - * _snd_hda_set_pin_ctl - Set a pin-control value safely - * @codec: the codec instance - * @pin: the pin NID to set the control - * @val: the pin-control value (AC_PINCTL_* bits) - * - * This function sets the pin-control value to the given pin, but - * filters out the invalid pin-control bits when the pin has no such - * capabilities. For example, when PIN_HP is passed but the pin has no - * HP-drive capability, the HP bit is omitted. - * - * The function doesn't check the input VREF capability bits, though. - * Use snd_hda_get_default_vref() to guess the right value. - * Also, this function is only for analog pins, not for HDMI pins. - */ -static inline int -snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin, unsigned int val) -{ - return _snd_hda_set_pin_ctl(codec, pin, val, false); -} - -/** - * snd_hda_set_pin_ctl_cache - Set a pin-control value safely - * @codec: the codec instance - * @pin: the pin NID to set the control - * @val: the pin-control value (AC_PINCTL_* bits) - * - * Just like snd_hda_set_pin_ctl() but write to cache as well. - */ -static inline int -snd_hda_set_pin_ctl_cache(struct hda_codec *codec, hda_nid_t pin, - unsigned int val) -{ - return _snd_hda_set_pin_ctl(codec, pin, val, true); -} - /* * get widget capabilities */ diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index d8b2d6dee986..7143393927da 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -28,7 +28,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" @@ -1743,7 +1742,9 @@ static int ad1981_hp_master_sw_put(struct snd_kcontrol *kcontrol, if (! ad198x_eapd_put(kcontrol, ucontrol)) return 0; /* change speaker pin appropriately */ - snd_hda_set_pin_ctl(codec, 0x05, spec->cur_eapd ? PIN_OUT : 0); + snd_hda_codec_write(codec, 0x05, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->cur_eapd ? PIN_OUT : 0); /* toggle HP mute appropriately */ snd_hda_codec_amp_stereo(codec, 0x06, HDA_OUTPUT, 0, HDA_AMP_MUTE, @@ -3102,7 +3103,7 @@ static void ad1988_auto_set_output_and_unmute(struct hda_codec *codec, int dac_idx) { /* set as output */ - snd_hda_set_pin_ctl(codec, nid, pin_type); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE); switch (nid) { case 0x11: /* port-A - DAC 03 */ @@ -3156,7 +3157,6 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) for (i = 0; i < cfg->num_inputs; i++) { hda_nid_t nid = cfg->inputs[i].pin; int type = cfg->inputs[i].type; - int val; switch (nid) { case 0x15: /* port-C */ snd_hda_codec_write(codec, 0x33, 0, AC_VERB_SET_CONNECT_SEL, 0x0); @@ -3165,10 +3165,8 @@ static void ad1988_auto_init_analog_input(struct hda_codec *codec) snd_hda_codec_write(codec, 0x34, 0, AC_VERB_SET_CONNECT_SEL, 0x0); break; } - val = PIN_IN; - if (type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + type == AUTO_PIN_MIC ? PIN_VREF80 : PIN_IN); if (nid != AD1988_PIN_CD_NID) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE); diff --git a/trunk/sound/pci/hda/patch_ca0110.c b/trunk/sound/pci/hda/patch_ca0110.c index 19ae14f739cb..09ccfabb4a17 100644 --- a/trunk/sound/pci/hda/patch_ca0110.c +++ b/trunk/sound/pci/hda/patch_ca0110.c @@ -26,7 +26,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" /* */ @@ -342,7 +341,8 @@ static int ca0110_build_pcms(struct hda_codec *codec) static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_HP); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -356,8 +356,8 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) { if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_IN | - snd_hda_get_default_vref(codec, pin)); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80); if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, diff --git a/trunk/sound/pci/hda/patch_ca0132.c b/trunk/sound/pci/hda/patch_ca0132.c index d0d3540e39e7..21d91d580da8 100644 --- a/trunk/sound/pci/hda/patch_ca0132.c +++ b/trunk/sound/pci/hda/patch_ca0132.c @@ -30,7 +30,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #define WIDGET_CHIP_CTRL 0x15 #define WIDGET_DSP_CTRL 0x16 @@ -240,7 +239,8 @@ enum get_set { static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) { if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_HP); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -254,8 +254,9 @@ static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) { if (pin) { - snd_hda_set_pin_ctl(codec, pin, PIN_IN | - snd_hda_get_default_vref(codec, pin)); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_VREF80); if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_AMP_GAIN_MUTE, diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index 9647ed4d7929..c83ccdba1e5a 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -26,7 +26,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_jack.h" #include @@ -934,7 +933,8 @@ static void cs_automute(struct hda_codec *codec) pin_ctl = 0; nid = cfg->speaker_pins[i]; - snd_hda_set_pin_ctl(codec, nid, pin_ctl); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_ctl); } if (spec->gpio_eapd_hp) { unsigned int gpio = hp_present ? @@ -948,14 +948,16 @@ static void cs_automute(struct hda_codec *codec) /* mute HPs if spdif jack (SENSE_B) is present */ for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, (spdif_present && spec->sense_b) ? 0 : PIN_HP); } /* SPDIF TX on/off */ if (cfg->dig_outs) { nid = cfg->dig_out_pins[0]; - snd_hda_set_pin_ctl(codec, nid, + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, spdif_present ? PIN_OUT : 0); } @@ -1022,11 +1024,13 @@ static void init_output(struct hda_codec *codec) /* set appropriate pin controls */ for (i = 0; i < cfg->line_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->line_out_pins[i], PIN_OUT); + snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); /* HP */ for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; - snd_hda_set_pin_ctl(codec, nid, PIN_HP); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (!cfg->speaker_outs) continue; if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { @@ -1037,7 +1041,8 @@ static void init_output(struct hda_codec *codec) /* Speaker */ for (i = 0; i < cfg->speaker_outs; i++) - snd_hda_set_pin_ctl(codec, cfg->speaker_pins[i], PIN_OUT); + snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); /* SPDIF is enabled on presence detect for CS421x */ if (spec->hp_detect || spec->spdif_detect) @@ -1058,9 +1063,14 @@ static void init_input(struct hda_codec *codec) continue; /* set appropriate pin control and mute first */ ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, ctl); + if (cfg->inputs[i].type == AUTO_PIN_MIC) { + unsigned int caps = snd_hda_query_pin_caps(codec, pin); + caps >>= AC_PINCAP_VREF_SHIFT; + if (caps & AC_PINCAP_VREF_80) + ctl = PIN_VREF80; + } + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); snd_hda_codec_write(codec, spec->adc_nid[i], 0, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(spec->adc_idx[i])); diff --git a/trunk/sound/pci/hda/patch_cmedia.c b/trunk/sound/pci/hda/patch_cmedia.c index c8fdaaefe702..b6767b4ced44 100644 --- a/trunk/sound/pci/hda/patch_cmedia.c +++ b/trunk/sound/pci/hda/patch_cmedia.c @@ -29,7 +29,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #define NUM_PINS 11 diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 3acb5824ad39..d906c5b74cf0 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -30,7 +30,6 @@ #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" @@ -67,7 +66,6 @@ struct imux_info { }; struct conexant_spec { - struct hda_gen_spec gen; const struct snd_kcontrol_new *mixers[5]; int num_mixers; @@ -143,7 +141,6 @@ struct conexant_spec { unsigned int hp_laptop:1; unsigned int asus:1; unsigned int pin_eapd_ctrls:1; - unsigned int fixup_stereo_dmic:1; unsigned int adc_switching:1; @@ -1604,13 +1601,17 @@ static void cxt5051_update_speaker(struct hda_codec *codec) unsigned int pinctl; /* headphone pin */ pinctl = (spec->hp_present && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x16, pinctl); + snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); /* speaker pin */ pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1a, pinctl); + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); /* on ideapad there is an additional speaker (subwoofer) to mute */ if (spec->ideapad) - snd_hda_set_pin_ctl(codec, 0x1b, pinctl); + snd_hda_codec_write(codec, 0x1b, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); } /* turn on/off EAPD (+ mute HP) as a master switch */ @@ -1995,7 +1996,8 @@ static void cxt5066_update_speaker(struct hda_codec *codec) /* Port A (HP) */ pinctl = (hp_port_a_present(spec) && spec->cur_eapd) ? PIN_HP : 0; - snd_hda_set_pin_ctl(codec, 0x19, pinctl); + snd_hda_codec_write(codec, 0x19, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); /* Port D (HP/LO) */ pinctl = spec->cur_eapd ? spec->port_d_mode : 0; @@ -2008,11 +2010,13 @@ static void cxt5066_update_speaker(struct hda_codec *codec) if (!hp_port_d_present(spec)) pinctl = 0; } - snd_hda_set_pin_ctl(codec, 0x1c, pinctl); + snd_hda_codec_write(codec, 0x1c, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); /* CLASS_D AMP */ pinctl = (!spec->hp_present && spec->cur_eapd) ? PIN_OUT : 0; - snd_hda_set_pin_ctl(codec, 0x1f, pinctl); + snd_hda_codec_write(codec, 0x1f, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pinctl); } /* turn on/off EAPD (+ mute HP) as a master switch */ @@ -2043,7 +2047,8 @@ static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) /* Even though port F is the DC input, the bias is controlled on port B. * we also leave that port as an active input (but unselected) in DC mode * just in case that is necessary to make the bias setting take effect. */ - return snd_hda_set_pin_ctl_cache(codec, 0x1a, + return snd_hda_codec_write_cache(codec, 0x1a, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); } @@ -2076,14 +2081,14 @@ static void cxt5066_olpc_select_mic(struct hda_codec *codec) } /* disable DC (port F) */ - snd_hda_set_pin_ctl(codec, 0x1e, 0); + snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); /* external mic, port B */ - snd_hda_set_pin_ctl(codec, 0x1a, + snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); /* internal mic, port C */ - snd_hda_set_pin_ctl(codec, 0x1b, + snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_present ? 0 : PIN_VREF80); } @@ -3352,7 +3357,9 @@ static void do_automute(struct hda_codec *codec, int num_pins, struct conexant_spec *spec = codec->spec; int i; for (i = 0; i < num_pins; i++) - snd_hda_set_pin_ctl(codec, pins[i], on ? PIN_OUT : 0); + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + on ? PIN_OUT : 0); if (spec->pin_eapd_ctrls) cx_auto_turn_eapd(codec, num_pins, pins, on); } @@ -3969,7 +3976,8 @@ static void cx_auto_init_output(struct hda_codec *codec) if (snd_hda_query_pin_caps(codec, cfg->hp_pins[i]) & AC_PINCAP_HP_DRV) val |= AC_PINCTL_HP_EN; - snd_hda_set_pin_ctl(codec, cfg->hp_pins[i], val); + snd_hda_codec_write(codec, cfg->hp_pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); } mute_outputs(codec, cfg->hp_outs, cfg->hp_pins); mute_outputs(codec, cfg->line_outs, cfg->line_out_pins); @@ -4022,11 +4030,13 @@ static void cx_auto_init_input(struct hda_codec *codec) } for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - unsigned int type = PIN_IN; + unsigned int type; if (cfg->inputs[i].type == AUTO_PIN_MIC) - type |= snd_hda_get_default_vref(codec, pin); - snd_hda_set_pin_ctl(codec, pin, type); + type = PIN_VREF80; + else + type = PIN_IN; + snd_hda_codec_write(codec, cfg->inputs[i].pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, type); } if (spec->auto_mic) { @@ -4053,9 +4063,11 @@ static void cx_auto_init_digital(struct hda_codec *codec) struct auto_pin_cfg *cfg = &spec->autocfg; if (spec->multiout.dig_out_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_out_pins[0], PIN_OUT); + snd_hda_codec_write(codec, cfg->dig_out_pins[0], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); if (spec->dig_in_nid) - snd_hda_set_pin_ctl(codec, cfg->dig_in_pin, PIN_IN); + snd_hda_codec_write(codec, cfg->dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); } static int cx_auto_init(struct hda_codec *codec) @@ -4072,9 +4084,9 @@ static int cx_auto_init(struct hda_codec *codec) static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, const char *dir, int cidx, - hda_nid_t nid, int hda_dir, int amp_idx, int chs) + hda_nid_t nid, int hda_dir, int amp_idx) { - static char name[44]; + static char name[32]; static struct snd_kcontrol_new knew[] = { HDA_CODEC_VOLUME(name, 0, 0, 0), HDA_CODEC_MUTE(name, 0, 0, 0), @@ -4084,7 +4096,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, for (i = 0; i < 2; i++) { struct snd_kcontrol *kctl; - knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, chs, amp_idx, + knew[i].private_value = HDA_COMPOSE_AMP_VAL(nid, 3, amp_idx, hda_dir); knew[i].subdevice = HDA_SUBDEV_AMP_FLAG; knew[i].index = cidx; @@ -4103,7 +4115,7 @@ static int cx_auto_add_volume_idx(struct hda_codec *codec, const char *basename, } #define cx_auto_add_volume(codec, str, dir, cidx, nid, hda_dir) \ - cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0, 3) + cx_auto_add_volume_idx(codec, str, dir, cidx, nid, hda_dir, 0) #define cx_auto_add_pb_volume(codec, nid, str, idx) \ cx_auto_add_volume(codec, str, " Playback", idx, nid, HDA_OUTPUT) @@ -4173,36 +4185,6 @@ static int cx_auto_build_output_controls(struct hda_codec *codec) return 0; } -/* Returns zero if this is a normal stereo channel, and non-zero if it should - be split in two independent channels. - dest_label must be at least 44 characters. */ -static int cx_auto_get_rightch_label(struct hda_codec *codec, const char *label, - char *dest_label, int nid) -{ - struct conexant_spec *spec = codec->spec; - int i; - - if (!spec->fixup_stereo_dmic) - return 0; - - for (i = 0; i < AUTO_CFG_MAX_INS; i++) { - int def_conf; - if (spec->autocfg.inputs[i].pin != nid) - continue; - - if (spec->autocfg.inputs[i].type != AUTO_PIN_MIC) - return 0; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) - return 0; - - /* Finally found the inverted internal mic! */ - snprintf(dest_label, 44, "Inverted %s", label); - return 1; - } - return 0; -} - static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, const char *label, const char *pfx, int cidx) @@ -4211,25 +4193,14 @@ static int cx_auto_add_capture_volume(struct hda_codec *codec, hda_nid_t nid, int i; for (i = 0; i < spec->num_adc_nids; i++) { - char rightch_label[44]; hda_nid_t adc_nid = spec->adc_nids[i]; int idx = get_input_connection(codec, adc_nid, nid); if (idx < 0) continue; if (codec->single_adc_amp) idx = 0; - - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - /* Make two independent kcontrols for left and right */ - int err = cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 2); - } return cx_auto_add_volume_idx(codec, label, pfx, - cidx, adc_nid, HDA_INPUT, idx, 3); + cidx, adc_nid, HDA_INPUT, idx); } return 0; } @@ -4242,19 +4213,9 @@ static int cx_auto_add_boost_volume(struct hda_codec *codec, int idx, int i, con; nid = spec->imux_info[idx].pin; - if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) { - char rightch_label[44]; - if (cx_auto_get_rightch_label(codec, label, rightch_label, nid)) { - int err = cx_auto_add_volume_idx(codec, label, " Boost", - cidx, nid, HDA_INPUT, 0, 1); - if (err < 0) - return err; - return cx_auto_add_volume_idx(codec, rightch_label, " Boost", - cidx, nid, HDA_INPUT, 0, 2); - } + if (get_wcaps(codec, nid) & AC_WCAP_IN_AMP) return cx_auto_add_volume(codec, label, " Boost", cidx, nid, HDA_INPUT); - } con = __select_input_connection(codec, spec->imux_info[idx].adc, nid, &mux, false, 0); if (con < 0) @@ -4409,21 +4370,37 @@ static const struct hda_codec_ops cx_auto_patch_ops = { /* * pin fix-up */ -enum { - CXT_PINCFG_LENOVO_X200, - CXT_PINCFG_LENOVO_TP410, - CXT_FIXUP_STEREO_DMIC, +struct cxt_pincfg { + hda_nid_t nid; + u32 val; }; -static void cxt_fixup_stereo_dmic(struct hda_codec *codec, - const struct hda_fixup *fix, int action) +static void apply_pincfg(struct hda_codec *codec, const struct cxt_pincfg *cfg) { - struct conexant_spec *spec = codec->spec; - spec->fixup_stereo_dmic = 1; + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); + } +static void apply_pin_fixup(struct hda_codec *codec, + const struct snd_pci_quirk *quirk, + const struct cxt_pincfg **table) +{ + quirk = snd_pci_quirk_lookup(codec->bus->pci, quirk); + if (quirk) { + snd_printdd(KERN_INFO "hda_codec: applying pincfg for %s\n", + quirk->name); + apply_pincfg(codec, table[quirk->value]); + } +} + +enum { + CXT_PINCFG_LENOVO_X200, + CXT_PINCFG_LENOVO_TP410, +}; + /* ThinkPad X200 & co with cxt5051 */ -static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { +static const struct cxt_pincfg cxt_pincfg_lenovo_x200[] = { { 0x16, 0x042140ff }, /* HP (seq# overridden) */ { 0x17, 0x21a11000 }, /* dock-mic */ { 0x19, 0x2121103f }, /* dock-HP */ @@ -4432,26 +4409,16 @@ static const struct hda_pintbl cxt_pincfg_lenovo_x200[] = { }; /* ThinkPad 410/420/510/520, X201 & co with cxt5066 */ -static const struct hda_pintbl cxt_pincfg_lenovo_tp410[] = { +static const struct cxt_pincfg cxt_pincfg_lenovo_tp410[] = { { 0x19, 0x042110ff }, /* HP (seq# overridden) */ { 0x1a, 0x21a190f0 }, /* dock-mic */ { 0x1c, 0x212140ff }, /* dock-HP */ {} }; -static const struct hda_fixup cxt_fixups[] = { - [CXT_PINCFG_LENOVO_X200] = { - .type = HDA_FIXUP_PINS, - .v.pins = cxt_pincfg_lenovo_x200, - }, - [CXT_PINCFG_LENOVO_TP410] = { - .type = HDA_FIXUP_PINS, - .v.pins = cxt_pincfg_lenovo_tp410, - }, - [CXT_FIXUP_STEREO_DMIC] = { - .type = HDA_FIXUP_FUNC, - .v.func = cxt_fixup_stereo_dmic, - }, +static const struct cxt_pincfg *cxt_pincfg_tbl[] = { + [CXT_PINCFG_LENOVO_X200] = cxt_pincfg_lenovo_x200, + [CXT_PINCFG_LENOVO_TP410] = cxt_pincfg_lenovo_tp410, }; static const struct snd_pci_quirk cxt5051_fixups[] = { @@ -4465,7 +4432,6 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { SND_PCI_QUIRK(0x17aa, 0x215f, "Lenovo T510", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21ce, "Lenovo T420", CXT_PINCFG_LENOVO_TP410), SND_PCI_QUIRK(0x17aa, 0x21cf, "Lenovo T520", CXT_PINCFG_LENOVO_TP410), - SND_PCI_QUIRK(0x17aa, 0x3975, "Lenovo U300s", CXT_FIXUP_STEREO_DMIC), {} }; @@ -4505,16 +4471,13 @@ static int patch_conexant_auto(struct hda_codec *codec) case 0x14f15051: add_cx5051_fake_mutes(codec); codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5051_fixups, cxt_fixups); + apply_pin_fixup(codec, cxt5051_fixups, cxt_pincfg_tbl); break; default: codec->pin_amp_workaround = 1; - snd_hda_pick_fixup(codec, NULL, cxt5066_fixups, cxt_fixups); - break; + apply_pin_fixup(codec, cxt5066_fixups, cxt_pincfg_tbl); } - snd_hda_apply_fixup(codec, HDA_FIXUP_ACT_PRE_PROBE); - /* Show mute-led control only on HP laptops * This is a sort of white-list: on HP laptops, EAPD corresponds * only to the mute-LED without actualy amp function. Meanwhile, @@ -4593,12 +4556,6 @@ static const struct hda_codec_preset snd_hda_preset_conexant[] = { .patch = patch_conexant_auto }, { .id = 0x14f150b9, .name = "CX20665", .patch = patch_conexant_auto }, - { .id = 0x14f1510f, .name = "CX20751/2", - .patch = patch_conexant_auto }, - { .id = 0x14f15110, .name = "CX20751/2", - .patch = patch_conexant_auto }, - { .id = 0x14f15111, .name = "CX20753/4", - .patch = patch_conexant_auto }, {} /* terminator */ }; @@ -4619,9 +4576,6 @@ MODULE_ALIAS("snd-hda-codec-id:14f150ab"); MODULE_ALIAS("snd-hda-codec-id:14f150ac"); MODULE_ALIAS("snd-hda-codec-id:14f150b8"); MODULE_ALIAS("snd-hda-codec-id:14f150b9"); -MODULE_ALIAS("snd-hda-codec-id:14f1510f"); -MODULE_ALIAS("snd-hda-codec-id:14f15110"); -MODULE_ALIAS("snd-hda-codec-id:14f15111"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Conexant HD-audio codec"); diff --git a/trunk/sound/pci/hda/patch_hdmi.c b/trunk/sound/pci/hda/patch_hdmi.c index ad319d4dc32f..83f345f3c961 100644 --- a/trunk/sound/pci/hda/patch_hdmi.c +++ b/trunk/sound/pci/hda/patch_hdmi.c @@ -1592,10 +1592,10 @@ static int nvhdmi_8ch_7x_pcm_prepare(struct hda_pcm_stream *hinfo, unsigned int dataDCC2, channel_id; int i; struct hdmi_spec *spec = codec->spec; - struct hda_spdif_out *spdif; + struct hda_spdif_out *spdif = + snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); mutex_lock(&codec->spdif_mutex); - spdif = snd_hda_spdif_out_of_nid(codec, spec->cvts[0].cvt_nid); chs = substream->runtime->channels; diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 3cb1f7128b5f..7810913d07a0 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -32,7 +32,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" @@ -67,6 +66,8 @@ struct alc_customize_define { unsigned int fixup:1; /* Means that this sku is set by driver, not read from hw */ }; +struct alc_fixup; + struct alc_multi_io { hda_nid_t pin; /* multi-io widget pin NID */ hda_nid_t dac; /* DAC to be connected */ @@ -81,33 +82,19 @@ enum { #define MAX_VOL_NIDS 0x40 -/* make compatible with old code */ -#define alc_apply_pincfgs snd_hda_apply_pincfgs -#define alc_apply_fixup snd_hda_apply_fixup -#define alc_pick_fixup snd_hda_pick_fixup -#define alc_fixup hda_fixup -#define alc_pincfg hda_pintbl -#define alc_model_fixup hda_model_fixup - -#define ALC_FIXUP_PINS HDA_FIXUP_PINS -#define ALC_FIXUP_VERBS HDA_FIXUP_VERBS -#define ALC_FIXUP_FUNC HDA_FIXUP_FUNC - -#define ALC_FIXUP_ACT_PRE_PROBE HDA_FIXUP_ACT_PRE_PROBE -#define ALC_FIXUP_ACT_PROBE HDA_FIXUP_ACT_PROBE -#define ALC_FIXUP_ACT_INIT HDA_FIXUP_ACT_INIT -#define ALC_FIXUP_ACT_BUILD HDA_FIXUP_ACT_BUILD - - struct alc_spec { - struct hda_gen_spec gen; - /* codec parameterization */ const struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ unsigned int num_mixers; const struct snd_kcontrol_new *cap_mixer; /* capture mixer */ unsigned int beep_amp; /* beep amp value, set via set_beep_amp() */ + const struct hda_verb *init_verbs[10]; /* initialization verbs + * don't forget NULL + * termination! + */ + unsigned int num_init_verbs; + char stream_name_analog[32]; /* analog PCM stream */ const struct hda_pcm_stream *stream_analog_playback; const struct hda_pcm_stream *stream_analog_capture; @@ -223,6 +210,11 @@ struct alc_spec { unsigned int pll_coef_idx, pll_coef_bit; unsigned int coef0; + /* fix-up list */ + int fixup_id; + const struct alc_fixup *fixup_list; + const char *fixup_name; + /* multi-io */ int multi_ios; struct alc_multi_io multi_io[4]; @@ -327,16 +319,13 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, /* for shared I/O, change the pin-control accordingly */ if (spec->shared_mic_hp) { - unsigned int val; - hda_nid_t pin = spec->autocfg.inputs[1].pin; /* NOTE: this assumes that there are only two inputs, the * first is the real internal mic and the second is HP jack. */ - if (spec->cur_mux[adc_idx]) - val = snd_hda_get_default_vref(codec, pin) | PIN_IN; - else - val = PIN_HP; - snd_hda_set_pin_ctl(codec, pin, val); + snd_hda_codec_write(codec, spec->autocfg.inputs[1].pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->cur_mux[adc_idx] ? + PIN_VREF80 : PIN_HP); spec->automute_speaker = !spec->cur_mux[adc_idx]; call_update_outputs(codec); } @@ -349,7 +338,7 @@ static int alc_mux_select(struct hda_codec *codec, unsigned int adc_idx, nid = get_capsrc(spec, adc_idx); /* no selection? */ - num_conns = snd_hda_get_num_conns(codec, nid); + num_conns = snd_hda_get_conn_list(codec, nid, NULL); if (num_conns <= 1) return 1; @@ -387,9 +376,25 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, int auto_pin_type) { unsigned int val = PIN_IN; - if (auto_pin_type == AUTO_PIN_MIC) - val |= snd_hda_get_default_vref(codec, nid); - snd_hda_set_pin_ctl(codec, nid, val); + + if (auto_pin_type == AUTO_PIN_MIC) { + unsigned int pincap; + unsigned int oldval; + oldval = snd_hda_codec_read(codec, nid, 0, + AC_VERB_GET_PIN_WIDGET_CONTROL, 0); + pincap = snd_hda_query_pin_caps(codec, nid); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + /* if the default pin setup is vref50, we give it priority */ + if ((pincap & AC_PINCAP_VREF_80) && oldval != PIN_VREF50) + val = PIN_VREF80; + else if (pincap & AC_PINCAP_VREF_50) + val = PIN_VREF50; + else if (pincap & AC_PINCAP_VREF_100) + val = PIN_VREF100; + else if (pincap & AC_PINCAP_VREF_GRD) + val = PIN_VREFGRD; + } + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); } /* @@ -404,6 +409,13 @@ static void add_mixer(struct alc_spec *spec, const struct snd_kcontrol_new *mix) spec->mixers[spec->num_mixers++] = mix; } +static void add_verb(struct alc_spec *spec, const struct hda_verb *verb) +{ + if (snd_BUG_ON(spec->num_init_verbs >= ARRAY_SIZE(spec->init_verbs))) + return; + spec->init_verbs[spec->num_init_verbs++] = verb; +} + /* * GPIO setup tables, used in initialization */ @@ -505,7 +517,9 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins, } else val = 0; val |= pin_bits; - snd_hda_set_pin_ctl(codec, nid, val); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + val); break; case ALC_AUTOMUTE_AMP: snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, @@ -1186,16 +1200,6 @@ static void alc_auto_check_switches(struct hda_codec *codec) */ #define ALC_FIXUP_SKU_IGNORE (2) -static void alc_fixup_sku_ignore(struct hda_codec *codec, - const struct hda_fixup *fix, int action) -{ - struct alc_spec *spec = codec->spec; - if (action == HDA_FIXUP_ACT_PRE_PROBE) { - spec->cdefine.fixup = 1; - spec->cdefine.sku_cfg = ALC_FIXUP_SKU_IGNORE; - } -} - static int alc_auto_parse_customize_define(struct hda_codec *codec) { unsigned int ass, tmp, i; @@ -1398,6 +1402,178 @@ static void alc_ssid_check(struct hda_codec *codec, const hda_nid_t *ports) } } +/* + * Fix-up pin default configurations and add default verbs + */ + +struct alc_pincfg { + hda_nid_t nid; + u32 val; +}; + +struct alc_model_fixup { + const int id; + const char *name; +}; + +struct alc_fixup { + int type; + bool chained; + int chain_id; + union { + unsigned int sku; + const struct alc_pincfg *pins; + const struct hda_verb *verbs; + void (*func)(struct hda_codec *codec, + const struct alc_fixup *fix, + int action); + } v; +}; + +enum { + ALC_FIXUP_INVALID, + ALC_FIXUP_SKU, + ALC_FIXUP_PINS, + ALC_FIXUP_VERBS, + ALC_FIXUP_FUNC, +}; + +enum { + ALC_FIXUP_ACT_PRE_PROBE, + ALC_FIXUP_ACT_PROBE, + ALC_FIXUP_ACT_INIT, + ALC_FIXUP_ACT_BUILD, +}; + +static void alc_apply_pincfgs(struct hda_codec *codec, + const struct alc_pincfg *cfg) +{ + for (; cfg->nid; cfg++) + snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); +} + +static void alc_apply_fixup(struct hda_codec *codec, int action) +{ + struct alc_spec *spec = codec->spec; + int id = spec->fixup_id; +#ifdef CONFIG_SND_DEBUG_VERBOSE + const char *modelname = spec->fixup_name; +#endif + int depth = 0; + + if (!spec->fixup_list) + return; + + while (id >= 0) { + const struct alc_fixup *fix = spec->fixup_list + id; + const struct alc_pincfg *cfg; + + switch (fix->type) { + case ALC_FIXUP_SKU: + if (action != ALC_FIXUP_ACT_PRE_PROBE || !fix->v.sku) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply sku override for %s\n", + codec->chip_name, modelname); + spec->cdefine.sku_cfg = fix->v.sku; + spec->cdefine.fixup = 1; + break; + case ALC_FIXUP_PINS: + cfg = fix->v.pins; + if (action != ALC_FIXUP_ACT_PRE_PROBE || !cfg) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply pincfg for %s\n", + codec->chip_name, modelname); + alc_apply_pincfgs(codec, cfg); + break; + case ALC_FIXUP_VERBS: + if (action != ALC_FIXUP_ACT_PROBE || !fix->v.verbs) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply fix-verbs for %s\n", + codec->chip_name, modelname); + add_verb(codec->spec, fix->v.verbs); + break; + case ALC_FIXUP_FUNC: + if (!fix->v.func) + break; + snd_printdd(KERN_INFO "hda_codec: %s: " + "Apply fix-func for %s\n", + codec->chip_name, modelname); + fix->v.func(codec, fix, action); + break; + default: + snd_printk(KERN_ERR "hda_codec: %s: " + "Invalid fixup type %d\n", + codec->chip_name, fix->type); + break; + } + if (!fix->chained) + break; + if (++depth > 10) + break; + id = fix->chain_id; + } +} + +static void alc_pick_fixup(struct hda_codec *codec, + const struct alc_model_fixup *models, + const struct snd_pci_quirk *quirk, + const struct alc_fixup *fixlist) +{ + struct alc_spec *spec = codec->spec; + const struct snd_pci_quirk *q; + int id = -1; + const char *name = NULL; + + /* when model=nofixup is given, don't pick up any fixups */ + if (codec->modelname && !strcmp(codec->modelname, "nofixup")) { + spec->fixup_list = NULL; + spec->fixup_id = -1; + return; + } + + if (codec->modelname && models) { + while (models->name) { + if (!strcmp(codec->modelname, models->name)) { + id = models->id; + name = models->name; + break; + } + models++; + } + } + if (id < 0) { + q = snd_pci_quirk_lookup(codec->bus->pci, quirk); + if (q) { + id = q->value; +#ifdef CONFIG_SND_DEBUG_VERBOSE + name = q->name; +#endif + } + } + if (id < 0) { + for (q = quirk; q->subvendor; q++) { + unsigned int vendorid = + q->subdevice | (q->subvendor << 16); + if (vendorid == codec->subsystem_id) { + id = q->value; +#ifdef CONFIG_SND_DEBUG_VERBOSE + name = q->name; +#endif + break; + } + } + } + + spec->fixup_id = id; + if (id >= 0) { + spec->fixup_list = fixlist; + spec->fixup_name = name; + } +} + /* * COEF access helper functions */ @@ -1445,7 +1621,8 @@ static void alc_auto_init_digital(struct hda_codec *codec) pin = spec->autocfg.dig_out_pins[i]; if (!pin) continue; - snd_hda_set_pin_ctl(codec, pin, PIN_OUT); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); if (!i) dac = spec->multiout.dig_out_nid; else @@ -1458,7 +1635,9 @@ static void alc_auto_init_digital(struct hda_codec *codec) } pin = spec->autocfg.dig_in_pin; if (pin) - snd_hda_set_pin_ctl(codec, pin, PIN_IN); + snd_hda_codec_write(codec, pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_IN); } /* parse digital I/Os and set up NIDs in BIOS auto-parse mode */ @@ -1889,6 +2068,7 @@ static void alc_auto_init_std(struct hda_codec *codec); static int alc_init(struct hda_codec *codec) { struct alc_spec *spec = codec->spec; + unsigned int i; if (spec->init_hook) spec->init_hook(codec); @@ -1896,6 +2076,8 @@ static int alc_init(struct hda_codec *codec) alc_fix_pll(codec); alc_auto_init_amp(codec, spec->init_amp); + for (i = 0; i < spec->num_init_verbs; i++) + snd_hda_sequence_write(codec, spec->init_verbs[i]); alc_init_special_input_src(codec); alc_auto_init_std(codec); @@ -2543,6 +2725,7 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { hda_nid_t src; + const hda_nid_t *list; unsigned int caps = get_wcaps(codec, nid); int type = get_wcaps_type(caps); @@ -2560,14 +2743,13 @@ static int alc_auto_fill_adc_caps(struct hda_codec *codec) cap_nids[nums] = src; break; } - n = snd_hda_get_num_conns(codec, src); + n = snd_hda_get_conn_list(codec, src, &list); if (n > 1) { cap_nids[nums] = src; break; } else if (n != 1) break; - if (snd_hda_get_connections(codec, src, &src, 1) != 1) - break; + src = *list; } if (++nums >= max_nums) break; @@ -2674,7 +2856,8 @@ static int alc_auto_create_shared_input(struct hda_codec *codec) static void alc_set_pin_output(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_type) { - snd_hda_set_pin_ctl(codec, nid, pin_type); + snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); /* unmute pin */ if (nid_has_mute(codec, nid, HDA_OUTPUT)) snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -2708,7 +2891,7 @@ static void alc_auto_init_analog_input(struct hda_codec *codec) /* mute all loopback inputs */ if (spec->mixer_nid) { - int nums = snd_hda_get_num_conns(codec, spec->mixer_nid); + int nums = snd_hda_get_conn_list(codec, spec->mixer_nid, NULL); for (i = 0; i < nums; i++) snd_hda_codec_write(codec, spec->mixer_nid, 0, AC_VERB_SET_AMP_GAIN_MUTE, @@ -3338,7 +3521,7 @@ static int alc_auto_add_sw_ctl(struct hda_codec *codec, if (wid_type == AC_WID_PIN || wid_type == AC_WID_AUD_OUT) { type = ALC_CTL_WIDGET_MUTE; val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_OUTPUT); - } else if (snd_hda_get_num_conns(codec, nid) == 1) { + } else if (snd_hda_get_conn_list(codec, nid, NULL) == 1) { type = ALC_CTL_WIDGET_MUTE; val = HDA_COMPOSE_AMP_VAL(nid, chs, 0, HDA_INPUT); } else { @@ -3815,7 +3998,9 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); if (output) { - snd_hda_set_pin_ctl_cache(codec, nid, PIN_OUT); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + PIN_OUT); if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, 0); @@ -3824,8 +4009,9 @@ static int alc_set_multi_io(struct hda_codec *codec, int idx, bool output) if (get_wcaps(codec, nid) & AC_WCAP_OUT_AMP) snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, HDA_AMP_MUTE, HDA_AMP_MUTE); - snd_hda_set_pin_ctl_cache(codec, nid, - spec->multi_io[idx].ctl_in); + snd_hda_codec_update_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + spec->multi_io[idx].ctl_in); } return 0; } @@ -3898,7 +4084,7 @@ static void alc_remove_invalid_adc_nids(struct hda_codec *codec) nums = 0; for (n = 0; n < spec->num_adc_nids; n++) { hda_nid_t cap = spec->private_capsrc_nids[n]; - int num_conns = snd_hda_get_num_conns(codec, cap); + int num_conns = snd_hda_get_conn_list(codec, cap, NULL); for (i = 0; i < imux->num_items; i++) { hda_nid_t pin = spec->imux_pins[i]; if (pin) { @@ -4027,7 +4213,7 @@ static void select_or_unmute_capsrc(struct hda_codec *codec, hda_nid_t cap, if (get_wcaps_type(get_wcaps(codec, cap)) == AC_WID_AUD_MIX) { snd_hda_codec_amp_stereo(codec, cap, HDA_INPUT, idx, HDA_AMP_MUTE, 0); - } else if (snd_hda_get_num_conns(codec, cap) > 1) { + } else if (snd_hda_get_conn_list(codec, cap, NULL) > 1) { snd_hda_codec_write_cache(codec, cap, 0, AC_VERB_SET_CONNECT_SEL, idx); } @@ -4241,25 +4427,6 @@ static int alc_parse_auto_config(struct hda_codec *codec, return 1; } -/* common preparation job for alc_spec */ -static int alc_alloc_spec(struct hda_codec *codec, hda_nid_t mixer_nid) -{ - struct alc_spec *spec = kzalloc(sizeof(*spec), GFP_KERNEL); - int err; - - if (!spec) - return -ENOMEM; - codec->spec = spec; - spec->mixer_nid = mixer_nid; - - err = alc_codec_rename_from_preset(codec); - if (err < 0) { - kfree(spec); - return err; - } - return 0; -} - static int alc880_parse_auto_config(struct hda_codec *codec) { static const hda_nid_t alc880_ignore[] = { 0x1d, 0 }; @@ -4641,11 +4808,13 @@ static int patch_alc880(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; - spec = codec->spec; + spec->mixer_nid = 0x0b; spec->need_dac_fix = 1; alc_pick_fixup(codec, alc880_fixup_models, alc880_fixup_tbl, @@ -4721,7 +4890,7 @@ static void alc260_fixup_gpio1_toggle(struct hda_codec *codec, spec->autocfg.hp_pins[0] = 0x0f; /* copy it for automute */ snd_hda_jack_detect_enable(codec, 0x0f, ALC_HP_EVENT); spec->unsol_event = alc_sku_unsol_event; - snd_hda_gen_add_verbs(&spec->gen, alc_gpio1_init_verbs); + add_verb(codec->spec, alc_gpio1_init_verbs); } } @@ -4832,11 +5001,13 @@ static int patch_alc260(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x07); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; - spec = codec->spec; + spec->mixer_nid = 0x07; alc_pick_fixup(codec, NULL, alc260_fixup_tbl, alc260_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -5000,7 +5171,8 @@ static void alc889_fixup_mbp_vref(struct hda_codec *codec, val = snd_hda_codec_read(codec, nids[i], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); val |= AC_PINCTL_VREF_80; - snd_hda_set_pin_ctl(codec, nids[i], val); + snd_hda_codec_write(codec, nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); spec->keep_vref_in_automute = 1; break; } @@ -5021,7 +5193,8 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec, val = snd_hda_codec_read(codec, nids[i], 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); val |= AC_PINCTL_VREF_50; - snd_hda_set_pin_ctl(codec, nids[i], val); + snd_hda_codec_write(codec, nids[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); } spec->keep_vref_in_automute = 1; } @@ -5052,8 +5225,8 @@ static const struct alc_fixup alc882_fixups[] = { } }, [ALC882_FIXUP_ACER_ASPIRE_7736] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, }, [ALC882_FIXUP_ASUS_W90V] = { .type = ALC_FIXUP_PINS, @@ -5303,11 +5476,13 @@ static int patch_alc882(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; - spec = codec->spec; + spec->mixer_nid = 0x0b; switch (codec->vendor_id) { case 0x10ec0882: @@ -5319,6 +5494,10 @@ static int patch_alc882(struct hda_codec *codec) break; } + err = alc_codec_rename_from_preset(codec); + if (err < 0) + goto error; + alc_pick_fixup(codec, alc882_fixup_models, alc882_fixup_tbl, alc882_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -5442,11 +5621,13 @@ static int patch_alc262(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - spec = codec->spec; + codec->spec = spec; + + spec->mixer_nid = 0x0b; #if 0 /* pshou 07/11/05 set a zero PCM sample to DAC when FIFO is @@ -5529,7 +5710,7 @@ static int alc268_parse_auto_config(struct hda_codec *codec) if (err > 0) { if (!spec->no_analog && spec->autocfg.speaker_pins[0] != 0x1d) { add_mixer(spec, alc268_beep_mixer); - snd_hda_gen_add_verbs(&spec->gen, alc268_beep_init_verbs); + add_verb(spec, alc268_beep_init_verbs); } } return err; @@ -5542,12 +5723,13 @@ static int patch_alc268(struct hda_codec *codec) struct alc_spec *spec; int i, has_beep, err; - /* ALC268 has no aa-loopback mixer */ - err = alc_alloc_spec(codec, 0); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - spec = codec->spec; + codec->spec = spec; + + /* ALC268 has no aa-loopback mixer */ /* automatic parse from the BIOS config */ err = alc268_parse_auto_config(codec); @@ -5764,7 +5946,9 @@ static void alc269_fixup_mic2_mute_hook(void *private_data, int enabled) { struct hda_codec *codec = private_data; unsigned int pinval = enabled ? 0x20 : 0x24; - snd_hda_set_pin_ctl_cache(codec, 0x19, pinval); + snd_hda_codec_update_cache(codec, 0x19, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pinval); } static void alc269_fixup_mic2_mute(struct hda_codec *codec, @@ -5831,8 +6015,8 @@ static const struct alc_fixup alc269_fixups[] = { } }, [ALC269_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, }, [ALC269_FIXUP_ASUS_G73JW] = { .type = ALC_FIXUP_PINS, @@ -6058,13 +6242,19 @@ static void alc269_fill_coef(struct hda_codec *codec) static int patch_alc269(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int err = 0; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + + spec->mixer_nid = 0x0b; - spec = codec->spec; + err = alc_codec_rename_from_preset(codec); + if (err < 0) + goto error; if (codec->vendor_id == 0x10ec0269) { spec->codec_variant = ALC269_TYPE_ALC269VA; @@ -6156,7 +6346,8 @@ static void alc861_fixup_asus_amp_vref_0f(struct hda_codec *codec, if (!(val & (AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN))) val |= AC_PINCTL_IN_EN; val |= AC_PINCTL_VREF_50; - snd_hda_set_pin_ctl(codec, 0x0f, val); + snd_hda_codec_write(codec, 0x0f, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, val); spec->keep_vref_in_automute = 1; } @@ -6210,11 +6401,13 @@ static int patch_alc861(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x15); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - spec = codec->spec; + codec->spec = spec; + + spec->mixer_nid = 0x15; alc_pick_fixup(codec, NULL, alc861_fixup_tbl, alc861_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -6311,11 +6504,13 @@ static int patch_alc861vd(struct hda_codec *codec) struct alc_spec *spec; int err; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; - spec = codec->spec; + codec->spec = spec; + + spec->mixer_nid = 0x0b; alc_pick_fixup(codec, NULL, alc861vd_fixup_tbl, alc861vd_fixups); alc_apply_fixup(codec, ALC_FIXUP_ACT_PRE_PROBE); @@ -6327,7 +6522,7 @@ static int patch_alc861vd(struct hda_codec *codec) if (codec->vendor_id == 0x10ec0660) { /* always turn on EAPD */ - snd_hda_gen_add_verbs(&spec->gen, alc660vd_eapd_verbs); + add_verb(spec, alc660vd_eapd_verbs); } if (!spec->no_analog) { @@ -6440,8 +6635,8 @@ static const struct alc_fixup alc662_fixups[] = { } }, [ALC662_FIXUP_SKU_IGNORE] = { - .type = ALC_FIXUP_FUNC, - .v.func = alc_fixup_sku_ignore, + .type = ALC_FIXUP_SKU, + .v.sku = ALC_FIXUP_SKU_IGNORE, }, [ALC662_FIXUP_HP_RP5800] = { .type = ALC_FIXUP_PINS, @@ -6654,19 +6849,25 @@ static const struct alc_model_fixup alc662_fixup_models[] = { static int patch_alc662(struct hda_codec *codec) { struct alc_spec *spec; - int err; + int err = 0; - err = alc_alloc_spec(codec, 0x0b); - if (err < 0) - return err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (!spec) + return -ENOMEM; - spec = codec->spec; + codec->spec = spec; + + spec->mixer_nid = 0x0b; /* handle multiple HPs as is */ spec->parse_flags = HDA_PINCFG_NO_HP_FIXUP; alc_fix_pll_init(codec, 0x20, 0x04, 15); + err = alc_codec_rename_from_preset(codec); + if (err < 0) + goto error; + if ((alc_get_coef0(codec) & (1 << 14)) && codec->bus->pci->subsystem_vendor == 0x1025 && spec->cdefine.platform_type == 1) { @@ -6729,12 +6930,16 @@ static int alc680_parse_auto_config(struct hda_codec *codec) */ static int patch_alc680(struct hda_codec *codec) { + struct alc_spec *spec; int err; + spec = kzalloc(sizeof(*spec), GFP_KERNEL); + if (spec == NULL) + return -ENOMEM; + + codec->spec = spec; + /* ALC680 has no aa-loopback mixer */ - err = alc_alloc_spec(codec, 0); - if (err < 0) - return err; /* automatic parse from the BIOS config */ err = alc680_parse_auto_config(codec); diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index 7db8228f1b88..4742cac26aa9 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -36,7 +36,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_beep.h" #include "hda_jack.h" @@ -222,7 +221,6 @@ struct sigmatel_spec { unsigned char aloopback_shift; /* power management */ - unsigned int power_map_bits; unsigned int num_pwrs; const hda_nid_t *pwr_nids; const hda_nid_t *dac_list; @@ -316,9 +314,6 @@ struct sigmatel_spec { struct hda_vmaster_mute_hook vmaster_mute; }; -#define AC_VERB_IDT_SET_POWER_MAP 0x7ec -#define AC_VERB_IDT_GET_POWER_MAP 0xfec - static const hda_nid_t stac9200_adc_nids[1] = { 0x03, }; @@ -686,7 +681,8 @@ static int stac_vrefout_set(struct hda_codec *codec, pinctl &= ~AC_PINCTL_VREFEN; pinctl |= (new_vref & AC_PINCTL_VREFEN); - error = snd_hda_set_pin_ctl_cache(codec, nid, pinctl); + error = snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pinctl); if (error < 0) return error; @@ -710,7 +706,8 @@ static unsigned int stac92xx_vref_set(struct hda_codec *codec, else pincfg |= AC_PINCTL_IN_EN; - error = snd_hda_set_pin_ctl_cache(codec, nid, pincfg); + error = snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); if (error < 0) return error; else @@ -2508,10 +2505,27 @@ static int stac92xx_build_pcms(struct hda_codec *codec) return 0; } +static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, + hda_nid_t nid) +{ + unsigned int pincap = snd_hda_query_pin_caps(codec, nid); + pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; + if (pincap & AC_PINCAP_VREF_100) + return AC_PINCTL_VREF_100; + if (pincap & AC_PINCAP_VREF_80) + return AC_PINCTL_VREF_80; + if (pincap & AC_PINCAP_VREF_50) + return AC_PINCTL_VREF_50; + if (pincap & AC_PINCAP_VREF_GRD) + return AC_PINCTL_VREF_GRD; + return 0; +} + static void stac92xx_auto_set_pinctl(struct hda_codec *codec, hda_nid_t nid, int pin_type) { - snd_hda_set_pin_ctl_cache(codec, nid, pin_type); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, pin_type); } #define stac92xx_hp_switch_info snd_ctl_boolean_mono_info @@ -2580,7 +2594,7 @@ static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, hda_nid_t nid = kcontrol->private_value; unsigned int vref = stac92xx_vref_get(codec, nid); - if (vref == snd_hda_get_default_vref(codec, nid)) + if (vref == stac92xx_get_default_vref(codec, nid)) ucontrol->value.enumerated.item[0] = 0; else if (vref == AC_PINCTL_VREF_GRD) ucontrol->value.enumerated.item[0] = 1; @@ -2599,7 +2613,7 @@ static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, hda_nid_t nid = kcontrol->private_value; if (ucontrol->value.enumerated.item[0] == 0) - new_vref = snd_hda_get_default_vref(codec, nid); + new_vref = stac92xx_get_default_vref(codec, nid); else if (ucontrol->value.enumerated.item[0] == 1) new_vref = AC_PINCTL_VREF_GRD; else if (ucontrol->value.enumerated.item[0] == 2) @@ -2665,7 +2679,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ else { unsigned int pinctl = AC_PINCTL_IN_EN; if (io_idx) /* set VREF for mic */ - pinctl |= snd_hda_get_default_vref(codec, nid); + pinctl |= stac92xx_get_default_vref(codec, nid); stac92xx_auto_set_pinctl(codec, nid, pinctl); } @@ -2833,7 +2847,7 @@ static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, char name[22]; if (snd_hda_get_input_pin_attr(def_conf) != INPUT_PIN_ATTR_INT) { - if (snd_hda_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD + if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD && nid == spec->line_switch) control = STAC_CTL_WIDGET_IO_SWITCH; else if (snd_hda_query_pin_caps(codec, nid) @@ -4236,6 +4250,13 @@ static void stac_store_hints(struct hda_codec *codec) val = snd_hda_get_bool_hint(codec, "eapd_switch"); if (val >= 0) spec->eapd_switch = val; + get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); + if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { + spec->gpio_mask |= spec->gpio_led; + spec->gpio_dir |= spec->gpio_led; + if (spec->gpio_led_polarity) + spec->gpio_data |= spec->gpio_led; + } } static void stac_issue_unsol_events(struct hda_codec *codec, int num_pins, @@ -4333,7 +4354,7 @@ static int stac92xx_init(struct hda_codec *codec) unsigned int pinctl, conf; if (type == AUTO_PIN_MIC) { /* for mic pins, force to initialize */ - pinctl = snd_hda_get_default_vref(codec, nid); + pinctl = stac92xx_get_default_vref(codec, nid); pinctl |= AC_PINCTL_IN_EN; stac92xx_auto_set_pinctl(codec, nid, pinctl); } else { @@ -4369,18 +4390,10 @@ static int stac92xx_init(struct hda_codec *codec) hda_nid_t nid = spec->pwr_nids[i]; int pinctl, def_conf; - def_conf = snd_hda_codec_get_pincfg(codec, nid); - def_conf = get_defcfg_connect(def_conf); - if (def_conf == AC_JACK_PORT_NONE) { - /* power off unused ports */ - stac_toggle_power_map(codec, nid, 0); - continue; - } /* power on when no jack detection is available */ /* or when the VREF is used for controlling LED */ if (!spec->hp_detect || - spec->vref_mute_led_nid == nid || - !is_jack_detectable(codec, nid)) { + spec->vref_mute_led_nid == nid) { stac_toggle_power_map(codec, nid, 1); continue; } @@ -4398,6 +4411,15 @@ static int stac92xx_init(struct hda_codec *codec) stac_toggle_power_map(codec, nid, 1); continue; } + def_conf = snd_hda_codec_get_pincfg(codec, nid); + def_conf = get_defcfg_connect(def_conf); + /* skip any ports that don't have jacks since presence + * detection is useless */ + if (def_conf != AC_JACK_PORT_COMPLEX) { + if (def_conf != AC_JACK_PORT_NONE) + stac_toggle_power_map(codec, nid, 1); + continue; + } if (enable_pin_detect(codec, nid, STAC_PWR_EVENT)) { stac_issue_unsol_event(codec, nid); continue; @@ -4410,12 +4432,6 @@ static int stac92xx_init(struct hda_codec *codec) /* sync mute LED */ snd_hda_sync_vmaster_hook(&spec->vmaster_mute); - - /* sync the power-map */ - if (spec->num_pwrs) - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_IDT_SET_POWER_MAP, - spec->power_map_bits); if (spec->dac_list) stac92xx_power_down(codec); return 0; @@ -4444,7 +4460,8 @@ static void stac92xx_shutup_pins(struct hda_codec *codec) struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); def_conf = snd_hda_codec_get_pincfg(codec, pin->nid); if (get_defcfg_connect(def_conf) != AC_JACK_PORT_NONE) - snd_hda_set_pin_ctl(codec, pin->nid, 0); + snd_hda_codec_write(codec, pin->nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, 0); } } @@ -4500,7 +4517,9 @@ static void stac92xx_set_pinctl(struct hda_codec *codec, hda_nid_t nid, pin_ctl |= flag; if (old_ctl != pin_ctl) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_ctl); } static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, @@ -4509,7 +4528,9 @@ static void stac92xx_reset_pinctl(struct hda_codec *codec, hda_nid_t nid, unsigned int pin_ctl = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PIN_WIDGET_CONTROL, 0x00); if (pin_ctl & flag) - snd_hda_set_pin_ctl_cache(codec, nid, pin_ctl & ~flag); + snd_hda_codec_write_cache(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_ctl & ~flag); } static inline int get_pin_presence(struct hda_codec *codec, hda_nid_t nid) @@ -4661,18 +4682,14 @@ static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, idx = 1 << idx; - val = spec->power_map_bits; + val = snd_hda_codec_read(codec, codec->afg, 0, 0x0fec, 0x0) & 0xff; if (enable) val &= ~idx; else val |= idx; /* power down unused output ports */ - if (val != spec->power_map_bits) { - spec->power_map_bits = val; - snd_hda_codec_write(codec, codec->afg, 0, - AC_VERB_IDT_SET_POWER_MAP, val); - } + snd_hda_codec_write(codec, codec->afg, 0, 0x7ec, val); } static void stac92xx_pin_sense(struct hda_codec *codec, hda_nid_t nid) @@ -4849,11 +4866,6 @@ static int find_mute_led_cfg(struct hda_codec *codec, int default_polarity) struct sigmatel_spec *spec = codec->spec; const struct dmi_device *dev = NULL; - if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { - get_int_hint(codec, "gpio_led_polarity", - &spec->gpio_led_polarity); - return 1; - } if ((codec->subsystem_id >> 16) == PCI_VENDOR_ID_HP) { while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) { @@ -4940,8 +4952,7 @@ static void stac92hd_proc_hook(struct snd_info_buffer *buffer, { if (nid == codec->afg) snd_iprintf(buffer, "Power-Map: 0x%02x\n", - snd_hda_codec_read(codec, nid, 0, - AC_VERB_IDT_GET_POWER_MAP, 0)); + snd_hda_codec_read(codec, nid, 0, 0x0fec, 0x0)); } static void analog_loop_proc_hook(struct snd_info_buffer *buffer, @@ -4998,6 +5009,20 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) return 0; } +static int stac92xx_pre_resume(struct hda_codec *codec) +{ + struct sigmatel_spec *spec = codec->spec; + + /* sync mute LED */ + if (spec->vref_mute_led_nid) + stac_vrefout_set(codec, spec->vref_mute_led_nid, + spec->vref_led); + else if (spec->gpio_led) + stac_gpio_set(codec, spec->gpio_mask, + spec->gpio_dir, spec->gpio_data); + return 0; +} + static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, unsigned int power_state) { @@ -5021,6 +5046,7 @@ static void stac92xx_set_power_state(struct hda_codec *codec, hda_nid_t fg, #else #define stac92xx_suspend NULL #define stac92xx_resume NULL +#define stac92xx_pre_resume NULL #define stac92xx_set_power_state NULL #endif /* CONFIG_PM */ @@ -5566,6 +5592,9 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) codec->patch_ops.set_power_state = stac92xx_set_power_state; } +#ifdef CONFIG_PM + codec->patch_ops.pre_resume = stac92xx_pre_resume; +#endif } err = stac92xx_parse_auto_config(codec); @@ -5872,6 +5901,9 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) codec->patch_ops.set_power_state = stac92xx_set_power_state; } +#ifdef CONFIG_PM + codec->patch_ops.pre_resume = stac92xx_pre_resume; +#endif } spec->multiout.dac_nids = spec->dac_nids; diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index 82b368068e08..06214fdc9486 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -54,7 +54,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include "hda_auto_parser.h" #include "hda_jack.h" /* Pin Widget NID */ @@ -485,7 +484,7 @@ static void activate_output_mix(struct hda_codec *codec, struct nid_path *path, if (!path) return; - num = snd_hda_get_num_conns(codec, mix_nid); + num = snd_hda_get_conn_list(codec, mix_nid, NULL); for (i = 0; i < num; i++) { if (i == idx) val = AMP_IN_UNMUTE(i); @@ -533,7 +532,8 @@ static void init_output_pin(struct hda_codec *codec, hda_nid_t pin, { if (!pin) return; - snd_hda_set_pin_ctl(codec, pin, pin_type); + snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, + pin_type); if (snd_hda_query_pin_caps(codec, pin) & AC_PINCAP_EAPD) snd_hda_codec_write(codec, pin, 0, AC_VERB_SET_EAPD_BTLENABLE, 0x02); @@ -662,12 +662,12 @@ static void via_auto_init_analog_input(struct hda_codec *codec) hda_nid_t nid = cfg->inputs[i].pin; if (spec->smart51_enabled && is_smart51_pins(codec, nid)) ctl = PIN_OUT; - else { + else if (cfg->inputs[i].type == AUTO_PIN_MIC) + ctl = PIN_VREF50; + else ctl = PIN_IN; - if (cfg->inputs[i].type == AUTO_PIN_MIC) - ctl |= snd_hda_get_default_vref(codec, nid); - } - snd_hda_set_pin_ctl(codec, nid, ctl); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, ctl); } /* init input-src */ @@ -1006,7 +1006,9 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, AC_VERB_GET_PIN_WIDGET_CONTROL, 0); parm &= ~(AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); parm |= out_in; - snd_hda_set_pin_ctl(codec, nid, parm); + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + parm); if (out_in == AC_PINCTL_OUT_EN) { mute_aa_path(codec, 1); notify_aa_path_ctls(codec); @@ -1645,7 +1647,8 @@ static void toggle_output_mutes(struct hda_codec *codec, int num_pins, parm &= ~AC_PINCTL_OUT_EN; else parm |= AC_PINCTL_OUT_EN; - snd_hda_set_pin_ctl(codec, pins[i], parm); + snd_hda_codec_write(codec, pins[i], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, parm); } } @@ -1706,7 +1709,8 @@ static void via_gpio_control(struct hda_codec *codec) if (gpio_data == 0x02) { /* unmute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], + snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); if (vol_counter & 0x20) { /* decrease volume */ @@ -1724,7 +1728,9 @@ static void via_gpio_control(struct hda_codec *codec) } } else if (!(gpio_data & 0x02)) { /* mute line out */ - snd_hda_set_pin_ctl(codec, spec->autocfg.line_out_pins[0], 0); + snd_hda_codec_write(codec, spec->autocfg.line_out_pins[0], 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, + 0); } } @@ -2751,7 +2757,8 @@ static void via_auto_init_dig_in(struct hda_codec *codec) struct via_spec *spec = codec->spec; if (!spec->dig_in_nid) return; - snd_hda_set_pin_ctl(codec, spec->autocfg.dig_in_pin, PIN_IN); + snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, + AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); } /* initialize the unsolicited events */ diff --git a/trunk/sound/pci/ice1712/ice1712.c b/trunk/sound/pci/ice1712/ice1712.c index 5be2e120a14e..132a86e09d07 100644 --- a/trunk/sound/pci/ice1712/ice1712.c +++ b/trunk/sound/pci/ice1712/ice1712.c @@ -2803,11 +2803,22 @@ static void __devexit snd_ice1712_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver ice1712_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_ice1712_ids, .probe = snd_ice1712_probe, .remove = __devexit_p(snd_ice1712_remove), }; -module_pci_driver(ice1712_driver); +static int __init alsa_card_ice1712_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_ice1712_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ice1712_init) +module_exit(alsa_card_ice1712_exit) diff --git a/trunk/sound/pci/ice1712/ice1724.c b/trunk/sound/pci/ice1712/ice1724.c index a01a00d1cf4d..812d10e43ae0 100644 --- a/trunk/sound/pci/ice1712/ice1724.c +++ b/trunk/sound/pci/ice1712/ice1724.c @@ -2873,7 +2873,7 @@ static int snd_vt1724_resume(struct pci_dev *pci) } #endif -static struct pci_driver vt1724_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_vt1724_ids, .probe = snd_vt1724_probe, @@ -2884,4 +2884,15 @@ static struct pci_driver vt1724_driver = { #endif }; -module_pci_driver(vt1724_driver); +static int __init alsa_card_ice1724_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_ice1724_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ice1724_init) +module_exit(alsa_card_ice1724_exit) diff --git a/trunk/sound/pci/intel8x0.c b/trunk/sound/pci/intel8x0.c index f4e2dd4da8cf..e0a4263baa20 100644 --- a/trunk/sound/pci/intel8x0.c +++ b/trunk/sound/pci/intel8x0.c @@ -3338,7 +3338,7 @@ static void __devexit snd_intel8x0_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver intel8x0_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0_ids, .probe = snd_intel8x0_probe, @@ -3349,4 +3349,16 @@ static struct pci_driver intel8x0_driver = { #endif }; -module_pci_driver(intel8x0_driver); + +static int __init alsa_card_intel8x0_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_intel8x0_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_intel8x0_init) +module_exit(alsa_card_intel8x0_exit) diff --git a/trunk/sound/pci/intel8x0m.c b/trunk/sound/pci/intel8x0m.c index fc27a6a69e77..d689913a61be 100644 --- a/trunk/sound/pci/intel8x0m.c +++ b/trunk/sound/pci/intel8x0m.c @@ -1324,7 +1324,7 @@ static void __devexit snd_intel8x0m_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver intel8x0m_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_intel8x0m_ids, .probe = snd_intel8x0m_probe, @@ -1335,4 +1335,16 @@ static struct pci_driver intel8x0m_driver = { #endif }; -module_pci_driver(intel8x0m_driver); + +static int __init alsa_card_intel8x0m_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_intel8x0m_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_intel8x0m_init) +module_exit(alsa_card_intel8x0m_exit) diff --git a/trunk/sound/pci/korg1212/korg1212.c b/trunk/sound/pci/korg1212/korg1212.c index e69ce5f9c31e..8fea45ab5882 100644 --- a/trunk/sound/pci/korg1212/korg1212.c +++ b/trunk/sound/pci/korg1212/korg1212.c @@ -2476,11 +2476,22 @@ static void __devexit snd_korg1212_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver korg1212_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_korg1212_ids, .probe = snd_korg1212_probe, .remove = __devexit_p(snd_korg1212_remove), }; -module_pci_driver(korg1212_driver); +static int __init alsa_card_korg1212_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_korg1212_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_korg1212_init) +module_exit(alsa_card_korg1212_exit) diff --git a/trunk/sound/pci/lola/lola.c b/trunk/sound/pci/lola/lola.c index ac15166bee68..375982736858 100644 --- a/trunk/sound/pci/lola/lola.c +++ b/trunk/sound/pci/lola/lola.c @@ -770,11 +770,22 @@ static DEFINE_PCI_DEVICE_TABLE(lola_ids) = { MODULE_DEVICE_TABLE(pci, lola_ids); /* pci_driver definition */ -static struct pci_driver lola_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = lola_ids, .probe = lola_probe, .remove = __devexit_p(lola_remove), }; -module_pci_driver(lola_driver); +static int __init alsa_card_lola_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_lola_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_lola_init) +module_exit(alsa_card_lola_exit) diff --git a/trunk/sound/pci/lx6464es/lx6464es.c b/trunk/sound/pci/lx6464es/lx6464es.c index d1ab43706735..d94c0c292bd0 100644 --- a/trunk/sound/pci/lx6464es/lx6464es.c +++ b/trunk/sound/pci/lx6464es/lx6464es.c @@ -1141,11 +1141,24 @@ static void __devexit snd_lx6464es_remove(struct pci_dev *pci) } -static struct pci_driver lx6464es_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_lx6464es_ids, .probe = snd_lx6464es_probe, .remove = __devexit_p(snd_lx6464es_remove), }; -module_pci_driver(lx6464es_driver); + +/* module initialization */ +static int __init mod_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit mod_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(mod_init); +module_exit(mod_exit); diff --git a/trunk/sound/pci/maestro3.c b/trunk/sound/pci/maestro3.c index deef21399586..78229b0dad2b 100644 --- a/trunk/sound/pci/maestro3.c +++ b/trunk/sound/pci/maestro3.c @@ -2837,7 +2837,7 @@ static void __devexit snd_m3_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver m3_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_m3_ids, .probe = snd_m3_probe, @@ -2848,4 +2848,15 @@ static struct pci_driver m3_driver = { #endif }; -module_pci_driver(m3_driver); +static int __init alsa_card_m3_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_m3_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_m3_init) +module_exit(alsa_card_m3_exit) diff --git a/trunk/sound/pci/mixart/mixart.c b/trunk/sound/pci/mixart/mixart.c index 0762610c99c0..487837c01c9f 100644 --- a/trunk/sound/pci/mixart/mixart.c +++ b/trunk/sound/pci/mixart/mixart.c @@ -1380,11 +1380,22 @@ static void __devexit snd_mixart_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver mixart_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_mixart_ids, .probe = snd_mixart_probe, .remove = __devexit_p(snd_mixart_remove), }; -module_pci_driver(mixart_driver); +static int __init alsa_card_mixart_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_mixart_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_mixart_init) +module_exit(alsa_card_mixart_exit) diff --git a/trunk/sound/pci/nm256/nm256.c b/trunk/sound/pci/nm256/nm256.c index 8159b05ee94d..ade2c64bd606 100644 --- a/trunk/sound/pci/nm256/nm256.c +++ b/trunk/sound/pci/nm256/nm256.c @@ -1742,7 +1742,7 @@ static void __devexit snd_nm256_remove(struct pci_dev *pci) } -static struct pci_driver nm256_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_nm256_ids, .probe = snd_nm256_probe, @@ -1753,4 +1753,16 @@ static struct pci_driver nm256_driver = { #endif }; -module_pci_driver(nm256_driver); + +static int __init alsa_card_nm256_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_nm256_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_nm256_init) +module_exit(alsa_card_nm256_exit) diff --git a/trunk/sound/pci/oxygen/oxygen.c b/trunk/sound/pci/oxygen/oxygen.c index 610275bfbaeb..eab663eef117 100644 --- a/trunk/sound/pci/oxygen/oxygen.c +++ b/trunk/sound/pci/oxygen/oxygen.c @@ -94,7 +94,6 @@ enum { MODEL_2CH_OUTPUT, MODEL_HG2PCI, MODEL_XONAR_DG, - MODEL_XONAR_DGX, }; static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { @@ -110,8 +109,6 @@ static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { { OXYGEN_PCI_SUBID(0x1a58, 0x0910), .driver_data = MODEL_CMEDIA_REF }, /* Asus Xonar DG */ { OXYGEN_PCI_SUBID(0x1043, 0x8467), .driver_data = MODEL_XONAR_DG }, - /* Asus Xonar DGX */ - { OXYGEN_PCI_SUBID(0x1043, 0x8521), .driver_data = MODEL_XONAR_DGX }, /* PCI 2.0 HD Audio */ { OXYGEN_PCI_SUBID(0x13f6, 0x8782), .driver_data = MODEL_2CH_OUTPUT }, /* Kuroutoshikou CMI8787-HG2PCI */ @@ -830,11 +827,6 @@ static int __devinit get_oxygen_model(struct oxygen *chip, break; case MODEL_XONAR_DG: chip->model = model_xonar_dg; - chip->model.shortname = "Xonar DG"; - break; - case MODEL_XONAR_DGX: - chip->model = model_xonar_dg; - chip->model.shortname = "Xonar DGX"; break; } if (id->driver_data == MODEL_MERIDIAN || @@ -878,4 +870,15 @@ static struct pci_driver oxygen_driver = { #endif }; -module_pci_driver(oxygen_driver); +static int __init alsa_card_oxygen_init(void) +{ + return pci_register_driver(&oxygen_driver); +} + +static void __exit alsa_card_oxygen_exit(void) +{ + pci_unregister_driver(&oxygen_driver); +} + +module_init(alsa_card_oxygen_init) +module_exit(alsa_card_oxygen_exit) diff --git a/trunk/sound/pci/oxygen/virtuoso.c b/trunk/sound/pci/oxygen/virtuoso.c index 19962c6d38c3..3fdee4950174 100644 --- a/trunk/sound/pci/oxygen/virtuoso.c +++ b/trunk/sound/pci/oxygen/virtuoso.c @@ -100,4 +100,15 @@ static struct pci_driver xonar_driver = { .shutdown = oxygen_pci_shutdown, }; -module_pci_driver(xonar_driver); +static int __init alsa_card_xonar_init(void) +{ + return pci_register_driver(&xonar_driver); +} + +static void __exit alsa_card_xonar_exit(void) +{ + pci_unregister_driver(&xonar_driver); +} + +module_init(alsa_card_xonar_init) +module_exit(alsa_card_xonar_exit) diff --git a/trunk/sound/pci/oxygen/xonar_dg.c b/trunk/sound/pci/oxygen/xonar_dg.c index 77acd790ea47..793bdf03d7e0 100644 --- a/trunk/sound/pci/oxygen/xonar_dg.c +++ b/trunk/sound/pci/oxygen/xonar_dg.c @@ -1,5 +1,5 @@ /* - * card driver for the Xonar DG/DGX + * card driver for the Xonar DG * * Copyright (c) Clemens Ladisch * @@ -17,8 +17,8 @@ */ /* - * Xonar DG/DGX - * ------------ + * Xonar DG + * -------- * * CMI8788: * @@ -581,6 +581,7 @@ static void dump_cs4245_registers(struct oxygen *chip, } struct oxygen_model model_xonar_dg = { + .shortname = "Xonar DG", .longname = "C-Media Oxygen HD Audio", .chip = "CMI8786", .init = dg_init, diff --git a/trunk/sound/pci/pcxhr/pcxhr.c b/trunk/sound/pci/pcxhr/pcxhr.c index 0435f45e9513..fd1809ab73b4 100644 --- a/trunk/sound/pci/pcxhr/pcxhr.c +++ b/trunk/sound/pci/pcxhr/pcxhr.c @@ -1607,11 +1607,22 @@ static void __devexit pcxhr_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver pcxhr_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = pcxhr_ids, .probe = pcxhr_probe, .remove = __devexit_p(pcxhr_remove), }; -module_pci_driver(pcxhr_driver); +static int __init pcxhr_module_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit pcxhr_module_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(pcxhr_module_init) +module_exit(pcxhr_module_exit) diff --git a/trunk/sound/pci/riptide/riptide.c b/trunk/sound/pci/riptide/riptide.c index cbeb3f77350c..0481d94aac9b 100644 --- a/trunk/sound/pci/riptide/riptide.c +++ b/trunk/sound/pci/riptide/riptide.c @@ -1837,7 +1837,8 @@ static int snd_riptide_free(struct snd_riptide *chip) } if (chip->irq >= 0) free_irq(chip->irq, chip); - release_firmware(chip->fw_entry); + if (chip->fw_entry) + release_firmware(chip->fw_entry); release_and_free_resource(chip->res_port); kfree(chip); return 0; diff --git a/trunk/sound/pci/rme32.c b/trunk/sound/pci/rme32.c index 46b3629dda22..b4819d5e41db 100644 --- a/trunk/sound/pci/rme32.c +++ b/trunk/sound/pci/rme32.c @@ -1984,11 +1984,22 @@ static void __devexit snd_rme32_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver rme32_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_rme32_ids, .probe = snd_rme32_probe, .remove = __devexit_p(snd_rme32_remove), }; -module_pci_driver(rme32_driver); +static int __init alsa_card_rme32_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_rme32_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_rme32_init) +module_exit(alsa_card_rme32_exit) diff --git a/trunk/sound/pci/rme96.c b/trunk/sound/pci/rme96.c index 9b98dc406988..ba894158e76c 100644 --- a/trunk/sound/pci/rme96.c +++ b/trunk/sound/pci/rme96.c @@ -2395,11 +2395,22 @@ static void __devexit snd_rme96_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver rme96_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_rme96_ids, .probe = snd_rme96_probe, .remove = __devexit_p(snd_rme96_remove), }; -module_pci_driver(rme96_driver); +static int __init alsa_card_rme96_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_rme96_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_rme96_init) +module_exit(alsa_card_rme96_exit) diff --git a/trunk/sound/pci/rme9652/hdsp.c b/trunk/sound/pci/rme9652/hdsp.c index 0d6930c4f4b7..0b2aea2ce172 100644 --- a/trunk/sound/pci/rme9652/hdsp.c +++ b/trunk/sound/pci/rme9652/hdsp.c @@ -5636,11 +5636,22 @@ static void __devexit snd_hdsp_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver hdsp_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_hdsp_ids, .probe = snd_hdsp_probe, .remove = __devexit_p(snd_hdsp_remove), }; -module_pci_driver(hdsp_driver); +static int __init alsa_card_hdsp_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_hdsp_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_hdsp_init) +module_exit(alsa_card_hdsp_exit) diff --git a/trunk/sound/pci/rme9652/hdspm.c b/trunk/sound/pci/rme9652/hdspm.c index 0a5027b94714..bc030a2088da 100644 --- a/trunk/sound/pci/rme9652/hdspm.c +++ b/trunk/sound/pci/rme9652/hdspm.c @@ -6918,11 +6918,23 @@ static void __devexit snd_hdspm_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver hdspm_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_hdspm_ids, .probe = snd_hdspm_probe, .remove = __devexit_p(snd_hdspm_remove), }; -module_pci_driver(hdspm_driver); + +static int __init alsa_card_hdspm_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_hdspm_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_hdspm_init) +module_exit(alsa_card_hdspm_exit) diff --git a/trunk/sound/pci/rme9652/rme9652.c b/trunk/sound/pci/rme9652/rme9652.c index a15fc100ab0c..b737d1619cc7 100644 --- a/trunk/sound/pci/rme9652/rme9652.c +++ b/trunk/sound/pci/rme9652/rme9652.c @@ -2631,11 +2631,22 @@ static void __devexit snd_rme9652_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver rme9652_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_rme9652_ids, .probe = snd_rme9652_probe, .remove = __devexit_p(snd_rme9652_remove), }; -module_pci_driver(rme9652_driver); +static int __init alsa_card_hammerfall_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_hammerfall_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_hammerfall_init) +module_exit(alsa_card_hammerfall_exit) diff --git a/trunk/sound/pci/sis7019.c b/trunk/sound/pci/sis7019.c index 1552642765d6..ff500a87f769 100644 --- a/trunk/sound/pci/sis7019.c +++ b/trunk/sound/pci/sis7019.c @@ -1488,4 +1488,15 @@ static struct pci_driver sis7019_driver = { #endif }; -module_pci_driver(sis7019_driver); +static int __init sis7019_init(void) +{ + return pci_register_driver(&sis7019_driver); +} + +static void __exit sis7019_exit(void) +{ + pci_unregister_driver(&sis7019_driver); +} + +module_init(sis7019_init); +module_exit(sis7019_exit); diff --git a/trunk/sound/pci/sonicvibes.c b/trunk/sound/pci/sonicvibes.c index baa9946bedf0..54cc802050f7 100644 --- a/trunk/sound/pci/sonicvibes.c +++ b/trunk/sound/pci/sonicvibes.c @@ -1530,11 +1530,22 @@ static void __devexit snd_sonic_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver sonicvibes_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_sonic_ids, .probe = snd_sonic_probe, .remove = __devexit_p(snd_sonic_remove), }; -module_pci_driver(sonicvibes_driver); +static int __init alsa_card_sonicvibes_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_sonicvibes_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_sonicvibes_init) +module_exit(alsa_card_sonicvibes_exit) diff --git a/trunk/sound/pci/trident/trident.c b/trunk/sound/pci/trident/trident.c index 611983ec7321..5f1def7f45e5 100644 --- a/trunk/sound/pci/trident/trident.c +++ b/trunk/sound/pci/trident/trident.c @@ -172,7 +172,7 @@ static void __devexit snd_trident_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver trident_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_trident_ids, .probe = snd_trident_probe, @@ -183,4 +183,15 @@ static struct pci_driver trident_driver = { #endif }; -module_pci_driver(trident_driver); +static int __init alsa_card_trident_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_trident_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_trident_init) +module_exit(alsa_card_trident_exit) diff --git a/trunk/sound/pci/via82xx.c b/trunk/sound/pci/via82xx.c index b5afab48943e..75630408c6db 100644 --- a/trunk/sound/pci/via82xx.c +++ b/trunk/sound/pci/via82xx.c @@ -2619,7 +2619,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver via82xx_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_ids, .probe = snd_via82xx_probe, @@ -2630,4 +2630,15 @@ static struct pci_driver via82xx_driver = { #endif }; -module_pci_driver(via82xx_driver); +static int __init alsa_card_via82xx_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_via82xx_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_via82xx_init) +module_exit(alsa_card_via82xx_exit) diff --git a/trunk/sound/pci/via82xx_modem.c b/trunk/sound/pci/via82xx_modem.c index 59fd47ed0a31..5efcbcac506a 100644 --- a/trunk/sound/pci/via82xx_modem.c +++ b/trunk/sound/pci/via82xx_modem.c @@ -1223,7 +1223,7 @@ static void __devexit snd_via82xx_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver via82xx_modem_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_via82xx_modem_ids, .probe = snd_via82xx_probe, @@ -1234,4 +1234,15 @@ static struct pci_driver via82xx_modem_driver = { #endif }; -module_pci_driver(via82xx_modem_driver); +static int __init alsa_card_via82xx_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_via82xx_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_via82xx_init) +module_exit(alsa_card_via82xx_exit) diff --git a/trunk/sound/pci/vx222/vx222.c b/trunk/sound/pci/vx222/vx222.c index 1ea1f656a5dc..6a534bfe1274 100644 --- a/trunk/sound/pci/vx222/vx222.c +++ b/trunk/sound/pci/vx222/vx222.c @@ -289,7 +289,7 @@ static int snd_vx222_resume(struct pci_dev *pci) } #endif -static struct pci_driver vx222_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_vx222_ids, .probe = snd_vx222_probe, @@ -300,4 +300,15 @@ static struct pci_driver vx222_driver = { #endif }; -module_pci_driver(vx222_driver); +static int __init alsa_card_vx222_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_vx222_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_vx222_init) +module_exit(alsa_card_vx222_exit) diff --git a/trunk/sound/pci/ymfpci/ymfpci.c b/trunk/sound/pci/ymfpci/ymfpci.c index 9a1d01d653a7..94ab728f5ca8 100644 --- a/trunk/sound/pci/ymfpci/ymfpci.c +++ b/trunk/sound/pci/ymfpci/ymfpci.c @@ -350,7 +350,7 @@ static void __devexit snd_card_ymfpci_remove(struct pci_dev *pci) pci_set_drvdata(pci, NULL); } -static struct pci_driver ymfpci_driver = { +static struct pci_driver driver = { .name = KBUILD_MODNAME, .id_table = snd_ymfpci_ids, .probe = snd_card_ymfpci_probe, @@ -361,4 +361,15 @@ static struct pci_driver ymfpci_driver = { #endif }; -module_pci_driver(ymfpci_driver); +static int __init alsa_card_ymfpci_init(void) +{ + return pci_register_driver(&driver); +} + +static void __exit alsa_card_ymfpci_exit(void) +{ + pci_unregister_driver(&driver); +} + +module_init(alsa_card_ymfpci_init) +module_exit(alsa_card_ymfpci_exit) diff --git a/trunk/sound/sh/sh_dac_audio.c b/trunk/sound/sh/sh_dac_audio.c index f8b01c77b298..b11f82b5718f 100644 --- a/trunk/sound/sh/sh_dac_audio.c +++ b/trunk/sound/sh/sh_dac_audio.c @@ -433,7 +433,7 @@ static int __devinit snd_sh_dac_probe(struct platform_device *devptr) /* * "driver" definition */ -static struct platform_driver sh_dac_driver = { +static struct platform_driver driver = { .probe = snd_sh_dac_probe, .remove = snd_sh_dac_remove, .driver = { @@ -441,4 +441,4 @@ static struct platform_driver sh_dac_driver = { }, }; -module_platform_driver(sh_dac_driver); +module_platform_driver(driver); diff --git a/trunk/sound/soc/codecs/Kconfig b/trunk/sound/soc/codecs/Kconfig index 22c686444633..1e1613a438dd 100644 --- a/trunk/sound/soc/codecs/Kconfig +++ b/trunk/sound/soc/codecs/Kconfig @@ -46,6 +46,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_MAX9877 if I2C select SND_SOC_MC13783 if MFD_MC13XXX select SND_SOC_ML26124 if I2C + select SND_SOC_OMAP_HDMI_CODEC if OMAP4_DSS_HDMI select SND_SOC_PCM3008 select SND_SOC_RT5631 if I2C select SND_SOC_SGTL5000 if I2C @@ -236,6 +237,9 @@ config SND_SOC_MAX98095 config SND_SOC_MAX9850 tristate +config SND_SOC_OMAP_HDMI_CODEC + tristate + config SND_SOC_PCM3008 tristate diff --git a/trunk/sound/soc/codecs/Makefile b/trunk/sound/soc/codecs/Makefile index a9663e9c375b..fc27fec39487 100644 --- a/trunk/sound/soc/codecs/Makefile +++ b/trunk/sound/soc/codecs/Makefile @@ -33,6 +33,7 @@ snd-soc-max98095-objs := max98095.o snd-soc-max9850-objs := max9850.o snd-soc-mc13783-objs := mc13783.o snd-soc-ml26124-objs := ml26124.o +snd-soc-omap-hdmi-codec-objs := omap-hdmi.o snd-soc-pcm3008-objs := pcm3008.o snd-soc-rt5631-objs := rt5631.o snd-soc-sgtl5000-objs := sgtl5000.o @@ -143,6 +144,7 @@ obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_OMAP_HDMI_CODEC) += snd-soc-omap-hdmi-codec.o obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o diff --git a/trunk/sound/soc/codecs/cs42l73.c b/trunk/sound/soc/codecs/cs42l73.c index e0d45fdaa750..5a537b7713a3 100644 --- a/trunk/sound/soc/codecs/cs42l73.c +++ b/trunk/sound/soc/codecs/cs42l73.c @@ -565,22 +565,22 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = { attn_tlv), SOC_SINGLE_TLV("SPK-IP Mono Volume", - CS42L73_SPKMIPMA, 0, 0x3F, 1, attn_tlv), + CS42L73_SPKMIPMA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("SPK-XSP Mono Volume", - CS42L73_SPKMXSPA, 0, 0x3F, 1, attn_tlv), + CS42L73_SPKMXSPA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("SPK-ASP Mono Volume", - CS42L73_SPKMASPA, 0, 0x3F, 1, attn_tlv), + CS42L73_SPKMASPA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("SPK-VSP Mono Volume", - CS42L73_SPKMVSPMA, 0, 0x3F, 1, attn_tlv), + CS42L73_SPKMVSPMA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("ESL-IP Mono Volume", - CS42L73_ESLMIPMA, 0, 0x3F, 1, attn_tlv), + CS42L73_ESLMIPMA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("ESL-XSP Mono Volume", - CS42L73_ESLMXSPA, 0, 0x3F, 1, attn_tlv), + CS42L73_ESLMXSPA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("ESL-ASP Mono Volume", - CS42L73_ESLMASPA, 0, 0x3F, 1, attn_tlv), + CS42L73_ESLMASPA, 0, 0x3E, 1, attn_tlv), SOC_SINGLE_TLV("ESL-VSP Mono Volume", - CS42L73_ESLMVSPMA, 0, 0x3F, 1, attn_tlv), + CS42L73_ESLMVSPMA, 0, 0x3E, 1, attn_tlv), SOC_ENUM("IP Digital Swap/Mono Select", ip_swap_enum), diff --git a/trunk/sound/soc/codecs/omap-hdmi.c b/trunk/sound/soc/codecs/omap-hdmi.c new file mode 100644 index 000000000000..1bf5c74f5f96 --- /dev/null +++ b/trunk/sound/soc/codecs/omap-hdmi.c @@ -0,0 +1,69 @@ +/* + * ALSA SoC codec driver for HDMI audio on OMAP processors. + * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ + * Author: Ricardo Neri + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + * + */ +#include +#include + +#define DRV_NAME "hdmi-audio-codec" + +static struct snd_soc_codec_driver omap_hdmi_codec; + +static struct snd_soc_dai_driver omap_hdmi_codec_dai = { + .name = "omap-hdmi-hifi", + .playback = { + .channels_min = 2, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_32000 | + SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + }, +}; + +static __devinit int omap_hdmi_codec_probe(struct platform_device *pdev) +{ + return snd_soc_register_codec(&pdev->dev, &omap_hdmi_codec, + &omap_hdmi_codec_dai, 1); +} + +static __devexit int omap_hdmi_codec_remove(struct platform_device *pdev) +{ + snd_soc_unregister_codec(&pdev->dev); + return 0; +} + +static struct platform_driver omap_hdmi_codec_driver = { + .driver = { + .name = DRV_NAME, + .owner = THIS_MODULE, + }, + + .probe = omap_hdmi_codec_probe, + .remove = __devexit_p(omap_hdmi_codec_remove), +}; + +module_platform_driver(omap_hdmi_codec_driver); + +MODULE_AUTHOR("Ricardo Neri "); +MODULE_DESCRIPTION("ASoC OMAP HDMI codec driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" DRV_NAME); diff --git a/trunk/sound/soc/codecs/wm8994.c b/trunk/sound/soc/codecs/wm8994.c index 993639d694ce..2f9870aa0cf1 100644 --- a/trunk/sound/soc/codecs/wm8994.c +++ b/trunk/sound/soc/codecs/wm8994.c @@ -1127,7 +1127,7 @@ static int aif2clk_ev(struct snd_soc_dapm_widget *w, snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, WM8994_AIF2DACL_ENA | WM8994_AIF2DACR_ENA, 0); - snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_4, + snd_soc_update_bits(codec, WM8994_POWER_MANAGEMENT_5, WM8994_AIF2ADCL_ENA | WM8994_AIF2ADCR_ENA, 0); diff --git a/trunk/sound/soc/omap/Kconfig b/trunk/sound/soc/omap/Kconfig index deafbfaacdbf..9ccfa5e1c11b 100644 --- a/trunk/sound/soc/omap/Kconfig +++ b/trunk/sound/soc/omap/Kconfig @@ -113,6 +113,7 @@ config SND_OMAP_SOC_OMAP4_HDMI tristate "SoC Audio support for Texas Instruments OMAP4 HDMI" depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS && ARCH_OMAP4 select SND_OMAP_SOC_HDMI + select SND_SOC_OMAP_HDMI_CODEC help Say Y if you want to add support for SoC HDMI audio on Texas Instruments OMAP4 chips diff --git a/trunk/sound/sound_core.c b/trunk/sound/sound_core.c index fb9255cca214..c6e81fb928e9 100644 --- a/trunk/sound/sound_core.c +++ b/trunk/sound/sound_core.c @@ -361,7 +361,7 @@ int register_sound_special_device(const struct file_operations *fops, int unit, struct device *dev) { const int chain = unit % SOUND_STEP; - int max_unit = 256; + int max_unit = 128 + chain; const char *name; char _name[16]; diff --git a/trunk/sound/usb/card.c b/trunk/sound/usb/card.c index d5b5c3388e28..4a7be7b98331 100644 --- a/trunk/sound/usb/card.c +++ b/trunk/sound/usb/card.c @@ -131,9 +131,8 @@ static void snd_usb_stream_disconnect(struct list_head *head) subs = &as->substream[idx]; if (!subs->num_formats) continue; + snd_usb_release_substream_urbs(subs, 1); subs->interface = -1; - subs->data_endpoint = NULL; - subs->sync_endpoint = NULL; } } @@ -277,7 +276,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) static int snd_usb_audio_free(struct snd_usb_audio *chip) { - mutex_destroy(&chip->mutex); kfree(chip); return 0; } @@ -338,7 +336,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, return -ENOMEM; } - mutex_init(&chip->mutex); mutex_init(&chip->shutdown_mutex); chip->index = idx; chip->dev = dev; @@ -351,7 +348,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx, chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), le16_to_cpu(dev->descriptor.idProduct)); INIT_LIST_HEAD(&chip->pcm_list); - INIT_LIST_HEAD(&chip->ep_list); INIT_LIST_HEAD(&chip->midi_list); INIT_LIST_HEAD(&chip->mixer_list); @@ -569,10 +565,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev, list_for_each(p, &chip->pcm_list) { snd_usb_stream_disconnect(p); } - /* release the endpoint resources */ - list_for_each(p, &chip->ep_list) { - snd_usb_endpoint_free(p); - } /* release the midi resources */ list_for_each(p, &chip->midi_list) { snd_usbmidi_disconnect(p); diff --git a/trunk/sound/usb/card.h b/trunk/sound/usb/card.h index 0d37238b8457..da5fa1ac4eda 100644 --- a/trunk/sound/usb/card.h +++ b/trunk/sound/usb/card.h @@ -30,71 +30,20 @@ struct audioformat { }; struct snd_usb_substream; -struct snd_usb_endpoint; struct snd_urb_ctx { struct urb *urb; unsigned int buffer_size; /* size of data buffer, if data URB */ struct snd_usb_substream *subs; - struct snd_usb_endpoint *ep; int index; /* index for urb array */ int packets; /* number of packets per urb */ - int packet_size[MAX_PACKS_HS]; /* size of packets for next submission */ - struct list_head ready_list; }; -struct snd_usb_endpoint { - struct snd_usb_audio *chip; - - int use_count; - int ep_num; /* the referenced endpoint number */ - int type; /* SND_USB_ENDPOINT_TYPE_* */ - unsigned long flags; - - void (*prepare_data_urb) (struct snd_usb_substream *subs, - struct urb *urb); - void (*retire_data_urb) (struct snd_usb_substream *subs, - struct urb *urb); - - struct snd_usb_substream *data_subs; - struct snd_usb_endpoint *sync_master; - struct snd_usb_endpoint *sync_slave; - - struct snd_urb_ctx urb[MAX_URBS]; - - struct snd_usb_packet_info { - uint32_t packet_size[MAX_PACKS_HS]; - int packets; - } next_packet[MAX_URBS]; - int next_packet_read_pos, next_packet_write_pos; - struct list_head ready_playback_urbs; - - unsigned int nurbs; /* # urbs */ - unsigned long active_mask; /* bitmask of active urbs */ - unsigned long unlink_mask; /* bitmask of unlinked urbs */ - char *syncbuf; /* sync buffer for all sync URBs */ - dma_addr_t sync_dma; /* DMA address of syncbuf */ - - unsigned int pipe; /* the data i/o pipe */ - unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ - unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ - int freqshift; /* how much to shift the feedback value to get Q16.16 */ - unsigned int freqmax; /* maximum sampling rate, used for buffer management */ - unsigned int phase; /* phase accumulator */ - unsigned int maxpacksize; /* max packet size in bytes */ - unsigned int maxframesize; /* max packet size in frames */ - unsigned int curpacksize; /* current packet size in bytes (for capture) */ - unsigned int curframesize; /* current packet size in frames (for capture) */ - unsigned int syncmaxsize; /* sync endpoint packet size */ - unsigned int fill_max:1; /* fill max packet size always */ - unsigned int datainterval; /* log_2 of data packet interval */ - unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ - unsigned char silence_value; - unsigned int stride; - int iface, alt_idx; - - spinlock_t lock; - struct list_head list; +struct snd_urb_ops { + int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); + int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); + int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); + int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u); }; struct snd_usb_substream { @@ -108,6 +57,21 @@ struct snd_usb_substream { unsigned int cur_rate; /* current rate (for hw_params callback) */ unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int altset_idx; /* USB data format: index of alternate setting */ + unsigned int datapipe; /* the data i/o pipe */ + unsigned int syncpipe; /* 1 - async out or adaptive in */ + unsigned int datainterval; /* log_2 of data packet interval */ + unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */ + unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */ + unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */ + int freqshift; /* how much to shift the feedback value to get Q16.16 */ + unsigned int freqmax; /* maximum sampling rate, used for buffer management */ + unsigned int phase; /* phase accumulator */ + unsigned int maxpacksize; /* max packet size in bytes */ + unsigned int maxframesize; /* max packet size in frames */ + unsigned int curpacksize; /* current packet size in bytes (for capture) */ + unsigned int curframesize; /* current packet size in frames (for capture) */ + unsigned int syncmaxsize; /* sync endpoint packet size */ + unsigned int fill_max: 1; /* fill max packet size always */ unsigned int txfr_quirk:1; /* allow sub-frame alignment */ unsigned int fmt_type; /* USB audio format type (1-3) */ @@ -118,10 +82,11 @@ struct snd_usb_substream { unsigned long active_mask; /* bitmask of active urbs */ unsigned long unlink_mask; /* bitmask of unlinked urbs */ - /* data and sync endpoints for this stream */ - struct snd_usb_endpoint *data_endpoint; - struct snd_usb_endpoint *sync_endpoint; - unsigned long flags; + unsigned int nurbs; /* # urbs */ + struct snd_urb_ctx dataurb[MAX_URBS]; /* data urb table */ + struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */ + char *syncbuf; /* sync buffer for all sync URBs */ + dma_addr_t sync_dma; /* DMA address of syncbuf */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ @@ -129,6 +94,7 @@ struct snd_usb_substream { struct snd_pcm_hw_constraint_list rate_list; /* limited rates */ spinlock_t lock; + struct snd_urb_ops ops; /* callbacks (must be filled at init) */ int last_frame_number; /* stored frame number */ int last_delay; /* stored delay */ }; diff --git a/trunk/sound/usb/endpoint.c b/trunk/sound/usb/endpoint.c index e6906901debb..08dcce53720b 100644 --- a/trunk/sound/usb/endpoint.c +++ b/trunk/sound/usb/endpoint.c @@ -20,11 +20,9 @@ #include #include #include -#include #include #include -#include #include "usbaudio.h" #include "helper.h" @@ -32,36 +30,6 @@ #include "endpoint.h" #include "pcm.h" -#define EP_FLAG_ACTIVATED 0 -#define EP_FLAG_RUNNING 1 - -/* - * snd_usb_endpoint is a model that abstracts everything related to an - * USB endpoint and its streaming. - * - * There are functions to activate and deactivate the streaming URBs and - * optional callbacks to let the pcm logic handle the actual content of the - * packets for playback and record. Thus, the bus streaming and the audio - * handlers are fully decoupled. - * - * There are two different types of endpoints in audio applications. - * - * SND_USB_ENDPOINT_TYPE_DATA handles full audio data payload for both - * inbound and outbound traffic. - * - * SND_USB_ENDPOINT_TYPE_SYNC endpoints are for inbound traffic only and - * expect the payload to carry Q10.14 / Q16.16 formatted sync information - * (3 or 4 bytes). - * - * Each endpoint has to be configured prior to being used by calling - * snd_usb_endpoint_set_params(). - * - * The model incorporates a reference counting, so that multiple users - * can call snd_usb_endpoint_start() and snd_usb_endpoint_stop(), and - * only the first user will effectively start the URBs, and only the last - * one to stop it will tear the URBs down again. - */ - /* * convert a sampling rate into our full speed format (fs/1000 in Q16.16) * this will overflow at approx 524 kHz @@ -81,415 +49,71 @@ static inline unsigned get_usb_high_speed_rate(unsigned int rate) } /* - * release a urb data - */ -static void release_urb_ctx(struct snd_urb_ctx *u) -{ - if (u->buffer_size) - usb_free_coherent(u->ep->chip->dev, u->buffer_size, - u->urb->transfer_buffer, - u->urb->transfer_dma); - usb_free_urb(u->urb); - u->urb = NULL; -} - -static const char *usb_error_string(int err) -{ - switch (err) { - case -ENODEV: - return "no device"; - case -ENOENT: - return "endpoint not enabled"; - case -EPIPE: - return "endpoint stalled"; - case -ENOSPC: - return "not enough bandwidth"; - case -ESHUTDOWN: - return "device disabled"; - case -EHOSTUNREACH: - return "device suspended"; - case -EINVAL: - case -EAGAIN: - case -EFBIG: - case -EMSGSIZE: - return "internal error"; - default: - return "unknown error"; - } -} - -/** - * snd_usb_endpoint_implicit_feedback_sink: Report endpoint usage type - * - * @ep: The snd_usb_endpoint - * - * Determine whether an endpoint is driven by an implicit feedback - * data endpoint source. - */ -int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep) -{ - return ep->sync_master && - ep->sync_master->type == SND_USB_ENDPOINT_TYPE_DATA && - ep->type == SND_USB_ENDPOINT_TYPE_DATA && - usb_pipeout(ep->pipe); -} - -/* - * For streaming based on information derived from sync endpoints, - * prepare_outbound_urb_sizes() will call next_packet_size() to - * determine the number of samples to be sent in the next packet. - * - * For implicit feedback, next_packet_size() is unused. + * unlink active urbs. */ -static int next_packet_size(struct snd_usb_endpoint *ep) -{ - unsigned long flags; - int ret; - - if (ep->fill_max) - return ep->maxframesize; - - spin_lock_irqsave(&ep->lock, flags); - ep->phase = (ep->phase & 0xffff) - + (ep->freqm << ep->datainterval); - ret = min(ep->phase >> 16, ep->maxframesize); - spin_unlock_irqrestore(&ep->lock, flags); - - return ret; -} - -static void retire_outbound_urb(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *urb_ctx) -{ - if (ep->retire_data_urb) - ep->retire_data_urb(ep->data_subs, urb_ctx->urb); -} - -static void retire_inbound_urb(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *urb_ctx) +static int deactivate_urbs(struct snd_usb_substream *subs, int force, int can_sleep) { - struct urb *urb = urb_ctx->urb; - - if (ep->sync_slave) - snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); - - if (ep->retire_data_urb) - ep->retire_data_urb(ep->data_subs, urb); -} + struct snd_usb_audio *chip = subs->stream->chip; + unsigned int i; + int async; -static void prepare_outbound_urb_sizes(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *ctx) -{ - int i; + subs->running = 0; - for (i = 0; i < ctx->packets; ++i) - ctx->packet_size[i] = next_packet_size(ep); -} + if (!force && subs->stream->chip->shutdown) /* to be sure... */ + return -EBADFD; -/* - * Prepare a PLAYBACK urb for submission to the bus. - */ -static void prepare_outbound_urb(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *ctx) -{ - int i; - struct urb *urb = ctx->urb; - unsigned char *cp = urb->transfer_buffer; + async = !can_sleep && chip->async_unlink; - urb->dev = ep->chip->dev; /* we need to set this at each time */ + if (!async && in_interrupt()) + return 0; - switch (ep->type) { - case SND_USB_ENDPOINT_TYPE_DATA: - if (ep->prepare_data_urb) { - ep->prepare_data_urb(ep->data_subs, urb); - } else { - /* no data provider, so send silence */ - unsigned int offs = 0; - for (i = 0; i < ctx->packets; ++i) { - int counts = ctx->packet_size[i]; - urb->iso_frame_desc[i].offset = offs * ep->stride; - urb->iso_frame_desc[i].length = counts * ep->stride; - offs += counts; + for (i = 0; i < subs->nurbs; i++) { + if (test_bit(i, &subs->active_mask)) { + if (!test_and_set_bit(i, &subs->unlink_mask)) { + struct urb *u = subs->dataurb[i].urb; + if (async) + usb_unlink_urb(u); + else + usb_kill_urb(u); } - - urb->number_of_packets = ctx->packets; - urb->transfer_buffer_length = offs * ep->stride; - memset(urb->transfer_buffer, ep->silence_value, - offs * ep->stride); } - break; - - case SND_USB_ENDPOINT_TYPE_SYNC: - if (snd_usb_get_speed(ep->chip->dev) >= USB_SPEED_HIGH) { - /* - * fill the length and offset of each urb descriptor. - * the fixed 12.13 frequency is passed as 16.16 through the pipe. - */ - urb->iso_frame_desc[0].length = 4; - urb->iso_frame_desc[0].offset = 0; - cp[0] = ep->freqn; - cp[1] = ep->freqn >> 8; - cp[2] = ep->freqn >> 16; - cp[3] = ep->freqn >> 24; - } else { - /* - * fill the length and offset of each urb descriptor. - * the fixed 10.14 frequency is passed through the pipe. - */ - urb->iso_frame_desc[0].length = 3; - urb->iso_frame_desc[0].offset = 0; - cp[0] = ep->freqn >> 2; - cp[1] = ep->freqn >> 10; - cp[2] = ep->freqn >> 18; - } - - break; } -} - -/* - * Prepare a CAPTURE or SYNC urb for submission to the bus. - */ -static inline void prepare_inbound_urb(struct snd_usb_endpoint *ep, - struct snd_urb_ctx *urb_ctx) -{ - int i, offs; - struct urb *urb = urb_ctx->urb; - - urb->dev = ep->chip->dev; /* we need to set this at each time */ - - switch (ep->type) { - case SND_USB_ENDPOINT_TYPE_DATA: - offs = 0; - for (i = 0; i < urb_ctx->packets; i++) { - urb->iso_frame_desc[i].offset = offs; - urb->iso_frame_desc[i].length = ep->curpacksize; - offs += ep->curpacksize; + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (test_bit(i+16, &subs->active_mask)) { + if (!test_and_set_bit(i+16, &subs->unlink_mask)) { + struct urb *u = subs->syncurb[i].urb; + if (async) + usb_unlink_urb(u); + else + usb_kill_urb(u); + } + } } - - urb->transfer_buffer_length = offs; - urb->number_of_packets = urb_ctx->packets; - break; - - case SND_USB_ENDPOINT_TYPE_SYNC: - urb->iso_frame_desc[0].length = min(4u, ep->syncmaxsize); - urb->iso_frame_desc[0].offset = 0; - break; } + return 0; } -/* - * Send output urbs that have been prepared previously. URBs are dequeued - * from ep->ready_playback_urbs and in case there there aren't any available - * or there are no packets that have been prepared, this function does - * nothing. - * - * The reason why the functionality of sending and preparing URBs is separated - * is that host controllers don't guarantee the order in which they return - * inbound and outbound packets to their submitters. - * - * This function is only used for implicit feedback endpoints. For endpoints - * driven by dedicated sync endpoints, URBs are immediately re-submitted - * from their completion handler. - */ -static void queue_pending_output_urbs(struct snd_usb_endpoint *ep) -{ - while (test_bit(EP_FLAG_RUNNING, &ep->flags)) { - - unsigned long flags; - struct snd_usb_packet_info *uninitialized_var(packet); - struct snd_urb_ctx *ctx = NULL; - struct urb *urb; - int err, i; - - spin_lock_irqsave(&ep->lock, flags); - if (ep->next_packet_read_pos != ep->next_packet_write_pos) { - packet = ep->next_packet + ep->next_packet_read_pos; - ep->next_packet_read_pos++; - ep->next_packet_read_pos %= MAX_URBS; - - /* take URB out of FIFO */ - if (!list_empty(&ep->ready_playback_urbs)) - ctx = list_first_entry(&ep->ready_playback_urbs, - struct snd_urb_ctx, ready_list); - } - spin_unlock_irqrestore(&ep->lock, flags); - - if (ctx == NULL) - return; - - list_del_init(&ctx->ready_list); - urb = ctx->urb; - - /* copy over the length information */ - for (i = 0; i < packet->packets; i++) - ctx->packet_size[i] = packet->packet_size[i]; - - /* call the data handler to fill in playback data */ - prepare_outbound_urb(ep, ctx); - - err = usb_submit_urb(ctx->urb, GFP_ATOMIC); - if (err < 0) - snd_printk(KERN_ERR "Unable to submit urb #%d: %d (urb %p)\n", - ctx->index, err, ctx->urb); - else - set_bit(ctx->index, &ep->active_mask); - } -} /* - * complete callback for urbs - */ -static void snd_complete_urb(struct urb *urb) -{ - struct snd_urb_ctx *ctx = urb->context; - struct snd_usb_endpoint *ep = ctx->ep; - int err; - - if (unlikely(urb->status == -ENOENT || /* unlinked */ - urb->status == -ENODEV || /* device removed */ - urb->status == -ECONNRESET || /* unlinked */ - urb->status == -ESHUTDOWN || /* device disabled */ - ep->chip->shutdown)) /* device disconnected */ - goto exit_clear; - - if (usb_pipeout(ep->pipe)) { - retire_outbound_urb(ep, ctx); - /* can be stopped during retire callback */ - if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) - goto exit_clear; - - if (snd_usb_endpoint_implict_feedback_sink(ep)) { - unsigned long flags; - - spin_lock_irqsave(&ep->lock, flags); - list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); - spin_unlock_irqrestore(&ep->lock, flags); - queue_pending_output_urbs(ep); - - goto exit_clear; - } - - prepare_outbound_urb_sizes(ep, ctx); - prepare_outbound_urb(ep, ctx); - } else { - retire_inbound_urb(ep, ctx); - /* can be stopped during retire callback */ - if (unlikely(!test_bit(EP_FLAG_RUNNING, &ep->flags))) - goto exit_clear; - - prepare_inbound_urb(ep, ctx); - } - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err == 0) - return; - - snd_printk(KERN_ERR "cannot submit urb (err = %d)\n", err); - //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); - -exit_clear: - clear_bit(ctx->index, &ep->active_mask); -} - -/** - * snd_usb_add_endpoint: Add an endpoint to an USB audio chip - * - * @chip: The chip - * @alts: The USB host interface - * @ep_num: The number of the endpoint to use - * @direction: SNDRV_PCM_STREAM_PLAYBACK or SNDRV_PCM_STREAM_CAPTURE - * @type: SND_USB_ENDPOINT_TYPE_DATA or SND_USB_ENDPOINT_TYPE_SYNC - * - * If the requested endpoint has not been added to the given chip before, - * a new instance is created. Otherwise, a pointer to the previoulsy - * created instance is returned. In case of any error, NULL is returned. - * - * New endpoints will be added to chip->ep_list and must be freed by - * calling snd_usb_endpoint_free(). + * release a urb data */ -struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int ep_num, int direction, int type) +static void release_urb_ctx(struct snd_urb_ctx *u) { - struct list_head *p; - struct snd_usb_endpoint *ep; - int ret, is_playback = direction == SNDRV_PCM_STREAM_PLAYBACK; - - mutex_lock(&chip->mutex); - - list_for_each(p, &chip->ep_list) { - ep = list_entry(p, struct snd_usb_endpoint, list); - if (ep->ep_num == ep_num && - ep->iface == alts->desc.bInterfaceNumber && - ep->alt_idx == alts->desc.bAlternateSetting) { - snd_printdd(KERN_DEBUG "Re-using EP %x in iface %d,%d @%p\n", - ep_num, ep->iface, ep->alt_idx, ep); - goto __exit_unlock; - } - } - - snd_printdd(KERN_DEBUG "Creating new %s %s endpoint #%x\n", - is_playback ? "playback" : "capture", - type == SND_USB_ENDPOINT_TYPE_DATA ? "data" : "sync", - ep_num); - - /* select the alt setting once so the endpoints become valid */ - ret = usb_set_interface(chip->dev, alts->desc.bInterfaceNumber, - alts->desc.bAlternateSetting); - if (ret < 0) { - snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n", - __func__, ret); - ep = NULL; - goto __exit_unlock; + if (u->urb) { + if (u->buffer_size) + usb_free_coherent(u->subs->dev, u->buffer_size, + u->urb->transfer_buffer, + u->urb->transfer_dma); + usb_free_urb(u->urb); + u->urb = NULL; } - - ep = kzalloc(sizeof(*ep), GFP_KERNEL); - if (!ep) - goto __exit_unlock; - - ep->chip = chip; - spin_lock_init(&ep->lock); - ep->type = type; - ep->ep_num = ep_num; - ep->iface = alts->desc.bInterfaceNumber; - ep->alt_idx = alts->desc.bAlternateSetting; - INIT_LIST_HEAD(&ep->ready_playback_urbs); - ep_num &= USB_ENDPOINT_NUMBER_MASK; - - if (is_playback) - ep->pipe = usb_sndisocpipe(chip->dev, ep_num); - else - ep->pipe = usb_rcvisocpipe(chip->dev, ep_num); - - if (type == SND_USB_ENDPOINT_TYPE_SYNC) { - if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && - get_endpoint(alts, 1)->bRefresh >= 1 && - get_endpoint(alts, 1)->bRefresh <= 9) - ep->syncinterval = get_endpoint(alts, 1)->bRefresh; - else if (snd_usb_get_speed(chip->dev) == USB_SPEED_FULL) - ep->syncinterval = 1; - else if (get_endpoint(alts, 1)->bInterval >= 1 && - get_endpoint(alts, 1)->bInterval <= 16) - ep->syncinterval = get_endpoint(alts, 1)->bInterval - 1; - else - ep->syncinterval = 3; - - ep->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); - } - - list_add_tail(&ep->list, &chip->ep_list); - -__exit_unlock: - mutex_unlock(&chip->mutex); - - return ep; } /* * wait until all urbs are processed. */ -static int wait_clear_urbs(struct snd_usb_endpoint *ep) +static int wait_clear_urbs(struct snd_usb_substream *subs) { unsigned long end_time = jiffies + msecs_to_jiffies(1000); unsigned int i; @@ -497,148 +121,153 @@ static int wait_clear_urbs(struct snd_usb_endpoint *ep) do { alive = 0; - for (i = 0; i < ep->nurbs; i++) - if (test_bit(i, &ep->active_mask)) + for (i = 0; i < subs->nurbs; i++) { + if (test_bit(i, &subs->active_mask)) alive++; - - if (!alive) + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (test_bit(i + 16, &subs->active_mask)) + alive++; + } + } + if (! alive) break; - schedule_timeout_uninterruptible(1); } while (time_before(jiffies, end_time)); - if (alive) - snd_printk(KERN_ERR "timeout: still %d active urbs on EP #%x\n", - alive, ep->ep_num); - + snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive); return 0; } /* - * unlink active urbs. + * release a substream */ -static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep) +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force) { - unsigned int i; - int async; - - if (!force && ep->chip->shutdown) /* to be sure... */ - return -EBADFD; - - async = !can_sleep && ep->chip->async_unlink; - - clear_bit(EP_FLAG_RUNNING, &ep->flags); - - INIT_LIST_HEAD(&ep->ready_playback_urbs); - ep->next_packet_read_pos = 0; - ep->next_packet_write_pos = 0; + int i; - if (!async && in_interrupt()) - return 0; + /* stop urbs (to be sure) */ + deactivate_urbs(subs, force, 1); + wait_clear_urbs(subs); + + for (i = 0; i < MAX_URBS; i++) + release_urb_ctx(&subs->dataurb[i]); + for (i = 0; i < SYNC_URBS; i++) + release_urb_ctx(&subs->syncurb[i]); + usb_free_coherent(subs->dev, SYNC_URBS * 4, + subs->syncbuf, subs->sync_dma); + subs->syncbuf = NULL; + subs->nurbs = 0; +} - for (i = 0; i < ep->nurbs; i++) { - if (test_bit(i, &ep->active_mask)) { - if (!test_and_set_bit(i, &ep->unlink_mask)) { - struct urb *u = ep->urb[i].urb; - if (async) - usb_unlink_urb(u); - else - usb_kill_urb(u); - } +/* + * complete callback from data urb + */ +static void snd_complete_urb(struct urb *urb) +{ + struct snd_urb_ctx *ctx = urb->context; + struct snd_usb_substream *subs = ctx->subs; + struct snd_pcm_substream *substream = ctx->subs->pcm_substream; + int err = 0; + + if ((subs->running && subs->ops.retire(subs, substream->runtime, urb)) || + !subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare(subs, substream->runtime, urb)) < 0 || + (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + clear_bit(ctx->index, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); } } - - return 0; } + /* - * release an endpoint's urbs + * complete callback from sync urb */ -static void release_urbs(struct snd_usb_endpoint *ep, int force) +static void snd_complete_sync_urb(struct urb *urb) { - int i; - - /* route incoming urbs to nirvana */ - ep->retire_data_urb = NULL; - ep->prepare_data_urb = NULL; - - /* stop urbs */ - deactivate_urbs(ep, force, 1); - wait_clear_urbs(ep); - - for (i = 0; i < ep->nurbs; i++) - release_urb_ctx(&ep->urb[i]); - - if (ep->syncbuf) - usb_free_coherent(ep->chip->dev, SYNC_URBS * 4, - ep->syncbuf, ep->sync_dma); - - ep->syncbuf = NULL; - ep->nurbs = 0; + struct snd_urb_ctx *ctx = urb->context; + struct snd_usb_substream *subs = ctx->subs; + struct snd_pcm_substream *substream = ctx->subs->pcm_substream; + int err = 0; + + if ((subs->running && subs->ops.retire_sync(subs, substream->runtime, urb)) || + !subs->running || /* can be stopped during retire callback */ + (err = subs->ops.prepare_sync(subs, substream->runtime, urb)) < 0 || + (err = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + clear_bit(ctx->index + 16, &subs->active_mask); + if (err < 0) { + snd_printd(KERN_ERR "cannot submit sync urb (err = %d)\n", err); + snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); + } + } } + /* - * configure a data endpoint + * initialize a substream for plaback/capture */ -static int data_ep_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, + unsigned int period_bytes, + unsigned int rate, + unsigned int frame_bits) { - unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; - int period_bytes = params_period_bytes(hw_params); - int format = params_format(hw_params); - int is_playback = usb_pipeout(ep->pipe); - int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) * - params_channels(hw_params); - - ep->datainterval = fmt->datainterval; - ep->stride = frame_bits >> 3; - ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; + unsigned int maxsize, i; + int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; + unsigned int urb_packs, total_packs, packs_per_ms; + struct snd_usb_audio *chip = subs->stream->chip; + /* calculate the frequency in 16.16 format */ + if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + subs->freqn = get_usb_full_speed_rate(rate); + else + subs->freqn = get_usb_high_speed_rate(rate); + subs->freqm = subs->freqn; + subs->freqshift = INT_MIN; /* calculate max. frequency */ - if (ep->maxpacksize) { + if (subs->maxpacksize) { /* whatever fits into a max. size packet */ - maxsize = ep->maxpacksize; - ep->freqmax = (maxsize / (frame_bits >> 3)) - << (16 - ep->datainterval); + maxsize = subs->maxpacksize; + subs->freqmax = (maxsize / (frame_bits >> 3)) + << (16 - subs->datainterval); } else { /* no max. packet size: just take 25% higher than nominal */ - ep->freqmax = ep->freqn + (ep->freqn >> 2); - maxsize = ((ep->freqmax + 0xffff) * (frame_bits >> 3)) - >> (16 - ep->datainterval); + subs->freqmax = subs->freqn + (subs->freqn >> 2); + maxsize = ((subs->freqmax + 0xffff) * (frame_bits >> 3)) + >> (16 - subs->datainterval); } + subs->phase = 0; - if (ep->fill_max) - ep->curpacksize = ep->maxpacksize; + if (subs->fill_max) + subs->curpacksize = subs->maxpacksize; else - ep->curpacksize = maxsize; + subs->curpacksize = maxsize; - if (snd_usb_get_speed(ep->chip->dev) != USB_SPEED_FULL) - packs_per_ms = 8 >> ep->datainterval; + if (snd_usb_get_speed(subs->dev) != USB_SPEED_FULL) + packs_per_ms = 8 >> subs->datainterval; else packs_per_ms = 1; - if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) { - urb_packs = max(ep->chip->nrpacks, 1); - urb_packs = min(urb_packs, (unsigned int) MAX_PACKS); - } else { + if (is_playback) { + urb_packs = max(chip->nrpacks, 1); + urb_packs = min(urb_packs, (unsigned int)MAX_PACKS); + } else urb_packs = 1; - } - urb_packs *= packs_per_ms; - - if (sync_ep && !snd_usb_endpoint_implict_feedback_sink(ep)) - urb_packs = min(urb_packs, 1U << sync_ep->syncinterval); + if (subs->syncpipe) + urb_packs = min(urb_packs, 1U << subs->syncinterval); /* decide how many packets to be used */ - if (is_playback && !snd_usb_endpoint_implict_feedback_sink(ep)) { + if (is_playback) { unsigned int minsize, maxpacks; /* determine how small a packet can be */ - minsize = (ep->freqn >> (16 - ep->datainterval)) + minsize = (subs->freqn >> (16 - subs->datainterval)) * (frame_bits >> 3); /* with sync from device, assume it can be 12% lower */ - if (sync_ep) + if (subs->syncpipe) minsize -= minsize >> 3; minsize = max(minsize, 1u); total_packs = (period_bytes + minsize - 1) / minsize; @@ -655,472 +284,284 @@ static int data_ep_set_params(struct snd_usb_endpoint *ep, urb_packs >>= 1; total_packs = MAX_URBS * urb_packs; } - - ep->nurbs = (total_packs + urb_packs - 1) / urb_packs; - if (ep->nurbs > MAX_URBS) { + subs->nurbs = (total_packs + urb_packs - 1) / urb_packs; + if (subs->nurbs > MAX_URBS) { /* too much... */ - ep->nurbs = MAX_URBS; + subs->nurbs = MAX_URBS; total_packs = MAX_URBS * urb_packs; - } else if (ep->nurbs < 2) { + } else if (subs->nurbs < 2) { /* too little - we need at least two packets * to ensure contiguous playback/capture */ - ep->nurbs = 2; + subs->nurbs = 2; } /* allocate and initialize data urbs */ - for (i = 0; i < ep->nurbs; i++) { - struct snd_urb_ctx *u = &ep->urb[i]; + for (i = 0; i < subs->nurbs; i++) { + struct snd_urb_ctx *u = &subs->dataurb[i]; u->index = i; - u->ep = ep; - u->packets = (i + 1) * total_packs / ep->nurbs - - i * total_packs / ep->nurbs; + u->subs = subs; + u->packets = (i + 1) * total_packs / subs->nurbs + - i * total_packs / subs->nurbs; u->buffer_size = maxsize * u->packets; - - if (fmt->fmt_type == UAC_FORMAT_TYPE_II) + if (subs->fmt_type == UAC_FORMAT_TYPE_II) u->packets++; /* for transfer delimiter */ u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); if (!u->urb) goto out_of_memory; - u->urb->transfer_buffer = - usb_alloc_coherent(ep->chip->dev, u->buffer_size, + usb_alloc_coherent(subs->dev, u->buffer_size, GFP_KERNEL, &u->urb->transfer_dma); if (!u->urb->transfer_buffer) goto out_of_memory; - u->urb->pipe = ep->pipe; + u->urb->pipe = subs->datapipe; u->urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; - u->urb->interval = 1 << ep->datainterval; + u->urb->interval = 1 << subs->datainterval; u->urb->context = u; u->urb->complete = snd_complete_urb; - INIT_LIST_HEAD(&u->ready_list); } + if (subs->syncpipe) { + /* allocate and initialize sync urbs */ + subs->syncbuf = usb_alloc_coherent(subs->dev, SYNC_URBS * 4, + GFP_KERNEL, &subs->sync_dma); + if (!subs->syncbuf) + goto out_of_memory; + for (i = 0; i < SYNC_URBS; i++) { + struct snd_urb_ctx *u = &subs->syncurb[i]; + u->index = i; + u->subs = subs; + u->packets = 1; + u->urb = usb_alloc_urb(1, GFP_KERNEL); + if (!u->urb) + goto out_of_memory; + u->urb->transfer_buffer = subs->syncbuf + i * 4; + u->urb->transfer_dma = subs->sync_dma + i * 4; + u->urb->transfer_buffer_length = 4; + u->urb->pipe = subs->syncpipe; + u->urb->transfer_flags = URB_ISO_ASAP | + URB_NO_TRANSFER_DMA_MAP; + u->urb->number_of_packets = 1; + u->urb->interval = 1 << subs->syncinterval; + u->urb->context = u; + u->urb->complete = snd_complete_sync_urb; + } + } return 0; out_of_memory: - release_urbs(ep, 0); + snd_usb_release_substream_urbs(subs, 0); return -ENOMEM; } /* - * configure a sync endpoint + * prepare urb for full speed capture sync pipe + * + * fill the length and offset of each urb descriptor. + * the fixed 10.14 frequency is passed through the pipe. */ -static int sync_ep_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, - struct audioformat *fmt) +static int prepare_capture_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - int i; - - ep->syncbuf = usb_alloc_coherent(ep->chip->dev, SYNC_URBS * 4, - GFP_KERNEL, &ep->sync_dma); - if (!ep->syncbuf) - return -ENOMEM; - - for (i = 0; i < SYNC_URBS; i++) { - struct snd_urb_ctx *u = &ep->urb[i]; - u->index = i; - u->ep = ep; - u->packets = 1; - u->urb = usb_alloc_urb(1, GFP_KERNEL); - if (!u->urb) - goto out_of_memory; - u->urb->transfer_buffer = ep->syncbuf + i * 4; - u->urb->transfer_dma = ep->sync_dma + i * 4; - u->urb->transfer_buffer_length = 4; - u->urb->pipe = ep->pipe; - u->urb->transfer_flags = URB_ISO_ASAP | - URB_NO_TRANSFER_DMA_MAP; - u->urb->number_of_packets = 1; - u->urb->interval = 1 << ep->syncinterval; - u->urb->context = u; - u->urb->complete = snd_complete_urb; - } - - ep->nurbs = SYNC_URBS; + unsigned char *cp = urb->transfer_buffer; + struct snd_urb_ctx *ctx = urb->context; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = 3; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn >> 2; + cp[1] = subs->freqn >> 10; + cp[2] = subs->freqn >> 18; return 0; - -out_of_memory: - release_urbs(ep, 0); - return -ENOMEM; } -/** - * snd_usb_endpoint_set_params: configure an snd_usb_endpoint - * - * @ep: the snd_usb_endpoint to configure - * @hw_params: the hardware parameters - * @fmt: the USB audio format information - * @sync_ep: the sync endpoint to use, if any +/* + * prepare urb for high speed capture sync pipe * - * Determine the number of URBs to be used on this endpoint. - * An endpoint must be configured before it can be started. - * An endpoint that is already running can not be reconfigured. + * fill the length and offset of each urb descriptor. + * the fixed 12.13 frequency is passed as 16.16 through the pipe. */ -int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep) +static int prepare_capture_sync_urb_hs(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - int err; - - if (ep->use_count != 0) { - snd_printk(KERN_WARNING "Unable to change format on ep #%x: already in use\n", - ep->ep_num); - return -EBUSY; - } - - /* release old buffers, if any */ - release_urbs(ep, 0); - - ep->datainterval = fmt->datainterval; - ep->maxpacksize = fmt->maxpacksize; - ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); - - if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) - ep->freqn = get_usb_full_speed_rate(params_rate(hw_params)); - else - ep->freqn = get_usb_high_speed_rate(params_rate(hw_params)); - - /* calculate the frequency in 16.16 format */ - ep->freqm = ep->freqn; - ep->freqshift = INT_MIN; - - ep->phase = 0; - - switch (ep->type) { - case SND_USB_ENDPOINT_TYPE_DATA: - err = data_ep_set_params(ep, hw_params, fmt, sync_ep); - break; - case SND_USB_ENDPOINT_TYPE_SYNC: - err = sync_ep_set_params(ep, hw_params, fmt); - break; - default: - err = -EINVAL; - } - - snd_printdd(KERN_DEBUG "Setting params for ep #%x (type %d, %d urbs), ret=%d\n", - ep->ep_num, ep->type, ep->nurbs, err); + unsigned char *cp = urb->transfer_buffer; + struct snd_urb_ctx *ctx = urb->context; - return err; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = 4; + urb->iso_frame_desc[0].offset = 0; + cp[0] = subs->freqn; + cp[1] = subs->freqn >> 8; + cp[2] = subs->freqn >> 16; + cp[3] = subs->freqn >> 24; + return 0; } -/** - * snd_usb_endpoint_start: start an snd_usb_endpoint - * - * @ep: the endpoint to start - * - * A call to this function will increment the use count of the endpoint. - * In case it is not already running, the URBs for this endpoint will be - * submitted. Otherwise, this function does nothing. - * - * Must be balanced to calls of snd_usb_endpoint_stop(). - * - * Returns an error if the URB submission failed, 0 in all other cases. +/* + * process after capture sync complete + * - nothing to do */ -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) +static int retire_capture_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - int err; - unsigned int i; - - if (ep->chip->shutdown) - return -EBADFD; - - /* already running? */ - if (++ep->use_count != 1) - return 0; - - if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags))) - return -EINVAL; - - /* just to be sure */ - deactivate_urbs(ep, 0, 1); - wait_clear_urbs(ep); - - ep->active_mask = 0; - ep->unlink_mask = 0; - ep->phase = 0; - - /* - * If this endpoint has a data endpoint as implicit feedback source, - * don't start the urbs here. Instead, mark them all as available, - * wait for the record urbs to return and queue the playback urbs - * from that context. - */ - - set_bit(EP_FLAG_RUNNING, &ep->flags); - - if (snd_usb_endpoint_implict_feedback_sink(ep)) { - for (i = 0; i < ep->nurbs; i++) { - struct snd_urb_ctx *ctx = ep->urb + i; - list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs); - } - - return 0; - } - - for (i = 0; i < ep->nurbs; i++) { - struct urb *urb = ep->urb[i].urb; - - if (snd_BUG_ON(!urb)) - goto __error; - - if (usb_pipeout(ep->pipe)) { - prepare_outbound_urb_sizes(ep, urb->context); - prepare_outbound_urb(ep, urb->context); - } else { - prepare_inbound_urb(ep, urb->context); - } - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err < 0) { - snd_printk(KERN_ERR "cannot submit urb %d, error %d: %s\n", - i, err, usb_error_string(err)); - goto __error; - } - set_bit(i, &ep->active_mask); - } - return 0; - -__error: - clear_bit(EP_FLAG_RUNNING, &ep->flags); - ep->use_count--; - deactivate_urbs(ep, 0, 0); - return -EPIPE; } -/** - * snd_usb_endpoint_stop: stop an snd_usb_endpoint - * - * @ep: the endpoint to stop (may be NULL) +/* + * prepare urb for capture data pipe * - * A call to this function will decrement the use count of the endpoint. - * In case the last user has requested the endpoint stop, the URBs will - * actually be deactivated. + * fill the offset and length of each descriptor. * - * Must be balanced to calls of snd_usb_endpoint_start(). + * we use a temporary buffer to write the captured data. + * since the length of written data is determined by host, we cannot + * write onto the pcm buffer directly... the data is thus copied + * later at complete callback to the global buffer. */ -void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, - int force, int can_sleep, int wait) +static int prepare_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - if (!ep) - return; - - if (snd_BUG_ON(ep->use_count == 0)) - return; - - if (snd_BUG_ON(!test_bit(EP_FLAG_ACTIVATED, &ep->flags))) - return; - - if (--ep->use_count == 0) { - deactivate_urbs(ep, force, can_sleep); - ep->data_subs = NULL; - ep->sync_slave = NULL; - ep->retire_data_urb = NULL; - ep->prepare_data_urb = NULL; + int i, offs; + struct snd_urb_ctx *ctx = urb->context; - if (wait) - wait_clear_urbs(ep); + offs = 0; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + for (i = 0; i < ctx->packets; i++) { + urb->iso_frame_desc[i].offset = offs; + urb->iso_frame_desc[i].length = subs->curpacksize; + offs += subs->curpacksize; } + urb->transfer_buffer_length = offs; + urb->number_of_packets = ctx->packets; + return 0; } -/** - * snd_usb_endpoint_activate: activate an snd_usb_endpoint - * - * @ep: the endpoint to activate - * - * If the endpoint is not currently in use, this functions will select the - * correct alternate interface setting for the interface of this endpoint. - * - * In case of any active users, this functions does nothing. +/* + * process after capture complete * - * Returns an error if usb_set_interface() failed, 0 in all other - * cases. + * copy the data from each desctiptor to the pcm buffer, and + * update the current position. */ -int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep) +static int retire_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - if (ep->use_count != 0) - return 0; + unsigned long flags; + unsigned char *cp; + int i; + unsigned int stride, frames, bytes, oldptr; + int period_elapsed = 0; - if (!ep->chip->shutdown && - !test_and_set_bit(EP_FLAG_ACTIVATED, &ep->flags)) { - int ret; + stride = runtime->frame_bits >> 3; - ret = usb_set_interface(ep->chip->dev, ep->iface, ep->alt_idx); - if (ret < 0) { - snd_printk(KERN_ERR "%s() usb_set_interface() failed, ret = %d\n", - __func__, ret); - clear_bit(EP_FLAG_ACTIVATED, &ep->flags); - return ret; + for (i = 0; i < urb->number_of_packets; i++) { + cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (urb->iso_frame_desc[i].status && printk_ratelimit()) { + snd_printdd("frame %d active: %d\n", i, urb->iso_frame_desc[i].status); + // continue; + } + bytes = urb->iso_frame_desc[i].actual_length; + frames = bytes / stride; + if (!subs->txfr_quirk) + bytes = frames * stride; + if (bytes % (runtime->sample_bits >> 3) != 0) { +#ifdef CONFIG_SND_DEBUG_VERBOSE + int oldbytes = bytes; +#endif + bytes = frames * stride; + snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", + oldbytes, bytes); + } + /* update the current pointer */ + spin_lock_irqsave(&subs->lock, flags); + oldptr = subs->hwptr_done; + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + frames = (bytes + (oldptr % stride)) / stride; + subs->transfer_done += frames; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + } + spin_unlock_irqrestore(&subs->lock, flags); + /* copy a data chunk */ + if (oldptr + bytes > runtime->buffer_size * stride) { + unsigned int bytes1 = + runtime->buffer_size * stride - oldptr; + memcpy(runtime->dma_area + oldptr, cp, bytes1); + memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); + } else { + memcpy(runtime->dma_area + oldptr, cp, bytes); } - - return 0; } - - return -EBUSY; + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); + return 0; } -/** - * snd_usb_endpoint_deactivate: deactivate an snd_usb_endpoint - * - * @ep: the endpoint to deactivate - * - * If the endpoint is not currently in use, this functions will select the - * alternate interface setting 0 for the interface of this endpoint. - * - * In case of any active users, this functions does nothing. - * - * Returns an error if usb_set_interface() failed, 0 in all other - * cases. +/* + * Process after capture complete when paused. Nothing to do. */ -int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep) +static int retire_paused_capture_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - if (!ep) - return -EINVAL; - - if (ep->use_count != 0) - return 0; - - if (!ep->chip->shutdown && - test_and_clear_bit(EP_FLAG_ACTIVATED, &ep->flags)) { - int ret; - - ret = usb_set_interface(ep->chip->dev, ep->iface, 0); - if (ret < 0) { - snd_printk(KERN_ERR "%s(): usb_set_interface() failed, ret = %d\n", - __func__, ret); - return ret; - } - - return 0; - } - - return -EBUSY; + return 0; } -/** - * snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint - * - * @ep: the list header of the endpoint to free + +/* + * prepare urb for playback sync pipe * - * This function does not care for the endpoint's use count but will tear - * down all the streaming URBs immediately and free all resources. + * set up the offset and length to receive the current frequency. */ -void snd_usb_endpoint_free(struct list_head *head) +static int prepare_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - struct snd_usb_endpoint *ep; + struct snd_urb_ctx *ctx = urb->context; - ep = list_entry(head, struct snd_usb_endpoint, list); - release_urbs(ep, 1); - kfree(ep); + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->iso_frame_desc[0].length = min(4u, ctx->subs->syncmaxsize); + urb->iso_frame_desc[0].offset = 0; + return 0; } -/** - * snd_usb_handle_sync_urb: parse an USB sync packet - * - * @ep: the endpoint to handle the packet - * @sender: the sending endpoint - * @urb: the received packet - * - * This function is called from the context of an endpoint that received - * the packet and is used to let another endpoint object handle the payload. +/* + * process after playback sync complete + * + * Full speed devices report feedback values in 10.14 format as samples per + * frame, high speed devices in 16.16 format as samples per microframe. + * Because the Audio Class 1 spec was written before USB 2.0, many high speed + * devices use a wrong interpretation, some others use an entirely different + * format. Therefore, we cannot predict what format any particular device uses + * and must detect it automatically. */ -void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, - struct snd_usb_endpoint *sender, - const struct urb *urb) +static int retire_playback_sync_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) { - int shift; unsigned int f; + int shift; unsigned long flags; - snd_BUG_ON(ep == sender); - - /* - * In case the endpoint is operating in implicit feedback mode, prepare - * a new outbound URB that has the same layout as the received packet - * and add it to the list of pending urbs. queue_pending_output_urbs() - * will take care of them later. - */ - if (snd_usb_endpoint_implict_feedback_sink(ep) && - ep->use_count != 0) { - - /* implicit feedback case */ - int i, bytes = 0; - struct snd_urb_ctx *in_ctx; - struct snd_usb_packet_info *out_packet; - - in_ctx = urb->context; - - /* Count overall packet size */ - for (i = 0; i < in_ctx->packets; i++) - if (urb->iso_frame_desc[i].status == 0) - bytes += urb->iso_frame_desc[i].actual_length; - - /* - * skip empty packets. At least M-Audio's Fast Track Ultra stops - * streaming once it received a 0-byte OUT URB - */ - if (bytes == 0) - return; - - spin_lock_irqsave(&ep->lock, flags); - out_packet = ep->next_packet + ep->next_packet_write_pos; - - /* - * Iterate through the inbound packet and prepare the lengths - * for the output packet. The OUT packet we are about to send - * will have the same amount of payload bytes than the IN - * packet we just received. - */ - - out_packet->packets = in_ctx->packets; - for (i = 0; i < in_ctx->packets; i++) { - if (urb->iso_frame_desc[i].status == 0) - out_packet->packet_size[i] = - urb->iso_frame_desc[i].actual_length / ep->stride; - else - out_packet->packet_size[i] = 0; - } - - ep->next_packet_write_pos++; - ep->next_packet_write_pos %= MAX_URBS; - spin_unlock_irqrestore(&ep->lock, flags); - queue_pending_output_urbs(ep); - - return; - } - - /* - * process after playback sync complete - * - * Full speed devices report feedback values in 10.14 format as samples - * per frame, high speed devices in 16.16 format as samples per - * microframe. - * - * Because the Audio Class 1 spec was written before USB 2.0, many high - * speed devices use a wrong interpretation, some others use an - * entirely different format. - * - * Therefore, we cannot predict what format any particular device uses - * and must detect it automatically. - */ - if (urb->iso_frame_desc[0].status != 0 || urb->iso_frame_desc[0].actual_length < 3) - return; + return 0; f = le32_to_cpup(urb->transfer_buffer); if (urb->iso_frame_desc[0].actual_length == 3) f &= 0x00ffffff; else f &= 0x0fffffff; - if (f == 0) - return; + return 0; - if (unlikely(ep->freqshift == INT_MIN)) { + if (unlikely(subs->freqshift == INT_MIN)) { /* * The first time we see a feedback value, determine its format * by shifting it left or right until it matches the nominal @@ -1128,34 +569,398 @@ void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, * differ from the nominal value more than +50% or -25%. */ shift = 0; - while (f < ep->freqn - ep->freqn / 4) { + while (f < subs->freqn - subs->freqn / 4) { f <<= 1; shift++; } - while (f > ep->freqn + ep->freqn / 2) { + while (f > subs->freqn + subs->freqn / 2) { f >>= 1; shift--; } - ep->freqshift = shift; - } else if (ep->freqshift >= 0) - f <<= ep->freqshift; + subs->freqshift = shift; + } + else if (subs->freqshift >= 0) + f <<= subs->freqshift; else - f >>= -ep->freqshift; + f >>= -subs->freqshift; - if (likely(f >= ep->freqn - ep->freqn / 8 && f <= ep->freqmax)) { + if (likely(f >= subs->freqn - subs->freqn / 8 && f <= subs->freqmax)) { /* * If the frequency looks valid, set it. * This value is referred to in prepare_playback_urb(). */ - spin_lock_irqsave(&ep->lock, flags); - ep->freqm = f; - spin_unlock_irqrestore(&ep->lock, flags); + spin_lock_irqsave(&subs->lock, flags); + subs->freqm = f; + spin_unlock_irqrestore(&subs->lock, flags); } else { /* * Out of range; maybe the shift value is wrong. * Reset it so that we autodetect again the next time. */ - ep->freqshift = INT_MIN; + subs->freqshift = INT_MIN; + } + + return 0; +} + +/* determine the number of frames in the next packet */ +static int snd_usb_audio_next_packet_size(struct snd_usb_substream *subs) +{ + if (subs->fill_max) + return subs->maxframesize; + else { + subs->phase = (subs->phase & 0xffff) + + (subs->freqm << subs->datainterval); + return min(subs->phase >> 16, subs->maxframesize); } } +/* + * Prepare urb for streaming before playback starts or when paused. + * + * We don't have any data, so we send silence. + */ +static int prepare_nodata_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned int i, offs, counts; + struct snd_urb_ctx *ctx = urb->context; + int stride = runtime->frame_bits >> 3; + + offs = 0; + urb->dev = ctx->subs->dev; + for (i = 0; i < ctx->packets; ++i) { + counts = snd_usb_audio_next_packet_size(subs); + urb->iso_frame_desc[i].offset = offs * stride; + urb->iso_frame_desc[i].length = counts * stride; + offs += counts; + } + urb->number_of_packets = ctx->packets; + urb->transfer_buffer_length = offs * stride; + memset(urb->transfer_buffer, + runtime->format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0, + offs * stride); + return 0; +} + +/* + * prepare urb for playback data pipe + * + * Since a URB can handle only a single linear buffer, we must use double + * buffering when the data to be transferred overflows the buffer boundary. + * To avoid inconsistencies when updating hwptr_done, we use double buffering + * for all URBs. + */ +static int prepare_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + int i, stride; + unsigned int counts, frames, bytes; + unsigned long flags; + int period_elapsed = 0; + struct snd_urb_ctx *ctx = urb->context; + + stride = runtime->frame_bits >> 3; + + frames = 0; + urb->dev = ctx->subs->dev; /* we need to set this at each time */ + urb->number_of_packets = 0; + spin_lock_irqsave(&subs->lock, flags); + for (i = 0; i < ctx->packets; i++) { + counts = snd_usb_audio_next_packet_size(subs); + /* set up descriptor */ + urb->iso_frame_desc[i].offset = frames * stride; + urb->iso_frame_desc[i].length = counts * stride; + frames += counts; + urb->number_of_packets++; + subs->transfer_done += counts; + if (subs->transfer_done >= runtime->period_size) { + subs->transfer_done -= runtime->period_size; + period_elapsed = 1; + if (subs->fmt_type == UAC_FORMAT_TYPE_II) { + if (subs->transfer_done > 0) { + /* FIXME: fill-max mode is not + * supported yet */ + frames -= subs->transfer_done; + counts -= subs->transfer_done; + urb->iso_frame_desc[i].length = + counts * stride; + subs->transfer_done = 0; + } + i++; + if (i < ctx->packets) { + /* add a transfer delimiter */ + urb->iso_frame_desc[i].offset = + frames * stride; + urb->iso_frame_desc[i].length = 0; + urb->number_of_packets++; + } + break; + } + } + if (period_elapsed) /* finish at the period boundary */ + break; + } + bytes = frames * stride; + if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { + /* err, the transferred area goes over buffer boundary. */ + unsigned int bytes1 = + runtime->buffer_size * stride - subs->hwptr_done; + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done, bytes1); + memcpy(urb->transfer_buffer + bytes1, + runtime->dma_area, bytes - bytes1); + } else { + memcpy(urb->transfer_buffer, + runtime->dma_area + subs->hwptr_done, bytes); + } + subs->hwptr_done += bytes; + if (subs->hwptr_done >= runtime->buffer_size * stride) + subs->hwptr_done -= runtime->buffer_size * stride; + + /* update delay with exact number of samples queued */ + runtime->delay = subs->last_delay; + runtime->delay += frames; + subs->last_delay = runtime->delay; + + /* realign last_frame_number */ + subs->last_frame_number = usb_get_current_frame_number(subs->dev); + subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ + + spin_unlock_irqrestore(&subs->lock, flags); + urb->transfer_buffer_length = bytes; + if (period_elapsed) + snd_pcm_period_elapsed(subs->pcm_substream); + return 0; +} + +/* + * process after playback data complete + * - decrease the delay count again + */ +static int retire_playback_urb(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime, + struct urb *urb) +{ + unsigned long flags; + int stride = runtime->frame_bits >> 3; + int processed = urb->transfer_buffer_length / stride; + int est_delay; + + spin_lock_irqsave(&subs->lock, flags); + + est_delay = snd_usb_pcm_delay(subs, runtime->rate); + /* update delay with exact number of samples played */ + if (processed > subs->last_delay) + subs->last_delay = 0; + else + subs->last_delay -= processed; + runtime->delay = subs->last_delay; + + /* + * Report when delay estimate is off by more than 2ms. + * The error should be lower than 2ms since the estimate relies + * on two reads of a counter updated every ms. + */ + if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) + snd_printk(KERN_DEBUG "delay: estimated %d, actual %d\n", + est_delay, subs->last_delay); + + spin_unlock_irqrestore(&subs->lock, flags); + return 0; +} + +static const char *usb_error_string(int err) +{ + switch (err) { + case -ENODEV: + return "no device"; + case -ENOENT: + return "endpoint not enabled"; + case -EPIPE: + return "endpoint stalled"; + case -ENOSPC: + return "not enough bandwidth"; + case -ESHUTDOWN: + return "device disabled"; + case -EHOSTUNREACH: + return "device suspended"; + case -EINVAL: + case -EAGAIN: + case -EFBIG: + case -EMSGSIZE: + return "internal error"; + default: + return "unknown error"; + } +} + +/* + * set up and start data/sync urbs + */ +static int start_urbs(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime) +{ + unsigned int i; + int err; + + if (subs->stream->chip->shutdown) + return -EBADFD; + + for (i = 0; i < subs->nurbs; i++) { + if (snd_BUG_ON(!subs->dataurb[i].urb)) + return -EINVAL; + if (subs->ops.prepare(subs, runtime, subs->dataurb[i].urb) < 0) { + snd_printk(KERN_ERR "cannot prepare datapipe for urb %d\n", i); + goto __error; + } + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + if (snd_BUG_ON(!subs->syncurb[i].urb)) + return -EINVAL; + if (subs->ops.prepare_sync(subs, runtime, subs->syncurb[i].urb) < 0) { + snd_printk(KERN_ERR "cannot prepare syncpipe for urb %d\n", i); + goto __error; + } + } + } + + subs->active_mask = 0; + subs->unlink_mask = 0; + subs->running = 1; + for (i = 0; i < subs->nurbs; i++) { + err = usb_submit_urb(subs->dataurb[i].urb, GFP_ATOMIC); + if (err < 0) { + snd_printk(KERN_ERR "cannot submit datapipe " + "for urb %d, error %d: %s\n", + i, err, usb_error_string(err)); + goto __error; + } + set_bit(i, &subs->active_mask); + } + if (subs->syncpipe) { + for (i = 0; i < SYNC_URBS; i++) { + err = usb_submit_urb(subs->syncurb[i].urb, GFP_ATOMIC); + if (err < 0) { + snd_printk(KERN_ERR "cannot submit syncpipe " + "for urb %d, error %d: %s\n", + i, err, usb_error_string(err)); + goto __error; + } + set_bit(i + 16, &subs->active_mask); + } + } + return 0; + + __error: + // snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN); + deactivate_urbs(subs, 0, 0); + return -EPIPE; +} + + +/* + */ +static struct snd_urb_ops audio_urb_ops[2] = { + { + .prepare = prepare_nodata_playback_urb, + .retire = retire_playback_urb, + .prepare_sync = prepare_playback_sync_urb, + .retire_sync = retire_playback_sync_urb, + }, + { + .prepare = prepare_capture_urb, + .retire = retire_capture_urb, + .prepare_sync = prepare_capture_sync_urb, + .retire_sync = retire_capture_sync_urb, + }, +}; + +/* + * initialize the substream instance. + */ + +void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, struct audioformat *fp) +{ + struct snd_usb_substream *subs = &as->substream[stream]; + + INIT_LIST_HEAD(&subs->fmt_list); + spin_lock_init(&subs->lock); + + subs->stream = as; + subs->direction = stream; + subs->dev = as->chip->dev; + subs->txfr_quirk = as->chip->txfr_quirk; + subs->ops = audio_urb_ops[stream]; + if (snd_usb_get_speed(subs->dev) >= USB_SPEED_HIGH) + subs->ops.prepare_sync = prepare_capture_sync_urb_hs; + + snd_usb_set_pcm_ops(as->pcm, stream); + + list_add_tail(&fp->list, &subs->fmt_list); + subs->formats |= fp->formats; + subs->endpoint = fp->endpoint; + subs->num_formats++; + subs->fmt_type = fp->fmt_type; +} + +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + subs->ops.prepare = prepare_playback_urb; + return 0; + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.prepare = prepare_nodata_playback_urb; + return 0; + } + + return -EINVAL; +} + +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + subs->ops.retire = retire_capture_urb; + return start_urbs(subs, substream->runtime); + case SNDRV_PCM_TRIGGER_STOP: + return deactivate_urbs(subs, 0, 0); + case SNDRV_PCM_TRIGGER_PAUSE_PUSH: + subs->ops.retire = retire_paused_capture_urb; + return 0; + case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: + subs->ops.retire = retire_capture_urb; + return 0; + } + + return -EINVAL; +} + +int snd_usb_substream_prepare(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime) +{ + /* clear urbs (to be sure) */ + deactivate_urbs(subs, 0, 1); + wait_clear_urbs(subs); + + /* for playback, submit the URBs now; otherwise, the first hwptr_done + * updates for all URBs would happen at the same time when starting */ + if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { + subs->ops.prepare = prepare_nodata_playback_urb; + return start_urbs(subs, runtime); + } + + return 0; +} + diff --git a/trunk/sound/usb/endpoint.h b/trunk/sound/usb/endpoint.h index ee2723fb174f..88eb63a636eb 100644 --- a/trunk/sound/usb/endpoint.h +++ b/trunk/sound/usb/endpoint.h @@ -1,29 +1,21 @@ #ifndef __USBAUDIO_ENDPOINT_H #define __USBAUDIO_ENDPOINT_H -#define SND_USB_ENDPOINT_TYPE_DATA 0 -#define SND_USB_ENDPOINT_TYPE_SYNC 1 +void snd_usb_init_substream(struct snd_usb_stream *as, + int stream, + struct audioformat *fp); -struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, - struct usb_host_interface *alts, - int ep_num, int direction, int type); +int snd_usb_init_substream_urbs(struct snd_usb_substream *subs, + unsigned int period_bytes, + unsigned int rate, + unsigned int frame_bits); -int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, - struct audioformat *fmt, - struct snd_usb_endpoint *sync_ep); +void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force); -int snd_usb_endpoint_start(struct snd_usb_endpoint *ep); -void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep, - int force, int can_sleep, int wait); -int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep); -int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep); -void snd_usb_endpoint_free(struct list_head *head); +int snd_usb_substream_prepare(struct snd_usb_substream *subs, + struct snd_pcm_runtime *runtime); -int snd_usb_endpoint_implict_feedback_sink(struct snd_usb_endpoint *ep); - -void snd_usb_handle_sync_urb(struct snd_usb_endpoint *ep, - struct snd_usb_endpoint *sender, - const struct urb *urb); +int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd); +int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd); #endif /* __USBAUDIO_ENDPOINT_H */ diff --git a/trunk/sound/usb/mixer.c b/trunk/sound/usb/mixer.c index 4f40ba823163..ab23869c01bb 100644 --- a/trunk/sound/usb/mixer.c +++ b/trunk/sound/usb/mixer.c @@ -486,7 +486,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, /* * TLV callback for mixer volume controls */ -int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, +static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, unsigned int size, unsigned int __user *_tlv) { struct usb_mixer_elem_info *cval = kcontrol->private_data; @@ -770,26 +770,6 @@ static void volume_control_quirks(struct usb_mixer_elem_info *cval, struct snd_kcontrol *kctl) { switch (cval->mixer->chip->usb_id) { - case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ - case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ - if (strcmp(kctl->id.name, "Effect Duration") == 0) { - snd_printk(KERN_INFO - "usb-audio: set quirk for FTU Effect Duration\n"); - cval->min = 0x0000; - cval->max = 0x7f00; - cval->res = 0x0100; - break; - } - if (strcmp(kctl->id.name, "Effect Volume") == 0 || - strcmp(kctl->id.name, "Effect Feedback Volume") == 0) { - snd_printk(KERN_INFO - "usb-audio: set quirks for FTU Effect Feedback/Volume\n"); - cval->min = 0x00; - cval->max = 0x7f; - break; - } - break; - case USB_ID(0x0471, 0x0101): case USB_ID(0x0471, 0x0104): case USB_ID(0x0471, 0x0105): @@ -1141,6 +1121,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); + /* get min/max values */ + get_min_max_with_quirks(cval, 0, kctl); + switch (control) { case UAC_FU_MUTE: case UAC_FU_VOLUME: @@ -1172,7 +1155,17 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, } append_ctl_name(kctl, control == UAC_FU_MUTE ? " Switch" : " Volume"); + if (control == UAC_FU_VOLUME) { + check_mapped_dB(map, cval); + if (cval->dBmin < cval->dBmax || !cval->initialized) { + kctl->tlv.c = mixer_vol_tlv; + kctl->vd[0].access |= + SNDRV_CTL_ELEM_ACCESS_TLV_READ | + SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } + } break; + default: if (! len) strlcpy(kctl->id.name, audio_feature_info[control-1].name, @@ -1180,19 +1173,6 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, break; } - /* get min/max values */ - get_min_max_with_quirks(cval, 0, kctl); - - if (control == UAC_FU_VOLUME) { - check_mapped_dB(map, cval); - if (cval->dBmin < cval->dBmax || !cval->initialized) { - kctl->tlv.c = snd_usb_mixer_vol_tlv; - kctl->vd[0].access |= - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; - } - } - range = (cval->max - cval->min) / cval->res; /* Are there devices with volume range more than 255? I use a bit more * to be sure. 384 is a resolution magic number found on Logitech @@ -1408,7 +1388,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, void *r for (pin = 0; pin < input_pins; pin++) { err = parse_audio_unit(state, desc->baSourceID[pin]); if (err < 0) - continue; + return err; err = check_input_term(state, desc->baSourceID[pin], &iterm); if (err < 0) return err; diff --git a/trunk/sound/usb/mixer.h b/trunk/sound/usb/mixer.h index a7f3d45a8acf..81b2d8a32fb0 100644 --- a/trunk/sound/usb/mixer.h +++ b/trunk/sound/usb/mixer.h @@ -68,7 +68,4 @@ int snd_usb_mixer_activate(struct usb_mixer_interface *mixer); int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer, struct snd_kcontrol *kctl); -int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, - unsigned int size, unsigned int __user *_tlv); - #endif /* __USBMIXER_H */ diff --git a/trunk/sound/usb/mixer_maps.c b/trunk/sound/usb/mixer_maps.c index 41daaa24c25f..f1324c423835 100644 --- a/trunk/sound/usb/mixer_maps.c +++ b/trunk/sound/usb/mixer_maps.c @@ -288,15 +288,6 @@ static struct usbmix_name_map scratch_live_map[] = { { 0 } /* terminator */ }; -static struct usbmix_name_map ebox44_map[] = { - { 4, NULL }, /* FU */ - { 6, NULL }, /* MU */ - { 7, NULL }, /* FU */ - { 10, NULL }, /* FU */ - { 11, NULL }, /* MU */ - { 0 } -}; - /* "Gamesurround Muse Pocket LT" looks same like "Sound Blaster MP3+" * most importand difference is SU[8], it should be set to "Capture Source" * to make alsamixer and PA working properly. @@ -380,10 +371,6 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { .map = scratch_live_map, .ignore_ctl_error = 1, }, - { - .id = USB_ID(0x200c, 0x1018), - .map = ebox44_map, - }, { 0 } /* terminator */ }; diff --git a/trunk/sound/usb/mixer_quirks.c b/trunk/sound/usb/mixer_quirks.c index 41f4b6911920..ab125ee0b0f0 100644 --- a/trunk/sound/usb/mixer_quirks.c +++ b/trunk/sound/usb/mixer_quirks.c @@ -42,77 +42,6 @@ extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl; -/* private_free callback */ -static void usb_mixer_elem_free(struct snd_kcontrol *kctl) -{ - kfree(kctl->private_data); - kctl->private_data = NULL; -} - -/* This function allows for the creation of standard UAC controls. - * See the quirks for M-Audio FTUs or Ebox-44. - * If you don't want to set a TLV callback pass NULL. - * - * Since there doesn't seem to be a devices that needs a multichannel - * version, we keep it mono for simplicity. - */ -static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer, - unsigned int unitid, - unsigned int control, - unsigned int cmask, - int val_type, - const char *name, - snd_kcontrol_tlv_rw_t *tlv_callback) -{ - int err; - struct usb_mixer_elem_info *cval; - struct snd_kcontrol *kctl; - - cval = kzalloc(sizeof(*cval), GFP_KERNEL); - if (!cval) - return -ENOMEM; - - cval->id = unitid; - cval->mixer = mixer; - cval->val_type = val_type; - cval->channels = 1; - cval->control = control; - cval->cmask = cmask; - - /* get_min_max() is called only for integer volumes later, - * so provide a short-cut for booleans */ - cval->min = 0; - cval->max = 1; - cval->res = 0; - cval->dBmin = 0; - cval->dBmax = 0; - - /* Create control */ - kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); - if (!kctl) { - kfree(cval); - return -ENOMEM; - } - - /* Set name */ - snprintf(kctl->id.name, sizeof(kctl->id.name), name); - kctl->private_free = usb_mixer_elem_free; - - /* set TLV */ - if (tlv_callback) { - kctl->tlv.c = tlv_callback; - kctl->vd[0].access |= - SNDRV_CTL_ELEM_ACCESS_TLV_READ | - SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; - } - /* Add control to mixer */ - err = snd_usb_mixer_add_control(mixer, kctl); - if (err < 0) - return err; - - return 0; -} - /* * Sound Blaster remote control configuration * @@ -566,218 +495,60 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer, } /* M-Audio FastTrack Ultra quirks */ -/* FTU Effect switch */ -struct snd_ftu_eff_switch_priv_val { - struct usb_mixer_interface *mixer; - int cached_value; - int is_cached; -}; - -static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - static const char *texts[8] = {"Room 1", - "Room 2", - "Room 3", - "Hall 1", - "Hall 2", - "Plate", - "Delay", - "Echo" - }; - - uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; - uinfo->count = 1; - uinfo->value.enumerated.items = 8; - if (uinfo->value.enumerated.item > 7) - uinfo->value.enumerated.item = 7; - strcpy(uinfo->value.enumerated.name, - texts[uinfo->value.enumerated.item]); - - return 0; -} - -static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) -{ - struct snd_usb_audio *chip; - struct usb_mixer_interface *mixer; - struct snd_ftu_eff_switch_priv_val *pval; - int err; - unsigned char value[2]; - - const int id = 6; - const int validx = 1; - const int val_len = 2; - value[0] = 0x00; - value[1] = 0x00; - - pval = (struct snd_ftu_eff_switch_priv_val *) - kctl->private_value; - - if (pval->is_cached) { - ucontrol->value.enumerated.item[0] = pval->cached_value; - return 0; - } - - mixer = (struct usb_mixer_interface *) pval->mixer; - if (snd_BUG_ON(!mixer)) - return -EINVAL; - - chip = (struct snd_usb_audio *) mixer->chip; - if (snd_BUG_ON(!chip)) - return -EINVAL; - - - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - if (err < 0) - return err; - - ucontrol->value.enumerated.item[0] = value[0]; - pval->cached_value = value[0]; - pval->is_cached = 1; - - return 0; -} - -static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl, - struct snd_ctl_elem_value *ucontrol) +/* private_free callback */ +static void usb_mixer_elem_free(struct snd_kcontrol *kctl) { - struct snd_usb_audio *chip; - struct snd_ftu_eff_switch_priv_val *pval; - - struct usb_mixer_interface *mixer; - int changed, cur_val, err, new_val; - unsigned char value[2]; - - - const int id = 6; - const int validx = 1; - const int val_len = 2; - - changed = 0; - - pval = (struct snd_ftu_eff_switch_priv_val *) - kctl->private_value; - cur_val = pval->cached_value; - new_val = ucontrol->value.enumerated.item[0]; - - mixer = (struct usb_mixer_interface *) pval->mixer; - if (snd_BUG_ON(!mixer)) - return -EINVAL; - - chip = (struct snd_usb_audio *) mixer->chip; - if (snd_BUG_ON(!chip)) - return -EINVAL; - - if (!pval->is_cached) { - /* Read current value */ - err = snd_usb_ctl_msg(chip->dev, - usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - if (err < 0) - return err; - - cur_val = value[0]; - pval->cached_value = cur_val; - pval->is_cached = 1; - } - /* update value if needed */ - if (cur_val != new_val) { - value[0] = new_val; - value[1] = 0; - err = snd_usb_ctl_msg(chip->dev, - usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, - USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, - validx << 8, snd_usb_ctrl_intf(chip) | (id << 8), - value, val_len); - if (err < 0) - return err; - - pval->cached_value = new_val; - pval->is_cached = 1; - changed = 1; - } - - return changed; + kfree(kctl->private_data); + kctl->private_data = NULL; } -static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer) +static int snd_maudio_ftu_create_ctl(struct usb_mixer_interface *mixer, + int in, int out, const char *name) { - static struct snd_kcontrol_new template = { - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Effect Program Switch", - .index = 0, - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = snd_ftu_eff_switch_info, - .get = snd_ftu_eff_switch_get, - .put = snd_ftu_eff_switch_put - }; - - int err; + struct usb_mixer_elem_info *cval; struct snd_kcontrol *kctl; - struct snd_ftu_eff_switch_priv_val *pval; - pval = kzalloc(sizeof(*pval), GFP_KERNEL); - if (!pval) + cval = kzalloc(sizeof(*cval), GFP_KERNEL); + if (!cval) return -ENOMEM; - pval->cached_value = 0; - pval->is_cached = 0; - pval->mixer = mixer; + cval->id = 5; + cval->mixer = mixer; + cval->val_type = USB_MIXER_S16; + cval->channels = 1; + cval->control = out + 1; + cval->cmask = 1 << in; - template.private_value = (unsigned long) pval; - kctl = snd_ctl_new1(&template, mixer->chip); + kctl = snd_ctl_new1(snd_usb_feature_unit_ctl, cval); if (!kctl) { - kfree(pval); + kfree(cval); return -ENOMEM; } - err = snd_ctl_add(mixer->chip->card, kctl); - if (err < 0) - return err; - - return 0; + snprintf(kctl->id.name, sizeof(kctl->id.name), name); + kctl->private_free = usb_mixer_elem_free; + return snd_usb_mixer_add_control(mixer, kctl); } -/* Create volume controls for FTU devices*/ -static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) +static int snd_maudio_ftu_create_mixer(struct usb_mixer_interface *mixer) { char name[64]; - unsigned int control, cmask; int in, out, err; - const unsigned int id = 5; - const int val_type = USB_MIXER_S16; - for (out = 0; out < 8; out++) { - control = out + 1; for (in = 0; in < 8; in++) { - cmask = 1 << in; snprintf(name, sizeof(name), - "AIn%d - Out%d Capture Volume", - in + 1, out + 1); - err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - &snd_usb_mixer_vol_tlv); + "AIn%d - Out%d Capture Volume", in + 1, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); if (err < 0) return err; } + for (in = 8; in < 16; in++) { - cmask = 1 << in; snprintf(name, sizeof(name), - "DIn%d - Out%d Playback Volume", - in - 7, out + 1); - err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - &snd_usb_mixer_vol_tlv); + "DIn%d - Out%d Playback Volume", in - 7, out + 1); + err = snd_maudio_ftu_create_ctl(mixer, in, out, name); if (err < 0) return err; } @@ -786,191 +557,6 @@ static int snd_ftu_create_volume_ctls(struct usb_mixer_interface *mixer) return 0; } -/* This control needs a volume quirk, see mixer.c */ -static int snd_ftu_create_effect_volume_ctl(struct usb_mixer_interface *mixer) -{ - static const char name[] = "Effect Volume"; - const unsigned int id = 6; - const int val_type = USB_MIXER_U8; - const unsigned int control = 2; - const unsigned int cmask = 0; - - return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, snd_usb_mixer_vol_tlv); -} - -/* This control needs a volume quirk, see mixer.c */ -static int snd_ftu_create_effect_duration_ctl(struct usb_mixer_interface *mixer) -{ - static const char name[] = "Effect Duration"; - const unsigned int id = 6; - const int val_type = USB_MIXER_S16; - const unsigned int control = 3; - const unsigned int cmask = 0; - - return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, snd_usb_mixer_vol_tlv); -} - -/* This control needs a volume quirk, see mixer.c */ -static int snd_ftu_create_effect_feedback_ctl(struct usb_mixer_interface *mixer) -{ - static const char name[] = "Effect Feedback Volume"; - const unsigned int id = 6; - const int val_type = USB_MIXER_U8; - const unsigned int control = 4; - const unsigned int cmask = 0; - - return snd_create_std_mono_ctl(mixer, id, control, cmask, val_type, - name, NULL); -} - -static int snd_ftu_create_effect_return_ctls(struct usb_mixer_interface *mixer) -{ - unsigned int cmask; - int err, ch; - char name[48]; - - const unsigned int id = 7; - const int val_type = USB_MIXER_S16; - const unsigned int control = 7; - - for (ch = 0; ch < 4; ++ch) { - cmask = 1 << ch; - snprintf(name, sizeof(name), - "Effect Return %d Volume", ch + 1); - err = snd_create_std_mono_ctl(mixer, id, control, - cmask, val_type, name, - snd_usb_mixer_vol_tlv); - if (err < 0) - return err; - } - - return 0; -} - -static int snd_ftu_create_effect_send_ctls(struct usb_mixer_interface *mixer) -{ - unsigned int cmask; - int err, ch; - char name[48]; - - const unsigned int id = 5; - const int val_type = USB_MIXER_S16; - const unsigned int control = 9; - - for (ch = 0; ch < 8; ++ch) { - cmask = 1 << ch; - snprintf(name, sizeof(name), - "Effect Send AIn%d Volume", ch + 1); - err = snd_create_std_mono_ctl(mixer, id, control, cmask, - val_type, name, - snd_usb_mixer_vol_tlv); - if (err < 0) - return err; - } - for (ch = 8; ch < 16; ++ch) { - cmask = 1 << ch; - snprintf(name, sizeof(name), - "Effect Send DIn%d Volume", ch - 7); - err = snd_create_std_mono_ctl(mixer, id, control, cmask, - val_type, name, - snd_usb_mixer_vol_tlv); - if (err < 0) - return err; - } - return 0; -} - -static int snd_ftu_create_mixer(struct usb_mixer_interface *mixer) -{ - int err; - - err = snd_ftu_create_volume_ctls(mixer); - if (err < 0) - return err; - - err = snd_ftu_create_effect_switch(mixer); - if (err < 0) - return err; - err = snd_ftu_create_effect_volume_ctl(mixer); - if (err < 0) - return err; - - err = snd_ftu_create_effect_duration_ctl(mixer); - if (err < 0) - return err; - - err = snd_ftu_create_effect_feedback_ctl(mixer); - if (err < 0) - return err; - - err = snd_ftu_create_effect_return_ctls(mixer); - if (err < 0) - return err; - - err = snd_ftu_create_effect_send_ctls(mixer); - if (err < 0) - return err; - - return 0; -} - - -/* - * Create mixer for Electrix Ebox-44 - * - * The mixer units from this device are corrupt, and even where they - * are valid they presents mono controls as L and R channels of - * stereo. So we create a good mixer in code. - */ - -static int snd_ebox44_create_mixer(struct usb_mixer_interface *mixer) -{ - int err; - - err = snd_create_std_mono_ctl(mixer, 4, 1, 0x0, USB_MIXER_INV_BOOLEAN, - "Headphone Playback Switch", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 4, 2, 0x1, USB_MIXER_S16, - "Headphone A Mix Playback Volume", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 4, 2, 0x2, USB_MIXER_S16, - "Headphone B Mix Playback Volume", NULL); - if (err < 0) - return err; - - err = snd_create_std_mono_ctl(mixer, 7, 1, 0x0, USB_MIXER_INV_BOOLEAN, - "Output Playback Switch", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 7, 2, 0x1, USB_MIXER_S16, - "Output A Playback Volume", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 7, 2, 0x2, USB_MIXER_S16, - "Output B Playback Volume", NULL); - if (err < 0) - return err; - - err = snd_create_std_mono_ctl(mixer, 10, 1, 0x0, USB_MIXER_INV_BOOLEAN, - "Input Capture Switch", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 10, 2, 0x1, USB_MIXER_S16, - "Input A Capture Volume", NULL); - if (err < 0) - return err; - err = snd_create_std_mono_ctl(mixer, 10, 2, 0x2, USB_MIXER_S16, - "Input B Capture Volume", NULL); - if (err < 0) - return err; - - return 0; -} - void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, unsigned char samplerate_id) { @@ -1014,7 +600,7 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) case USB_ID(0x0763, 0x2080): /* M-Audio Fast Track Ultra */ case USB_ID(0x0763, 0x2081): /* M-Audio Fast Track Ultra 8R */ - err = snd_ftu_create_mixer(mixer); + err = snd_maudio_ftu_create_mixer(mixer); break; case USB_ID(0x0b05, 0x1739): @@ -1033,10 +619,6 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) snd_nativeinstruments_ta10_mixers, ARRAY_SIZE(snd_nativeinstruments_ta10_mixers)); break; - - case USB_ID(0x200c, 0x1018): /* Electrix Ebox-44 */ - err = snd_ebox44_create_mixer(mixer); - break; } return err; diff --git a/trunk/sound/usb/pcm.c b/trunk/sound/usb/pcm.c index 24839d932648..0eed6115c2d4 100644 --- a/trunk/sound/usb/pcm.c +++ b/trunk/sound/usb/pcm.c @@ -16,7 +16,6 @@ #include #include -#include #include #include #include @@ -35,9 +34,6 @@ #include "clock.h" #include "power.h" -#define SUBSTREAM_FLAG_DATA_EP_STARTED 0 -#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 - /* return the estimated delay based on USB frame counters */ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, unsigned int rate) @@ -212,84 +208,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, } } -static int start_endpoints(struct snd_usb_substream *subs) -{ - int err; - - if (!subs->data_endpoint) - return -EINVAL; - - if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { - struct snd_usb_endpoint *ep = subs->data_endpoint; - - snd_printdd(KERN_DEBUG "Starting data EP @%p\n", ep); - - ep->data_subs = subs; - err = snd_usb_endpoint_start(ep); - if (err < 0) { - clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); - return err; - } - } - - if (subs->sync_endpoint && - !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { - struct snd_usb_endpoint *ep = subs->sync_endpoint; - - snd_printdd(KERN_DEBUG "Starting sync EP @%p\n", ep); - - ep->sync_slave = subs->data_endpoint; - err = snd_usb_endpoint_start(ep); - if (err < 0) { - clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); - return err; - } - } - - return 0; -} - -static void stop_endpoints(struct snd_usb_substream *subs, - int force, int can_sleep, int wait) -{ - if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) - snd_usb_endpoint_stop(subs->sync_endpoint, - force, can_sleep, wait); - - if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) - snd_usb_endpoint_stop(subs->data_endpoint, - force, can_sleep, wait); -} - -static int activate_endpoints(struct snd_usb_substream *subs) -{ - if (subs->sync_endpoint) { - int ret; - - ret = snd_usb_endpoint_activate(subs->sync_endpoint); - if (ret < 0) - return ret; - } - - return snd_usb_endpoint_activate(subs->data_endpoint); -} - -static int deactivate_endpoints(struct snd_usb_substream *subs) -{ - int reta, retb; - - reta = snd_usb_endpoint_deactivate(subs->sync_endpoint); - retb = snd_usb_endpoint_deactivate(subs->data_endpoint); - - if (reta < 0) - return reta; - - if (retb < 0) - return retb; - - return 0; -} - /* * find a matching format and set up the interface */ @@ -301,7 +219,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) struct usb_interface *iface; unsigned int ep, attr; int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; - int err, implicit_fb = 0; + int err; iface = usb_ifnum_to_if(dev, fmt->iface); if (WARN_ON(!iface)) @@ -314,11 +232,40 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) if (fmt == subs->cur_audiofmt) return 0; - subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, - alts, fmt->endpoint, subs->direction, - SND_USB_ENDPOINT_TYPE_DATA); - if (!subs->data_endpoint) - return -EINVAL; + /* close the old interface */ + if (subs->interface >= 0 && subs->interface != fmt->iface) { + if (usb_set_interface(subs->dev, subs->interface, 0) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: return to setting 0 failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } + subs->interface = -1; + subs->altset_idx = 0; + } + + /* set interface */ + if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) { + if (usb_set_interface(dev, fmt->iface, fmt->altsetting) < 0) { + snd_printk(KERN_ERR "%d:%d:%d: usb_set_interface failed\n", + dev->devnum, fmt->iface, fmt->altsetting); + return -EIO; + } + snd_printdd(KERN_INFO "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); + subs->interface = fmt->iface; + subs->altset_idx = fmt->altset_idx; + } + + /* create a data pipe */ + ep = fmt->endpoint & USB_ENDPOINT_NUMBER_MASK; + if (is_playback) + subs->datapipe = usb_sndisocpipe(dev, ep); + else + subs->datapipe = usb_rcvisocpipe(dev, ep); + subs->datainterval = fmt->datainterval; + subs->syncpipe = subs->syncinterval = 0; + subs->maxpacksize = fmt->maxpacksize; + subs->syncmaxsize = 0; + subs->fill_max = 0; /* we need a sync pipe in async OUT or adaptive IN mode */ /* check the number of EP, since some devices have broken @@ -326,25 +273,8 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) * assume it as adaptive-out or sync-in. */ attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; - - switch (subs->stream->chip->usb_id) { - case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ - case USB_ID(0x0763, 0x2081): - if (is_playback) { - implicit_fb = 1; - ep = 0x81; - iface = usb_ifnum_to_if(dev, 2); - - if (!iface || iface->num_altsetting == 0) - return -EINVAL; - - alts = &iface->altsetting[1]; - goto add_sync_ep; - } - } - if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || - (!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && + (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && altsd->bNumEndpoints >= 2) { /* check sync-pipe endpoint */ /* ... and check descriptor size before accessing bSynchAddress @@ -352,8 +282,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) the audio fields in the endpoint descriptors */ if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != 0x01 || (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && - get_endpoint(alts, 1)->bSynchAddress != 0 && - !implicit_fb)) { + get_endpoint(alts, 1)->bSynchAddress != 0)) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; @@ -361,27 +290,33 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) ep = get_endpoint(alts, 1)->bEndpointAddress; if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && (( is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || - (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)) || - ( is_playback && !implicit_fb))) { + (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { snd_printk(KERN_ERR "%d:%d:%d : invalid synch pipe\n", dev->devnum, fmt->iface, fmt->altsetting); return -EINVAL; } - - implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) - == USB_ENDPOINT_USAGE_IMPLICIT_FB; - -add_sync_ep: - subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, - alts, ep, !subs->direction, - implicit_fb ? - SND_USB_ENDPOINT_TYPE_DATA : - SND_USB_ENDPOINT_TYPE_SYNC); - if (!subs->sync_endpoint) - return -EINVAL; - - subs->data_endpoint->sync_master = subs->sync_endpoint; - } + ep &= USB_ENDPOINT_NUMBER_MASK; + if (is_playback) + subs->syncpipe = usb_rcvisocpipe(dev, ep); + else + subs->syncpipe = usb_sndisocpipe(dev, ep); + if (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && + get_endpoint(alts, 1)->bRefresh >= 1 && + get_endpoint(alts, 1)->bRefresh <= 9) + subs->syncinterval = get_endpoint(alts, 1)->bRefresh; + else if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) + subs->syncinterval = 1; + else if (get_endpoint(alts, 1)->bInterval >= 1 && + get_endpoint(alts, 1)->bInterval <= 16) + subs->syncinterval = get_endpoint(alts, 1)->bInterval - 1; + else + subs->syncinterval = 3; + subs->syncmaxsize = le16_to_cpu(get_endpoint(alts, 1)->wMaxPacketSize); + } + + /* always fill max packet size */ + if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) + subs->fill_max = 1; if ((err = snd_usb_init_pitch(subs->stream->chip, subs->interface, alts, fmt)) < 0) return err; @@ -455,30 +390,15 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, if (changed) { mutex_lock(&subs->stream->chip->shutdown_mutex); /* format changed */ - stop_endpoints(subs, 0, 0, 0); - deactivate_endpoints(subs); - - ret = activate_endpoints(subs); - if (ret < 0) - goto unlock; - - ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, - subs->sync_endpoint); - if (ret < 0) - goto unlock; - - if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->sync_endpoint, - hw_params, fmt, NULL); -unlock: + snd_usb_release_substream_urbs(subs, 0); + /* influenced: period_bytes, channels, rate, format, */ + ret = snd_usb_init_substream_urbs(subs, params_period_bytes(hw_params), + params_rate(hw_params), + snd_pcm_format_physical_width(params_format(hw_params)) * + params_channels(hw_params)); mutex_unlock(&subs->stream->chip->shutdown_mutex); } - if (ret == 0) { - subs->interface = fmt->iface; - subs->altset_idx = fmt->altset_idx; - } - return ret; } @@ -495,7 +415,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) subs->cur_rate = 0; subs->period_bytes = 0; mutex_lock(&subs->stream->chip->shutdown_mutex); - stop_endpoints(subs, 0, 1, 1); + snd_usb_release_substream_urbs(subs, 0); mutex_unlock(&subs->stream->chip->shutdown_mutex); return snd_pcm_lib_free_vmalloc_buffer(substream); } @@ -515,28 +435,19 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) return -ENXIO; } - if (snd_BUG_ON(!subs->data_endpoint)) - return -EIO; - /* some unit conversions in runtime */ - subs->data_endpoint->maxframesize = - bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); - subs->data_endpoint->curframesize = - bytes_to_frames(runtime, subs->data_endpoint->curpacksize); + subs->maxframesize = bytes_to_frames(runtime, subs->maxpacksize); + subs->curframesize = bytes_to_frames(runtime, subs->curpacksize); /* reset the pointer */ subs->hwptr_done = 0; subs->transfer_done = 0; + subs->phase = 0; subs->last_delay = 0; subs->last_frame_number = 0; runtime->delay = 0; - /* for playback, submit the URBs now; otherwise, the first hwptr_done - * updates for all URBs would happen at the same time when starting */ - if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) - return start_endpoints(subs); - - return 0; + return snd_usb_substream_prepare(subs, runtime); } static struct snd_pcm_hardware snd_usb_hardware = @@ -931,171 +842,16 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) { - int ret; struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; - stop_endpoints(subs, 0, 0, 0); - ret = deactivate_endpoints(subs); + if (!as->chip->shutdown && subs->interface >= 0) { + usb_set_interface(subs->dev, subs->interface, 0); + subs->interface = -1; + } subs->pcm_substream = NULL; snd_usb_autosuspend(subs->stream->chip); - - return ret; -} - -/* Since a URB can handle only a single linear buffer, we must use double - * buffering when the data to be transferred overflows the buffer boundary. - * To avoid inconsistencies when updating hwptr_done, we use double buffering - * for all URBs. - */ -static void retire_capture_urb(struct snd_usb_substream *subs, - struct urb *urb) -{ - struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - unsigned int stride, frames, bytes, oldptr; - int i, period_elapsed = 0; - unsigned long flags; - unsigned char *cp; - - stride = runtime->frame_bits >> 3; - - for (i = 0; i < urb->number_of_packets; i++) { - cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset; - if (urb->iso_frame_desc[i].status && printk_ratelimit()) { - snd_printdd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); - // continue; - } - bytes = urb->iso_frame_desc[i].actual_length; - frames = bytes / stride; - if (!subs->txfr_quirk) - bytes = frames * stride; - if (bytes % (runtime->sample_bits >> 3) != 0) { -#ifdef CONFIG_SND_DEBUG_VERBOSE - int oldbytes = bytes; -#endif - bytes = frames * stride; - snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", - oldbytes, bytes); - } - /* update the current pointer */ - spin_lock_irqsave(&subs->lock, flags); - oldptr = subs->hwptr_done; - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; - frames = (bytes + (oldptr % stride)) / stride; - subs->transfer_done += frames; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; - } - spin_unlock_irqrestore(&subs->lock, flags); - /* copy a data chunk */ - if (oldptr + bytes > runtime->buffer_size * stride) { - unsigned int bytes1 = - runtime->buffer_size * stride - oldptr; - memcpy(runtime->dma_area + oldptr, cp, bytes1); - memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); - } else { - memcpy(runtime->dma_area + oldptr, cp, bytes); - } - } - - if (period_elapsed) - snd_pcm_period_elapsed(subs->pcm_substream); -} - -static void prepare_playback_urb(struct snd_usb_substream *subs, - struct urb *urb) -{ - struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - struct snd_urb_ctx *ctx = urb->context; - unsigned int counts, frames, bytes; - int i, stride, period_elapsed = 0; - unsigned long flags; - - stride = runtime->frame_bits >> 3; - - frames = 0; - urb->number_of_packets = 0; - spin_lock_irqsave(&subs->lock, flags); - for (i = 0; i < ctx->packets; i++) { - counts = ctx->packet_size[i]; - /* set up descriptor */ - urb->iso_frame_desc[i].offset = frames * stride; - urb->iso_frame_desc[i].length = counts * stride; - frames += counts; - urb->number_of_packets++; - subs->transfer_done += counts; - if (subs->transfer_done >= runtime->period_size) { - subs->transfer_done -= runtime->period_size; - period_elapsed = 1; - if (subs->fmt_type == UAC_FORMAT_TYPE_II) { - if (subs->transfer_done > 0) { - /* FIXME: fill-max mode is not - * supported yet */ - frames -= subs->transfer_done; - counts -= subs->transfer_done; - urb->iso_frame_desc[i].length = - counts * stride; - subs->transfer_done = 0; - } - i++; - if (i < ctx->packets) { - /* add a transfer delimiter */ - urb->iso_frame_desc[i].offset = - frames * stride; - urb->iso_frame_desc[i].length = 0; - urb->number_of_packets++; - } - break; - } - } - if (period_elapsed && - !snd_usb_endpoint_implict_feedback_sink(subs->data_endpoint)) /* finish at the period boundary */ - break; - } - bytes = frames * stride; - if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { - /* err, the transferred area goes over buffer boundary. */ - unsigned int bytes1 = - runtime->buffer_size * stride - subs->hwptr_done; - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes1); - memcpy(urb->transfer_buffer + bytes1, - runtime->dma_area, bytes - bytes1); - } else { - memcpy(urb->transfer_buffer, - runtime->dma_area + subs->hwptr_done, bytes); - } - subs->hwptr_done += bytes; - if (subs->hwptr_done >= runtime->buffer_size * stride) - subs->hwptr_done -= runtime->buffer_size * stride; - runtime->delay += frames; - spin_unlock_irqrestore(&subs->lock, flags); - urb->transfer_buffer_length = bytes; - if (period_elapsed) - snd_pcm_period_elapsed(subs->pcm_substream); -} - -/* - * process after playback data complete - * - decrease the delay count again - */ -static void retire_playback_urb(struct snd_usb_substream *subs, - struct urb *urb) -{ - unsigned long flags; - struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; - int stride = runtime->frame_bits >> 3; - int processed = urb->transfer_buffer_length / stride; - - spin_lock_irqsave(&subs->lock, flags); - if (processed > runtime->delay) - runtime->delay = 0; - else - runtime->delay -= processed; - spin_unlock_irqrestore(&subs->lock, flags); + return 0; } static int snd_usb_playback_open(struct snd_pcm_substream *substream) @@ -1118,63 +874,6 @@ static int snd_usb_capture_close(struct snd_pcm_substream *substream) return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); } -static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, - int cmd) -{ - struct snd_usb_substream *subs = substream->runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->data_endpoint->prepare_data_urb = prepare_playback_urb; - subs->data_endpoint->retire_data_urb = retire_playback_urb; - subs->running = 1; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, 0, 0, 0); - subs->running = 0; - return 0; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->data_endpoint->prepare_data_urb = NULL; - subs->data_endpoint->retire_data_urb = NULL; - subs->running = 0; - return 0; - } - - return -EINVAL; -} - -int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd) -{ - int err; - struct snd_usb_substream *subs = substream->runtime->private_data; - - switch (cmd) { - case SNDRV_PCM_TRIGGER_START: - err = start_endpoints(subs); - if (err < 0) - return err; - - subs->data_endpoint->retire_data_urb = retire_capture_urb; - subs->running = 1; - return 0; - case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, 0, 0, 0); - subs->running = 0; - return 0; - case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - subs->data_endpoint->retire_data_urb = NULL; - subs->running = 0; - return 0; - case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: - subs->data_endpoint->retire_data_urb = retire_capture_urb; - subs->running = 1; - return 0; - } - - return -EINVAL; -} - static struct snd_pcm_ops snd_usb_playback_ops = { .open = snd_usb_playback_open, .close = snd_usb_playback_close, diff --git a/trunk/sound/usb/proc.c b/trunk/sound/usb/proc.c index ebc1a5b5b3f1..961c9a250686 100644 --- a/trunk/sound/usb/proc.c +++ b/trunk/sound/usb/proc.c @@ -25,7 +25,6 @@ #include "usbaudio.h" #include "helper.h" #include "card.h" -#include "endpoint.h" #include "proc.h" /* convert our full speed USB rate into sampling rate in Hz */ @@ -116,33 +115,28 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s } } -static void proc_dump_ep_status(struct snd_usb_substream *subs, - struct snd_usb_endpoint *ep, - struct snd_info_buffer *buffer) -{ - if (!ep) - return; - snd_iprintf(buffer, " Packet Size = %d\n", ep->curpacksize); - snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", - snd_usb_get_speed(subs->dev) == USB_SPEED_FULL - ? get_full_speed_hz(ep->freqm) - : get_high_speed_hz(ep->freqm), - ep->freqm >> 16, ep->freqm & 0xffff); - if (ep->freqshift != INT_MIN) { - int res = 16 - ep->freqshift; - snd_iprintf(buffer, " Feedback Format = %d.%d\n", - (ep->syncmaxsize > 3 ? 32 : 24) - res, res); - } -} - static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer) { if (subs->running) { + unsigned int i; snd_iprintf(buffer, " Status: Running\n"); snd_iprintf(buffer, " Interface = %d\n", subs->interface); snd_iprintf(buffer, " Altset = %d\n", subs->altset_idx); - proc_dump_ep_status(subs, subs->data_endpoint, buffer); - proc_dump_ep_status(subs, subs->sync_endpoint, buffer); + snd_iprintf(buffer, " URBs = %d [ ", subs->nurbs); + for (i = 0; i < subs->nurbs; i++) + snd_iprintf(buffer, "%d ", subs->dataurb[i].packets); + snd_iprintf(buffer, "]\n"); + snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize); + snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n", + snd_usb_get_speed(subs->dev) == USB_SPEED_FULL + ? get_full_speed_hz(subs->freqm) + : get_high_speed_hz(subs->freqm), + subs->freqm >> 16, subs->freqm & 0xffff); + if (subs->freqshift != INT_MIN) + snd_iprintf(buffer, " Feedback Format = %d.%d\n", + (subs->syncmaxsize > 3 ? 32 : 24) + - (16 - subs->freqshift), + 16 - subs->freqshift); } else { snd_iprintf(buffer, " Status: Stop\n"); } diff --git a/trunk/sound/usb/stream.c b/trunk/sound/usb/stream.c index 6b7d7a2b7baa..5ff8010b2d6f 100644 --- a/trunk/sound/usb/stream.c +++ b/trunk/sound/usb/stream.c @@ -73,31 +73,6 @@ static void snd_usb_audio_pcm_free(struct snd_pcm *pcm) } } -/* - * initialize the substream instance. - */ - -static void snd_usb_init_substream(struct snd_usb_stream *as, - int stream, - struct audioformat *fp) -{ - struct snd_usb_substream *subs = &as->substream[stream]; - - INIT_LIST_HEAD(&subs->fmt_list); - spin_lock_init(&subs->lock); - - subs->stream = as; - subs->direction = stream; - subs->dev = as->chip->dev; - subs->txfr_quirk = as->chip->txfr_quirk; - - snd_usb_set_pcm_ops(as->pcm, stream); - - list_add_tail(&fp->list, &subs->fmt_list); - subs->formats |= fp->formats; - subs->num_formats++; - subs->fmt_type = fp->fmt_type; -} /* * add this endpoint to the chip instance. @@ -119,9 +94,9 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, if (as->fmt_type != fp->fmt_type) continue; subs = &as->substream[stream]; - if (!subs->data_endpoint) + if (!subs->endpoint) continue; - if (subs->data_endpoint->ep_num == fp->endpoint) { + if (subs->endpoint == fp->endpoint) { list_add_tail(&fp->list, &subs->fmt_list); subs->num_formats++; subs->formats |= fp->formats; @@ -134,7 +109,7 @@ int snd_usb_add_audio_stream(struct snd_usb_audio *chip, if (as->fmt_type != fp->fmt_type) continue; subs = &as->substream[stream]; - if (subs->data_endpoint) + if (subs->endpoint) continue; err = snd_pcm_new_stream(as->pcm, stream, 1); if (err < 0) diff --git a/trunk/sound/usb/usbaudio.h b/trunk/sound/usb/usbaudio.h index b8233ebe250f..3e2b03577936 100644 --- a/trunk/sound/usb/usbaudio.h +++ b/trunk/sound/usb/usbaudio.h @@ -36,7 +36,6 @@ struct snd_usb_audio { struct snd_card *card; struct usb_interface *pm_intf; u32 usb_id; - struct mutex mutex; struct mutex shutdown_mutex; unsigned int shutdown:1; unsigned int probing:1; @@ -47,7 +46,6 @@ struct snd_usb_audio { int num_suspended_intf; struct list_head pcm_list; /* list of pcm streams */ - struct list_head ep_list; /* list of audio-related endpoints */ int pcm_devs; struct list_head midi_list; /* list of midi interfaces */