diff options
Diffstat (limited to 'sound/drivers/aloop.c')
| -rw-r--r-- | sound/drivers/aloop.c | 174 | 
1 files changed, 97 insertions, 77 deletions
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index 12b44b0b677..2a16c86a60b 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c @@ -34,7 +34,7 @@  #include <linux/slab.h>  #include <linux/time.h>  #include <linux/wait.h> -#include <linux/moduleparam.h> +#include <linux/module.h>  #include <linux/platform_device.h>  #include <sound/core.h>  #include <sound/control.h> @@ -51,7 +51,7 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Loopback soundcard}}");  static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;	/* Index 0-MAX */  static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;	/* ID for this card */ -static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; +static bool enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0};  static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8};  static int pcm_notify[SNDRV_CARDS]; @@ -117,6 +117,7 @@ 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;  }; @@ -164,6 +165,7 @@ static inline unsigned int get_rate_shift(struct loopback_pcm *dpcm)  	return get_setup(dpcm)->rate_shift;  } +/* call in cable->lock */  static void loopback_timer_start(struct loopback_pcm *dpcm)  {  	unsigned long tick; @@ -183,6 +185,7 @@ static void loopback_timer_start(struct loopback_pcm *dpcm)  	add_timer(&dpcm->timer);  } +/* call in cable->lock */  static inline void loopback_timer_stop(struct loopback_pcm *dpcm)  {  	del_timer(&dpcm->timer); @@ -264,11 +267,12 @@ 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; -		spin_unlock(&cable->lock);  		loopback_timer_start(dpcm); +		spin_unlock(&cable->lock);  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  			loopback_active_notify(dpcm);  		break; @@ -276,23 +280,25 @@ static int loopback_trigger(struct snd_pcm_substream *substream, int cmd)  		spin_lock(&cable->lock);	  		cable->running &= ~stream;  		cable->pause &= ~stream; -		spin_unlock(&cable->lock);  		loopback_timer_stop(dpcm); +		spin_unlock(&cable->lock);  		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)  			loopback_active_notify(dpcm);  		break;  	case SNDRV_PCM_TRIGGER_PAUSE_PUSH: +	case SNDRV_PCM_TRIGGER_SUSPEND:  		spin_lock(&cable->lock);	  		cable->pause |= stream; -		spin_unlock(&cable->lock);  		loopback_timer_stop(dpcm); +		spin_unlock(&cable->lock);  		break;  	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: +	case SNDRV_PCM_TRIGGER_RESUME:  		spin_lock(&cable->lock);  		dpcm->last_jiffies = jiffies;  		cable->pause &= ~stream; -		spin_unlock(&cable->lock);  		loopback_timer_start(dpcm); +		spin_unlock(&cable->lock);  		break;  	default:  		return -EINVAL; @@ -319,7 +325,7 @@ static void params_change(struct snd_pcm_substream *substream)  	struct loopback_pcm *dpcm = runtime->private_data;  	struct loopback_cable *cable = dpcm->cable; -	cable->hw.formats = (1ULL << runtime->format); +	cable->hw.formats = pcm_format_to_bits(runtime->format);  	cable->hw.rate_min = runtime->rate;  	cable->hw.rate_max = runtime->rate;  	cable->hw.channels_min = runtime->channels; @@ -444,36 +450,33 @@ static void copy_play_buf(struct loopback_pcm *play,  	}  } -#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) +static inline unsigned int bytepos_delta(struct loopback_pcm *dpcm, +					 unsigned int jiffies_delta)  { -	unsigned int count;  	unsigned long last_pos; +	unsigned int delta;  	last_pos = byte_pos(dpcm, dpcm->irq_pos); -	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; +	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;  	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;  } +/* call in cable->lock */  static unsigned int loopback_pos_update(struct loopback_cable *cable)  {  	struct loopback_pcm *dpcm_play = @@ -481,9 +484,8 @@ 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; +	unsigned int running, count1, count2; -	spin_lock(&cable->lock);	  	running = cable->running ^ cable->pause;  	if (running & (1 << SNDRV_PCM_STREAM_PLAYBACK)) {  		delta_play = jiffies - dpcm_play->last_jiffies; @@ -495,60 +497,76 @@ static unsigned int loopback_pos_update(struct loopback_cable *cable)  		dpcm_capt->last_jiffies += delta_capt;  	} -	if (delta_play == 0 && delta_capt == 0) { -		spin_unlock(&cable->lock); -		return running; -	} +	if (delta_play == 0 && delta_capt == 0) +		goto unlock;  	if (delta_play > delta_capt) { -		loopback_bytepos_update(dpcm_play, delta_play - delta_capt, -					BYTEPOS_UPDATE_POSONLY); +		count1 = bytepos_delta(dpcm_play, delta_play - delta_capt); +		bytepos_finish(dpcm_play, count1);  		delta_play = delta_capt;  	} else if (delta_play < delta_capt) { -		loopback_bytepos_update(dpcm_capt, delta_capt - delta_play, -					BYTEPOS_UPDATE_CLEAR); +		count1 = bytepos_delta(dpcm_capt, delta_capt - delta_play); +		clear_capture_buf(dpcm_capt, count1); +		bytepos_finish(dpcm_capt, count1);  		delta_capt = delta_play;  	} -	if (delta_play == 0 && delta_capt == 0) { -		spin_unlock(&cable->lock); -		return running; -	} +	if (delta_play == 0 && delta_capt == 0) +		goto unlock; +  	/* note delta_capt == delta_play at this moment */ -	loopback_bytepos_update(dpcm_capt, delta_capt, BYTEPOS_UPDATE_COPY); -	loopback_bytepos_update(dpcm_play, delta_play, BYTEPOS_UPDATE_POSONLY); -	spin_unlock(&cable->lock); +	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); + unlock:  	return running;  }  static void loopback_timer_function(unsigned long data)  {  	struct loopback_pcm *dpcm = (struct loopback_pcm *)data; -	unsigned int running; +	unsigned long flags; -	running = loopback_pos_update(dpcm->cable); -	if (running & (1 << dpcm->substream->stream)) { +	spin_lock_irqsave(&dpcm->cable->lock, flags); +	if (loopback_pos_update(dpcm->cable) & (1 << dpcm->substream->stream)) {  		loopback_timer_start(dpcm);  		if (dpcm->period_update_pending) {  			dpcm->period_update_pending = 0; +			spin_unlock_irqrestore(&dpcm->cable->lock, flags); +			/* need to unlock before calling below */  			snd_pcm_period_elapsed(dpcm->substream); +			return;  		}  	} +	spin_unlock_irqrestore(&dpcm->cable->lock, flags);  }  static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)  {  	struct snd_pcm_runtime *runtime = substream->runtime;  	struct loopback_pcm *dpcm = runtime->private_data; +	snd_pcm_uframes_t pos; +	spin_lock(&dpcm->cable->lock);  	loopback_pos_update(dpcm->cable); -	return bytes_to_frames(runtime, dpcm->buf_pos); +	pos = dpcm->buf_pos; +	spin_unlock(&dpcm->cable->lock); +	return bytes_to_frames(runtime, pos);  }  static struct snd_pcm_hardware loopback_pcm_hardware =  {  	.info =		(SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_MMAP | -			 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE), +			 SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_PAUSE | +			 SNDRV_PCM_INFO_RESUME),  	.formats =	(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |  			 SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |  			 SNDRV_PCM_FMTBIT_FLOAT_LE | SNDRV_PCM_FMTBIT_FLOAT_BE), @@ -576,7 +594,8 @@ static void loopback_runtime_free(struct snd_pcm_runtime *runtime)  static int loopback_hw_params(struct snd_pcm_substream *substream,  			      struct snd_pcm_hw_params *params)  { -	return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(params)); +	return snd_pcm_lib_alloc_vmalloc_buffer(substream, +						params_buffer_bytes(params));  }  static int loopback_hw_free(struct snd_pcm_substream *substream) @@ -588,7 +607,7 @@ static int loopback_hw_free(struct snd_pcm_substream *substream)  	mutex_lock(&dpcm->loopback->cable_lock);  	cable->valid &= ~(1 << substream->stream);  	mutex_unlock(&dpcm->loopback->cable_lock); -	return snd_pcm_lib_free_pages(substream); +	return snd_pcm_lib_free_vmalloc_buffer(substream);  }  static unsigned int get_cable_index(struct snd_pcm_substream *substream) @@ -741,6 +760,8 @@ static struct snd_pcm_ops loopback_playback_ops = {  	.prepare =	loopback_prepare,  	.trigger =	loopback_trigger,  	.pointer =	loopback_pointer, +	.page =		snd_pcm_lib_get_vmalloc_page, +	.mmap =		snd_pcm_lib_mmap_vmalloc,  };  static struct snd_pcm_ops loopback_capture_ops = { @@ -752,10 +773,12 @@ static struct snd_pcm_ops loopback_capture_ops = {  	.prepare =	loopback_prepare,  	.trigger =	loopback_trigger,  	.pointer =	loopback_pointer, +	.page =		snd_pcm_lib_get_vmalloc_page, +	.mmap =		snd_pcm_lib_mmap_vmalloc,  }; -static int __devinit loopback_pcm_new(struct loopback *loopback, -				      int device, int substreams) +static int loopback_pcm_new(struct loopback *loopback, +			    int device, int substreams)  {  	struct snd_pcm *pcm;  	int err; @@ -772,10 +795,6 @@ static int __devinit loopback_pcm_new(struct loopback *loopback,  	strcpy(pcm->name, "Loopback PCM");  	loopback->pcm[device] = pcm; - -	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS, -			snd_dma_continuous_data(GFP_KERNEL), -			0, 2 * 1024 * 1024);  	return 0;  } @@ -933,7 +952,7 @@ static int loopback_channels_get(struct snd_kcontrol *kcontrol,  	return 0;  } -static struct snd_kcontrol_new loopback_controls[]  __devinitdata = { +static struct snd_kcontrol_new loopback_controls[]  = {  {  	.iface =        SNDRV_CTL_ELEM_IFACE_PCM,  	.name =         "PCM Rate Shift 100000", @@ -982,7 +1001,7 @@ static struct snd_kcontrol_new loopback_controls[]  __devinitdata = {  }  }; -static int __devinit loopback_mixer_new(struct loopback *loopback, int notify) +static int loopback_mixer_new(struct loopback *loopback, int notify)  {  	struct snd_card *card = loopback->card;  	struct snd_pcm *pcm; @@ -1095,7 +1114,7 @@ static void print_cable_info(struct snd_info_entry *entry,  	mutex_unlock(&loopback->cable_lock);  } -static int __devinit loopback_proc_new(struct loopback *loopback, int cidx) +static int loopback_proc_new(struct loopback *loopback, int cidx)  {  	char name[32];  	struct snd_info_entry *entry; @@ -1116,15 +1135,15 @@ static int __devinit loopback_proc_new(struct loopback *loopback, int cidx)  #endif -static int __devinit loopback_probe(struct platform_device *devptr) +static int loopback_probe(struct platform_device *devptr)  {  	struct snd_card *card;  	struct loopback *loopback;  	int dev = devptr->id;  	int err; -	err = snd_card_create(index[dev], id[dev], THIS_MODULE, -			      sizeof(struct loopback), &card); +	err = snd_card_new(&devptr->dev, index[dev], id[dev], THIS_MODULE, +			   sizeof(struct loopback), &card);  	if (err < 0)  		return err;  	loopback = card->private_data; @@ -1161,18 +1180,16 @@ static int __devinit loopback_probe(struct platform_device *devptr)  	return err;  } -static int __devexit loopback_remove(struct platform_device *devptr) +static int loopback_remove(struct platform_device *devptr)  {  	snd_card_free(platform_get_drvdata(devptr)); -	platform_set_drvdata(devptr, NULL);  	return 0;  } -#ifdef CONFIG_PM -static int loopback_suspend(struct platform_device *pdev, -				pm_message_t state) +#ifdef CONFIG_PM_SLEEP +static int loopback_suspend(struct device *pdev)  { -	struct snd_card *card = platform_get_drvdata(pdev); +	struct snd_card *card = dev_get_drvdata(pdev);  	struct loopback *loopback = card->private_data;  	snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); @@ -1182,26 +1199,29 @@ static int loopback_suspend(struct platform_device *pdev,  	return 0;  } -static int loopback_resume(struct platform_device *pdev) +static int loopback_resume(struct device *pdev)  { -	struct snd_card *card = platform_get_drvdata(pdev); +	struct snd_card *card = dev_get_drvdata(pdev);  	snd_power_change_state(card, SNDRV_CTL_POWER_D0);  	return 0;  } + +static SIMPLE_DEV_PM_OPS(loopback_pm, loopback_suspend, loopback_resume); +#define LOOPBACK_PM_OPS	&loopback_pm +#else +#define LOOPBACK_PM_OPS	NULL  #endif  #define SND_LOOPBACK_DRIVER	"snd_aloop"  static struct platform_driver loopback_driver = {  	.probe		= loopback_probe, -	.remove		= __devexit_p(loopback_remove), -#ifdef CONFIG_PM -	.suspend	= loopback_suspend, -	.resume		= loopback_resume, -#endif +	.remove		= loopback_remove,  	.driver		= { -		.name	= SND_LOOPBACK_DRIVER +		.name	= SND_LOOPBACK_DRIVER, +		.owner	= THIS_MODULE, +		.pm	= LOOPBACK_PM_OPS,  	},  };  | 
