static void transfer_done_callback(unsigned long param) { int result; struct ksnd_pcm_streaming *streaming = (struct ksnd_pcm_streaming *)param; snd_pcm_sframes_t commited_frames; BUG_ON(streaming->magic != magic_good); BUG_ON(test_bit(FLAG_BUSY, &streaming->flags) != 1); // Check if the transfer wasn't stopped by any chance... if (test_bit(FLAG_STOPPED, &streaming->flags)) return; // "Commit" playback data commited_frames = ksnd_pcm_mmap_commit(streaming->playback_handle, streaming->playback_offset, streaming->playback_frames); if (commited_frames < 0 || (snd_pcm_uframes_t)commited_frames != streaming->playback_frames) { ERROR("Playback XRUN!\n"); result = ksnd_pcm_prepare(streaming->playback_handle); if (result != 0) { ERROR("Can't recover from playback XRUN!\n"); return; } } // "Commit" captured data commited_frames = ksnd_pcm_mmap_commit(streaming->capture_handle, streaming->capture_offset, streaming->playback_frames); if (commited_frames < 0 || (snd_pcm_uframes_t)commited_frames != streaming->playback_frames) { ERROR("Capture XRUN!\n"); result = ksnd_pcm_prepare(streaming->capture_handle); if (result != 0) { ERROR("Can't recover from capture XRUN!\n"); return; } ksnd_pcm_start(streaming->capture_handle); } // Release the lock clear_bit(FLAG_BUSY, &streaming->flags); // If another data period has been received in meantime, trigger it not // (period_captured_callback could be skipped because of transfer in progress) if (ksnd_pcm_avail_update(streaming->capture_handle) >= streaming->capture_handle->substream->runtime->period_size) period_captured_callback(streaming->capture_handle->substream); }
int ksnd_pcm_mute(ksnd_pcm_t *kpcm, unsigned int push) { int err; snd_pcm_substream_t *substream = kpcm->substream; if (push == 0) { err = ksnd_pcm_prepare(kpcm); if (err < 0) return err; ksnd_pcm_start(kpcm); } else { _ksnd_pcm_pause(substream, push); _ksnd_pcm_drop(substream); } return 0; }
int ksnd_pcm_streaming_start(ksnd_pcm_streaming_t *handle, ksnd_pcm_t *capture, ksnd_pcm_t *playback) { int result; struct ksnd_pcm_streaming *streaming; const char *fdmac_id[] = { STM_DMAC_ID, NULL }; const char *lb_cap[] = { STM_DMA_CAP_LOW_BW, NULL }; const char *hb_cap[] = { STM_DMA_CAP_HIGH_BW, NULL }; // Allocate and clean streaming structure streaming = kzalloc(sizeof(*streaming), GFP_KERNEL); if (streaming == NULL) { ERROR("Can't get memory for streaming structure!\n"); return -ENOMEM; } // Prepare description streaming->capture_handle = capture; streaming->playback_handle = playback; streaming->magic = magic_good; // Initialize FDMA streaming->fdma_channel = request_dma_bycap(fdmac_id, lb_cap, "KSOUND_STREAMING"); if (streaming->fdma_channel < 0) { streaming->fdma_channel = request_dma_bycap(fdmac_id, hb_cap, "KSOUND_STREAMING"); if (streaming->fdma_channel < 0) { ERROR("Can't allocate FDMA channel!\n"); kfree(streaming); return -EBUSY; } } dma_params_init(&streaming->fdma_params, MODE_FREERUNNING, STM_DMA_LIST_OPEN); dma_params_comp_cb(&streaming->fdma_params, transfer_done_callback, (unsigned long)streaming, STM_DMA_CB_CONTEXT_TASKLET); dma_params_err_cb(&streaming->fdma_params, transfer_error_callback, (unsigned long)streaming, STM_DMA_CB_CONTEXT_TASKLET); dma_params_DIM_1_x_1(&streaming->fdma_params); result = dma_compile_list(streaming->fdma_channel, &streaming->fdma_params, GFP_KERNEL); if (result < 0) { ERROR("Can't compile FDMA parameters!\n"); free_dma(streaming->fdma_channel); kfree(streaming); return -EFAULT; } // Initialize ALSA capture->substream->runtime->transfer_ack_end = period_captured_callback; BUG_ON(capture->substream->runtime->private_data != NULL); // It used to be not used ;-) capture->substream->runtime->private_data = streaming; ksnd_pcm_start(capture); // Return handle *handle = streaming; return 0; }