struct device
zephyr内核对象,用于管理所有的设备
struct device_config
zephyr内核对象,属于struct device的成员
/** Version:V1.14, directory:/zephyr/include/device.h **/
struct device
{
struct device_config *config; /** **/
const void *driver_api; /** 驱动的api接口,共有代码**/
void *driver_data; /** 驱动设备的私有数据 struct xxx_device_data**/
#if defined(__x86_64) && __SIZEOF_POINTER__ == 4
/* The x32 ABI hits an edge case. This is a 12 byte struct,
* but the x86_64 linker will pack them only in units of 8
* bytes, leading to alignment problems when iterating over
* the link-time array.
*/
void *padding;
#endif
};
struct device_config
{
const char *name; /*驱动名称*/
int (*init)(struct device *device); /*设备初始化接口*/
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
int (*device_pm_control)(struct device *device, u32_t command,
void *context, device_pm_cb cb, void *arg);
struct device_pm *pm;
#endif
const void *config_info; /*驱动设备私有配置,struct xxx_device_config*/
};
设备驱动的初始化和优先级
宏定义 DEVICE_AND_API_INIT 创建一个内核对象,配置了驱动加载优先级和在内存中段的位置。
/** Version:zephyrV1.14, Directory:/zephyr/include/device.h **/
#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \
level, prio, api) \
static struct device_config _CONCAT(__config_, dev_name) __used \
__attribute__((__section__(".devconfig.init"))) = { \
.name = drv_name, .init = (init_fn), \
.config_info = (cfg_info) \
}; \
static struct device _CONCAT(__device_, dev_name) __used \
__attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \
.config = &_CONCAT(__config_, dev_name), \
.driver_api = api, \
.driver_data = data \
}
dev_name — input,设备名,一般没啥作用;
drv_name — input,重要参数,设备的驱动名,用于在device_get_binding中查找设备
init_fn -------- input,设备的初始化接口,在内核启动的驱动设备初始化阶段被调用
data ---------- input,其实就是struct xxx_device_data 类型的变量
cfg_info ----- input,其实就是struct xxx_device_config 类型的变量
level ---------- input,重要参数,与prio一起确定设备的初始化顺序
prio ----------- input,重要参数,与level一起驱动设备的初始化顺序
api--------------input,stuct xxx_driver_api,提供系统调用的接口
DEVICE_AND_API_INIT 在这个宏定义中,有两个参数 level 和 prio。这两个参数没有出现在具体的代码中,而是出现在 attribute 属性中:
__attribute__((__section__(".init_" #level STRINGIFY(prio))))
编译器在预编译的时候会将 “#” 后面到参数转换为字符串,STRINGIFY(s) 的作用也是将参数 s 转换为字符串 “s”。
举个例如,如果在调用 DEVICE_AND_API_INIT 时传入的参数 level 和 prio 分别为 PRIMARY 和 50,那么编译器就会将上面那段代码放到名为 .init_PRIMARY50 的段中。
通过 attribut 设置了变量 _device_dev_name 在编译后所属的段为(".init" #level STRINGIFY(prio)),这是一个与level&prio相关的段,在zephyr应用完成编译之后,会根据level & prio 参数将所有的驱动设备汇聚在一起。
在zephyr运行时,会将所有的device变量拷贝到内存中,并根据level & prio参数完成设备的初始化。