生命的意义在于一直坚持做一些有意义的事情
1.驱动加载流程
接着上文我们一起看一下codec、dai和platform这三个逻辑设备,也就对应的codec编解码芯片驱动,i2s音频传输总线驱动,dma高速缓存驱动。
说道这里可能你对这三个驱动还是不是很了解,或者你是第一次听说这三种设备写别急,后续我会单独写文章介绍这几个设备和这几个设备的工作原理以及具体的驱动实现,这里我们先不深入了解,只需要知道会涉及这三种驱动,我们先从声卡的角度了解一下当声卡加载的时候这三种设备是怎么一起被初始化和加载的。
2. 驱动配置介绍
这张图是从官方文档种找出来的一张图,这张图介绍了dma、codec、dai、dsp这四种驱动的加载过程,dsp普通的应用场景基本不涉及,所以我们暂时不讨论dsp,从上图中可以看到所有的驱动都是由hcs拉起来的,上文已经介绍过,如果想让你的驱动在系统启动的时候被调用拉起,只需要将你的驱动配置到device_info.hcs文件中,系统启动的时候会读取这个文件,在这个文件中根据配置信息找对应的驱动,执行驱动中的bind函数和init函数。接下来我们看一下dma、codec、dai这三种驱动在device_info.hcs文件中的配置。
device_primary :: deviceNode {
policy = 1;
priority = 50;
preload = 0;
permission = 0666;
moduleName = "CODEC_RK809";
serviceName = "codec_service_0";
deviceMatchAttr = "hdf_codec_driver_0";
}
这个是codec的配置
device_primary :: deviceNode {
policy = 1;
priority = 50;
preload = 0;
permission = 0666;
moduleName = "DMA_RK3568";
serviceName = "dma_service_0";
deviceMatchAttr = "hdf_dma_driver";
}
这个是dma的配置
device_primary :: deviceNode {
policy = 1;
priority = 50;
preload = 0;
permission = 0666;
moduleName = "DAI_RK3568";
serviceName = "dai_service";
deviceMatchAttr = "hdf_dai_driver";
}
这个是dai的配置
看上面这三个配置我们可以发现一些共同点,他们的节点名称都是device_primary,primary是一种声卡一般是默认声卡,基本上带有音频功能的设备如果支持多声卡的话都会有一个默认声卡,这个默认声卡就可以叫做primary声卡。这三个设备节点的配置的参数数量是相同的参数内容大体上也很相似,接下来我们就详细看一下这几个参数。这些参数的功能和作用OpenHarmony官方文档里面都有详细介绍我这里就简单介绍一下:
3. 配置参数介绍
policy翻译过来是策略,也就是这个驱动谁都可以用,可以赋五种值分别是:
typedef enum {
/* 驱动不提供服务 */
SERVICE_POLICY_NONE = 0,
/* 驱动对内核态发布服务 */
SERVICE_POLICY_PUBLIC = 1,
/* 驱动对内核态和用户态都发布服务 */
SERVICE_POLICY_CAPACITY = 2,
/* 驱动服务不对外发布服务,但可以被订阅 */
SERVICE_POLICY_FRIENDLY = 3,
/* 驱动私有服务不对外发布服务,也不能被订阅 */
SERVICE_POLICY_PRIVATE = 4,
/* 错误的服务策略 */
SERVICE_POLICY_INVALID
} ServicePolicy;
我们这里配置的是1,也就是我们只对内核发布服务,只有内核的驱动可以和他交互,上层服务是获取不到这个驱动节点的,这个驱动也不会在/dev下生成服务节点。
priority 翻译过来是优先权,也就是优先级,官方说明:驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序。我们这里配置的50是因为我们声卡的各个驱动需要优先于我们声卡服务节点加载。上文可以看到我们声卡的priority节点配置的是60。我们各个驱动需要优先于声卡服务加载这里就配置50.
preload翻译过来是预加载,这里是驱动加载的方式,可以配置三种数值:
typedef enum {
DEVICE_PRELOAD_ENABLE = 0,
DEVICE_PRELOAD_ENABLE_STEP2 = 1,
DEVICE_PRELOAD_DISABLE = 2,
DEVICE_PRELOAD_INVALID
} DevicePreload;
官方介绍:
preload字段配置为0(DEVICE_PRELOAD_ENABLE),则系统启动过程中默认加载。
preload字段配置为1(DEVICE_PRELOAD_ENABLE_STEP2),当系统支持快速启动的时候,则在系统完成之后再加载这一类驱动,否则和DEVICE_PRELOAD_ENABLE含义相同。
preload字段配置为2(DEVICE_PRELOAD_DISABLE),则系统启动过程中默认不加载,支持后续动态加载,当用户态获取驱动服务消息机制时,如果驱动服务不存在,HDF框架会尝试动态加载该驱动。
我们这里配置的是0,表示系统启动过程中默认加载,也就是说,系统启动过程中会拉起我们这里配置的这三个驱动会执行这三个驱动中的bind和init函数。
permission这个是驱动节点的权限,这个给666就可以,一般很少涉及权限问题,当碰到了不满足再改。
moduleName这个参数上一篇文章已经讲到驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。
serviceName这个是服务名称 驱动对外发布服务的名称,必须唯一。 当你的policy字段配置的是2的时候,这个名称会在/dev目录下出现。
deviceMatchAttr 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。这个等到下文讲到私有配置的时候会看到。
4. 声卡节点介绍
讲到这里我们对一个声卡的三种设备节点的主要配置就说完了,接下来我们有必要对一个完整的声卡都有哪些配置做一个详细的介绍。出过上面介绍过的配置一个声卡还会有下面这几个配置:
device_stream :: device {
device0 :: deviceNode {
policy = 2;
priority = 80;
preload = 0;
permission = 0666;
moduleName = "HDF_AUDIO_STREAM";
serviceName = "hdf_audio_render";
}
device1 :: deviceNode {
policy = 2;
priority = 80;
preload = 0;
permission = 0666;
moduleName = "HDF_AUDIO_STREAM";
serviceName = "hdf_audio_capture";
}
}
device_control :: device {
device0 :: deviceNode {
policy = 2;
priority = 80;
preload = 0;
permission = 0666;
moduleName = "HDF_AUDIO_CONTROL";
serviceName = "hdf_audio_control";
}
}
我们都知道一个声卡一般都要支持播放、录音和控制功能,控制功能主要有音量控制、静音、声道、增益等控制功能。这三个节点就是生成三个声卡驱动服务,驱动服务就相当于设备节点,这三个policy都是2,用户和内核都可以和他进行交互。hdf_audio_render服务就是用来播放,hdf_audio_capture服务就用来录音的,hdf_audio_control服务就用来发送控制指令的。
device_primary :: deviceNode {
policy = 2;
priority = 60;
preload = 0;
permission = 0666;
moduleName = "HDF_AUDIO";
deviceMatchAttr = "hdf_audio_driver_0";
serviceName = "hdf_audio_codec_primary_dev0";
}
device_hdmi :: deviceNode {
policy = 2;
priority = 60;
preload = 2;
permission = 0666;
moduleName = "HDF_AUDIO";
deviceMatchAttr = "hdf_audio_driver_1";
serviceName = "hdf_audio_codec_hdmi_dev0";
}
device_usb :: deviceNode {
policy = 2;
priority = 60;
preload = 2;
permission = 0666;
moduleName = "HDF_AUDIO";
deviceMatchAttr = "hdf_audio_driver_2";
serviceName = "hdf_audio_codec_usb_dev0";
}
上面这三个是三个声卡配置,分别是primary声卡、HDMI声卡、USB声卡这三种声卡。如果你把这三种声卡都配置了当系统起来后你会发现在/dev路径下面会生成下面几个节点:
hdf_audio_codec_primary_dev0
hdf_audio_codec_hdmi_dev0
hdf_audio_codec_usb_dev0
hdf_audio_render
hdf_audio_capture
hdf_audio_control
你会看到上面这些节点信息,如果你做过ALSA声卡驱动,你会发现差异很大,ALSA声卡驱动每个上卡都会有一个control节点都会有pcmC0D0c、pcmC0D0p ,但是ADM框架有多个声卡只有一组hdf_audio_render、hdf_audio_capture和hdf_audio_control,这是因为,ADM框架这三个服务是负责数据流和控制流分发的,当播放的时候用户态下发播放的数据流时,数据流中会包含有声卡信息,调用hdf_audio_render服务,hdf_audio_render服务会将数据流分发给对应的声卡,录音和控制也一样。这样只需要调用相同的服务使用不同的声卡下发不同的参数。
接下来我们继续看声卡的配置文件,等这些配置文件看完了,我们再回到声卡的加载流程。
上图是声卡的配置文件,红框框出来的都是配置文件,我们前面已经详细介绍了device_info.hcs文件接下来我介绍一下声卡的其他配置文件,今天先讲到这里把,下一篇我们详细介绍一下声卡的私有配置文件。
转载请说明出处--------------------------