Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
BaiXuePrincess
rt-thread
提交
559e297e
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,发现更多精彩内容 >>
提交
559e297e
编写于
8月 06, 2019
作者:
E
EvalZero
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
[bsp][qemu-vexpress-a9]update qemu-vexpress-a9 audio device drivers.
上级
87267b41
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
355 addition
and
745 deletion
+355
-745
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
+0
-191
bsp/qemu-vexpress-a9/drivers/audio/audio_device.h
bsp/qemu-vexpress-a9/drivers/audio/audio_device.h
+0
-51
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.c
+0
-328
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
+0
-29
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.c
+1
-1
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
+1
-1
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c
+340
-0
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h
+13
-0
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
+0
-144
未找到文件。
bsp/qemu-vexpress-a9/drivers/audio/audio_device.c
已删除
100644 → 0
浏览文件 @
87267b41
/*
* 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
已删除
100644 → 0
浏览文件 @
87267b41
/*
* 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_audio.c
已删除
100644 → 0
浏览文件 @
87267b41
/*
* 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
;
}
#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
);
bsp/qemu-vexpress-a9/drivers/audio/drv_audio.h
已删除
100644 → 0
浏览文件 @
87267b41
/*
* 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
浏览文件 @
559e297e
...
...
@@ -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
++
)
{
...
...
bsp/qemu-vexpress-a9/drivers/audio/drv_pl041.h
浏览文件 @
559e297e
...
...
@@ -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
c
gf
);
int
aaci_pl041_channle_cfg
(
int
channle
,
pl041_cfg_t
c
fg
);
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
);
...
...
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.c
0 → 100644
浏览文件 @
559e297e
/*
* SPDX-License-Identifier: Apache-2.0
*
* Date Author Notes
* 2019-07-23 Zero-Free first implementation
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <drv_sound.h>
#include <drv_pl041.h>
#include <drv_ac97.h>
#define DBG_TAG "drv.sound"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#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
);
bsp/qemu-vexpress-a9/drivers/audio/drv_sound.h
0 → 100644
浏览文件 @
559e297e
/*
* 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
bsp/qemu-vexpress-a9/drivers/audio/wav_play.c
已删除
100644 → 0
浏览文件 @
87267b41
#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.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录