A10+Android4.0 音频驱动(树莓派II 源码)
linux-3.0目录
make ARCH=arm menuconfig
进到内核配置界面,可以看到
 
知道我们的配置项名字,然后进

目录 :\lichee\linux-3.0\sound\soc 
看Kconfig文件,可以看到

  1. config SOUND_SUN4I
  2. tristate "SOUND driver for sun4i"
  3. depends on ARCH_SUN4I
  4. help
  5. SOUND driver for sun4i
  6. if SOUND_SUN4I
  7. source "sound/soc/sun4i/Kconfig"
  8. source "sound/soc/sun4i/hdmiaudio/Kconfig"
  9. source "sound/soc/sun4i/spdif/Kconfig"
  10. source "sound/soc/sun4i/i2s/Kconfig"
  11. endif

复制代码

它只是打开了下面有关sun4i这个芯片的其他音频项。
所以,A10内置CODEC的驱动主要是在
\lichee\linux-3.0\sound\soc\sun4i
sun4i-codec.c文件
sun4i_codec_probe 入口函数

kernel 层寄存器设置

在Kernel层定义了供amixer命令设置的内容。Kernel层寄存器设置分多种类型。

设备初始化函数sun4i_codec_probe中包含注册控制接口:

snd_chip_codec_mixer_new()它添加控制接口

if ((err =  snd_ctl_add(card, snd_ctl_new1(&codec_snd_controls_b_c[idx],clnt))) < 0) {
        return err;
      }

控制接口control对于许多开关(switch)和调节器(slider)而言应用相当广泛,它能从用户空间被存取。control的最主要用 途是mixer,所有的mixer 元素基于control 内核API 实现,在ALSA 中,control 用snd_kcontrol结构体描述(Y:\lichee\linux-3.0\sound\core\control.c)。

创建一个control,调用snd_ctl_add()和snd_ctl_new1()这两个函数来完成,这两个函数的原型为:

int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol);

struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,void *private_data);

snd_ctl_new1()函数用于创建一个snd_kcontrol 并返回其指针, 
snd_ctl_add()函数用于将创建的snd_kcontrol 添加到对应的card 中。 
A10的android4.0系统里, 创建一个control控制各通道静音开关和音量大小,如下

static const struct snd_kcontrol_new codec_snd_controls_b_c[] = {
  //FOR B C VERSION
  CODEC_SINGLE("Master Playback Volume", SUN4I_DAC_ACTL,0,0x3f,0),
  CODEC_SINGLE("layback Switch", SUN4I_DAC_ACTL,6,1,0),//全局输出开关
  CODEC_SINGLE("Capture Volume",SUN4I_ADC_ACTL,20,7,0),//录音音量
  CODEC_SINGLE("Fm Volume",SUN4I_DAC_ACTL,23,7,0),//Fm 音量
  CODEC_SINGLE("Line Volume",SUN4I_DAC_ACTL,26,1,0),//Line音量
  CODEC_SINGLE("MicL Volume",SUN4I_ADC_ACTL,25,3,0),//mic左音量
  CODEC_SINGLE("MicR Volume",SUN4I_ADC_ACTL,23,3,0),//mic右音量
  CODEC_SINGLE("FmL Switch",SUN4I_DAC_ACTL,17,1,0),//Fm左开关
  CODEC_SINGLE("FmR Switch",SUN4I_DAC_ACTL,16,1,0),//Fm右开关
  CODEC_SINGLE("LineL Switch",SUN4I_DAC_ACTL,19,1,0),//Line左开关
  CODEC_SINGLE("LineR Switch",SUN4I_DAC_ACTL,18,1,0),//Line右开关
  CODEC_SINGLE("Ldac Left Mixer",SUN4I_DAC_ACTL,15,1,0),
  CODEC_SINGLE("Rdac Right Mixer",SUN4I_DAC_ACTL,14,1,0),
  CODEC_SINGLE("Ldac Right Mixer",SUN4I_DAC_ACTL,13,1,0),
  CODEC_SINGLE("Mic Input Mux",SUN4I_DAC_ACTL,9,15,0),//from bit 9 to bit 12.Mic(麦克风)输入静音
  CODEC_SINGLE("ADC Input Mux",SUN4I_ADC_ACTL,17,7,0),//ADC输入静音
};

创建一个新的control 至少需要实现snd_kcontrol_new 中的info()、get()和put()这3 个成员函数
数组codec_snd_controls_b_c[]内容单值元素 
SOC_SINGLE()的 info()、get()、put()成员函数分别为: 
snd_soc_info_volsw ()、snd_soc_get_volsw ()和snd_soc_put_volsw (); 
看原型定义

  1. #define CODEC_SINGLE(xname,  reg,  shift,  max,  invert)\
  2. {  .iface  = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
  3. .info  = snd_codec_info_volsw,  .get = snd_codec_get_volsw,\
  4. .put  = snd_codec_put_volsw,\
  5. .private_value  = CODEC_SINGLE_VALUE(reg, shift, max, invert)
  6. }

复制代码

上面的数据就是分别代表这些意思的
(1) iface 字段定义了control 的类型,形式为SNDRV_CTL_ELEM_IFACE_XXX,通常是MIXER,对于不属于mixer的全局控制,使用CARD。如果关联于某类设 备,则使用HWDEP、 PCM、RAWMIDI、TIMER 或SEQUENCER。 
(2)name 是名称标识字符串,control 的名称非常重要,因为control 的作用由名称来区分。
     对于名称相同的control,则使用index 区分。name 定义的标准是“SOURCE DIRECTION FUNCTION”即“源、方向、功能”
SOURCE 定义了control 的源,如“Master”“PCM““CD”和“Line”等,
例如上面表格,第三个
CODEC_SINGLE("Capture Volume",SUN4I_ADC_ACTL,20,7,0),//录音音量
它定义了name 是"Capture Volume"

iface 和 name 可以通过上层输入amixer命令获取,如下:

# # amixer controls

numid=30,iface=MIXER,name=‘Capture Volume’

(3) info()函数用于获得该control 的详细信息,该函数必须填充传递给它的第二个参数。
(4) get()函数用于得到control 的目前值并返回用户空间。
(5) put()函数用于从用户空间写入值,如果值被改变,该函数返回1,否则返回0;如果发生错误,该函数返回错误码。
get()和put()的第二个参数的类型为snd_ctl_elem_value。snd_ctl_elem_value结构体的内部也包含一个 由integer、integer64、enumerated 等组成的值联合体,它的具体类型依赖于control 的类型和info()函数。
对于get()和put()函数而言,如果control 有多于一个元素,即count>1,则每个元素都需要被返回或写入。在使用amixer命令配置声卡时都会调用到get()和put()函数。 get()和put()函数中讲判断设置值与原有值,判断是否配置寄存器。
连接平板到PC上,adb shell
cd /dev/snd
ls -l 
可以看到

  1. root@android:/dev/snd # ls -l
  2. ls -l
  3. crw-rw---- system   audio    116,   0 2012-05-04 14:40 controlC0
  4. crw-rw---- system   audio    116,  32 2012-05-04 14:40 controlC1
  5. crwxrwxrwx system   system   116,  24 2012-05-04 14:40 pcmC0D0c
  6. crwxrwxrwx system   system   116,  16 2012-05-04 14:40 pcmC0D0p
  7. crw-rw---- system   audio    116,  48 2012-05-04 14:40 pcmC1D0p
  8. crw-rw---- system   audio    116,  33 2012-05-04 14:40 timer

复制代码

分别解释如下

  • controlC0 –>                 用于声卡的控制,例如通道选择,混音,麦克风的控制等
  • controlC1 ->         用于声卡的控制,例如通道选择,混音,麦克风的控制等
  • pcmC1D0p  –>                用于播放的pcm设备
  • pcmC0D0c –〉               用于录音的pcm设备
  • pcmC0D0p –〉               用于播放的pcm设备
  • timer –〉                       定时器

其中,C0D0代表的是声卡0中的设备0,pcmC0D0c最后一个c代表capture,pcmC0D0p最后一个p代表playback,这些都是alsa-driver中的命名规则。从上面的列表可以看出,声卡下挂了6个设备,根据声卡的实际能力,驱动实际上可以挂上更多种类的设备,在include/sound/core.h中,定义了以下设备类型:

  1. #define SNDRV_DEV_TYPE_RANGE_SIZE    0x1000
  2. typedef int __bitwise snd_device_type_t;
  3. #define  SNDRV_DEV_TOPLEVEL  ((__force snd_device_type_t) 0)
  4. #define  SNDRV_DEV_CONTROL  ((__force snd_device_type_t) 1)
  5. #define  SNDRV_DEV_LOWLEVEL_PRE  ((__force snd_device_type_t) 2)
  6. #define  SNDRV_DEV_LOWLEVEL_NORMAL ((__force snd_device_type_t) 0x1000)
  7. #define  SNDRV_DEV_PCM    ((__force snd_device_type_t) 0x1001)
  8. #define  SNDRV_DEV_RAWMIDI  ((__force snd_device_type_t) 0x1002)
  9. #define  SNDRV_DEV_TIMER    ((__force snd_device_type_t) 0x1003)
  10. #define  SNDRV_DEV_SEQUENCER  ((__force snd_device_type_t) 0x1004)
  11. #define  SNDRV_DEV_HWDEP    ((__force snd_device_type_t) 0x1005)
  12. #define  SNDRV_DEV_INFO    ((__force snd_device_type_t) 0x1006)
  13. #define  SNDRV_DEV_BUS    ((__force snd_device_type_t) 0x1007)
  14. #define  SNDRV_DEV_CODEC    ((__force snd_device_type_t) 0x1008)
  15. #define  SNDRV_DEV_JACK          ((__force snd_device_type_t) 0x1009)
  16. #define  SNDRV_DEV_LOWLEVEL  ((__force snd_device_type_t) 0x2000)

复制代码

通常,我们更关心的是pcm和control这两种设备。

通话相关的语音通路切换原理、震动接口目录:andorid4.0/hardware/libhardware_legacy/audio/ AudioHardwareInterface.cpp

注册电话相关的接口

  1. static const char* routingModeStrings[] =
  2. {
  3. "OUT OF RANGE",
  4. "INVALID",
  5. "CURRENT",
  6. "NORMAL",
  7. "RINGTONE",
  8. "IN_CALL",
  9. "IN_COMMUNICATION"
  10. };
  11. static const char* displayMode(int mode)
  12. {
  13. if ((mode < AudioSystem::MODE_INVALID) || (mode >= AudioSystem::NUM_MODES))
  14. return routingModeStrings[0];
  15. return routingModeStrings[mode+3];
  16. }

复制代码

在status_t AudioHardwareBase::setMode(int mode)里调用

  1. status_t AudioHardwareBase::setMode(int mode)
  2. {
  3. #if LOG_ROUTING_CALLS
  4. LOGD("setMode(%s)", displayMode(mode));
  5. #endif
  6. if ((mode < 0) || (mode >= AudioSystem::NUM_MODES))
  7. return BAD_VALUE;
  8. if (mMode == mode)
  9. return ALREADY_EXISTS;
  10. mMode = mode;
  11. return NO_ERROR;
  12. }

复制代码

1、拨号调用到中间层的
android4.\frameworks\base\core\jni\android_media_AudioSystem.cpp
     android_media_AudioSystem_setPhoneState()函数  
2、android4.0\frameworks\base\media\libmedia\AudioSystem.cpp

AudioSystem::setPhoneState(state)
     get_audio_policy_service();   ---导入"media.audio_policy"服务
    它是在
Service_manager.c (y:\android4.0\frameworks\base\cmds\servicemanager)这里实例化了

libmedia--Audio System.cpp ----- setMode(2)... 
     进如到RIL的HW层 
3、 调用 \android4.0\device\softwinner\common\hardware\audio
audio_hw.c文件 ---->   select_mode() 函数      两种情况  1)当打电话时 
                        AudioSystem.cpp -----setMode(2) 
                         则这里in_call=0 
                            select_output_device() ->
                                         AUDIO_MODE_IN_CALL 的值是0x02
               选择了
            if ((adev->devices & AUDIO_DEVICE_OUT_ALL) == AUDIO_DEVICE_OUT_SPEAKER)
              {
                  LOGE("select_mode()  AUDIO_DEVICE_OUT_SPEAKER ");
                adev->devices = AUDIO_DEVICE_OUT_EARPIECE | AUDIO_DEVICE_IN_BUILTIN_MIC; 
              }
                     2)当挂断电话时 
                        AudioSystem.cpp -----setMode(0) 
                        则这里in_call=1                        ril_interface.c

audio_hw.c文件 ----> select_output_device()     //---全部静音        if (adev->mode == AUDIO_MODE_IN_CALL) 
    {
            for (channel = 0; channel < 2; channel++)
            mixer_ctl_set_value(adev->mixer_ctls.voice_ul_volume, channel, 0);
    }

解析音频设备的功能,例如有没有蓝牙,或是在耳机上,还是走喇叭等
    headset_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADSET;     headphone_on = adev->devices & AUDIO_DEVICE_OUT_WIRED_HEADPHONE;
    speaker_on = adev->devices & AUDIO_DEVICE_OUT_SPEAKER;
    earpiece_on = adev->devices & AUDIO_DEVICE_OUT_EARPIECE;
    bt_on = adev->devices & AUDIO_DEVICE_OUT_ALL_SCO;

进到
E/audio_hw_primary(   87): Entering IN_CALL state, in_call=0
E/audio_hw_primary(   87): Opening modem PCMs
E/audio_hw_primary(   87): cannot open PCM modem DL stream: cannot set hw params: Invalid argument

2、挂机调用到中间层的

A、MIC送话到3G模组

PREG1  ---MIC1 输入放大
           PREG1EN   0x28【29】=enable
           PREG1        0x28【25:26】= 00-0db  01-35db 10-38db 11 -41db
MIC1OUT
           MIC1NEN  0x28[12]   Mic1outn 1=enable   
-------------------------------------------------------------------------
    //for Mic1out  out put stream to the 3G module
    //MIC1OUT = enable   0X28[12]  = 1 
        mixer_ctl_set_value(adev->mixer_ctls.Mic_Input_Mux, 0,0);//--0X10[9:12] = 0000 
       mixer_ctl_set_value(adev->mixer_ctls.Mic1out_Switch, 0,1);//--0X28[12] = 1 Mic1out = enable
       mixer_ctl_set_value(adev->mixer_ctls.MicL_Volume, 0,0);//--0X28[25:26] = 0x0  0db
     mixer_ctl_set_value(adev->mixer_ctls.MIC1_amplifier, 0,1);//-- 0x28【29】=enable MIC amplifier
     mixer_ctl_set_value(adev->mixer_ctls.MIC2_amplifier, 0,0);//-- 
     mixer_ctl_set_value(adev->mixer_ctls.VMIC_Switch, 0,1);//--  0x28[27] VMICEN  1= VMIC pin voltage enable    
-------------------------------------------------------------------------

B、3G模组送话到A10 
   Linein --adc --DAC  --pa

0X10  
DACAREN [31]   Internal DAC Analog Right channel Enable 
DACAREN [30]   Internal DAC Analog Left channel Enable 
MIXEN[29]        Analog Output MP Enable 
LDACLMIXS[15] Left DAC to left output MP Mute   1=not mute 
RDACRMIXS[14] Right DAC to right output MP Mute 
LDACRMIXS[13] Left DAC to right output MP Mute

LINEIN -->MP  --> A
打开功放
  gpio_write_one_pin_value(gpio_pa_shutdown, 1, "audio_pa_ctrl");

关闭功放
  gpio_write_one_pin_value(gpio_pa_shutdown, 0, "audio_pa_ctrl");

电话呼入:
RINGING ...
LOGO如下
select_output_device()->

//---------------------------------------
呼入与呼出,就是呼入在接通的时候,设了寄存器后,多了一个
[ 2359.420000] [audio codec] snd_sun4icard_playback_open  
[ 2359.430000] [audio codec] sun4i_codec_pcm_hw_params
[ 2359.480000] snd_sun4i_codec_prepare,841  ,substream->stream = 0,->rate=48000
[ 2359.480000] [audio codec] codec_play_open  
[ 2359.490000] [audio codec] codec_play_start  
[ 2361.670000] [audio codec] codec_play_stop  
[ 2361.680000] [audio codec] snd_sun4icard_playback_close  
这是因为多了这一个操作,后面的codec_play_stop 和snd_sun4icard_playback_close,关闭了功放的电。造成了呼入时没有声音。

接听电话流程
android4.0\packages\apps\phone\src\com\android\phone\InCallScreen.java
    internalAnswerCall()  -->answerCall()

packages/apps/phone/src/com/android/phone/PhoneUtils.java
answerCall()函数

  1. static boolean answerCall(Call ringing) {
  2. log("answerCall(" + ringing + ")...");
  3. final PhoneApp app = PhoneApp.getInstance();
  4. app.getRinger().stopRing();  //-------我认为主要是因为在关铃声的时候,调用了
  5. codec_play_stop ,把 "audio_pa_ctrl"拉低了,所以没有声音输出

复制代码


X:\sumeipai\android4.0\device\softwinner\common\hardware\audio
audio_hw.c
控制驱动的接口
static int adev_open(const hw_module_t* module, const char* name,
{} 
X:\sumeipai\lichee\linux-3.0\sound\soc\sun4i
sun4i-codec.c
写对应的接口static const struct snd_kcontrol_new codec_snd_controls_b_c[] = {

设置默认输入/出

  1. /* These are values that never change */
  2. struct route_setting defaults[] = {
  3. // open dacpas
  4. {
  5. .ctl_name = MIXER_PLAYBACK_DACPAS,
  6. .intval = 1,
  7. },
  8. {
  9. .ctl_name = MIXER_PLAYBACK_PAMUTE_SWITCH,
  10. .intval = 1,
  11. },
  12. // close capture
  13. {
  14. .ctl_name = MIXER_MIC2_AMPLIFIER_ENABLE,
  15. .intval = 0,
  16. },
  17. {
  18. .ctl_name = MIXER_ADCL_ENABLE,
  19. .intval = 0,
  20. },
  21. {
  22. .ctl_name = MIXER_ADCR_ENABLE,
  23. .intval = 0,
  24. },
  25. {
  26. .ctl_name = MIXER_MIC1_GAIN_VOLUME,
  27. .intval = 0,
  28. },
  29. // to do ......
  30. {
  31. .ctl_name = MIXER_VMIC_ENABLE,      // for ear phone dectect
  32. .intval = 1,
  33. },
  34. {
  35. .ctl_name = MIXER_MIC1_AMPLIFIER_ENABLE,
  36. .intval = 1,
  37. },
  38. {
  39. .ctl_name = NULL,
  40. },
  41. };

Android 音频驱动分析--A10相关推荐

  1. 免费分享:5本安卓开发经典书籍,Android 7编程入门经典(第4版),Android底层驱动分析和移植,底层驱动分析和移植

    1.Android 7编程入门经典(第4版) 使用Android Studio 2  PDF 下载 下载地址: http://www.askwinds.com/r-c/down-info-02/579 ...

  2. Linux/Android 音频驱动从概念到 APP

    这里写自定义目录标题 前言 硬件介绍 Codec 通用结构 ADC 框图 DAC 框图 常用数字接口 其他相关术语 Codec 实际结构 硬件原理图 芯片手册框图 软硬件对应示例 Codec 硬件逻辑 ...

  3. android 触摸屏驱动分析,Android 触摸屏驱动代码分析(ADC 类型触摸屏 CPU:s3c

    Android 2.1 farsight version for s5pc100 File Name: s3c-ts.c 1           简介 1.1          本例基于s5pc100 ...

  4. Android音频驱动学习(一) Audio HAL

    Hal加载过程 加载audio hal需要分三步 1.hw_get_module_by_class :加载hal module 2.audio_hw_device_open:调用audio devic ...

  5. android 音频切换分析,Android音频可视化操作

    在我们使用各大音乐软件时,会发现,很多软件都会有一个音频的特效--鲸云特效,而鲸云特效,实际上就是对音频的一种可视化处理. 音频可视化,顾名思义就是将声音以视觉的方式呈现出来.那么怎么实现音频可视化呢 ...

  6. Android Camera驱动分析

    文章目录 一.Camera的硬件接口 二.代码路径 三.Camera代码分析 1.硬件接口设置 2.Camera设备驱动 3.模组驱动代码 一.Camera的硬件接口 引脚 名称及作用 VCAMA 就 ...

  7. rk3188--8.android camera驱动分析

    驱动初始化 在drivers/media/video/sp0a19.c中 device_initcall_sync(sp0a_mod_init); static struct i2c_driver s ...

  8. Android音频驱动-ASOC之CPU DAI

    dai驱动通常对应cpu的一个或几个I2S/PCM接口,与snd_soc_platform一样,dai驱动也是实现为一个platform driver, 实现一个dai驱动大致可以分为以下几个步骤: ...

  9. android 触摸屏驱动分析,rk3188--6.android 触摸屏驱动分析

    在drivers/input/touchscreen/ft5302_tp/ft5302_ts.c中 module_init(ft5x0x_ts_init); static int __init ft5 ...

最新文章

  1. 用Python分析了1982场英雄联盟数据,开局前预测游戏对局胜负!
  2. 【Flutter】Image 组件 ( 加载网络图片 | 加载静态图片 | 加载本地图片 | path_provider 插件 )
  3. Leetcode 208. 实现 Trie (前缀树) 解题思路及C++实现
  4. 对discuz的代码分析学习(三)mysql驱动
  5. 20175223 MySQL
  6. 计算机操作系统(4):操作系统的重要功能
  7. django图片上传到oss_django 配置阿里云OSS存储media文件的例子
  8. 【Filebeat】logstash 和filebeat 是什么关系
  9. [Android] SharedPreference的使用
  10. 大数据之-Hadoop完全分布式_完全分布式配置总结---大数据之hadoop工作笔记0040
  11. python数字保留两位_Python 鲜为人知的数值格式化
  12. OpenCV 图像编解码操作【imencode/imdecode】使用
  13. 凸优化第五章对偶 5.3几何解释
  14. PTA程序设计基础题目集(1)
  15. QQ游戏连连看的脚本
  16. HR不排斥的三大跳槽理由
  17. 2020计算机考研英语国家线,2020考研英语国家分数线?
  18. HTTP 错误 404.3 - Not Found 由于扩展配置问题而无法提供您请求的页面。
  19. 华为计算机网络认证软件,华为认证入门计算机网络基础
  20. 关于微信授权登录的用户取消-2的问题

热门文章

  1. java序列化机制Serialize接口使用
  2. 常见的滚动widget
  3. 天津室内设计培训班:3分钟带你了解室内设计的6大原则
  4. java 大文件上传 断点续传(Socket、IO流)
  5. 基于SSM框架的百度人脸识别
  6. python三剑客是什么意思_python数据分析三剑客之: Numpy
  7. 论文解读:SpellBERT:A Lightweight Pretrained Model for Chinese Spelling Checking
  8. 什么PDF在线压缩器好用,怎么操作?
  9. 亲宝宝APP声明遭恶意评论攻击 将不惜成本挖幕后黑手
  10. 河南出版团体召开宣扬工作会议