浏览代码

Merge branch 'topic/misc' into topic/pcsp-fix

Conflicts:
	sound/drivers/pcsp/pcsp_lib.c
Takashi Iwai 16 年之前
父节点
当前提交
e7dd8c1bda

+ 25 - 3
include/sound/core.h

@@ -353,7 +353,7 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
  * snd_printk - printk wrapper
  * @fmt: format string
  *
- * Works like print() but prints the file and the line of the caller
+ * Works like printk() but prints the file and the line of the caller
  * when configured with CONFIG_SND_VERBOSE_PRINTK.
  */
 #define snd_printk(fmt, args...) \
@@ -380,18 +380,40 @@ void snd_verbose_printd(const char *file, int line, const char *format, ...)
 	printk(fmt ,##args)
 #endif
 
+/**
+ * snd_BUG - give a BUG warning message and stack trace
+ *
+ * Calls WARN() if CONFIG_SND_DEBUG is set.
+ * Ignored when CONFIG_SND_DEBUG is not set.
+ */
 #define snd_BUG()		WARN(1, "BUG?\n")
+
+/**
+ * snd_BUG_ON - debugging check macro
+ * @cond: condition to evaluate
+ *
+ * When CONFIG_SND_DEBUG is set, this macro evaluates the given condition,
+ * and call WARN() and returns the value if it's non-zero.
+ * 
+ * When CONFIG_SND_DEBUG is not set, this just returns zero, and the given
+ * condition is ignored.
+ *
+ * NOTE: the argument won't be evaluated at all when CONFIG_SND_DEBUG=n.
+ * Thus, don't put any statement that influences on the code behavior,
+ * such as pre/post increment, to the argument of this macro.
+ * If you want to evaluate and give a warning, use standard WARN_ON().
+ */
 #define snd_BUG_ON(cond)	WARN((cond), "BUG? (%s)\n", __stringify(cond))
 
 #else /* !CONFIG_SND_DEBUG */
 
 #define snd_printd(fmt, args...)	do { } while (0)
 #define snd_BUG()			do { } while (0)
-static inline int __snd_bug_on(void)
+static inline int __snd_bug_on(int cond)
 {
 	return 0;
 }
-#define snd_BUG_ON(cond)		__snd_bug_on()  /* always false */
+#define snd_BUG_ON(cond)	__snd_bug_on(0 && (cond))  /* always false */
 
 #endif /* CONFIG_SND_DEBUG */
 

+ 1 - 1
include/sound/version.h

@@ -1,3 +1,3 @@
 /* include/version.h */
-#define CONFIG_SND_VERSION "1.0.18rc3"
+#define CONFIG_SND_VERSION "1.0.18a"
 #define CONFIG_SND_DATE ""

+ 2 - 2
sound/core/device.c

@@ -98,7 +98,7 @@ int snd_device_free(struct snd_card *card, void *device_data)
 		kfree(dev);
 		return 0;
 	}
-	snd_printd("device free %p (from %p), not found\n", device_data,
+	snd_printd("device free %p (from %pF), not found\n", device_data,
 		   __builtin_return_address(0));
 	return -ENXIO;
 }
@@ -135,7 +135,7 @@ int snd_device_disconnect(struct snd_card *card, void *device_data)
 		}
 		return 0;
 	}
-	snd_printd("device disconnect %p (from %p), not found\n", device_data,
+	snd_printd("device disconnect %p (from %pF), not found\n", device_data,
 		   __builtin_return_address(0));
 	return -ENXIO;
 }

+ 3 - 5
sound/drivers/pcsp/pcsp.c

@@ -96,7 +96,7 @@ static int __devinit snd_card_pcsp_probe(int devnum, struct device *dev)
 		return -EINVAL;
 
 	hrtimer_init(&pcsp_chip.timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
-	pcsp_chip.timer.cb_mode = HRTIMER_CB_SOFTIRQ;
+	pcsp_chip.timer.cb_mode = HRTIMER_CB_IRQSAFE_UNLOCKED;
 	pcsp_chip.timer.function = pcsp_do_timer;
 
 	card = snd_card_new(index, id, THIS_MODULE, 0);
@@ -188,10 +188,8 @@ static int __devexit pcsp_remove(struct platform_device *dev)
 
 static void pcsp_stop_beep(struct snd_pcsp *chip)
 {
-	spin_lock_irq(&chip->substream_lock);
-	if (!chip->playback_substream)
-		pcspkr_stop_sound();
-	spin_unlock_irq(&chip->substream_lock);
+	pcsp_sync_stop(chip);
+	pcspkr_stop_sound();
 }
 
 #ifdef CONFIG_PM

+ 1 - 0
sound/drivers/pcsp/pcsp.h

@@ -77,6 +77,7 @@ struct snd_pcsp {
 extern struct snd_pcsp pcsp_chip;
 
 extern enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle);
+extern void pcsp_sync_stop(struct snd_pcsp *chip);
 
 extern int snd_pcsp_new_pcm(struct snd_pcsp *chip);
 extern int snd_pcsp_new_mixer(struct snd_pcsp *chip);

+ 52 - 43
sound/drivers/pcsp/pcsp_lib.c

@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/moduleparam.h>
+#include <linux/interrupt.h>
 #include <sound/pcm.h>
 #include <asm/io.h>
 #include "pcsp.h"
@@ -19,6 +20,22 @@ MODULE_PARM_DESC(nforce_wa, "Apply NForce chipset workaround "
 
 #define DMIX_WANTS_S16	1
 
+/*
+ * Call snd_pcm_period_elapsed in a tasklet
+ * This avoids spinlock messes and long-running irq contexts
+ */
+static void pcsp_call_pcm_elapsed(unsigned long priv)
+{
+	if (atomic_read(&pcsp_chip.timer_active)) {
+		struct snd_pcm_substream *substream;
+		substream = pcsp_chip.playback_substream;
+		if (substream)
+			snd_pcm_period_elapsed(substream);
+	}
+}
+
+static DECLARE_TASKLET(pcsp_pcm_tasklet, pcsp_call_pcm_elapsed, 0);
+
 enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
 {
 	unsigned char timer_cnt, val;
@@ -28,41 +45,23 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
 	struct snd_pcm_substream *substream;
 	struct snd_pcm_runtime *runtime;
 	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
+	unsigned long flags;
 
 	if (chip->thalf) {
 		outb(chip->val61, 0x61);
 		chip->thalf = 0;
 		if (!atomic_read(&chip->timer_active))
-			return HRTIMER_NORESTART;
+			goto stop;
 		hrtimer_forward(&chip->timer, hrtimer_get_expires(&chip->timer),
 				ktime_set(0, chip->ns_rem));
 		return HRTIMER_RESTART;
 	}
 
-	spin_lock_irq(&chip->substream_lock);
-	/* Takashi Iwai says regarding this extra lock:
-
-	If the irq handler handles some data on the DMA buffer, it should
-	do snd_pcm_stream_lock().
-	That protects basically against all races among PCM callbacks, yes.
-	However, there are two remaining issues:
-	1. The substream pointer you try to lock isn't protected _before_
-	  this lock yet.
-	2. snd_pcm_period_elapsed() itself acquires the lock.
-	The requirement of another lock is because of 1.  When you get
-	chip->playback_substream, it's not protected.
-	Keeping this lock while snd_pcm_period_elapsed() assures the substream
-	is still protected (at least, not released).  And the other status is
-	handled properly inside snd_pcm_stream_lock() in
-	snd_pcm_period_elapsed().
-
-	*/
-	if (!chip->playback_substream)
-		goto exit_nr_unlock1;
-	substream = chip->playback_substream;
-	snd_pcm_stream_lock(substream);
 	if (!atomic_read(&chip->timer_active))
-		goto exit_nr_unlock2;
+		goto stop;
+	substream = chip->playback_substream;
+	if (!substream)
+		goto stop;
 
 	runtime = substream->runtime;
 	fmt_size = snd_pcm_format_physical_width(runtime->format) >> 3;
@@ -87,6 +86,8 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
 
 	period_bytes = snd_pcm_lib_period_bytes(substream);
 	buffer_bytes = snd_pcm_lib_buffer_bytes(substream);
+
+	spin_lock_irqsave(&chip->substream_lock, flags);
 	chip->playback_ptr += PCSP_INDEX_INC() * fmt_size;
 	periods_elapsed = chip->playback_ptr - chip->period_ptr;
 	if (periods_elapsed < 0) {
@@ -102,18 +103,15 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
 	 * or ALSA will BUG on us. */
 	chip->playback_ptr %= buffer_bytes;
 
-	snd_pcm_stream_unlock(substream);
-
 	if (periods_elapsed) {
-		snd_pcm_period_elapsed(substream);
 		chip->period_ptr += periods_elapsed * period_bytes;
 		chip->period_ptr %= buffer_bytes;
+		tasklet_schedule(&pcsp_pcm_tasklet);
 	}
-
-	spin_unlock_irq(&chip->substream_lock);
+	spin_unlock_irqrestore(&chip->substream_lock, flags);
 
 	if (!atomic_read(&chip->timer_active))
-		return HRTIMER_NORESTART;
+		goto stop;
 
 	chip->ns_rem = PCSP_PERIOD_NS();
 	ns = (chip->thalf ? PCSP_CALC_NS(timer_cnt) : chip->ns_rem);
@@ -122,10 +120,7 @@ enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
 							ktime_set(0, ns));
 	return HRTIMER_RESTART;
 
-exit_nr_unlock2:
-	snd_pcm_stream_unlock(substream);
-exit_nr_unlock1:
-	spin_unlock_irq(&chip->substream_lock);
+ stop:
 	return HRTIMER_NORESTART;
 }
 
@@ -165,26 +160,35 @@ static void pcsp_stop_playing(struct snd_pcsp *chip)
 	spin_unlock(&i8253_lock);
 }
 
+/*
+ * Force to stop and sync the stream
+ */
+void pcsp_sync_stop(struct snd_pcsp *chip)
+{
+	local_irq_disable();
+	pcsp_stop_playing(chip);
+	local_irq_enable();
+	hrtimer_cancel(&chip->timer);
+	tasklet_kill(&pcsp_pcm_tasklet);
+}
+
 static int snd_pcsp_playback_close(struct snd_pcm_substream *substream)
 {
 	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: close called\n");
 #endif
-	if (atomic_read(&chip->timer_active)) {
-		printk(KERN_ERR "PCSP: timer still active\n");
-		pcsp_stop_playing(chip);
-	}
-	spin_lock_irq(&chip->substream_lock);
+	pcsp_sync_stop(chip);
 	chip->playback_substream = NULL;
-	spin_unlock_irq(&chip->substream_lock);
 	return 0;
 }
 
 static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
 				       struct snd_pcm_hw_params *hw_params)
 {
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 	int err;
+	pcsp_sync_stop(chip);
 	err = snd_pcm_lib_malloc_pages(substream,
 				      params_buffer_bytes(hw_params));
 	if (err < 0)
@@ -194,9 +198,11 @@ static int snd_pcsp_playback_hw_params(struct snd_pcm_substream *substream,
 
 static int snd_pcsp_playback_hw_free(struct snd_pcm_substream *substream)
 {
+	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
 #if PCSP_DEBUG
 	printk(KERN_INFO "PCSP: hw_free called\n");
 #endif
+	pcsp_sync_stop(chip);
 	return snd_pcm_lib_free_pages(substream);
 }
 
@@ -212,6 +218,7 @@ static int snd_pcsp_playback_prepare(struct snd_pcm_substream *substream)
 			snd_pcm_lib_period_bytes(substream),
 			substream->runtime->periods);
 #endif
+	pcsp_sync_stop(chip);
 	chip->playback_ptr = 0;
 	chip->period_ptr = 0;
 	return 0;
@@ -242,7 +249,11 @@ static snd_pcm_uframes_t snd_pcsp_playback_pointer(struct snd_pcm_substream
 						   *substream)
 {
 	struct snd_pcsp *chip = snd_pcm_substream_chip(substream);
-	return bytes_to_frames(substream->runtime, chip->playback_ptr);
+	unsigned int pos;
+	spin_lock(&chip->substream_lock);
+	pos = chip->playback_ptr;
+	spin_unlock(&chip->substream_lock);
+	return bytes_to_frames(substream->runtime, pos);
 }
 
 static struct snd_pcm_hardware snd_pcsp_playback = {
@@ -279,9 +290,7 @@ static int snd_pcsp_playback_open(struct snd_pcm_substream *substream)
 		return -EBUSY;
 	}
 	runtime->hw = snd_pcsp_playback;
-	spin_lock_irq(&chip->substream_lock);
 	chip->playback_substream = substream;
-	spin_unlock_irq(&chip->substream_lock);
 	return 0;
 }
 

+ 2 - 0
sound/pci/ac97/ac97_patch.c

@@ -2832,6 +2832,8 @@ static int patch_alc655(struct snd_ac97 * ac97)
 			val &= ~(1 << 1); /* Pin 47 is EAPD (for internal speaker) */
 		else
 			val |= (1 << 1); /* Pin 47 is spdif input pin */
+		/* this seems missing on some hardwares */
+		ac97->ext_id |= AC97_EI_SPDIF;
 	}
 	val &= ~(1 << 12); /* vref enable */
 	snd_ac97_write_cache(ac97, 0x7a, val);

文件差异内容过多而无法显示
+ 212 - 205
sound/pci/emu10k1/emu10k1_main.c


+ 12 - 11
sound/pci/ice1712/ice1724.c

@@ -382,23 +382,25 @@ static irqreturn_t snd_vt1724_interrupt(int irq, void *dev_id)
 	unsigned char status_mask =
 		VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX | VT1724_IRQ_MTPCM;
 	int handled = 0;
-#ifdef CONFIG_SND_DEBUG
 	int timeout = 0;
-#endif
 
 	while (1) {
 		status = inb(ICEREG1724(ice, IRQSTAT));
 		status &= status_mask;
 		if (status == 0)
 			break;
-#ifdef CONFIG_SND_DEBUG
 		if (++timeout > 10) {
-			printk(KERN_ERR
-			       "ice1724: Too long irq loop, status = 0x%x\n",
-			       status);
+			status = inb(ICEREG1724(ice, IRQSTAT));
+			printk(KERN_ERR "ice1724: Too long irq loop, "
+			       "status = 0x%x\n", status);
+			if (status & VT1724_IRQ_MPU_TX) {
+				printk(KERN_ERR "ice1724: Disabling MPU_TX\n");
+				outb(inb(ICEREG1724(ice, IRQMASK)) |
+				     VT1724_IRQ_MPU_TX,
+				     ICEREG1724(ice, IRQMASK));
+			}
 			break;
 		}
-#endif
 		handled = 1;
 		if (status & VT1724_IRQ_MPU_TX) {
 			spin_lock(&ice->reg_lock);
@@ -2351,7 +2353,6 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
 {
 	struct snd_ice1712 *ice;
 	int err;
-	unsigned char mask;
 	static struct snd_device_ops ops = {
 		.dev_free =	snd_vt1724_dev_free,
 	};
@@ -2412,9 +2413,9 @@ static int __devinit snd_vt1724_create(struct snd_card *card,
 		return -EIO;
 	}
 
-	/* unmask used interrupts */
-	mask = VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX;
-	outb(mask, ICEREG1724(ice, IRQMASK));
+	/* MPU_RX and TX irq masks are cleared later dynamically */
+	outb(VT1724_IRQ_MPU_RX | VT1724_IRQ_MPU_TX , ICEREG1724(ice, IRQMASK));
+
 	/* don't handle FIFO overrun/underruns (just yet),
 	 * since they cause machine lockups
 	 */

+ 1 - 1
sound/ppc/pmac.c

@@ -1033,7 +1033,7 @@ static int __init snd_pmac_detect(struct snd_pmac *chip)
 	}
 	if (of_device_is_compatible(sound, "tumbler")) {
 		chip->model = PMAC_TUMBLER;
-		chip->can_capture = 0;  /* no capture */
+		chip->can_capture = machine_is_compatible("PowerMac4,2");
 		chip->can_duplex = 0;
 		// chip->can_byte_swap = 0; /* FIXME: check this */
 		chip->num_freqs = ARRAY_SIZE(tumbler_freqs);

+ 2 - 1
sound/ppc/tumbler.c

@@ -875,7 +875,8 @@ static struct snd_kcontrol_new snapper_mixers[] __initdata = {
 	  .put = tumbler_put_master_switch
 	},
 	DEFINE_SNAPPER_MIX("PCM Playback Volume", 0, VOL_IDX_PCM),
-	DEFINE_SNAPPER_MIX("PCM Playback Volume", 1, VOL_IDX_PCM2),
+	/* Alternative PCM is assigned to Mic analog loopback on iBook G4 */
+	DEFINE_SNAPPER_MIX("Mic Playback Volume", 0, VOL_IDX_PCM2),
 	DEFINE_SNAPPER_MIX("Monitor Mix Volume", 0, VOL_IDX_ADC),
 	DEFINE_SNAPPER_MONO("Tone Control - Bass", bass),
 	DEFINE_SNAPPER_MONO("Tone Control - Treble", treble),

部分文件因为文件数量过多而无法显示