From 73282fe2d8fe4f90e3160939f4ea588c787ab0e4 Mon Sep 17 00:00:00 2001 From: ligd Date: Fri, 24 Jul 2020 10:40:54 +0800 Subject: [PATCH] arch/sim: add sim alsa support Squashed commit of the following: sim audio: call alsa to playback/capture data sim/audio: correct the format capability sim/audio: add pause/resume support sim/audio: add auto stop when meet AUDIO_APB_FINAL sim/audio: fix abort when set small buffer_size sim/audio: move sim_audio.c to sim_alsa.c Change-Id: I8e00ece79159e844ca17fd4c363480b985ee0490 Signed-off-by: ligd --- arch/sim/Kconfig | 19 + arch/sim/src/Makefile | 5 + arch/sim/src/sim/up_alsa.c | 731 ++++++++++++++++++++++ arch/sim/src/sim/up_idle.c | 4 + arch/sim/src/sim/up_initialize.c | 6 + arch/sim/src/sim/up_internal.h | 7 + boards/sim/sim/sim/configs/alsa/defconfig | 59 ++ 7 files changed, 831 insertions(+) create mode 100644 arch/sim/src/sim/up_alsa.c create mode 100644 boards/sim/sim/sim/configs/alsa/defconfig diff --git a/arch/sim/Kconfig b/arch/sim/Kconfig index 13fc7add51..9498a68cf2 100644 --- a/arch/sim/Kconfig +++ b/arch/sim/Kconfig @@ -201,6 +201,25 @@ config SIM_NET_BRIDGE_DEVICE endif +config SIM_SOUND + bool "Simulated sound support" + depends on AUDIO + default y + +if SIM_SOUND + +choice + prompt "Simulated sound Type" + default SIM_SOUND_ALSA + +config SIM_SOUND_ALSA + bool "alsa support on sim" + depends on HOST_LINUX + +endchoice + +endif + config SIM_RPTUN_MASTER bool "Remote Processor Tunneling Role" depends on RPTUN diff --git a/arch/sim/src/Makefile b/arch/sim/src/Makefile index 6b726ceb6c..52982375bd 100644 --- a/arch/sim/src/Makefile +++ b/arch/sim/src/Makefile @@ -205,6 +205,11 @@ ifeq ($(CONFIG_RPTUN),y) CSRCS += up_rptun.c endif +ifeq ($(CONFIG_SIM_SOUND_ALSA),y) + CSRCS += up_alsa.c + STDLIBS += -lasound +endif + ifeq ($(CONFIG_FS_HOSTFS),y) ifneq ($(CONFIG_FS_HOSTFS_RPMSG),y) HOSTSRCS += up_hostfs.c diff --git a/arch/sim/src/sim/up_alsa.c b/arch/sim/src/sim/up_alsa.c new file mode 100644 index 0000000000..1218033720 --- /dev/null +++ b/arch/sim/src/sim/up_alsa.c @@ -0,0 +1,731 @@ +/**************************************************************************** + * arch/sim/src/sim/up_alsa.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include + +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define AUDMIN(a,b) ((a) > (b) ? (b) : (a)) + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct sim_audio_s +{ + struct audio_lowerhalf_s dev; + struct dq_queue_s pendq; + + sq_entry_t link; + + bool playback; + uint32_t frame_size; + uint32_t nbuffers; + uint32_t buffer_size; + + uint32_t sample_rate; + uint32_t channels; + uint32_t bps; + + snd_pcm_t *pcm; + snd_mixer_t *mixer; + snd_mixer_elem_t *volume; +}; + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +static int sim_audio_getcaps(struct audio_lowerhalf_s *dev, int type, + struct audio_caps_s *caps); +static int sim_audio_configure(struct audio_lowerhalf_s *dev, + const struct audio_caps_s *caps); +static int sim_audio_shutdown(struct audio_lowerhalf_s *dev); +static int sim_audio_start(struct audio_lowerhalf_s *dev); +#ifndef CONFIG_AUDIO_EXCLUDE_STOP +static int sim_audio_stop(struct audio_lowerhalf_s *dev); +#endif +#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME +static int sim_audio_pause(struct audio_lowerhalf_s *dev); +static int sim_audio_resume(struct audio_lowerhalf_s *dev); +#endif +static int sim_audio_enqueuebuffer(struct audio_lowerhalf_s *dev, + struct ap_buffer_s *apb); +static int sim_audio_ioctl(struct audio_lowerhalf_s *dev, int cmd, + unsigned long arg); +static int sim_audio_reserve(struct audio_lowerhalf_s *dev); +static int sim_audio_release(struct audio_lowerhalf_s *dev); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static const struct audio_ops_s g_sim_audio_ops = +{ + .getcaps = sim_audio_getcaps, + .configure = sim_audio_configure, + .shutdown = sim_audio_shutdown, + .start = sim_audio_start, +#ifndef CONFIG_AUDIO_EXCLUDE_STOP + .stop = sim_audio_stop, +#endif +#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME + .pause = sim_audio_pause, + .resume = sim_audio_resume, +#endif + .enqueuebuffer = sim_audio_enqueuebuffer, + .ioctl = sim_audio_ioctl, + .reserve = sim_audio_reserve, + .release = sim_audio_release, +}; + +static sq_queue_t g_sim_audio; + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int sim_audio_config_format(struct sim_audio_s *priv, snd_pcm_t *pcm) +{ + snd_pcm_hw_params_t *hw_params; + snd_pcm_uframes_t pframes; + snd_pcm_format_t format; + uint32_t total_size; + int ret; + + switch (priv->bps) + { + case 8: + format = SND_PCM_FORMAT_S8; + break; + case 24: + format = SND_PCM_FORMAT_S24; + break; + case 32: + format = SND_PCM_FORMAT_S32; + break; + default: + format = SND_PCM_FORMAT_S16; + break; + } + + ret = snd_pcm_hw_params_malloc(&hw_params); + if (ret < 0) + { + return ret; + } + + ret = snd_pcm_hw_params_any(pcm, hw_params); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_hw_params_set_access(pcm, hw_params, + SND_PCM_ACCESS_RW_INTERLEAVED); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_hw_params_set_format(pcm, hw_params, format); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_hw_params_set_rate(pcm, hw_params, + priv->sample_rate, 0); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_hw_params_set_channels(pcm, hw_params, + priv->channels); + if (ret < 0) + { + goto fail; + } + + total_size = priv->nbuffers * priv->buffer_size; + + pframes = priv->buffer_size / priv->frame_size; + ret = snd_pcm_hw_params_set_period_size_near(pcm, hw_params, + &pframes, NULL); + if (ret < 0) + { + goto fail; + } + + priv->buffer_size = pframes * priv->frame_size; + priv->nbuffers = total_size / priv->buffer_size; + ret = snd_pcm_hw_params_set_periods_near(pcm, hw_params, + &priv->nbuffers, NULL); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_hw_params(pcm, hw_params); + +fail: + snd_pcm_hw_params_free(hw_params); + return ret; +} + +static int sim_audio_open(struct sim_audio_s *priv) +{ + snd_pcm_t *pcm; + int direction; + int ret; + + if (priv->pcm) + { + return 0; + } + + direction = priv->playback ? SND_PCM_STREAM_PLAYBACK + : SND_PCM_STREAM_CAPTURE; + + ret = snd_pcm_open(&pcm, "default", direction, 0); + if (ret < 0) + { + return ret; + } + + ret = sim_audio_config_format(priv, pcm); + if (ret < 0) + { + goto fail; + } + + ret = snd_pcm_start(pcm); + if (ret < 0) + { + goto fail; + } + + priv->pcm = pcm; + + return 0; + +fail: + snd_pcm_close(pcm); + return ret; +} + +static int sim_audio_close(struct sim_audio_s *priv) +{ + if (!priv->pcm) + { + return 0; + } + + snd_pcm_close(priv->pcm); + + priv->pcm = NULL; + + return 0; +} + +static int sim_audio_getcaps(struct audio_lowerhalf_s *dev, int type, + struct audio_caps_s *caps) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + long val; + + caps->ac_format.hw = 0; + caps->ac_controls.w = 0; + + switch (caps->ac_type) + { + case AUDIO_TYPE_QUERY: + + caps->ac_channels = 2; /* Stereo output */ + + switch (caps->ac_subtype) + { + case AUDIO_TYPE_QUERY: + caps->ac_controls.b[0] = (priv->playback ? + AUDIO_TYPE_OUTPUT : + AUDIO_TYPE_INPUT) | + AUDIO_TYPE_FEATURE | + AUDIO_TYPE_PROCESSING; + caps->ac_format.hw = (1 << (AUDIO_FMT_PCM - 1)); + break; + default: + caps->ac_controls.b[0] = AUDIO_SUBFMT_END; + break; + } + + break; + + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + + caps->ac_channels = 2; + + switch (caps->ac_subtype) + { + case AUDIO_TYPE_QUERY: + + /* Report the Sample rates we support */ + + caps->ac_controls.b[0] = AUDIO_SAMP_RATE_8K | + AUDIO_SAMP_RATE_11K | + AUDIO_SAMP_RATE_16K | + AUDIO_SAMP_RATE_22K | + AUDIO_SAMP_RATE_32K | + AUDIO_SAMP_RATE_44K | + AUDIO_SAMP_RATE_48K; + break; + + default: + break; + } + + break; + + case AUDIO_TYPE_FEATURE: + + switch (caps->ac_format.hw) + { + case AUDIO_FU_VOLUME: + snd_mixer_selem_get_playback_volume(priv->volume, + SND_MIXER_SCHN_UNKNOWN, + &val); + caps->ac_controls.w = val; + break; + case AUDIO_FU_INP_GAIN: + snd_mixer_selem_get_capture_volume(priv->volume, + SND_MIXER_SCHN_MONO, + &val); + caps->ac_controls.w = val; + break; + default: + break; + } + + break; + + default: + caps->ac_subtype = 0; + caps->ac_channels = 0; + break; + } + + /* Return the length of the audio_caps_s struct for validation of + * proper Audio device type. + */ + + audinfo("Return %d\n", caps->ac_len); + return caps->ac_len; +} + +static int sim_audio_configure(struct audio_lowerhalf_s *dev, + const struct audio_caps_s *caps) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + int ret = 0; + + switch (caps->ac_type) + { + case AUDIO_TYPE_FEATURE: + switch (caps->ac_format.hw) + { + case AUDIO_FU_VOLUME: + ret = snd_mixer_selem_set_playback_volume_all(priv->volume, + caps->ac_controls.hw[0]); + break; + case AUDIO_FU_INP_GAIN: + ret = snd_mixer_selem_set_capture_volume_all(priv->volume, + caps->ac_controls.hw[0]); + break; + default: + ret = -ENOTTY; + break; + } + break; + + case AUDIO_TYPE_OUTPUT: + case AUDIO_TYPE_INPUT: + + priv->sample_rate = caps->ac_controls.hw[0] | + (caps->ac_controls.b[3] << 16); + priv->channels = caps->ac_channels; + priv->bps = caps->ac_controls.b[2]; + priv->frame_size = priv->bps / 8 * priv->channels; + + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static int sim_audio_shutdown(struct audio_lowerhalf_s *dev) +{ + return 0; +} + +static int sim_audio_start(struct audio_lowerhalf_s *dev) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + + return sim_audio_open(priv); +} + +#ifndef CONFIG_AUDIO_EXCLUDE_STOP +static int sim_audio_stop(struct audio_lowerhalf_s *dev) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + + sim_audio_close(priv); + + while (!dq_empty(&priv->pendq)) + { + struct ap_buffer_s *apb; + + apb = (struct ap_buffer_s *)dq_remfirst(&priv->pendq); + priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK); + } + + priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_COMPLETE, NULL, OK); + + return 0; +} +#endif + +#ifndef CONFIG_AUDIO_EXCLUDE_PAUSE_RESUME +static int sim_audio_pause(struct audio_lowerhalf_s *dev) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + int ret; + + if (!priv->pcm) + { + return 0; + } + + ret = snd_pcm_pause(priv->pcm, 0); + if (ret < 0) + { + return ret; + } + + return 0; +} + +static int sim_audio_resume(struct audio_lowerhalf_s *dev) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + int ret; + + if (!priv->pcm) + { + return 0; + } + + ret = snd_pcm_resume(priv->pcm); + if (ret < 0) + { + return ret; + } + + return ret; +} +#endif + +static int sim_audio_enqueuebuffer(struct audio_lowerhalf_s *dev, + struct ap_buffer_s *apb) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + + apb->flags |= AUDIO_APB_OUTPUT_ENQUEUED; + dq_addlast(&apb->dq_entry, &priv->pendq); + + return 0; +} + +static int sim_audio_ioctl(struct audio_lowerhalf_s *dev, int cmd, + unsigned long arg) +{ + struct sim_audio_s *priv = (struct sim_audio_s *)dev; + int ret = 0; + + switch (cmd) + { + case AUDIOIOC_SETBUFFERINFO: + { + struct ap_buffer_info_s *info = + (struct ap_buffer_info_s *)arg; + + priv->nbuffers = info->nbuffers; + priv->buffer_size = info->buffer_size; + } + break; + + case AUDIOIOC_GETBUFFERINFO: + { + struct ap_buffer_info_s *info = + (struct ap_buffer_info_s *)arg; + + info->nbuffers = priv->nbuffers; + info->buffer_size = priv->buffer_size; + } + break; + + default: + ret = -ENOTTY; + break; + } + + return ret; +} + +static int sim_audio_reserve(struct audio_lowerhalf_s *dev) +{ + return 0; +} + +static int sim_audio_release(struct audio_lowerhalf_s *dev) +{ + return 0; +} + +static void sim_audio_process(struct sim_audio_s *priv) +{ + struct ap_buffer_s *apb; + snd_pcm_sframes_t expect; + snd_pcm_sframes_t avail; + int ret = 0; + + if (!priv->pcm) + { + return; + } + + apb = (struct ap_buffer_s *)dq_peek(&priv->pendq); + if (!apb) + { + return; + } + + expect = priv->playback ? apb->nbytes / priv->frame_size + : AUDMIN(apb->nmaxbytes, priv->buffer_size) + / priv->frame_size; + avail = snd_pcm_avail(priv->pcm); + if (avail < expect) + { + ret = avail; + goto out; + } + + if (priv->playback) + { + ret = snd_pcm_writei(priv->pcm, apb->samp, expect); + } + else + { + ret = snd_pcm_readi(priv->pcm, apb->samp, expect); + } + + if (ret >= 0) + { + bool final = false; + + dq_remfirst(&priv->pendq); + + apb->nbytes = ret * priv->frame_size; + if (apb->flags & AUDIO_APB_FINAL) + { + final = true; + } + + priv->dev.upper(priv->dev.priv, AUDIO_CALLBACK_DEQUEUE, apb, OK); + + if (final) + { + snd_pcm_drain(priv->pcm); + sim_audio_stop(&priv->dev); + } + } + +out: + if (ret == -EPIPE) + { + awarn("ALSA buffer xrun.\n"); + snd_pcm_prepare(priv->pcm); + snd_pcm_start(priv->pcm); + } + else if (ret < 0 && ret != -EAGAIN) + { + aerr("pcm writei/readi failed %d, %s\n", ret, snd_strerror(ret)); + } +} + +static int sim_mixer_open(struct sim_audio_s *priv) +{ + snd_mixer_selem_id_t *sid = NULL; + int ret; + + ret = snd_mixer_open(&priv->mixer, 0); + if (ret < 0) + { + return ret; + } + + ret = snd_mixer_attach(priv->mixer, "default"); + if (ret < 0) + { + goto fail; + } + + ret = snd_mixer_selem_register(priv->mixer, NULL, NULL); + if (ret < 0) + { + goto fail; + } + + ret = snd_mixer_load(priv->mixer); + if (ret < 0) + { + goto fail; + } + + ret = snd_mixer_selem_id_malloc(&sid); + if (ret < 0) + { + goto fail; + } + + if (priv->playback) + { + snd_mixer_selem_id_set_index(sid, 0); + snd_mixer_selem_id_set_name(sid, "Master"); + + priv->volume = snd_mixer_find_selem(priv->mixer, sid); + snd_mixer_selem_id_free(sid); + if (!priv->volume) + { + goto fail; + } + + ret = snd_mixer_selem_set_playback_volume_range(priv->volume, 0, 1000); + if (ret < 0) + { + goto fail; + } + } + else + { + snd_mixer_selem_id_set_index(sid, 0); + snd_mixer_selem_id_set_name(sid, "Capture"); + + priv->volume = snd_mixer_find_selem(priv->mixer, sid); + snd_mixer_selem_id_free(sid); + if (!priv->volume) + { + goto fail; + } + + ret = snd_mixer_selem_set_capture_volume_range(priv->volume, 0, 1000); + if (ret < 0) + { + goto fail; + } + } + + return 0; +fail: + snd_mixer_close(priv->mixer); + priv->mixer = NULL; + return 0; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +void sim_audio_loop(void) +{ + sq_entry_t *entry; + + for (entry = sq_peek(&g_sim_audio); entry; entry = sq_next(entry)) + { + struct sim_audio_s *priv = + container_of(entry, struct sim_audio_s, link); + + sim_audio_process(priv); + } +} + +struct audio_lowerhalf_s *sim_audio_initialize(bool playback) +{ + struct sim_audio_s *priv; + int ret; + + priv = kmm_zalloc(sizeof(struct sim_audio_s)); + if (!priv) + { + return NULL; + } + + priv->playback = playback; + priv->dev.ops = &g_sim_audio_ops; + + ret = sim_mixer_open(priv); + if (ret < 0) + { + kmm_free(priv); + return NULL; + } + + sq_addlast(&priv->link, &g_sim_audio); + + /* Setting default config */ + + priv->nbuffers = CONFIG_AUDIO_NUM_BUFFERS; + priv->buffer_size = CONFIG_AUDIO_BUFFER_NUMBYTES; + + priv->sample_rate = 48000; + priv->channels = 2; + priv->bps = 16; + priv->frame_size = 4; + + return &priv->dev; +} diff --git a/arch/sim/src/sim/up_idle.c b/arch/sim/src/sim/up_idle.c index b7fda31cfe..eacffeb660 100644 --- a/arch/sim/src/sim/up_idle.c +++ b/arch/sim/src/sim/up_idle.c @@ -113,6 +113,10 @@ void up_idle(void) bthcisock_loop(); #endif +#ifdef CONFIG_SIM_SOUND + sim_audio_loop(); +#endif + #ifdef CONFIG_ONESHOT /* Driver the simulated interval timer */ diff --git a/arch/sim/src/sim/up_initialize.c b/arch/sim/src/sim/up_initialize.c index ad253c183e..3f05b0d935 100644 --- a/arch/sim/src/sim/up_initialize.c +++ b/arch/sim/src/sim/up_initialize.c @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -281,4 +282,9 @@ void up_initialize(void) #if defined(CONFIG_FS_SMARTFS) && (defined(CONFIG_SIM_SPIFLASH) || defined(CONFIG_SIM_QSPIFLASH)) up_init_smartfs(); #endif + +#ifdef CONFIG_SIM_SOUND + audio_register("pcm0p", sim_audio_initialize(true)); + audio_register("pcm0c", sim_audio_initialize(false)); +#endif } diff --git a/arch/sim/src/sim/up_internal.h b/arch/sim/src/sim/up_internal.h index 2741c64f6c..23ebd2fd19 100644 --- a/arch/sim/src/sim/up_internal.h +++ b/arch/sim/src/sim/up_internal.h @@ -397,6 +397,13 @@ int bthcisock_register(int dev_id); int bthcisock_loop(void); #endif +/* up_audio.c ***************************************************************/ + +#ifdef CONFIG_SIM_SOUND +struct audio_lowerhalf_s *sim_audio_initialize(bool playback); +void sim_audio_loop(void); +#endif + /* Debug ********************************************************************/ #ifdef CONFIG_STACK_COLORATION diff --git a/boards/sim/sim/sim/configs/alsa/defconfig b/boards/sim/sim/sim/configs/alsa/defconfig new file mode 100644 index 0000000000..542e43caea --- /dev/null +++ b/boards/sim/sim/sim/configs/alsa/defconfig @@ -0,0 +1,59 @@ +# +# This file is autogenerated: PLEASE DO NOT EDIT IT. +# +# You can use "make menuconfig" to make any modifications to the installed .config file. +# You can then do "make savedefconfig" to generate a new defconfig file that includes your +# modifications. +# +# CONFIG_NSH_CMDOPT_HEXDUMP is not set +CONFIG_ARCH="sim" +CONFIG_ARCH_BOARD="sim" +CONFIG_ARCH_BOARD_SIM=y +CONFIG_ARCH_CHIP="sim" +CONFIG_ARCH_SIM=y +CONFIG_AUDIO=y +CONFIG_BOARDCTL_APP_SYMTAB=y +CONFIG_BOARDCTL_POWEROFF=y +CONFIG_BOARD_LOOPSPERMSEC=0 +CONFIG_BOOT_RUNFROMEXTSRAM=y +CONFIG_BUILTIN=y +CONFIG_DEBUG_SYMBOLS=y +CONFIG_DEV_LOOP=y +CONFIG_DEV_ZERO=y +CONFIG_EXAMPLES_HELLO=y +CONFIG_FAT_LCNAMES=y +CONFIG_FAT_LFN=y +CONFIG_FSUTILS_PASSWD=y +CONFIG_FSUTILS_PASSWD_READONLY=y +CONFIG_FS_BINFS=y +CONFIG_FS_FAT=y +CONFIG_FS_HOSTFS=y +CONFIG_FS_PROCFS=y +CONFIG_FS_ROMFS=y +CONFIG_IDLETHREAD_STACKSIZE=4096 +CONFIG_LIBC_EXECFUNCS=y +CONFIG_LIB_ENVPATH=y +CONFIG_MAX_TASKS=64 +CONFIG_NFILE_DESCRIPTORS=32 +CONFIG_NSH_ARCHINIT=y +CONFIG_NSH_ARCHROMFS=y +CONFIG_NSH_BUILTIN_APPS=y +CONFIG_NSH_FATDEVNO=2 +CONFIG_NSH_FILE_APPS=y +CONFIG_NSH_READLINE=y +CONFIG_NSH_ROMFSDEVNO=1 +CONFIG_NSH_ROMFSETC=y +CONFIG_PATH_INITIAL="/bin" +CONFIG_POSIX_SPAWN_PROXY_STACKSIZE=2048 +CONFIG_READLINE_TABCOMPLETION=y +CONFIG_SCHED_HAVE_PARENT=y +CONFIG_SCHED_ONEXIT=y +CONFIG_SCHED_WAITPID=y +CONFIG_SDCLONE_DISABLE=y +CONFIG_START_MONTH=6 +CONFIG_START_YEAR=2008 +CONFIG_SYSTEM_NSH=y +CONFIG_SYSTEM_NXPLAYER=y +CONFIG_SYSTEM_NXRECORDER=y +CONFIG_USERMAIN_STACKSIZE=4096 +CONFIG_USER_ENTRYPOINT="nsh_main"