/* compress stream operations */ static void sst_compr_fragment_elapsed(void *arg) { struct snd_compr_stream *cstream = (struct snd_compr_stream *)arg; pr_debug("fragment elapsed by driver\n"); if (cstream) snd_compr_fragment_elapsed(cstream); }
static int compr_event_handler(uint32_t cmd, uint32_t size, void* priv) { struct runtime_data *prtd = priv; struct snd_compr_runtime *runtime = prtd->cstream->runtime; u64 bytes_available; int ret; pr_debug("%s: event handler cmd(%x)\n", __func__, cmd); #ifdef AUDIO_PERF prtd->start_time[ISR_T] = sched_clock(); #endif switch(cmd) { case INTR_CREATED: pr_debug("%s: offload instance is created\n", __func__); break; case INTR_DECODED: spin_lock(&prtd->lock); /* update copied total bytes */ prtd->copied_total += size; prtd->byte_offset += size; if (prtd->byte_offset >= runtime->buffer_size) prtd->byte_offset -= runtime->buffer_size; snd_compr_fragment_elapsed(prtd->cstream); if (!atomic_read(&prtd->start) && runtime->state != SNDRV_PCM_STATE_PAUSED) { /* Writes must be restarted from _copy() */ pr_err("%s: write_done received while not started(%d)", __func__, runtime->state); spin_unlock(&prtd->lock); return -EIO; } bytes_available = prtd->received_total - prtd->copied_total; pr_debug("%s: current free bufsize(%llu)\n", __func__, runtime->buffer_size - bytes_available); if (bytes_available < runtime->fragment_size) { pr_debug("%s: WRITE_DONE Insufficient data to send.(avail:%llu)\n", __func__, bytes_available); } spin_unlock(&prtd->lock); break; case INTR_FLUSH: prtd->stop_ack = 1; wake_up(&prtd->flush_wait); break; case INTR_PAUSED: ret = compr_dai_cmd(prtd, cmd); if (ret) pr_err("%s: compr_dai_cmd fail(%d)\n", __func__, ret); break; case INTR_EOS: if (atomic_read(&prtd->eos)) { if (prtd->copied_total != prtd->received_total) pr_err("%s: EOS is not sync!(%llu/%llu)\n", __func__, prtd->copied_total, prtd->received_total); /* ALSA Framework callback to notify drain complete */ snd_compr_drain_notify(prtd->cstream); atomic_set(&prtd->eos, 0); pr_info("%s: DATA_CMD_EOS wake up\n", __func__); } break; case INTR_DESTROY: prtd->exit_ack = 1; wake_up(&prtd->exit_wait); break; default: pr_err("%s: unknown command(%x)\n", __func__, cmd); break; } #ifdef AUDIO_PERF prtd->end_time[ISR_T] = sched_clock(); prtd->total_time[ISR_T] += prtd->end_time[ISR_T] - prtd->start_time[ISR_T]; #endif return 0; }
static void compr_event_handler(uint32_t opcode, uint32_t token, uint32_t *payload, void *priv) { struct msm_compr_audio *prtd = priv; struct snd_compr_stream *cstream = prtd->cstream; struct audio_client *ac = prtd->audio_client; uint32_t chan_mode = 0; uint32_t sample_rate = 0; int bytes_available, stream_id; pr_debug("%s opcode =%08x\n", __func__, opcode); switch (opcode) { case ASM_DATA_EVENT_WRITE_DONE_V2: spin_lock(&prtd->lock); if (payload[3]) { pr_err("WRITE FAILED w/ err 0x%x !, paddr 0x%x" " byte_offset = %d, copied_total = %d, token = %d\n", payload[3], payload[0], prtd->byte_offset, prtd->copied_total, token); atomic_set(&prtd->start, 0); } else { pr_debug("ASM_DATA_EVENT_WRITE_DONE_V2 offset %d, length %d\n", prtd->byte_offset, token); } prtd->byte_offset += token; prtd->copied_total += token; if (prtd->byte_offset >= prtd->buffer_size) prtd->byte_offset -= prtd->buffer_size; snd_compr_fragment_elapsed(cstream); if (!atomic_read(&prtd->start)) { /* Writes must be restarted from _copy() */ pr_debug("write_done received while not started, treat as xrun"); atomic_set(&prtd->xrun, 1); spin_unlock(&prtd->lock); break; } bytes_available = prtd->bytes_received - prtd->copied_total; if (bytes_available < cstream->runtime->fragment_size) { pr_debug("WRITE_DONE Insufficient data to send. break out\n"); atomic_set(&prtd->xrun, 1); if (prtd->last_buffer) prtd->last_buffer = 0; if (atomic_read(&prtd->drain)) { pr_debug("wake up on drain\n"); prtd->drain_ready = 1; wake_up(&prtd->drain_wait); atomic_set(&prtd->drain, 0); } } else if ((bytes_available == cstream->runtime->fragment_size) && atomic_read(&prtd->drain)) { prtd->last_buffer = 1; msm_compr_send_buffer(prtd); prtd->last_buffer = 0; } else msm_compr_send_buffer(prtd); spin_unlock(&prtd->lock); break; case ASM_DATA_EVENT_RENDERED_EOS: pr_debug("ASM_DATA_CMDRSP_EOS\n"); spin_lock(&prtd->lock); if (atomic_read(&prtd->eos) && !prtd->gapless_state.set_next_stream_id) { pr_debug("ASM_DATA_CMDRSP_EOS wake up\n"); prtd->cmd_ack = 1; wake_up(&prtd->eos_wait); } atomic_set(&prtd->eos, 0); stream_id = ac->stream_id^1; /*prev stream */ if (prtd->gapless_state.set_next_stream_id && prtd->gapless_state.stream_opened[stream_id]) { q6asm_stream_cmd_nowait(prtd->audio_client, CMD_CLOSE, stream_id); atomic_set(&prtd->close, 1); prtd->gapless_state.stream_opened[stream_id] = 0; prtd->gapless_state.set_next_stream_id = false; } spin_unlock(&prtd->lock); break; case ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY: case ASM_DATA_EVENT_ENC_SR_CM_CHANGE_NOTIFY: { pr_debug("ASM_DATA_EVENT_SR_CM_CHANGE_NOTIFY\n"); chan_mode = payload[1] >> 16; sample_rate = payload[2] >> 16; if (prtd && (chan_mode != prtd->num_channels || sample_rate != prtd->sample_rate)) { prtd->num_channels = chan_mode; prtd->sample_rate = sample_rate; } } case APR_BASIC_RSP_RESULT: { switch (payload[0]) { case ASM_SESSION_CMD_RUN_V2: /* check if the first buffer need to be sent to DSP */ pr_debug("ASM_SESSION_CMD_RUN_V2\n"); spin_lock(&prtd->lock); /* FIXME: A state is a much better way of dealing with this */ if (!prtd->copied_total) { bytes_available = prtd->bytes_received - prtd->copied_total; if (bytes_available < cstream->runtime->fragment_size) { pr_debug("CMD_RUN_V2 Insufficient data to send. break out\n"); atomic_set(&prtd->xrun, 1); } else msm_compr_send_buffer(prtd); } spin_unlock(&prtd->lock); break; case ASM_STREAM_CMD_FLUSH: pr_debug("ASM_STREAM_CMD_FLUSH\n"); prtd->cmd_ack = 1; wake_up(&prtd->flush_wait); break; case ASM_DATA_CMD_REMOVE_INITIAL_SILENCE: pr_debug("ASM_DATA_CMD_REMOVE_INITIAL_SILENCE\n"); break; case ASM_DATA_CMD_REMOVE_TRAILING_SILENCE: pr_debug("ASM_DATA_CMD_REMOVE_TRAILING_SILENCE\n"); break; case ASM_STREAM_CMD_CLOSE: pr_debug("ASM_DATA_CMD_CLOSE\n"); if (atomic_read(&prtd->close) && atomic_read(&prtd->wait_on_close)) { prtd->cmd_ack = 1; wake_up(&prtd->close_wait); } atomic_set(&prtd->close, 0); break; default: break; } break; } case ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3: pr_debug("ASM_SESSION_CMDRSP_GET_SESSIONTIME_V3\n"); break; case RESET_EVENTS: pr_err("Received reset events CB, move to error state"); spin_lock(&prtd->lock); snd_compr_fragment_elapsed(cstream); prtd->copied_total = prtd->bytes_received; atomic_set(&prtd->error, 1); spin_unlock(&prtd->lock); break; default: pr_debug("Not Supported Event opcode[0x%x]\n", opcode); break; } }