Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
BaiXuePrincess
rt-thread
提交
bc544bec
R
rt-thread
项目概览
BaiXuePrincess
/
rt-thread
与 Fork 源项目一致
Fork自
RT-Thread / rt-thread
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rt-thread
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
bc544bec
编写于
5月 29, 2018
作者:
还_没_想_好
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[bsp][qemu]添加Audio驱动
上级
6a1e8d56
变更
12
隐藏空白更改
内联
并排
Showing
12 changed file
with
1584 addition
and
3 deletion
+1584
-3
bsp/qemu-vexpress-a9/drivers/Kconfig
bsp/qemu-vexpress-a9/drivers/Kconfig
+5
-0
bsp/qemu-vexpress-a9/drivers/SConscript
bsp/qemu-vexpress-a9/drivers/SConscript
+11
-3
bsp/qemu-vexpress-a9/drivers/audio/SConscript
bsp/qemu-vexpress-a9/drivers/audio/SConscript
+9
-0
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
+191
-0
bsp/qemu-vexpress-a9/drivers/audio/audio_device.h
bsp/qemu-vexpress-a9/drivers/audio/audio_device.h
+51
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.c
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.c
+121
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.h
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.h
+63
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c
+312
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
+29
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c
+411
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
+237
-0
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
+144
-0
未找到文件。
bsp/qemu-vexpress-a9/drivers/Kconfig
浏览文件 @
bc544bec
...
...
@@ -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
bsp/qemu-vexpress-a9/drivers/SConscript
浏览文件 @
bc544bec
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'
)
bsp/qemu-vexpress-a9/drivers/audio/SConscript
0 → 100644
浏览文件 @
bc544bec
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'
)
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
0 → 100644
浏览文件 @
bc544bec
/*
* 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
;
}
bsp/qemu-vexpress-a9/drivers/audio/audio_device.h
0 → 100644
浏览文件 @
bc544bec
/*
* 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
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.c
0 → 100644
浏览文件 @
bc544bec
/*
* 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
bsp/qemu-vexpress-a9/drivers/audio/drv_ac97.h
0 → 100644
浏览文件 @
bc544bec
/*
* 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
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c
0 → 100644
浏览文件 @
bc544bec
/*
* 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 <rtthread.h>
#include <rthw.h>
#include <rtdevice.h>
#include <string.h>
#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
;
}
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
;
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
;
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
);
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
0 → 100644
浏览文件 @
bc544bec
/*
* 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
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c
0 → 100644
浏览文件 @
bc544bec
/*
* File : drv_pl041.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"
#include "realview.h"
#define DBG_ENABLE
#define DBG_SECTION_NAME "[PL041]"
// #define DBG_LEVEL DBG_LOG
// #define DBG_LEVEL DBG_INFO
#define DBG_LEVEL DBG_WARNING
// #define DBG_LEVEL DBG_ERROR
#define DBG_COLOR
#include <rtdbg.h>
#define FRAME_PERIOD_US (50)
#define PL041_CHANNLE_NUM (4)
#define PL041_READ(_a) (*(volatile rt_uint32_t *)(_a))
#define PL041_WRITE(_a, _v) (*(volatile rt_uint32_t *)(_a) = (_v))
struct
pl041_irq_def
{
pl041_irq_fun_t
fun
;
void
*
user_data
;
};
static
struct
pl041_irq_def
irq_tbl
[
PL041_CHANNLE_NUM
];
static
void
aaci_pl041_delay
(
rt_uint32_t
us
)
{
volatile
int
i
;
for
(
i
=
us
*
10
;
i
!=
0
;
i
--
);
}
static
void
aaci_ac97_select_codec
(
void
)
{
rt_uint32_t
v
,
maincr
;
maincr
=
AACI_MAINCR_SCRA
(
0
)
|
AACI_MAINCR_IE
|
AACI_MAINCR_SL1RXEN
|
\
AACI_MAINCR_SL1TXEN
|
AACI_MAINCR_SL2RXEN
|
AACI_MAINCR_SL2TXEN
;
v
=
PL041_READ
(
&
PL041
->
slfr
);
if
(
v
&
AACI_SLFR_2RXV
)
{
PL041_READ
(
&
PL041
->
sl2rx
);
}
if
(
v
&
AACI_SLFR_1RXV
)
{
PL041_READ
(
&
PL041
->
sl1rx
);
}
if
(
maincr
!=
PL041_READ
(
&
PL041
->
maincr
))
{
PL041_WRITE
(
&
PL041
->
maincr
,
maincr
);
aaci_pl041_delay
(
1
);
}
}
void
aaci_ac97_write
(
rt_uint16_t
reg
,
rt_uint16_t
val
)
{
rt_uint32_t
v
,
timeout
;
aaci_ac97_select_codec
();
PL041_WRITE
(
&
PL041
->
sl2tx
,
val
<<
4
);
PL041_WRITE
(
&
PL041
->
sl1tx
,
reg
<<
12
);
aaci_pl041_delay
(
FRAME_PERIOD_US
);
timeout
=
FRAME_PERIOD_US
*
8
;
do
{
aaci_pl041_delay
(
1
);
v
=
PL041_READ
(
&
PL041
->
slfr
);
}
while
((
v
&
(
AACI_SLFR_1TXB
|
AACI_SLFR_2TXB
))
&&
--
timeout
);
if
(
v
&
(
AACI_SLFR_1TXB
|
AACI_SLFR_2TXB
))
{
dbg_log
(
DBG_ERROR
,
"timeout waiting for write to complete
\n
"
);
}
}
rt_uint16_t
aaci_ac97_read
(
rt_uint16_t
reg
)
{
rt_uint32_t
v
,
timeout
,
retries
=
10
;
aaci_ac97_select_codec
();
PL041_WRITE
(
&
PL041
->
sl1tx
,
(
reg
<<
12
)
|
(
1
<<
19
));
aaci_pl041_delay
(
FRAME_PERIOD_US
);
timeout
=
FRAME_PERIOD_US
*
8
;
do
{
aaci_pl041_delay
(
1
);
v
=
PL041_READ
(
&
PL041
->
slfr
);
}
while
((
v
&
AACI_SLFR_1TXB
)
&&
--
timeout
);
if
(
v
&
AACI_SLFR_1TXB
)
{
dbg_log
(
DBG_ERROR
,
"timeout on slot 1 TX busy
\n
"
);
v
=
~
0x0
;
return
v
;
}
aaci_pl041_delay
(
FRAME_PERIOD_US
);
timeout
=
FRAME_PERIOD_US
*
8
;
do
{
aaci_pl041_delay
(
1
);
v
=
PL041_READ
(
&
PL041
->
slfr
)
&
(
AACI_SLFR_1RXV
|
AACI_SLFR_2RXV
);
}
while
((
v
!=
(
AACI_SLFR_1RXV
|
AACI_SLFR_2RXV
))
&&
--
timeout
);
if
(
v
!=
(
AACI_SLFR_1RXV
|
AACI_SLFR_2RXV
))
{
dbg_log
(
DBG_ERROR
,
"timeout on RX valid
\n
"
);
v
=
~
0x0
;
return
v
;
}
do
{
v
=
PL041_READ
(
&
PL041
->
sl1rx
)
>>
12
;
if
(
v
==
reg
)
{
v
=
PL041_READ
(
&
PL041
->
sl2rx
)
>>
4
;
break
;
}
else
if
(
--
retries
)
{
dbg_log
(
DBG_ERROR
,
"ac97 read back fail. retry
\n
"
);
continue
;
}
else
{
dbg_log
(
DBG_ERROR
,
"wrong ac97 register read back (%x != %x)
\n
"
,
v
,
reg
);
v
=
~
0x0
;
}
}
while
(
retries
);
return
v
;
}
int
aaci_pl041_channle_disable
(
int
channle
)
{
rt_uint32_t
v
;
void
*
p_rx
,
*
p_tx
;
p_rx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
rxcr1
)
+
channle
*
0x14
);
p_tx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
txcr1
)
+
channle
*
0x14
);
v
=
PL041_READ
(
p_rx
);
v
&=
~
AACI_CR_EN
;
PL041_WRITE
(
p_rx
,
v
);
v
=
PL041_READ
(
p_tx
);
v
&=
~
AACI_CR_EN
;
PL041_WRITE
(
p_tx
,
v
);
return
0
;
}
int
aaci_pl041_channle_enable
(
int
channle
)
{
rt_uint32_t
v
;
void
*
p_rx
,
*
p_tx
;
p_rx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
rxcr1
)
+
channle
*
0x14
);
p_tx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
txcr1
)
+
channle
*
0x14
);
v
=
PL041_READ
(
p_rx
);
v
|=
AACI_CR_EN
;
PL041_WRITE
(
p_rx
,
v
);
v
=
PL041_READ
(
p_tx
);
v
|=
AACI_CR_EN
;
PL041_WRITE
(
p_tx
,
v
);
return
0
;
}
int
aaci_pl041_channle_read
(
int
channle
,
rt_uint16_t
*
buff
,
int
count
)
{
void
*
p_data
,
*
p_status
;
int
i
=
0
;
p_status
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
sr1
)
+
channle
*
0x14
);
p_data
=
(
void
*
)((
rt_uint32_t
)(
&
(
PL041
->
dr1
[
0
]))
+
channle
*
0x20
);
for
(
i
=
0
;
(
!
(
PL041_READ
(
p_status
)
&
AACI_SR_RXFE
))
&&
(
i
<
count
);
i
++
)
{
buff
[
i
]
=
(
rt_uint16_t
)
PL041_READ
(
p_data
);
}
return
i
;
}
int
aaci_pl041_channle_write
(
int
channle
,
rt_uint16_t
*
buff
,
int
count
)
{
void
*
p_data
,
*
p_status
;
int
i
=
0
;
p_status
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
sr1
)
+
channle
*
0x14
);
p_data
=
(
void
*
)((
rt_uint32_t
)(
&
(
PL041
->
dr1
[
0
]))
+
channle
*
0x20
);
for
(
i
=
0
;
(
!
(
PL041_READ
(
p_status
)
&
AACI_SR_TXFF
))
&&
(
i
<
count
);
i
++
)
{
PL041_WRITE
(
p_data
,
buff
[
i
]);
}
return
i
;
}
int
aaci_pl041_channle_cfg
(
int
channle
,
pl041_cfg_t
cgf
)
{
rt_uint32_t
v
;
void
*
p_rx
,
*
p_tx
;
p_rx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
rxcr1
)
+
channle
*
0x14
);
p_tx
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
txcr1
)
+
channle
*
0x14
);
v
=
AACI_CR_FEN
|
AACI_CR_SZ16
|
cgf
->
itype
;
PL041_WRITE
(
p_rx
,
v
);
v
=
AACI_CR_FEN
|
AACI_CR_SZ16
|
cgf
->
otype
;
PL041_WRITE
(
p_tx
,
v
);
ac97_set_vol
(
cgf
->
vol
);
ac97_set_rate
(
cgf
->
rate
);
return
0
;
}
void
aaci_pl041_irq_enable
(
int
channle
,
rt_uint32_t
vector
)
{
rt_uint32_t
v
;
void
*
p_irq
;
vector
&=
vector
&
0x7f
;
p_irq
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
iie1
)
+
channle
*
0x14
);
v
=
PL041_READ
(
p_irq
);
v
|=
vector
;
PL041_WRITE
(
p_irq
,
v
);
}
void
aaci_pl041_irq_disable
(
int
channle
,
rt_uint32_t
vector
)
{
rt_uint32_t
v
;
void
*
p_irq
;
vector
&=
vector
&
0x7f
;
p_irq
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
iie1
)
+
channle
*
0x14
);
v
=
PL041_READ
(
p_irq
);
v
&=
~
vector
;
PL041_WRITE
(
p_irq
,
v
);
}
rt_err_t
aaci_pl041_irq_register
(
int
channle
,
pl041_irq_fun_t
fun
,
void
*
user_data
)
{
if
(
channle
<
0
||
channle
>=
PL041_CHANNLE_NUM
)
{
dbg_log
(
DBG_ERROR
,
"%s channle:%d err.
\n
"
,
__FUNCTION__
,
channle
);
return
-
RT_ERROR
;
}
irq_tbl
[
channle
].
fun
=
fun
;
irq_tbl
[
channle
].
user_data
=
user_data
;
return
RT_EOK
;
}
rt_err_t
aaci_pl041_irq_unregister
(
int
channle
)
{
if
(
channle
<
0
||
channle
>=
PL041_CHANNLE_NUM
)
{
dbg_log
(
DBG_ERROR
,
"%s channle:%d err.
\n
"
,
__FUNCTION__
,
channle
);
return
-
RT_ERROR
;
}
irq_tbl
[
channle
].
fun
=
RT_NULL
;
irq_tbl
[
channle
].
user_data
=
RT_NULL
;
return
RT_EOK
;
}
static
void
aaci_pl041_irq_handle
(
int
irqno
,
void
*
param
)
{
rt_uint32_t
mask
,
channle
,
m
;
struct
pl041_irq_def
*
_irq
=
param
;
void
*
p_status
;
mask
=
PL041_READ
(
&
PL041
->
allints
);
PL041_WRITE
(
PL041
->
intclr
,
mask
);
for
(
channle
=
0
;
(
channle
<
PL041_CHANNLE_NUM
)
&&
(
mask
);
channle
++
)
{
mask
=
mask
>>
7
;
m
=
mask
&
0x7f
;
if
(
m
&
AACI_ISR_ORINTR
)
{
dbg_log
(
DBG_WARNING
,
"RX overrun on chan %d
\n
"
,
channle
);
}
if
(
m
&
AACI_ISR_RXTOINTR
)
{
dbg_log
(
DBG_WARNING
,
"RX timeout on chan %d
\n
"
,
channle
);
}
if
(
mask
&
AACI_ISR_URINTR
)
{
dbg_log
(
DBG_WARNING
,
"TX underrun on chan %d
\n
"
,
channle
);
}
p_status
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
sr1
)
+
channle
*
0x14
);
if
(
_irq
[
channle
].
fun
!=
RT_NULL
)
{
_irq
[
channle
].
fun
(
PL041_READ
(
p_status
),
_irq
[
channle
].
user_data
);
}
}
}
rt_err_t
aaci_pl041_init
(
void
)
{
rt_uint32_t
i
,
maincr
;
maincr
=
AACI_MAINCR_SCRA
(
0
)
|
AACI_MAINCR_IE
|
AACI_MAINCR_SL1RXEN
|
\
AACI_MAINCR_SL1TXEN
|
AACI_MAINCR_SL2RXEN
|
AACI_MAINCR_SL2TXEN
;
for
(
i
=
0
;
i
<
4
;
i
++
)
{
void
*
base
=
(
void
*
)((
rt_uint32_t
)(
&
PL041
->
rxcr1
)
+
i
*
0x14
);
PL041_WRITE
(
base
+
AACI_IE
,
0
);
PL041_WRITE
(
base
+
AACI_TXCR
,
0
);
PL041_WRITE
(
base
+
AACI_RXCR
,
0
);
}
PL041_WRITE
(
&
PL041
->
intclr
,
0x1fff
);
PL041_WRITE
(
&
PL041
->
maincr
,
maincr
);
PL041_WRITE
(
&
PL041
->
reset
,
0
);
aaci_pl041_delay
(
2
);
PL041_WRITE
(
&
PL041
->
reset
,
RESET_NRST
);
rt_hw_interrupt_install
(
43
,
aaci_pl041_irq_handle
,
&
irq_tbl
,
"aaci_pl041"
);
rt_hw_interrupt_umask
(
43
);
return
0
;
}
#if 0
#define PL041_DUMP(_v) rt_kprintf("%32s:addr:0x%08x data:0x%08x\n", #_v, &(_v), (_v))
int _aaci_pl041_reg_dump(int argc, char **argv)
{
PL041_DUMP(PL041->rxcr1);
PL041_DUMP(PL041->txcr1);
PL041_DUMP(PL041->sr1);
PL041_DUMP(PL041->isr1);
PL041_DUMP(PL041->iie1);
PL041_DUMP(PL041->rxcr2);
PL041_DUMP(PL041->txcr2);
PL041_DUMP(PL041->sr2);
PL041_DUMP(PL041->isr2);
PL041_DUMP(PL041->iie2);
PL041_DUMP(PL041->rxcr3);
PL041_DUMP(PL041->txcr3);
PL041_DUMP(PL041->sr3);
PL041_DUMP(PL041->isr3);
PL041_DUMP(PL041->iie3);
PL041_DUMP(PL041->rxcr4);
PL041_DUMP(PL041->txcr4);
PL041_DUMP(PL041->sr4);
PL041_DUMP(PL041->isr4);
PL041_DUMP(PL041->iie4);
PL041_DUMP(PL041->sl1rx);
PL041_DUMP(PL041->sl1tx);
PL041_DUMP(PL041->sl2rx);
PL041_DUMP(PL041->sl2tx);
PL041_DUMP(PL041->sl12rx);
PL041_DUMP(PL041->sl12tx);
PL041_DUMP(PL041->slfr);
PL041_DUMP(PL041->slistat);
PL041_DUMP(PL041->slien);
PL041_DUMP(PL041->intclr);
PL041_DUMP(PL041->maincr);
PL041_DUMP(PL041->reset);
PL041_DUMP(PL041->sync);
PL041_DUMP(PL041->allints);
PL041_DUMP(PL041->mainfr);
PL041_DUMP(PL041->dr1[0]);
PL041_DUMP(PL041->dr2[0]);
PL041_DUMP(PL041->dr3[0]);
PL041_DUMP(PL041->dr4[0]);
return 0;
}
FINSH_FUNCTION_EXPORT_ALIAS(_aaci_pl041_reg_dump, __cmd_pl041_dump, aaci pl041 dump reg.);
#endif
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
0 → 100644
浏览文件 @
bc544bec
/*
* File : drv_pl041.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_PL041_H__
#define __DRV_PL041_H__
#define PL041_BASE_ADDR (0x10004000)
/* offsets in CTRL_CH */
#define AACI_RXCR 0x00
/* 29 bits Control Rx FIFO */
#define AACI_TXCR 0x04
/* 17 bits Control Tx FIFO */
#define AACI_SR 0x08
/* 12 bits Status */
#define AACI_ISR 0x0C
/* 7 bits Int Status */
#define AACI_IE 0x10
/* 7 bits Int Enable */
/* both for AACI_RXCR and AACI_TXCR */
#define AACI_CR_FEN (1 << 16)
/* fifo enable */
#define AACI_CR_COMPACT (1 << 15)
/* compact mode */
#define AACI_CR_SZ16 (0 << 13)
/* 16 bits */
#define AACI_CR_SZ18 (1 << 13)
/* 18 bits */
#define AACI_CR_SZ20 (2 << 13)
/* 20 bits */
#define AACI_CR_SZ12 (3 << 13)
/* 12 bits */
#define AACI_CR_SL12 (1 << 12)
#define AACI_CR_SL11 (1 << 11)
#define AACI_CR_SL10 (1 << 10)
#define AACI_CR_SL9 (1 << 9)
#define AACI_CR_SL8 (1 << 8)
#define AACI_CR_SL7 (1 << 7)
#define AACI_CR_SL6 (1 << 6)
#define AACI_CR_SL5 (1 << 5)
#define AACI_CR_SL4 (1 << 4)
#define AACI_CR_SL3 (1 << 3)
#define AACI_CR_SL2 (1 << 2)
#define AACI_CR_SL1 (1 << 1)
#define AACI_CR_EN (1 << 0)
/* receive enable */
/* status register bits */
#define AACI_SR_RXTOFE (1 << 11)
/* rx timeout fifo empty */
#define AACI_SR_TXTO (1 << 10)
/* rx timeout fifo nonempty */
#define AACI_SR_TXU (1 << 9)
/* tx underrun */
#define AACI_SR_RXO (1 << 8)
/* rx overrun */
#define AACI_SR_TXB (1 << 7)
/* tx busy */
#define AACI_SR_RXB (1 << 6)
/* rx busy */
#define AACI_SR_TXFF (1 << 5)
/* tx fifo full */
#define AACI_SR_RXFF (1 << 4)
/* rx fifo full */
#define AACI_SR_TXHE (1 << 3)
/* tx fifo half empty */
#define AACI_SR_RXHF (1 << 2)
/* rx fifo half full */
#define AACI_SR_TXFE (1 << 1)
/* tx fifo empty */
#define AACI_SR_RXFE (1 << 0)
/* rx fifo empty */
#define AACI_ISR_RXTOFEINTR (1 << 6)
/* rx fifo empty */
#define AACI_ISR_URINTR (1 << 5)
/* tx underflow */
#define AACI_ISR_ORINTR (1 << 4)
/* rx overflow */
#define AACI_ISR_RXINTR (1 << 3)
/* rx fifo */
#define AACI_ISR_TXINTR (1 << 2)
/* tx fifo intr */
#define AACI_ISR_RXTOINTR (1 << 1)
/* rx timeout */
#define AACI_ISR_TXCINTR (1 << 0)
/* tx complete */
/* interrupt enable */
#define AACI_IE_RXTOIE (1 << 6)
/*rx timeout interrupt enable*/
#define AACI_IE_URIE (1 << 5)
/*Transmit underrun interrupt enable*/
#define AACI_IE_ORIE (1 << 4)
/*Overrun receive interrupt enable*/
#define AACI_IE_RXIE (1 << 3)
/*Receive interrupt enable*/
#define AACI_IE_TXIE (1 << 2)
/*Transmit interrupt enable*/
#define AACI_IE_RXTIE (1 << 1)
/*Receive timeout interrupt enable*/
#define AACI_IE_TXCIE (1 << 0)
/*Transmit complete interrupt enable*/
/* interrupt status */
#define AACI_ISR_RXTOFE (1 << 6)
/* rx timeout fifo empty */
#define AACI_ISR_UR (1 << 5)
/* tx fifo underrun */
#define AACI_ISR_OR (1 << 4)
/* rx fifo overrun */
#define AACI_ISR_RX (1 << 3)
/* rx interrupt status */
#define AACI_ISR_TX (1 << 2)
/* tx interrupt status */
#define AACI_ISR_RXTO (1 << 1)
/* rx timeout */
#define AACI_ISR_TXC (1 << 0)
/* tx complete */
/* interrupt enable */
#define AACI_IE_RXTOFE (1 << 6)
/* rx timeout fifo empty */
#define AACI_IE_UR (1 << 5)
/* tx fifo underrun */
#define AACI_IE_OR (1 << 4)
/* rx fifo overrun */
#define AACI_IE_RX (1 << 3)
/* rx interrupt status */
#define AACI_IE_TX (1 << 2)
/* tx interrupt status */
#define AACI_IE_RXTO (1 << 1)
/* rx timeout */
#define AACI_IE_TXC (1 << 0)
/* tx complete */
/* slot flag register bits */
#define AACI_SLFR_RWIS (1 << 13)
/* raw wake-up interrupt status */
#define AACI_SLFR_RGPIOINTR (1 << 12)
/* raw gpio interrupt */
#define AACI_SLFR_12TXE (1 << 11)
/* slot 12 tx empty */
#define AACI_SLFR_12RXV (1 << 10)
/* slot 12 rx valid */
#define AACI_SLFR_2TXE (1 << 9)
/* slot 2 tx empty */
#define AACI_SLFR_2RXV (1 << 8)
/* slot 2 rx valid */
#define AACI_SLFR_1TXE (1 << 7)
/* slot 1 tx empty */
#define AACI_SLFR_1RXV (1 << 6)
/* slot 1 rx valid */
#define AACI_SLFR_12TXB (1 << 5)
/* slot 12 tx busy */
#define AACI_SLFR_12RXB (1 << 4)
/* slot 12 rx busy */
#define AACI_SLFR_2TXB (1 << 3)
/* slot 2 tx busy */
#define AACI_SLFR_2RXB (1 << 2)
/* slot 2 rx busy */
#define AACI_SLFR_1TXB (1 << 1)
/* slot 1 tx busy */
#define AACI_SLFR_1RXB (1 << 0)
/* slot 1 rx busy */
/* Interrupt clear register */
#define AACI_ICLR_RXTOFEC4 (1 << 12)
/* Receive timeout FIFO empty clear */
#define AACI_ICLR_RXTOFEC3 (1 << 11)
/* Receive timeout FIFO empty clear */
#define AACI_ICLR_RXTOFEC2 (1 << 10)
/* Receive timeout FIFO empty clear */
#define AACI_ICLR_RXTOFEC1 (1 << 9)
/* Receive timeout FIFO empty clear */
#define AACI_ICLR_TXUEC4 (1 << 8)
/* Transmit underrun error clear */
#define AACI_ICLR_TXUEC3 (1 << 7)
/* Transmit underrun error clear */
#define AACI_ICLR_TXUEC2 (1 << 6)
/* Transmit underrun error clear*/
#define AACI_ICLR_TXUEC1 (1 << 5)
/* Transmit underrun error clear */
#define AACI_ICLR_RXOEC4 (1 << 4)
/* Receive overrun error clear */
#define AACI_ICLR_RXOEC3 (1 << 3)
/* Receive overrun error clear */
#define AACI_ICLR_RXOEC2 (1 << 2)
/* Receive overrun error clear */
#define AACI_ICLR_RXOEC1 (1 << 1)
/* Receive overrun error clear */
#define AACI_ICLR_WISC (1 << 0)
/* Wake-up interrupt status clear */
/* Main control register bits AACI_MAINCR */
#define AACI_MAINCR_SCRA(x) ((x) << 10)
/* secondary codec reg access */
#define AACI_MAINCR_DMAEN (1 << 9)
/* dma enable */
#define AACI_MAINCR_SL12TXEN (1 << 8)
/* slot 12 transmit enable */
#define AACI_MAINCR_SL12RXEN (1 << 7)
/* slot 12 receive enable */
#define AACI_MAINCR_SL2TXEN (1 << 6)
/* slot 2 transmit enable */
#define AACI_MAINCR_SL2RXEN (1 << 5)
/* slot 2 receive enable */
#define AACI_MAINCR_SL1TXEN (1 << 4)
/* slot 1 transmit enable */
#define AACI_MAINCR_SL1RXEN (1 << 3)
/* slot 1 receive enable */
#define AACI_MAINCR_LPM (1 << 2)
/* low power mode */
#define AACI_MAINCR_LOOPBK (1 << 1)
/* loopback */
#define AACI_MAINCR_IE (1 << 0)
/* aaci interface enable */
/* Reset register bits. P65 */
#define RESET_NRST (1 << 0)
/* Sync register bits. P65 */
#define SYNC_FORCE (1 << 0)
/* Main flag register bits. P66 */
#define MAINFR_TXB (1 << 1)
/* transmit busy */
#define MAINFR_RXB (1 << 0)
/* receive busy */
#define PL041_CHANNLE_LEFT_DAC (0x1 << 3)
#define PL041_CHANNLE_RIGHT_DAC (0x1 << 3)
#define PL041_CHANNLE_LEFT_ADC (0x1 << 3)
#define PL041_CHANNLE_RIGHT_ADC (0x1 << 3)
struct
reg_pl041
{
volatile
rt_uint32_t
rxcr1
;
/* 0x000 */
volatile
rt_uint32_t
txcr1
;
/* 0x004 */
volatile
rt_uint32_t
sr1
;
/* 0x008 */
volatile
rt_uint32_t
isr1
;
/* 0x00c */
volatile
rt_uint32_t
iie1
;
/* 0x010 */
volatile
rt_uint32_t
rxcr2
;
/* 0x014 */
volatile
rt_uint32_t
txcr2
;
/* 0x018 */
volatile
rt_uint32_t
sr2
;
/* 0x01c */
volatile
rt_uint32_t
isr2
;
/* 0x020 */
volatile
rt_uint32_t
iie2
;
/* 0x024 */
volatile
rt_uint32_t
rxcr3
;
/* 0x028 */
volatile
rt_uint32_t
txcr3
;
/* 0x02c */
volatile
rt_uint32_t
sr3
;
/* 0x030 */
volatile
rt_uint32_t
isr3
;
/* 0x034 */
volatile
rt_uint32_t
iie3
;
/* 0x038 */
volatile
rt_uint32_t
rxcr4
;
/* 0x03c */
volatile
rt_uint32_t
txcr4
;
/* 0x040 */
volatile
rt_uint32_t
sr4
;
/* 0x044 */
volatile
rt_uint32_t
isr4
;
/* 0x048 */
volatile
rt_uint32_t
iie4
;
/* 0x04c */
volatile
rt_uint32_t
sl1rx
;
/* 0x050 */
volatile
rt_uint32_t
sl1tx
;
/* 0x054 */
volatile
rt_uint32_t
sl2rx
;
/* 0x058 */
volatile
rt_uint32_t
sl2tx
;
/* 0x05c */
volatile
rt_uint32_t
sl12rx
;
/* 0x060 */
volatile
rt_uint32_t
sl12tx
;
/* 0x064 */
volatile
rt_uint32_t
slfr
;
/* 0x068 */
volatile
rt_uint32_t
slistat
;
/* 0x06c */
volatile
rt_uint32_t
slien
;
/* 0x070 */
volatile
rt_uint32_t
intclr
;
/* 0x074 */
volatile
rt_uint32_t
maincr
;
/* 0x078 */
volatile
rt_uint32_t
reset
;
/* 0x07c */
volatile
rt_uint32_t
sync
;
/* 0x080 */
volatile
rt_uint32_t
allints
;
/* 0x084 */
volatile
rt_uint32_t
mainfr
;
/* 0x088 */
volatile
rt_uint32_t
res08c
;
volatile
rt_uint32_t
dr1
[
8
];
/* 0x090 */
volatile
rt_uint32_t
dr2
[
8
];
/* 0x0b0 */
volatile
rt_uint32_t
dr3
[
8
];
/* 0x0d0 */
volatile
rt_uint32_t
dr4
[
8
];
/* 0x0f0 */
};
typedef
struct
reg_pl041
*
reg_pl041_t
;
#define PL041 ((reg_pl041_t)PL041_BASE_ADDR)
struct
pl041_cfg
{
rt_uint32_t
itype
;
rt_uint32_t
otype
;
int
vol
;
int
rate
;
};
typedef
struct
pl041_cfg
*
pl041_cfg_t
;
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_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
);
int
aaci_pl041_channle_disable
(
int
channle
);
rt_err_t
aaci_pl041_irq_register
(
int
channle
,
pl041_irq_fun_t
fun
,
void
*
user_data
);
rt_err_t
aaci_pl041_irq_unregister
(
int
channle
);
void
aaci_pl041_irq_disable
(
int
channle
,
rt_uint32_t
vector
);
void
aaci_pl041_irq_enable
(
int
channle
,
rt_uint32_t
vector
);
#endif
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
0 → 100644
浏览文件 @
bc544bec
#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
);
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录