From 559e297e4b17e73d30fc7317868889bc0f4d0e6a Mon Sep 17 00:00:00 2001 From: EvalZero Date: Tue, 6 Aug 2019 15:00:25 +0800 Subject: [PATCH] [bsp][qemu-vexpress-a9]update qemu-vexpress-a9 audio device drivers. --- .../drivers/audio/audio_device.c | 191 ---------- .../drivers/audio/audio_device.h | 51 --- .../drivers/audio/drv_audio.c | 328 ----------------- .../drivers/audio/drv_audio.h | 29 -- .../drivers/audio/drv_pl041.c | 2 +- .../drivers/audio/drv_pl041.h | 2 +- .../drivers/audio/drv_sound.c | 340 ++++++++++++++++++ .../drivers/audio/drv_sound.h | 13 + bsp/qemu-vexpress-a9/drivers/audio/wav_play.c | 144 -------- 9 files changed, 355 insertions(+), 745 deletions(-) delete mode 100644 bsp/qemu-vexpress-a9/drivers/audio/audio_device.c delete mode 100644 bsp/qemu-vexpress-a9/drivers/audio/audio_device.h delete mode 100644 bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c delete mode 100644 bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h create mode 100644 bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c create mode 100644 bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h delete mode 100644 bsp/qemu-vexpress-a9/drivers/audio/wav_play.c diff --git a/bsp/qemu-vexpress-a9/drivers/audio/audio_device.c b/bsp/qemu-vexpress-a9/drivers/audio/audio_device.c deleted file mode 100644 index a0f37ed621..0000000000 --- a/bsp/qemu-vexpress-a9/drivers/audio/audio_device.c +++ /dev/null @@ -1,191 +0,0 @@ -/* - * File : audio_device.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2017, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2018-05-26 RT-Thread the first version - */ - -#include -#include -#include -#include -#include "drv_pl041.h" -#include "drv_ac97.h" -#include "audio_device.h" - -struct audio_device -{ - struct rt_device *snd; - struct rt_mempool mp; - - int state; - - void (*evt_handler)(void *parameter, int state); - void *parameter; -}; - -static struct audio_device *_audio_device = NULL; - -void *audio_device_get_buffer(int *bufsz) -{ - if (bufsz) - { - *bufsz = AUDIO_DEVICE_DECODE_MP_BLOCK_SZ * 2; - } - - return rt_mp_alloc(&(_audio_device->mp), RT_WAITING_FOREVER); -} - -void audio_device_put_buffer(void *ptr) -{ - if (ptr) rt_mp_free(ptr); - return ; -} - -static rt_err_t audio_device_write_done(struct rt_device *device, void *ptr) -{ - if (!ptr) - { - rt_kprintf("device buf_release NULL\n"); - return -RT_ERROR; - } - - rt_mp_free(ptr); - return RT_EOK; -} - -void audio_device_write(void *buffer, int size) -{ - if (_audio_device->snd && size != 0) - { - if (_audio_device->state == AUDIO_DEVICE_IDLE) - { - if (_audio_device->evt_handler) - _audio_device->evt_handler(_audio_device->parameter, AUDIO_DEVICE_PLAYBACK); - - /* change audio device state */ - _audio_device->state = AUDIO_DEVICE_PLAYBACK; - } - - rt_device_write(_audio_device->snd, 0, buffer, size); - } - else - { - /* release buffer directly */ - rt_mp_free(buffer); - } - - return ; -} - -int audio_device_init(void) -{ - uint8_t *mempool_ptr; - - if (!_audio_device) - { - _audio_device = (struct audio_device *) rt_malloc(sizeof(struct audio_device) + AUDIO_DEVICE_DECODE_MP_SZ); - if (_audio_device == NULL) - { - rt_kprintf("malloc memeory for _audio_device failed! \n"); - return -RT_ERROR; - } - - _audio_device->evt_handler = NULL; - _audio_device->parameter = NULL; - - mempool_ptr = (uint8_t *)(_audio_device + 1); - rt_mp_init(&(_audio_device->mp), "adbuf", mempool_ptr, AUDIO_DEVICE_DECODE_MP_SZ, AUDIO_DEVICE_DECODE_MP_BLOCK_SZ * 2); - - /* find snd device */ - _audio_device->snd = rt_device_find("sound"); - if (_audio_device->snd == NULL) - { - rt_kprintf("sound device not found \n"); - return -1; - } - - /* set tx complete call back function */ - rt_device_set_tx_complete(_audio_device->snd, audio_device_write_done); - } - - return RT_EOK; -} - -int audio_device_set_evt_handler(void (*handler)(void *parameter, int state), void *parameter) -{ - if (_audio_device) - { - _audio_device->evt_handler = handler; - _audio_device->parameter = parameter; - } - - return 0; -} - -void audio_device_set_rate(int sample_rate) -{ - if (_audio_device->snd) - { - int rate = sample_rate; - - rt_device_control(_audio_device->snd, CODEC_CMD_SAMPLERATE, &rate); - } -} - -void audio_device_set_volume(int value) -{ - if (_audio_device->snd) - { - rt_device_control(_audio_device->snd, CODEC_CMD_SET_VOLUME, &value); - } -} - -int audio_device_get_volume(void) -{ - int value = 0; - - if (_audio_device->snd) - { - rt_device_control(_audio_device->snd, CODEC_CMD_GET_VOLUME, &value); - } - - return value; -} - -void audio_device_open(void) -{ - _audio_device->state = AUDIO_DEVICE_IDLE; - rt_device_open(_audio_device->snd, RT_DEVICE_OFLAG_WRONLY); -} - -void audio_device_close(void) -{ - rt_device_close(_audio_device->snd); - - if (_audio_device->state == AUDIO_DEVICE_PLAYBACK) - { - if (_audio_device->evt_handler) - _audio_device->evt_handler(_audio_device->parameter, AUDIO_DEVICE_CLOSE); - } - - /* set to idle */ - _audio_device->state = AUDIO_DEVICE_CLOSE; -} diff --git a/bsp/qemu-vexpress-a9/drivers/audio/audio_device.h b/bsp/qemu-vexpress-a9/drivers/audio/audio_device.h deleted file mode 100644 index d0143c231b..0000000000 --- a/bsp/qemu-vexpress-a9/drivers/audio/audio_device.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * File : audio_device.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2017, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2018-05-26 RT-Thread the first version - */ - -#ifndef AUDIO_DEVICE_H__ -#define AUDIO_DEVICE_H__ - -enum AUDIO_DEVICE_STATE -{ - AUDIO_DEVICE_IDLE, - AUDIO_DEVICE_PLAYBACK, - AUDIO_DEVICE_CLOSE, -}; - -void *audio_device_get_buffer(int *bufsz); -void audio_device_put_buffer(void *ptr); - -void audio_device_write(void *buffer, int size); - -int audio_device_init(void); -void audio_device_close(void); - -void audio_device_open(void); - -int audio_device_set_evt_handler(void (*handler)(void *parameter, int state), void *parameter); - -void audio_device_set_rate(int sample_rate); -void audio_device_set_volume(int volume); -void audio_device_wait_free(void); - -#endif \ No newline at end of file diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c b/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c deleted file mode 100644 index 53161ef22b..0000000000 --- a/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c +++ /dev/null @@ -1,328 +0,0 @@ -/* - * File : drv_audio.c - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2017, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2018-05-26 RT-Thread the first version - */ - -#include -#include -#include -#include -#include "drv_pl041.h" -#include "drv_ac97.h" -#include "drv_audio.h" - -#define DATA_NODE_MAX (10) -#define CODEC_TX_FIFO_SIZE (256) - -#define AUDIO_DEVICE_DECODE_MP_SIZE (4096) -#define AUDIO_DEVICE_DECODE_MP_CONUT (4) - -struct codec_data_node -{ - char *data_ptr; - rt_size_t data_size; -}; - -struct audio_buff_des -{ - struct codec_data_node *data_list; - void (*free_fun)(void *); - rt_uint32_t read_offset; - rt_uint16_t node_num; - rt_uint16_t read_index, put_index; -}; - -struct audio_device -{ - /* inherit from rt_device */ - struct rt_device parent; -}; - -static struct audio_device audio_device_drive; -static struct audio_buff_des *audio_buff; -static int irq_flag = 0; - -static void _audio_buff_cb(void *buff) -{ - if (audio_device_drive.parent.tx_complete != RT_NULL) - { - audio_device_drive.parent.tx_complete(&audio_device_drive.parent, buff); - } -} - -static rt_size_t _audio_buff_push(struct audio_buff_des *hdle, void *buff, int size) -{ - struct codec_data_node *node; - rt_uint16_t next_index; - rt_uint32_t level; - - if ((buff == RT_NULL) || (size == 0)) - { - return 0; - } - - next_index = hdle->put_index + 1; - if (next_index >= hdle->node_num) - next_index = 0; - /* check data_list full */ - if (next_index == hdle->read_index) - { - rt_kprintf("data_list full\n"); - rt_set_errno(-RT_EFULL); - return 0; - } - - level = rt_hw_interrupt_disable(); - node = &hdle->data_list[hdle->put_index]; - hdle->put_index = next_index; - - /* set node attribute */ - node->data_ptr = (char *) buff; - node->data_size = size; - rt_hw_interrupt_enable(level); - - return size; -} - -static rt_size_t _audio_buff_pop(struct audio_buff_des *hdle, void *buff, int size) -{ - struct codec_data_node *node; - rt_uint32_t next_index, count = 0, cp_size = 0, offset = 0; - - node = &hdle->data_list[hdle->read_index]; - if ((hdle->read_index == hdle->put_index) && (node->data_ptr == RT_NULL)) - { - memset(buff, 0xff, size); - return 0; - } - - while (count < size) - { - node = &hdle->data_list[hdle->read_index]; - offset = hdle->read_offset; - cp_size = (node->data_size - offset) > (size - count) ? (size - count) : (node->data_size - offset); - - if (node->data_ptr == RT_NULL) - { - memset(buff, 0, size - count); - return count; - } - - memcpy((rt_uint8_t *)buff + count, (rt_uint8_t *)(node->data_ptr) + offset, cp_size); - hdle->read_offset += cp_size; - count += cp_size; - - if (hdle->read_offset >= node->data_size) - { - /* notify transmitted complete. */ - if (hdle->free_fun != RT_NULL) - { - hdle->free_fun(node->data_ptr); - } - /* clear current node */ - memset(node, 0, sizeof(struct codec_data_node)); - next_index = hdle->read_index + 1; - if (next_index >= hdle->node_num) - { - next_index = 0; - } - hdle->read_offset = 0; - hdle->read_index = next_index; - } - } - - return count; -} - -static void transit_wav_data(rt_uint32_t status) -{ - rt_uint16_t sample[CODEC_TX_FIFO_SIZE]; - int i = 0, size; - - size = _audio_buff_pop(audio_buff, sample, CODEC_TX_FIFO_SIZE * sizeof(rt_uint16_t)); - if ((size == 0) && (irq_flag == 1)) - { - aaci_pl041_irq_disable(0, AACI_IE_UR | AACI_IE_TX | AACI_IE_TXC); - irq_flag = 0; - } - - for (i = 0; i < (size >> 1); i++) - { - aaci_pl041_channle_write(0, &sample[i], 1); - } -} - -static void rt_hw_aaci_isr(rt_uint32_t status, void *user_data) -{ - if (status & AACI_SR_TXHE) - { - transit_wav_data(status); - } -} - -static rt_err_t codec_init(rt_device_t dev) -{ - struct pl041_cfg _cfg; - - _cfg.itype = PL041_CHANNLE_LEFT_ADC | PL041_CHANNLE_RIGHT_ADC; - _cfg.otype = PL041_CHANNLE_LEFT_DAC | PL041_CHANNLE_RIGHT_DAC; - _cfg.vol = 50; - _cfg.rate = 8000; - - ac97_reset(); - aaci_pl041_channle_cfg(0, &_cfg); - aaci_pl041_irq_register(0, rt_hw_aaci_isr, RT_NULL); - - return RT_EOK; -} - -static rt_err_t codec_open(rt_device_t dev, rt_uint16_t oflag) -{ - return RT_EOK; -} - -static rt_err_t codec_close(rt_device_t dev) -{ - rt_uint16_t temp = 0, i = 1024 * 10; - - while (PL041->sr1 & AACI_SR_TXB); - while (i) - { - if (aaci_pl041_channle_write(0, &temp, 1) != 0) - { - i--; - } - } - return RT_EOK; -} - -static rt_size_t codec_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) -{ - return 0; -} - -static rt_size_t codec_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) -{ - _audio_buff_push(audio_buff, (void *)buffer, size); - - if (irq_flag == 0) - { - //open irq - irq_flag = 1; - aaci_pl041_channle_enable(0); - aaci_pl041_irq_enable(0, AACI_IE_UR | AACI_IE_TX | AACI_IE_TXC); - } - return 0; -} - -static rt_err_t codec_control(rt_device_t dev, int cmd, void *args) -{ - rt_err_t result = RT_EOK; - - switch (cmd) - { - case CODEC_CMD_RESET: - { - break; - } - case CODEC_CMD_SET_VOLUME: - { - uint32_t v; - - v = *(rt_uint32_t *)args; - result = ac97_set_vol(v); - break; - } - case CODEC_CMD_GET_VOLUME: - { - int *v = args; - *v = ac97_get_vol(); - break; - } - case CODEC_CMD_SAMPLERATE: - { - int v; - - v = *(rt_uint32_t *)args; - ac97_set_rate(v); - break; - } - - default: - result = RT_ERROR; - } - - return result; -} - -#ifdef RT_USING_DEVICE_OPS -const static struct rt_device_ops codec_ops = -{ - codec_init, - codec_open, - codec_close, - codec_read, - codec_write, - codec_control -}; -#endif - -int audio_hw_init(void) -{ - struct audio_device *codec = &audio_device_drive; - - codec->parent.type = RT_Device_Class_Sound; - codec->parent.rx_indicate = RT_NULL; - codec->parent.tx_complete = RT_NULL; - -#ifdef RT_USING_DEVICE_OPS - codec->parent.ops = &codec_ops; -#else - codec->parent.init = codec_init; - codec->parent.open = codec_open; - codec->parent.close = codec_close; - codec->parent.read = codec_read; - codec->parent.write = codec_write; - codec->parent.control = codec_control; -#endif - - codec->parent.user_data = RT_NULL; - - audio_buff = rt_malloc(sizeof(struct audio_buff_des) + sizeof(struct codec_data_node) * DATA_NODE_MAX); - if (audio_buff == RT_NULL) - { - rt_kprintf("audio buff malloc fail\n"); - return -1; - } - rt_memset(audio_buff, 0, sizeof(struct audio_buff_des) + sizeof(struct codec_data_node) * DATA_NODE_MAX); - audio_buff->data_list = (struct codec_data_node *)((rt_uint8_t *)audio_buff + sizeof(struct audio_buff_des)); - audio_buff->free_fun = _audio_buff_cb; - audio_buff->node_num = DATA_NODE_MAX; - /* register the device */ - rt_device_register(&codec->parent, "sound", RT_DEVICE_FLAG_WRONLY | RT_DEVICE_FLAG_DMA_TX); - - aaci_pl041_init(); - rt_device_init(&codec->parent); - - return 0; -} -INIT_DEVICE_EXPORT(audio_hw_init); diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h b/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h deleted file mode 100644 index b2c07b40e4..0000000000 --- a/bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h +++ /dev/null @@ -1,29 +0,0 @@ -/* - * File : drv_audio.h - * This file is part of RT-Thread RTOS - * COPYRIGHT (C) 2017, RT-Thread Development Team - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Change Logs: - * Date Author Notes - * 2018-05-26 RT-Thread the first version - */ - -#ifndef __DRV_AUDIO_H__ -#define __DRV_AUDIO_H__ - - -#endif diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c b/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c index 51cf3710ef..0b1ee9827d 100644 --- a/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c +++ b/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c @@ -302,7 +302,7 @@ static void aaci_pl041_irq_handle(int irqno, void *param) void *p_status; mask = PL041_READ(&PL041->allints); - PL041_WRITE(PL041->intclr, mask); + PL041_WRITE(&PL041->intclr, mask); for (channle = 0; (channle < PL041_CHANNLE_NUM) && (mask); channle++) { diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h b/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h index d0bacd8c61..5ea146e436 100644 --- a/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h +++ b/bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h @@ -225,7 +225,7 @@ typedef void (*pl041_irq_fun_t)(rt_uint32_t status, void * user_data); rt_err_t aaci_pl041_init(void); void aaci_ac97_write(rt_uint16_t reg, rt_uint16_t val); rt_uint16_t aaci_ac97_read(rt_uint16_t reg); -int aaci_pl041_channle_cfg(int channle, pl041_cfg_t cgf); +int aaci_pl041_channle_cfg(int channle, pl041_cfg_t cfg); int aaci_pl041_channle_write(int channle, rt_uint16_t *buff, int count); int aaci_pl041_channle_read(int channle, rt_uint16_t *buff, int count); int aaci_pl041_channle_enable(int channle); diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c b/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c new file mode 100644 index 0000000000..026008708c --- /dev/null +++ b/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c @@ -0,0 +1,340 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2019-07-23 Zero-Free first implementation + */ + +#include +#include + +#include +#include +#include + +#define DBG_TAG "drv.sound" +#define DBG_LVL DBG_INFO +#include + +#define TX_FIFO_SIZE (3840) + +struct sound_device +{ + struct rt_audio_device audio; + struct rt_audio_configure replay_config; + rt_uint8_t *tx_fifo; + rt_uint8_t volume; +}; + +static struct sound_device snd_dev = {0}; + +static void rt_hw_aaci_isr(rt_uint32_t status, void *user_data) +{ + if (status & AACI_SR_TXHE) + { + rt_audio_tx_complete(&snd_dev.audio); + } +} + +static rt_err_t sound_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + struct sound_device *snd_dev; + + RT_ASSERT(audio != RT_NULL); + snd_dev = (struct sound_device *)audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_QUERY: /* qurey the types of hw_codec device */ + { + switch (caps->sub_type) + { + case AUDIO_TYPE_QUERY: + caps->udata.mask = AUDIO_TYPE_OUTPUT | AUDIO_TYPE_MIXER; + break; + + default: + result = -RT_ERROR; + break; + } + + break; + } + + case AUDIO_TYPE_OUTPUT: /* Provide capabilities of OUTPUT unit */ + { + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + caps->udata.config.samplerate = snd_dev->replay_config.samplerate; + caps->udata.config.channels = snd_dev->replay_config.channels; + caps->udata.config.samplebits = snd_dev->replay_config.samplebits; + break; + + case AUDIO_DSP_SAMPLERATE: + caps->udata.config.samplerate = snd_dev->replay_config.samplerate; + break; + + case AUDIO_DSP_CHANNELS: + caps->udata.config.channels = snd_dev->replay_config.channels; + break; + + case AUDIO_DSP_SAMPLEBITS: + caps->udata.config.samplebits = snd_dev->replay_config.samplebits; + break; + + default: + result = -RT_ERROR; + break; + } + + break; + } + + case AUDIO_TYPE_MIXER: /* report the Mixer Units */ + { + switch (caps->sub_type) + { + case AUDIO_MIXER_QUERY: + caps->udata.mask = AUDIO_MIXER_VOLUME; + break; + + case AUDIO_MIXER_VOLUME: + caps->udata.value = snd_dev->volume; + break; + + default: + result = -RT_ERROR; + break; + } + + break; + } + + default: + result = -RT_ERROR; + break; + } + + return result; +} + +static rt_err_t sound_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps) +{ + rt_err_t result = RT_EOK; + struct sound_device *snd_dev; + struct rt_audio_replay *replay; + + RT_ASSERT(audio != RT_NULL); + snd_dev = (struct sound_device *)audio->parent.user_data; + + switch (caps->main_type) + { + case AUDIO_TYPE_MIXER: + { + switch (caps->sub_type) + { + case AUDIO_MIXER_VOLUME: + { + rt_uint8_t volume = caps->udata.value; + + snd_dev->volume = volume; + ac97_set_vol(volume); + LOG_I("set volume %d", volume); + break; + } + + default: + result = -RT_ERROR; + break; + } + + break; + } + + case AUDIO_TYPE_OUTPUT: + { + switch (caps->sub_type) + { + case AUDIO_DSP_PARAM: + { + /* set samplerate */ + ac97_set_rate(caps->udata.config.samplerate); + + /* update buffer fifo informaition according samplerate */ + replay = snd_dev->audio.replay; + replay->buf_info.total_size = caps->udata.config.samplerate / 50 * 4; + replay->buf_info.block_size = replay->buf_info.total_size / 2; + + /* save configs */ + snd_dev->replay_config.samplerate = caps->udata.config.samplerate; + snd_dev->replay_config.channels = caps->udata.config.channels; + snd_dev->replay_config.samplebits = caps->udata.config.samplebits; + LOG_D("set samplerate %d", snd_dev->replay_config.samplerate); + break; + } + + case AUDIO_DSP_SAMPLERATE: + { + ac97_set_rate(caps->udata.config.samplerate); + + snd_dev->replay_config.samplerate = caps->udata.config.samplerate; + LOG_D("set samplerate %d", snd_dev->replay_config.samplerate); + break; + } + + case AUDIO_DSP_CHANNELS: + { + /* not support */ + snd_dev->replay_config.channels = caps->udata.config.channels; + LOG_D("set channels %d", snd_dev->replay_config.channels); + break; + } + + case AUDIO_DSP_SAMPLEBITS: + { + /* not support */ + snd_dev->replay_config.samplebits = caps->udata.config.samplebits; + break; + } + + default: + result = -RT_ERROR; + break; + } + + break; + } + + default: + break; + } + + return result; +} + +static rt_err_t sound_init(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + struct sound_device *snd_dev; + struct pl041_cfg _cfg; + + RT_ASSERT(audio != RT_NULL); + snd_dev = (struct sound_device *)audio->parent.user_data; + + aaci_pl041_init(); + + _cfg.itype = PL041_CHANNLE_LEFT_ADC | PL041_CHANNLE_RIGHT_ADC; + _cfg.otype = PL041_CHANNLE_LEFT_DAC | PL041_CHANNLE_RIGHT_DAC; + _cfg.vol = snd_dev->volume; + _cfg.rate = snd_dev->replay_config.samplerate; + + ac97_reset(); + aaci_pl041_channle_cfg(0, &_cfg); + aaci_pl041_irq_register(0, rt_hw_aaci_isr, RT_NULL); + + return result; +} + +static rt_err_t sound_start(struct rt_audio_device *audio, int stream) +{ + RT_ASSERT(audio != RT_NULL); + + if (stream == AUDIO_STREAM_REPLAY) + { + LOG_D("open sound device"); + aaci_pl041_channle_enable(0); + aaci_pl041_irq_enable(0, AACI_IE_UR | AACI_IE_TX | AACI_IE_TXC); + } + + return RT_EOK; +} + +static rt_err_t sound_stop(struct rt_audio_device *audio, int stream) +{ + RT_ASSERT(audio != RT_NULL); + + if (stream == AUDIO_STREAM_REPLAY) + { + /* wait codec free */ + rt_thread_mdelay(100); + /* disable irq and channels 0 */ + aaci_pl041_irq_disable(0, AACI_IE_UR | AACI_IE_TX | AACI_IE_TXC); + aaci_pl041_channle_disable(0); + LOG_D("close sound device"); + } + + return RT_EOK; +} + +static void sound_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info) +{ + struct sound_device *snd_dev; + + RT_ASSERT(audio != RT_NULL); + snd_dev = (struct sound_device *)audio->parent.user_data; + + /** + * TX_FIFO + * +----------------+----------------+ + * | block1 | block2 | + * +----------------+----------------+ + * \ block_size / + */ + info->buffer = snd_dev->tx_fifo; + info->total_size = TX_FIFO_SIZE; + info->block_size = TX_FIFO_SIZE/2; + info->block_count = 2; +} + +static rt_size_t sound_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size) +{ + RT_ASSERT(audio != RT_NULL); + + /* write data to channel_0 fifo */ + aaci_pl041_channle_write(0, (rt_uint16_t *)writeBuf, size >> 1); + + return size; +} + +static struct rt_audio_ops snd_ops = +{ + .getcaps = sound_getcaps, + .configure = sound_configure, + .init = sound_init, + .start = sound_start, + .stop = sound_stop, + .transmit = sound_transmit, + .buffer_info = sound_buffer_info, +}; + +int rt_hw_audio_init(void) +{ + rt_uint8_t *tx_fifo; + + if (snd_dev.tx_fifo) + return RT_EOK; + + tx_fifo = rt_malloc(TX_FIFO_SIZE); + if (tx_fifo == RT_NULL) + return -RT_ENOMEM; + rt_memset(tx_fifo, 0, TX_FIFO_SIZE); + snd_dev.tx_fifo = tx_fifo; + + /* init default configuration */ + { + snd_dev.replay_config.samplerate = 44100; + snd_dev.replay_config.channels = 2; + snd_dev.replay_config.samplebits = 16; + snd_dev.volume = 55; + } + + /* register sound device */ + snd_dev.audio.ops = &snd_ops; + rt_audio_register(&snd_dev.audio, "sound0", RT_DEVICE_FLAG_WRONLY, &snd_dev); + + return RT_EOK; +} + +INIT_DEVICE_EXPORT(rt_hw_audio_init); diff --git a/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h b/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h new file mode 100644 index 0000000000..b7e880c9a7 --- /dev/null +++ b/bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h @@ -0,0 +1,13 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * + * Date Author Notes + * 2019-07-23 Zero-Free first implementation + */ + +#ifndef __DRV_SOUND_H__ +#define __DRV_SOUND_H__ + +int rt_hw_audio_init(void); + +#endif diff --git a/bsp/qemu-vexpress-a9/drivers/audio/wav_play.c b/bsp/qemu-vexpress-a9/drivers/audio/wav_play.c deleted file mode 100644 index c000a0b085..0000000000 --- a/bsp/qemu-vexpress-a9/drivers/audio/wav_play.c +++ /dev/null @@ -1,144 +0,0 @@ -#include -#include -#include - -#include -#include -#include - -#include "audio_device.h" - -#define BUFSZ 2048 - -struct RIFF_HEADER_DEF -{ - char riff_id[4]; // 'R','I','F','F' - uint32_t riff_size; - char riff_format[4]; // 'W','A','V','E' -}; - -struct WAVE_FORMAT_DEF -{ - uint16_t FormatTag; - uint16_t Channels; - uint32_t SamplesPerSec; - uint32_t AvgBytesPerSec; - uint16_t BlockAlign; - uint16_t BitsPerSample; -}; - -struct FMT_BLOCK_DEF -{ - char fmt_id[4]; // 'f','m','t',' ' - uint32_t fmt_size; - struct WAVE_FORMAT_DEF wav_format; -}; - -struct DATA_BLOCK_DEF -{ - char data_id[4]; // 'R','I','F','F' - uint32_t data_size; -}; - -struct wav_info -{ - struct RIFF_HEADER_DEF header; - struct FMT_BLOCK_DEF fmt_block; - struct DATA_BLOCK_DEF data_block; -}; - -static char file_name[32]; - -void wavplay_thread_entry(void *parameter) -{ - FILE *fp = NULL; - uint16_t *buffer = NULL; - struct wav_info *info = NULL; - - fp = fopen(file_name, "rb"); - if (!fp) - { - printf("open file failed!\n"); - goto __exit; - } - - info = (struct wav_info *) malloc(sizeof(*info)); - if (!info) goto __exit; - - if (fread(&(info->header), sizeof(struct RIFF_HEADER_DEF), 1, fp) != 1) goto __exit; - if (fread(&(info->fmt_block), sizeof(struct FMT_BLOCK_DEF), 1, fp) != 1) goto __exit; - if (fread(&(info->data_block), sizeof(struct DATA_BLOCK_DEF), 1, fp) != 1) goto __exit; - - printf("wav information:\n"); - printf("samplerate %u\n", info->fmt_block.wav_format.SamplesPerSec); - printf("channel %u\n", info->fmt_block.wav_format.Channels); - - audio_device_init(); - audio_device_open(); - audio_device_set_rate(info->fmt_block.wav_format.SamplesPerSec); - - while (!feof(fp)) - { - int length; - - buffer = (uint16_t *)audio_device_get_buffer(RT_NULL); - - length = fread(buffer, 1, BUFSZ, fp); - if (length) - { - if (info->fmt_block.wav_format.Channels == 1) - { - /* extend to stereo channels */ - int index; - uint16_t *ptr; - - ptr = (uint16_t *)((uint8_t *)buffer + BUFSZ * 2); - for (index = 1; index < BUFSZ / 2; index ++) - { - *ptr = *(ptr - 1) = buffer[BUFSZ / 2 - index]; - ptr -= 2; - } - - length = length * 2; - } - - audio_device_write((uint8_t *)buffer, length); - } - else - { - audio_device_put_buffer((uint8_t *)buffer); - break; - } - } - audio_device_close(); - -__exit: - if (fp) fclose(fp); - if (info) free(info); -} - -int wavplay(int argc, char **argv) -{ - rt_thread_t tid = RT_NULL; - - if (argc != 2) - { - printf("Usage:\n"); - printf("wavplay song.wav\n"); - return 0; - } - - memset(file_name, 0, sizeof(file_name)); - memcpy(file_name, argv[1], strlen(argv[1])); - - tid = rt_thread_create("wayplay", - wavplay_thread_entry, - RT_NULL, - 1024 * 8, - 22, - 10); - if (tid != RT_NULL) - rt_thread_startup(tid); -} - -MSH_CMD_EXPORT(wavplay, wavplay song.wav);