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 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_process_dma(audio_stream_t *s) { int ret; DPRINTK(__FUNCTION__ ": pending_frags = %d, usr_head = %d, dma_head = %d, dma_tail = %d, bytecount = %d, fragcount = %d\n", s->pending_frags, s->usr_head, s->dma_head, s->dma_tail, s->bytecount, s->fragcount); if (s->stopped) goto spin; if (s->dma_spinref > 0 && s->pending_frags) { s->dma_spinref = 0; DMA_CLEAR(s); } while (s->pending_frags) { audio_buf_t *b = &s->buffers[s->dma_head]; u_int dma_size = s->fragsize - b->offset; if (dma_size > MAX_DMA_SIZE) dma_size = CUT_DMA_SIZE; ret = DMA_START(s, b->dma_addr + b->offset, dma_size); if (ret) return; b->dma_ref++; b->offset += dma_size; if (b->offset >= s->fragsize) { s->pending_frags--; if (++s->dma_head >= s->nbfrags) s->dma_head = 0; } } spin: if (s->spin_idle) { int spincnt = 0; while (DMA_START(s, SPIN_ADDR, SPIN_SIZE) == 0) spincnt++; /* * Note: if there is still a data buffer being * processed then the ref count is negative. This * allows for the DMA termination to be accounted in * the proper order. Of course dma_spinref can't be * greater than 0 if dma_ref is not 0 since we kill * the spinning above as soon as there is real data to process. */ if (s->buffers && s->buffers[s->dma_tail].dma_ref) spincnt = -spincnt; s->dma_spinref += spincnt; } }
static void audio_stop_dma(audio_stream_t *s) { u_int pos; unsigned long flags; audio_buf_t *b; if (s->dma_spinref > 0 || !s->buffers) return; local_irq_save(flags); s->stopped = 1; DMA_STOP(s); pos = audio_get_dma_pos(s); DMA_CLEAR(s); if (s->spin_idle) { DMA_START(s, SPIN_ADDR, SPIN_SIZE); DMA_START(s, SPIN_ADDR, SPIN_SIZE); s->dma_spinref = 2; } else s->dma_spinref = 0; local_irq_restore(flags); /* back up pointers to be ready to restart from the same spot */ while (s->dma_head != s->dma_tail) { b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->dma_ref = 0; b->offset = 0; } s->pending_frags++; if (s->dma_head == 0) s->dma_head = s->nbfrags; s->dma_head--; } b = &s->buffers[s->dma_head]; if (b->dma_ref) { b->offset = pos; b->dma_ref = 0; } }
/*************************************************************************************** * * Process DMA requests - This will end up starting the transfer. Proper fragments of * Transfers will be initiated. * **************************************************************************************/ int audio_process_dma(audio_stream_t * s) { int ret = 0; unsigned long flags; FN_IN; /* Dont let the ISR over ride touching the in_use flag */ local_irq_save(flags); if (1 == s->in_use) { local_irq_restore(flags); ERR("Called again while In Use\n"); return 0; } s->in_use = 1; local_irq_restore(flags); if (s->stopped) goto spin; if (s->dma_spinref > 0 && s->pending_frags) { s->dma_spinref = 0; DMA_CLEAR(s); } while (s->pending_frags) { audio_buf_t *b = &s->buffers[s->dma_head]; u_int dma_size = s->fragsize - b->offset; if (dma_size > MAX_DMA_SIZE) dma_size = CUT_DMA_SIZE; ret = omap_start_sound_dma(s, b->dma_addr + b->offset, dma_size); if (ret) { goto process_out; } b->dma_ref++; b->offset += dma_size; if (b->offset >= s->fragsize) { s->pending_frags--; if (++s->dma_head >= s->nbfrags) s->dma_head = 0; } } spin: if (s->spin_idle) { int spincnt = 0; ERR("we are spinning\n"); while (omap_start_sound_dma(s, SPIN_ADDR, SPIN_SIZE) == 0) spincnt++; /* * Note: if there is still a data buffer being * processed then the ref count is negative. This * allows for the DMA termination to be accounted in * the proper order. Of course dma_spinref can't be * greater than 0 if dma_ref is not 0 since we kill * the spinning above as soon as there is real data to process. */ if (s->buffers && s->buffers[s->dma_tail].dma_ref) spincnt = -spincnt; s->dma_spinref += spincnt; } process_out: s->in_use = 0; FN_OUT(ret); return ret; }