Beispiel #1
0
void audio_ldm_suspend(void *data)
{
        audio_state_t *state = data;
        audio_stream_t *is = state->input_stream;
	audio_stream_t *os = state->output_stream;
	int stopstate;

        if (is && is->dma_regs) 
        {
	        stopstate = is->stopped;
		audio_stop_dma(is);
		DMA_CLEAR(is);
		is->dma_spinref = 0;
		is->stopped = stopstate;
	}
	if (os && os->dma_regs) 
        {
		stopstate = os->stopped;
		audio_stop_dma(os);
		DMA_CLEAR(os);
		os->dma_spinref = 0;
		os->stopped = stopstate;
	}
	if (AUDIO_ACTIVE(state) && state->hw_shutdown)
		state->hw_shutdown(state->data);
}
Beispiel #2
0
static int wmt_pdm_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	int stream_id = substream->pstr->stream;
	struct audio_stream_a *prtd = runtime->private_data;
	struct audio_stream_a *s = &prtd[stream_id];
	int ret = 0;

	DBG_DETAIL();
	DPRINTK("Enter, cmd=%d", cmd);
	
	spin_lock(&s->dma_lock);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
		s->active = 1;
		audio_process_dma(s);
		break;

	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
		s->active = 0;
		audio_stop_dma(s);
		/*prtd->period_index = -1;*/
		break;
	default:
		ret = -EINVAL;
	}
	spin_unlock(&s->dma_lock);

	return ret;
}
Beispiel #3
0
static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data)
{
	audio_state_t *state = pm_dev->data;
	audio_stream_t *is = state->input_stream;
	audio_stream_t *os = state->output_stream;
	int stopstate;

	switch (req) {
	case PM_SUSPEND: /* enter D1-D3 */
		if (is && is->dma_regs) {
			stopstate = is->stopped;
			audio_stop_dma(is);
			DMA_CLEAR(is);
			is->dma_spinref = 0;
			is->stopped = stopstate;
		}
		if (os && os->dma_regs) {
			stopstate = os->stopped;
			audio_stop_dma(os);
			DMA_CLEAR(os);
			os->dma_spinref = 0;
			os->stopped = stopstate;
		}
		if (AUDIO_ACTIVE(state) && state->hw_shutdown)
			state->hw_shutdown(state->data);
		break;
	case PM_RESUME:  /* enter D0 */
		if (AUDIO_ACTIVE(state) && state->hw_init)
			state->hw_init(state->data);
		if (os && os->dma_regs) {
			DMA_RESET(os);
			audio_process_dma(os);
		}
		if (is && is->dma_regs) {
			DMA_RESET(is);
			audio_process_dma(is);
		}
		break;
	}
	return 0;
}
Beispiel #4
0
static void audio_reset(audio_stream_t *s)
{
	if (s->buffers) {
		audio_stop_dma(s);
		s->buffers[s->dma_head].offset = 0;
		s->buffers[s->usr_head].offset = 0;
		s->usr_head = s->dma_head;
		s->pending_frags = 0;
		sema_init(&s->sem, s->nbfrags);
	}
	s->active = 0;
	s->stopped = 0;
}
Beispiel #5
0
int s3c_audio_suspend(audio_state_t *s, u32 state, u32 level)
{
	if (level == SUSPEND_DISABLE || level == SUSPEND_POWER_DOWN) {
		audio_stream_t *is = s->input_stream;
		audio_stream_t *os = s->output_stream;
		int stopstate;

		if (is  ) {
			stopstate = is->stopped;
			audio_stop_dma(is);
			s3c2410_dma_ctrl(is->dma, S3C2410_DMAOP_FLUSH);
			is->stopped = stopstate;
		}
		if (os ) {
			stopstate = os->stopped;
			audio_stop_dma(os);
			s3c2410_dma_ctrl(os->dma, S3C2410_DMAOP_FLUSH);
			os->stopped = stopstate;
		}
		if (AUDIO_ACTIVE(s) && s->hw_shutdown)
			s->hw_shutdown(s->data);
	}
	return 0;
}
Beispiel #6
0
/* ISRs have to be short and smart.. So we transfer every heavy duty stuff to the 
 * work item
 */
static void sound_dma_irq_handler(int sound_curr_lch, u16 ch_status, void *data)
{
	int dma_status = ch_status;
	audio_stream_t *s = (audio_stream_t *) data;
	FN_IN;
#ifdef IRQ_TRACE
	xyz[h++] = '0' + sound_curr_lch;
	if (h == MAX_UP - 1) {
		printk("%s-", xyz);
		h = 0;
	}
#endif
	DPRINTK("lch=%d,status=0x%x, dma_status=%d, data=%p\n", sound_curr_lch,
		ch_status, dma_status, data);

	if (dma_status) {
		if (cpu_is_omap16xx() && (dma_status & (DCSR_ERROR)))
			OMAP_DMA_CCR_REG(sound_curr_lch) &= ~DCCR_EN;
		ERR("DCSR_ERROR!\n");
		FN_OUT(-1);
		return;
	}

	if (AUDIO_QUEUE_LAST(s))
		audio_stop_dma(s);

	/* Start the work item  - we ping pong the work items */
	if (!work_item_running) {
		work1.current_lch = sound_curr_lch;
		work1.ch_status = ch_status;
		work1.s = s;
		/* schedule tasklet 1 */
		tasklet_schedule(&audio_isr_work1);
		work_item_running = 1;
	} else {
		work2.current_lch = sound_curr_lch;
		work2.ch_status = ch_status;
		work2.s = s;
		/* schedule tasklet 2 */
		tasklet_schedule(&audio_isr_work2);
		work_item_running = 0;
	}
	FN_OUT(0);
	return;
}
Beispiel #7
0
/***************************************************************************************
 *
 * Reset the audio buffers
 *
 **************************************************************************************/
void audio_reset(audio_stream_t * s)
{
	FN_IN;
	if (s->buffers) {
		audio_stop_dma(s);
		s->buffers[s->dma_head].offset = 0;
		s->buffers[s->usr_head].offset = 0;
		s->usr_head = s->dma_head;
		s->pending_frags = 0;
		init_completion(&s->wfc);
		s->wfc.done = s->nbfrags;
	}
	s->active = 0;
	s->stopped = 0;
	s->started = 0;
	FN_OUT(0);
	return;
}
Beispiel #8
0
static int audio_ioctl(struct inode *inode, struct file *file,
		       uint cmd, ulong arg)
{
	audio_state_t *state = file->private_data;
	audio_stream_t *os = state->output_stream;
	audio_stream_t *is = state->input_stream;
	long val;

	DPRINTK(__FILE__ " audio_ioctl 0x%08x\n", cmd);

	/* dispatch based on command */
	switch (cmd) {
	case OSS_GETVERSION:
		return put_user(SOUND_VERSION, (int *)arg);

	case SNDCTL_DSP_GETBLKSIZE:
		if (file->f_mode & FMODE_WRITE)
			return put_user(os->fragsize, (int *)arg);
		else
			return put_user(is->fragsize, (int *)arg);

	case SNDCTL_DSP_GETCAPS:
		val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP;
		if (is && os)
			val |= DSP_CAP_DUPLEX;
		return put_user(val, (int *)arg);

	case SNDCTL_DSP_SETFRAGMENT:
		if (get_user(val, (long *) arg))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			int ret = audio_set_fragments(is, val);
			if (ret < 0)
				return ret;
			ret = put_user(ret, (int *)arg);
			if (ret)
				return ret;
		}
		if (file->f_mode & FMODE_WRITE) {
			int ret = audio_set_fragments(os, val);
			if (ret < 0)
				return ret;
			ret = put_user(ret, (int *)arg);
			if (ret)
				return ret;
		}
		return 0;

	case SNDCTL_DSP_SYNC:
		return audio_sync(file);

	case SNDCTL_DSP_SETDUPLEX:
		return 0;

	case SNDCTL_DSP_POST:
		return 0;

	case SNDCTL_DSP_GETTRIGGER:
		val = 0;
		if (file->f_mode & FMODE_READ && is->active && !is->stopped)
			val |= PCM_ENABLE_INPUT;
		if (file->f_mode & FMODE_WRITE && os->active && !os->stopped)
			val |= PCM_ENABLE_OUTPUT;
		return put_user(val, (int *)arg);

	case SNDCTL_DSP_SETTRIGGER:
		if (get_user(val, (int *)arg))
			return -EFAULT;
		if (file->f_mode & FMODE_READ) {
			if (val & PCM_ENABLE_INPUT) {
				unsigned long flags;
				if (!is->active) {
					if (!is->buffers && audio_setup_buf(is))
						return -ENOMEM;
					audio_prime_rx(state);
				}
				local_irq_save(flags);
				is->stopped = 0;
				audio_process_dma(is);
				local_irq_restore(flags);
			} else {
				audio_stop_dma(is);
			}
		}
		if (file->f_mode & FMODE_WRITE) {
			if (val & PCM_ENABLE_OUTPUT) {
				unsigned long flags;
				if (!os->buffers && audio_setup_buf(os))
					return -ENOMEM;
				local_irq_save(flags);
				if (os->mapped && !os->pending_frags) {
					os->pending_frags = os->nbfrags;
					sema_init(&os->sem, 0);
					os->active = 1;
				}
				os->stopped = 0;
				audio_process_dma(os);
				local_irq_restore(flags);
			} else {
				audio_stop_dma(os);
			}
		}
		return 0;

	case SNDCTL_DSP_GETOPTR:
	case SNDCTL_DSP_GETIPTR:
	    {
		count_info inf = { 0, };
		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is;
		int bytecount, offset;
		unsigned long flags;

		if ((s == is && !(file->f_mode & FMODE_READ)) ||
		    (s == os && !(file->f_mode & FMODE_WRITE)))
			return -EINVAL;
		if (s->active) {
			local_irq_save(flags);
			offset = audio_get_dma_pos(s);
			inf.ptr = s->dma_tail * s->fragsize + offset;
			bytecount = s->bytecount + offset;
			s->bytecount = -offset;
			inf.blocks = s->fragcount;
			s->fragcount = 0;
			local_irq_restore(flags);
			if (bytecount < 0)
				bytecount = 0;
			inf.bytes = bytecount;
		}
		return copy_to_user((void *)arg, &inf, sizeof(inf));
	    }

	case SNDCTL_DSP_GETOSPACE:
	case SNDCTL_DSP_GETISPACE:
	    {
		audio_buf_info inf = { 0, };
		audio_stream_t *s = (cmd == SNDCTL_DSP_GETOSPACE) ? os : is;

		if ((s == is && !(file->f_mode & FMODE_READ)) ||
		    (s == os && !(file->f_mode & FMODE_WRITE)))
			return -EINVAL;
		if (!s->buffers && audio_setup_buf(s))
			return -ENOMEM;
		inf.bytes = atomic_read(&s->sem.count) * s->fragsize;
		/* inf.bytes -= s->buffers[s->usr_head].offset; */
		inf.fragments = inf.bytes / s->fragsize;
		inf.fragsize = s->fragsize;
		inf.fragstotal = s->nbfrags;
		return copy_to_user((void *)arg, &inf, sizeof(inf));
	    }

	case SNDCTL_DSP_NONBLOCK:
		file->f_flags |= O_NONBLOCK;
		return 0;

	case SNDCTL_DSP_RESET:
		if (file->f_mode & FMODE_READ) {
			audio_reset(is);
			if (state->need_tx_for_rx) {
				unsigned long flags;
				local_irq_save(flags);
				os->spin_idle = 0;
				local_irq_restore(flags);
			}
		}
		if (file->f_mode & FMODE_WRITE) {
			audio_reset(os);
		}
		return 0;

	default:
		/*
		 * Let the client of this module handle the
		 * non generic ioctls
		 */
		return state->client_ioctl(inode, file, cmd, arg);
	}

	return 0;
}