Merge pull request #1481 from enkiller/dev

[bsp][qemu]添加Audio驱动
This commit is contained in:
Bernard Xiong
2018-05-29 12:51:41 +08:00
committed by GitHub
12 changed files with 1584 additions and 3 deletions
+5
View File
@@ -15,3 +15,8 @@ config BSP_DRV_EMAC
bool "EMAC driver"
depends on RT_USING_LWIP
default y
config BSP_DRV_AUDIO
bool "Audio driver"
select RT_USING_AUDIO
default n
+11 -3
View File
@@ -1,8 +1,10 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c')
cwd = GetCurrentDir()
src = Glob('*.c')
list = os.listdir(cwd)
CPPPATH = [cwd]
objs = []
if not GetDepend('BSP_DRV_EMAC'):
SrcRemove(src, ['drv_smc911x.c'])
@@ -12,4 +14,10 @@ if not GetDepend('BSP_DRV_CLCD'):
group = DefineGroup('Drivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
for d in list:
path = os.path.join(cwd, d)
if os.path.isfile(os.path.join(path, 'SConscript')):
objs = objs + SConscript(os.path.join(d, 'SConscript'))
objs = objs + group
Return('objs')
@@ -0,0 +1,9 @@
from building import *
cwd = GetCurrentDir()
src = Glob('*.c') + Glob('*.S')
CPPPATH = [cwd]
group = DefineGroup('drv_audio', src, depend = ['BSP_DRV_AUDIO'], CPPPATH = CPPPATH)
Return('group')
@@ -0,0 +1,191 @@
/*
* 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 <rtthread.h>
#include <rthw.h>
#include <rtdevice.h>
#include <string.h>
#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;
}
@@ -0,0 +1,51 @@
/*
* 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
@@ -0,0 +1,121 @@
/*
* File : drv_ac97.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-25 RT-Thread the first version
*/
#include <rtthread.h>
#include <rthw.h>
#include "drv_pl041.h"
#include "drv_ac97.h"
void ac97_reset(void)
{
aaci_ac97_write(AC97_RESET, 0xFFFF);
}
rt_err_t ac97_set_vol(int vol)
{
rt_uint16_t tmp = vol | (vol << 8);
if (vol < 0 || vol > 0x3f)
{
return -RT_ERROR;
}
aaci_ac97_write(AC97_MASTER, tmp);
aaci_ac97_write(AC97_HEADPHONE, tmp);
aaci_ac97_write(AC97_MASTER_MONO, tmp);
aaci_ac97_write(AC97_PCM, tmp);
return RT_EOK;
}
int ac97_get_vol(void)
{
rt_uint16_t v;
v = aaci_ac97_read(AC97_MASTER);
if (v == (~0x0))
{
v = 0;
}
return 0x3F & v;
}
rt_err_t ac97_set_rate(int rate)
{
if (rate < 0)
{
return -RT_ERROR;
}
aaci_ac97_write(AC97_PCM_FRONT_DAC_RATE, rate);
return 0;
}
int ac97_get_rate(void)
{
rt_uint16_t v;
v = aaci_ac97_read(AC97_PCM_FRONT_DAC_RATE);
if (v == (~0x0))
{
v = 0;
}
return v;
}
#if 0
#define AC97_DUMP(_v) rt_kprintf("%32s:addr:0x%08x data:0x%08x\n", #_v, (_v), (aaci_ac97_read(_v)))
int _ac97_reg_dump(int argc, char **argv)
{
AC97_DUMP(AC97_RESET);
AC97_DUMP(AC97_MASTER);
AC97_DUMP(AC97_HEADPHONE);
AC97_DUMP(AC97_MASTER_MONO);
AC97_DUMP(AC97_MASTER_TONE);
AC97_DUMP(AC97_PC_BEEP);
AC97_DUMP(AC97_PHONE);
AC97_DUMP(AC97_MIC);
AC97_DUMP(AC97_LINE);
AC97_DUMP(AC97_CD);
AC97_DUMP(AC97_VIDEO);
AC97_DUMP(AC97_AUX);
AC97_DUMP(AC97_PCM);
AC97_DUMP(AC97_REC_SEL);
AC97_DUMP(AC97_REC_GAIN);
AC97_DUMP(AC97_REC_GAIN_MIC);
AC97_DUMP(AC97_GENERAL_PURPOSE);
AC97_DUMP(AC97_3D_CONTROL);
AC97_DUMP(AC97_INT_PAGING);
AC97_DUMP(AC97_POWERDOWN);
AC97_DUMP(AC97_PCM_FRONT_DAC_RATE);
AC97_DUMP(AC97_PCM_SURR_DAC_RATE);
AC97_DUMP(AC97_PCM_LFE_DAC_RATE);
AC97_DUMP(AC97_PCM_LR_ADC_RATE);
AC97_DUMP(AC97_PCM_MIC_ADC_RATE);
AC97_DUMP(AC97_DAC_SLOT_MAP);
AC97_DUMP(AC97_ADC_SLOT_MAP);
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(_ac97_reg_dump, __cmd_ac97_dump, ac97 dump reg.);
#endif
@@ -0,0 +1,63 @@
/*
* File : drv_ac97.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-25 RT-Thread the first version
*/
#ifndef __DRV_AC97_H__
#define __DRV_AC97_H__
/* Register offsets */
#define AC97_RESET 0x00
#define AC97_MASTER 0x02
#define AC97_HEADPHONE 0x04
#define AC97_MASTER_MONO 0x06
#define AC97_MASTER_TONE 0x08
#define AC97_PC_BEEP 0x0A //mixer volume
#define AC97_PHONE 0x0C
#define AC97_MIC 0x0E //qwert db
#define AC97_LINE 0x10
#define AC97_CD 0x12
#define AC97_VIDEO 0x14
#define AC97_AUX 0x16
#define AC97_PCM 0x18
#define AC97_REC_SEL 0x1A //0 represent mic
#define AC97_REC_GAIN 0x1C
#define AC97_REC_GAIN_MIC 0x1E
#define AC97_GENERAL_PURPOSE 0x20
#define AC97_3D_CONTROL 0x22
#define AC97_INT_PAGING 0x24 //qwert
#define AC97_POWERDOWN 0x26
#define AC97_PCM_FRONT_DAC_RATE 0x2c /* PCM Front DAC Rate */
#define AC97_PCM_SURR_DAC_RATE 0x2e /* PCM Surround DAC Rate */
#define AC97_PCM_LFE_DAC_RATE 0x30 /* PCM LFE DAC Rate */
#define AC97_PCM_LR_ADC_RATE 0x32 /* PCM LR ADC Rate */
#define AC97_PCM_MIC_ADC_RATE 0x34 /* PCM MIC ADC Rate */
#define AC97_DAC_SLOT_MAP 0x6C
#define AC97_ADC_SLOT_MAP 0x6E
void ac97_reset(void);
rt_err_t ac97_set_vol(int vol);
int ac97_get_vol(void);
rt_err_t ac97_set_rate(int rate);
int ac97_get_rate(void);
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,29 @@
/*
* 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
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,144 @@
#include <rtthread.h>
#include <rtdevice.h>
#include <finsh.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#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);