Lines Matching +full:pcm +full:- +full:interface +full:- +full:rate

1 // SPDX-License-Identifier: GPL-2.0
3 * sound.c - Sound component for Mostcore
16 #include <sound/pcm.h>
28 * struct channel - private structure to keep channel specific data
30 * @pcm_hardware: low-level hardware description
31 * @iface: interface for which the channel belongs to
42 * @copy_fn: copy function for PCM-specific format and width
93 while (i < bytes - 2) { in swap_copy24()
152 * get_channel - get pointer to channel
153 * @iface: interface structure
157 * ID and interface.
164 struct sound_adapter *adpt = iface->priv; in get_channel()
167 list_for_each_entry(channel, &adpt->dev_list, list) { in get_channel()
168 if ((channel->iface == iface) && (channel->id == channel_id)) in get_channel()
175 * copy_data - implements data copying function
183 struct snd_pcm_runtime *const runtime = channel->substream->runtime; in copy_data()
184 unsigned int const frame_bytes = channel->cfg->subbuffer_size; in copy_data()
185 unsigned int const buffer_size = runtime->buffer_size; in copy_data()
189 if (channel->cfg->direction & MOST_CH_RX) in copy_data()
190 frames = mbo->processed_length / frame_bytes; in copy_data()
192 frames = mbo->buffer_length / frame_bytes; in copy_data()
193 fr0 = min(buffer_size - channel->buffer_pos, frames); in copy_data()
195 channel->copy_fn(runtime->dma_area + channel->buffer_pos * frame_bytes, in copy_data()
196 mbo->virt_address, in copy_data()
201 channel->copy_fn(runtime->dma_area, in copy_data()
202 mbo->virt_address + fr0 * frame_bytes, in copy_data()
203 (frames - fr0) * frame_bytes); in copy_data()
206 channel->buffer_pos += frames; in copy_data()
207 if (channel->buffer_pos >= buffer_size) in copy_data()
208 channel->buffer_pos -= buffer_size; in copy_data()
209 channel->period_pos += frames; in copy_data()
210 if (channel->period_pos >= runtime->period_size) { in copy_data()
211 channel->period_pos -= runtime->period_size; in copy_data()
218 * playback_thread - function implements the playback thread
236 channel->playback_waitq, in playback_thread()
238 (channel->is_stream_running && in playback_thread()
239 (mbo = most_get_mbo(channel->iface, channel->id, in playback_thread()
244 if (channel->is_stream_running) in playback_thread()
247 memset(mbo->virt_address, 0, mbo->buffer_length); in playback_thread()
251 snd_pcm_period_elapsed(channel->substream); in playback_thread()
257 * pcm_open - implements open callback function for PCM middle layer
258 * @substream: pointer to ALSA PCM substream
260 * This is called when a PCM substream is opened. At least, the function should
261 * initialize the runtime->hw record.
267 struct channel *channel = substream->private_data; in pcm_open()
268 struct snd_pcm_runtime *runtime = substream->runtime; in pcm_open()
269 struct most_channel_config *cfg = channel->cfg; in pcm_open()
272 channel->substream = substream; in pcm_open()
274 if (cfg->direction == MOST_CH_TX) { in pcm_open()
275 channel->playback_task = kthread_run(playback_thread, channel, in pcm_open()
277 if (IS_ERR(channel->playback_task)) { in pcm_open()
279 return PTR_ERR(channel->playback_task); in pcm_open()
283 ret = most_start_channel(channel->iface, channel->id, &comp); in pcm_open()
286 if (cfg->direction == MOST_CH_TX) in pcm_open()
287 kthread_stop(channel->playback_task); in pcm_open()
291 runtime->hw = channel->pcm_hardware; in pcm_open()
296 * pcm_close - implements close callback function for PCM middle layer
297 * @substream: sub-stream pointer
299 * Obviously, this is called when a PCM substream is closed. Any private
300 * instance for a PCM substream allocated in the open callback will be
307 struct channel *channel = substream->private_data; in pcm_close()
309 if (channel->cfg->direction == MOST_CH_TX) in pcm_close()
310 kthread_stop(channel->playback_task); in pcm_close()
311 most_stop_channel(channel->iface, channel->id, &comp); in pcm_close()
316 * pcm_prepare - implements prepare callback function for PCM middle layer
319 * This callback is called when the PCM is "prepared". Format rate, sample rate,
326 struct channel *channel = substream->private_data; in pcm_prepare()
327 struct snd_pcm_runtime *runtime = substream->runtime; in pcm_prepare()
328 struct most_channel_config *cfg = channel->cfg; in pcm_prepare()
329 int width = snd_pcm_format_physical_width(runtime->format); in pcm_prepare()
331 channel->copy_fn = NULL; in pcm_prepare()
333 if (cfg->direction == MOST_CH_TX) { in pcm_prepare()
334 if (snd_pcm_format_big_endian(runtime->format) || width == 8) in pcm_prepare()
335 channel->copy_fn = alsa_to_most_memcpy; in pcm_prepare()
337 channel->copy_fn = alsa_to_most_copy16; in pcm_prepare()
339 channel->copy_fn = alsa_to_most_copy24; in pcm_prepare()
341 channel->copy_fn = alsa_to_most_copy32; in pcm_prepare()
343 if (snd_pcm_format_big_endian(runtime->format) || width == 8) in pcm_prepare()
344 channel->copy_fn = most_to_alsa_memcpy; in pcm_prepare()
346 channel->copy_fn = most_to_alsa_copy16; in pcm_prepare()
348 channel->copy_fn = most_to_alsa_copy24; in pcm_prepare()
350 channel->copy_fn = most_to_alsa_copy32; in pcm_prepare()
353 if (!channel->copy_fn) in pcm_prepare()
354 return -EINVAL; in pcm_prepare()
355 channel->period_pos = 0; in pcm_prepare()
356 channel->buffer_pos = 0; in pcm_prepare()
361 * pcm_trigger - implements trigger callback function for PCM middle layer
365 * This is called when the PCM is started, stopped or paused. The action will be
372 struct channel *channel = substream->private_data; in pcm_trigger()
376 channel->is_stream_running = true; in pcm_trigger()
377 wake_up_interruptible(&channel->playback_waitq); in pcm_trigger()
381 channel->is_stream_running = false; in pcm_trigger()
385 return -EINVAL; in pcm_trigger()
391 * pcm_pointer - implements pointer callback function for PCM middle layer
394 * This callback is called when the PCM middle layer inquires the current
396 * ranging from 0 to buffer_size-1.
400 struct channel *channel = substream->private_data; in pcm_pointer()
402 return channel->buffer_pos; in pcm_pointer()
433 pr_err("Bad PCM format\n"); in split_arg_list()
434 return -EINVAL; in split_arg_list()
458 pr_err("Unsupported PCM format\n"); in audio_set_hw_params()
459 return -EINVAL; in audio_set_hw_params()
464 return -EINVAL; in audio_set_hw_params()
467 if (cfg->subbuffer_size != ch_num * sinfo[i].bytes) { in audio_set_hw_params()
469 return -EINVAL; in audio_set_hw_params()
472 pcm_hw->info = MOST_PCM_INFO; in audio_set_hw_params()
473 pcm_hw->rates = SNDRV_PCM_RATE_48000; in audio_set_hw_params()
474 pcm_hw->rate_min = 48000; in audio_set_hw_params()
475 pcm_hw->rate_max = 48000; in audio_set_hw_params()
476 pcm_hw->buffer_bytes_max = cfg->num_buffers * cfg->buffer_size; in audio_set_hw_params()
477 pcm_hw->period_bytes_min = cfg->buffer_size; in audio_set_hw_params()
478 pcm_hw->period_bytes_max = cfg->buffer_size; in audio_set_hw_params()
479 pcm_hw->periods_min = 1; in audio_set_hw_params()
480 pcm_hw->periods_max = cfg->num_buffers; in audio_set_hw_params()
481 pcm_hw->channels_min = ch_num; in audio_set_hw_params()
482 pcm_hw->channels_max = ch_num; in audio_set_hw_params()
483 pcm_hw->formats = sinfo[i].formats; in audio_set_hw_params()
491 list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { in release_adapter()
492 list_del(&channel->list); in release_adapter()
495 if (adpt->card) in release_adapter()
496 snd_card_free(adpt->card); in release_adapter()
497 list_del(&adpt->list); in release_adapter()
502 * audio_probe_channel - probe function of the driver module
503 * @iface: pointer to interface instance
509 * Creates sound card, pcm device, sets pcm ops and registers sound card.
519 struct snd_pcm *pcm; in audio_probe_channel() local
528 if (cfg->data_type != MOST_CH_SYNC) { in audio_probe_channel()
530 return -EINVAL; in audio_probe_channel()
538 if (adpt->iface != iface) in audio_probe_channel()
540 if (adpt->registered) in audio_probe_channel()
541 return -ENOSPC; in audio_probe_channel()
542 adpt->pcm_dev_idx++; in audio_probe_channel()
547 return -ENOMEM; in audio_probe_channel()
549 adpt->iface = iface; in audio_probe_channel()
550 INIT_LIST_HEAD(&adpt->dev_list); in audio_probe_channel()
551 iface->priv = adpt; in audio_probe_channel()
552 list_add_tail(&adpt->list, &adpt_list); in audio_probe_channel()
553 ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, in audio_probe_channel()
554 sizeof(*channel), &adpt->card); in audio_probe_channel()
557 snprintf(adpt->card->driver, sizeof(adpt->card->driver), in audio_probe_channel()
559 snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), in audio_probe_channel()
561 snprintf(adpt->card->longname, sizeof(adpt->card->longname), in audio_probe_channel()
562 "%s at %s", adpt->card->shortname, iface->description); in audio_probe_channel()
566 iface->description, channel_id); in audio_probe_channel()
567 return -EEXIST; in audio_probe_channel()
570 if (cfg->direction == MOST_CH_TX) { in audio_probe_channel()
579 ret = -ENOMEM; in audio_probe_channel()
582 channel->card = adpt->card; in audio_probe_channel()
583 channel->cfg = cfg; in audio_probe_channel()
584 channel->iface = iface; in audio_probe_channel()
585 channel->id = channel_id; in audio_probe_channel()
586 init_waitqueue_head(&channel->playback_waitq); in audio_probe_channel()
587 list_add_tail(&channel->list, &adpt->dev_list); in audio_probe_channel()
589 ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, in audio_probe_channel()
594 ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, in audio_probe_channel()
595 playback_count, capture_count, &pcm); in audio_probe_channel()
600 pcm->private_data = channel; in audio_probe_channel()
601 strscpy(pcm->name, device_name, sizeof(pcm->name)); in audio_probe_channel()
602 snd_pcm_set_ops(pcm, direction, &pcm_ops); in audio_probe_channel()
603 snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); in audio_probe_channel()
617 if (!adpt->registered) in audio_create_sound_card()
620 return -ENODEV; in audio_create_sound_card()
622 ret = snd_card_register(adpt->card); in audio_create_sound_card()
627 adpt->registered = true; in audio_create_sound_card()
632 * audio_disconnect_channel - function to disconnect a channel
633 * @iface: pointer to interface instance
644 struct sound_adapter *adpt = iface->priv; in audio_disconnect_channel()
648 return -EINVAL; in audio_disconnect_channel()
650 list_del(&channel->list); in audio_disconnect_channel()
653 if (list_empty(&adpt->dev_list)) in audio_disconnect_channel()
659 * audio_rx_completion - completion handler for rx channels
669 struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); in audio_rx_completion()
673 return -EINVAL; in audio_rx_completion()
674 if (channel->is_stream_running) in audio_rx_completion()
678 snd_pcm_period_elapsed(channel->substream); in audio_rx_completion()
683 * audio_tx_completion - completion handler for tx channels
684 * @iface: pointer to interface instance
687 * This searches the channel that belongs to this combination of interface
698 return -EINVAL; in audio_tx_completion()
700 wake_up_interruptible(&channel->playback_waitq); in audio_tx_completion()