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