From f70575805708cabdedea7498aaa3f710fde4d920 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Wed, 31 Jan 2024 03:29:01 +0000 Subject: [PATCH] add lvds1024*800 --- kernel/drivers/staging/most/sound/sound.c | 275 ++++++++++++++++++++++++++---------------------------- 1 files changed, 134 insertions(+), 141 deletions(-) diff --git a/kernel/drivers/staging/most/sound/sound.c b/kernel/drivers/staging/most/sound/sound.c index fd9245d..b7666a7 100644 --- a/kernel/drivers/staging/most/sound/sound.c +++ b/kernel/drivers/staging/most/sound/sound.c @@ -10,18 +10,19 @@ #include <linux/module.h> #include <linux/printk.h> #include <linux/kernel.h> +#include <linux/slab.h> #include <linux/init.h> #include <sound/core.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <linux/sched.h> #include <linux/kthread.h> -#include <most/core.h> +#include <linux/most.h> #define DRIVER_NAME "sound" +#define STRING_SIZE 80 -static struct list_head dev_list; -static struct core_component comp; +static struct most_component comp; /** * struct channel - private structure to keep channel specific data @@ -49,12 +50,21 @@ unsigned int period_pos; unsigned int buffer_pos; bool is_stream_running; - struct task_struct *playback_task; wait_queue_head_t playback_waitq; - void (*copy_fn)(void *alsa, void *most, unsigned int bytes); }; + +struct sound_adapter { + struct list_head dev_list; + struct most_interface *iface; + struct snd_card *card; + struct list_head list; + bool registered; + int pcm_dev_idx; +}; + +static struct list_head adpt_list; #define MOST_PCM_INFO (SNDRV_PCM_INFO_MMAP | \ SNDRV_PCM_INFO_MMAP_VALID | \ @@ -159,13 +169,13 @@ static struct channel *get_channel(struct most_interface *iface, int channel_id) { + struct sound_adapter *adpt = iface->priv; struct channel *channel, *tmp; - list_for_each_entry_safe(channel, tmp, &dev_list, list) { + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { if ((channel->iface == iface) && (channel->id == channel_id)) return channel; } - return NULL; } @@ -209,7 +219,6 @@ channel->period_pos -= runtime->period_size; return true; } - return false; } @@ -249,7 +258,6 @@ if (period_elapsed) snd_pcm_period_elapsed(channel->substream); } - return 0; } @@ -267,6 +275,7 @@ struct channel *channel = substream->private_data; struct snd_pcm_runtime *runtime = substream->runtime; struct most_channel_config *cfg = channel->cfg; + int ret; channel->substream = substream; @@ -279,11 +288,12 @@ } } - if (most_start_channel(channel->iface, channel->id, &comp)) { + ret = most_start_channel(channel->iface, channel->id, &comp); + if (ret) { pr_err("most_start_channel() failed!\n"); if (cfg->direction == MOST_CH_TX) kthread_stop(channel->playback_task); - return -EBUSY; + return ret; } runtime->hw = channel->pcm_hardware; @@ -307,48 +317,7 @@ if (channel->cfg->direction == MOST_CH_TX) kthread_stop(channel->playback_task); most_stop_channel(channel->iface, channel->id, &comp); - return 0; -} - -/** - * pcm_hw_params - implements hw_params callback function for PCM middle layer - * @substream: sub-stream pointer - * @hw_params: contains the hardware parameters set by the application - * - * This is called when the hardware parameters is set by the application, that - * is, once when the buffer size, the period size, the format, etc. are defined - * for the PCM substream. Many hardware setups should be done is this callback, - * including the allocation of buffers. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_hw_params(struct snd_pcm_substream *substream, - struct snd_pcm_hw_params *hw_params) -{ - struct channel *channel = substream->private_data; - - if ((params_channels(hw_params) > channel->pcm_hardware.channels_max) || - (params_channels(hw_params) < channel->pcm_hardware.channels_min)) { - pr_err("Requested number of channels not supported.\n"); - return -EINVAL; - } - return snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); -} - -/** - * pcm_hw_free - implements hw_free callback function for PCM middle layer - * @substream: substream pointer - * - * This is called to release the resources allocated via hw_params. - * This function will be always called before the close callback is called. - * - * Returns 0 on success or error code otherwise. - */ -static int pcm_hw_free(struct snd_pcm_substream *substream) -{ - return snd_pcm_lib_free_vmalloc_buffer(substream); } /** @@ -389,14 +358,10 @@ channel->copy_fn = most_to_alsa_copy32; } - if (!channel->copy_fn) { - pr_err("unsupported format\n"); + if (!channel->copy_fn) return -EINVAL; - } - channel->period_pos = 0; channel->buffer_pos = 0; - return 0; } @@ -425,7 +390,6 @@ return 0; default: - pr_info("%s(), invalid\n", __func__); return -EINVAL; } return 0; @@ -452,26 +416,16 @@ static const struct snd_pcm_ops pcm_ops = { .open = pcm_open, .close = pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = pcm_hw_params, - .hw_free = pcm_hw_free, .prepare = pcm_prepare, .trigger = pcm_trigger, .pointer = pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; -static int split_arg_list(char *buf, char **card_name, u16 *ch_num, - char **sample_res) +static int split_arg_list(char *buf, u16 *ch_num, char **sample_res) { char *num; int ret; - *card_name = strsep(&buf, "."); - if (!*card_name) { - pr_err("Missing sound card name\n"); - return -EIO; - } num = strsep(&buf, "x"); if (!num) goto err; @@ -485,7 +439,7 @@ err: pr_err("Bad PCM format\n"); - return -EIO; + return -EINVAL; } static const struct sample_resolution_info { @@ -510,7 +464,7 @@ goto found; } pr_err("Unsupported PCM format\n"); - return -EIO; + return -EINVAL; found: if (!ch_num) { @@ -538,6 +492,20 @@ return 0; } +static void release_adapter(struct sound_adapter *adpt) +{ + struct channel *channel, *tmp; + + list_for_each_entry_safe(channel, tmp, &adpt->dev_list, list) { + list_del(&channel->list); + kfree(channel); + } + if (adpt->card) + snd_card_free(adpt->card); + list_del(&adpt->list); + kfree(adpt); +} + /** * audio_probe_channel - probe function of the driver module * @iface: pointer to interface instance @@ -552,31 +520,59 @@ */ static int audio_probe_channel(struct most_interface *iface, int channel_id, struct most_channel_config *cfg, - char *arg_list) + char *device_name, char *arg_list) { struct channel *channel; - struct snd_card *card; + struct sound_adapter *adpt; struct snd_pcm *pcm; int playback_count = 0; int capture_count = 0; int ret; int direction; - char *card_name; u16 ch_num; char *sample_res; - - if (!iface) - return -EINVAL; + char arg_list_cpy[STRING_SIZE]; if (cfg->data_type != MOST_CH_SYNC) { pr_err("Incompatible channel type\n"); return -EINVAL; } + strlcpy(arg_list_cpy, arg_list, STRING_SIZE); + ret = split_arg_list(arg_list_cpy, &ch_num, &sample_res); + if (ret < 0) + return ret; + list_for_each_entry(adpt, &adpt_list, list) { + if (adpt->iface != iface) + continue; + if (adpt->registered) + return -ENOSPC; + adpt->pcm_dev_idx++; + goto skip_adpt_alloc; + } + adpt = kzalloc(sizeof(*adpt), GFP_KERNEL); + if (!adpt) + return -ENOMEM; + + adpt->iface = iface; + INIT_LIST_HEAD(&adpt->dev_list); + iface->priv = adpt; + list_add_tail(&adpt->list, &adpt_list); + ret = snd_card_new(iface->driver_dev, -1, "INIC", THIS_MODULE, + sizeof(*channel), &adpt->card); + if (ret < 0) + goto err_free_adpt; + snprintf(adpt->card->driver, sizeof(adpt->card->driver), + "%s", DRIVER_NAME); + snprintf(adpt->card->shortname, sizeof(adpt->card->shortname), + "Microchip INIC"); + snprintf(adpt->card->longname, sizeof(adpt->card->longname), + "%s at %s", adpt->card->shortname, iface->description); +skip_adpt_alloc: if (get_channel(iface, channel_id)) { pr_err("channel (%s:%d) is already linked\n", iface->description, channel_id); - return -EINVAL; + return -EEXIST; } if (cfg->direction == MOST_CH_TX) { @@ -586,54 +582,58 @@ capture_count = 1; direction = SNDRV_PCM_STREAM_CAPTURE; } - - ret = split_arg_list(arg_list, &card_name, &ch_num, &sample_res); - if (ret < 0) - return ret; - - ret = snd_card_new(&iface->dev, -1, card_name, THIS_MODULE, - sizeof(*channel), &card); - if (ret < 0) - return ret; - - channel = card->private_data; - channel->card = card; + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (!channel) { + ret = -ENOMEM; + goto err_free_adpt; + } + channel->card = adpt->card; channel->cfg = cfg; channel->iface = iface; channel->id = channel_id; init_waitqueue_head(&channel->playback_waitq); + list_add_tail(&channel->list, &adpt->dev_list); ret = audio_set_hw_params(&channel->pcm_hardware, ch_num, sample_res, cfg); if (ret) - goto err_free_card; + goto err_free_adpt; - snprintf(card->driver, sizeof(card->driver), "%s", DRIVER_NAME); - snprintf(card->shortname, sizeof(card->shortname), "Microchip MOST:%d", - card->number); - snprintf(card->longname, sizeof(card->longname), "%s at %s, ch %d", - card->shortname, iface->description, channel_id); + ret = snd_pcm_new(adpt->card, device_name, adpt->pcm_dev_idx, + playback_count, capture_count, &pcm); - ret = snd_pcm_new(card, card_name, 0, playback_count, - capture_count, &pcm); if (ret < 0) - goto err_free_card; + goto err_free_adpt; pcm->private_data = channel; - + strscpy(pcm->name, device_name, sizeof(pcm->name)); snd_pcm_set_ops(pcm, direction, &pcm_ops); - - ret = snd_card_register(card); - if (ret < 0) - goto err_free_card; - - list_add_tail(&channel->list, &dev_list); - + snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); return 0; -err_free_card: - snd_card_free(card); +err_free_adpt: + release_adapter(adpt); return ret; +} + +static int audio_create_sound_card(void) +{ + int ret; + struct sound_adapter *adpt; + + list_for_each_entry(adpt, &adpt_list, list) { + if (!adpt->registered) + goto adpt_alloc; + } + return -ENODEV; +adpt_alloc: + ret = snd_card_register(adpt->card); + if (ret < 0) { + release_adapter(adpt); + return ret; + } + adpt->registered = true; + return 0; } /** @@ -649,17 +649,17 @@ int channel_id) { struct channel *channel; + struct sound_adapter *adpt = iface->priv; channel = get_channel(iface, channel_id); - if (!channel) { - pr_err("sound_disconnect_channel(), invalid channel %d\n", - channel_id); + if (!channel) return -EINVAL; - } list_del(&channel->list); - snd_card_free(channel->card); + kfree(channel); + if (list_empty(&adpt->dev_list)) + release_adapter(adpt); return 0; } @@ -677,20 +677,13 @@ struct channel *channel = get_channel(mbo->ifp, mbo->hdm_channel_id); bool period_elapsed = false; - if (!channel) { - pr_err("sound_rx_completion(), invalid channel %d\n", - mbo->hdm_channel_id); + if (!channel) return -EINVAL; - } - if (channel->is_stream_running) period_elapsed = copy_data(channel, mbo); - most_put_mbo(mbo); - if (period_elapsed) snd_pcm_period_elapsed(channel->substream); - return 0; } @@ -709,48 +702,48 @@ { struct channel *channel = get_channel(iface, channel_id); - if (!channel) { - pr_err("sound_tx_completion(), invalid channel %d\n", - channel_id); + if (!channel) return -EINVAL; - } wake_up_interruptible(&channel->playback_waitq); - return 0; } /** - * Initialization of the struct core_component + * Initialization of the struct most_component */ -static struct core_component comp = { +static struct most_component comp = { + .mod = THIS_MODULE, .name = DRIVER_NAME, .probe_channel = audio_probe_channel, .disconnect_channel = audio_disconnect_channel, .rx_completion = audio_rx_completion, .tx_completion = audio_tx_completion, + .cfg_complete = audio_create_sound_card, }; static int __init audio_init(void) { - pr_info("init()\n"); + int ret; - INIT_LIST_HEAD(&dev_list); + INIT_LIST_HEAD(&adpt_list); - return most_register_component(&comp); + ret = most_register_component(&comp); + if (ret) { + pr_err("Failed to register %s\n", comp.name); + return ret; + } + ret = most_register_configfs_subsys(&comp); + if (ret) { + pr_err("Failed to register %s configfs subsys\n", comp.name); + most_deregister_component(&comp); + } + return ret; } static void __exit audio_exit(void) { - struct channel *channel, *tmp; - - pr_info("exit()\n"); - - list_for_each_entry_safe(channel, tmp, &dev_list, list) { - list_del(&channel->list); - snd_card_free(channel->card); - } - + most_deregister_configfs_subsys(&comp); most_deregister_component(&comp); } -- Gitblit v1.6.2