发现intel curie平台的bsp部分驱动架构类似linux,今天花了一下午把curie bsp的驱动核心抽离出来了,并且做了几个小sample。
最小驱动框架核心代码
1、设备管理
device.c
#include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <stdint.h> #include <errno.h> #include "../../bsp/soc/soc_config.h" #include "../../bsp/soc/device.h" static struct td_device **all_devices = NULL; static uint32_t all_devices_count = 0; void init_devices(struct td_device **_all_devices, uint32_t _all_devices_count) { if (all_devices != NULL) /* Devices already init */ return; /* Link array with root device */ all_devices = _all_devices; all_devices_count = _all_devices_count; uint32_t i; int ret = 0; for (i = 0; i < all_devices_count; ++i) { struct td_device *dev = all_devices[i]; if (dev->driver->init && (ret = dev->driver->init(dev))) { dev->powerstate = PM_NOT_INIT; printf("dev(%d) is not init",dev->id); } dev->powerstate = PM_RUNNING; } } static void resume_devices_from_index(uint32_t i) { int ret = 0; struct td_device *dev = NULL; for (; i < all_devices_count; ++i) { dev = all_devices[i]; printf("resume device %d", dev->id); if (dev->powerstate <= PM_SHUTDOWN) { ret = -EINVAL; goto err_resume_device; } if (dev->powerstate == PM_RUNNING) /* Device already running */ continue; if (dev->driver->resume && (ret = dev->driver->resume(dev))) goto err_resume_device; /* Current device resumed */ dev->powerstate = PM_RUNNING; } return; err_resume_device: printf("failed to resume device %d (%d)", dev->id,ret); } void resume_devices(void) { resume_devices_from_index(0); } int suspend_devices(PM_POWERSTATE state) { int32_t i; int ret = 0; /* Use the reverse order used for init, i.e. we suspend bus devices first, * then buses, then top level devices */ for (i = all_devices_count - 1; i >= 0; --i) { struct td_device *dev = all_devices[i]; // device already suspended if (dev->powerstate <= state) continue; printf("suspend dev %d", dev->id); if (!dev->driver->suspend) { dev->powerstate = state; continue; } ret = dev->driver->suspend(dev, state); if (!ret) { dev->powerstate = state; continue; } break; } if (!ret) return 0; /* Suspend aborted, resume all devices starting from where we had * an issue */ if (state > PM_SHUTDOWN) resume_devices_from_index(i + 1); return -1; }
device.h
#ifndef __DEVICE_H_ #define __DEVICE_H_ #include <stdint.h> typedef enum { PM_NOT_INIT = 0, PM_SHUTDOWN, PM_SUSPENDED, PM_RUNNING, PM_COUNT } PM_POWERSTATE; struct td_device; struct driver; //struct __packed __aligned(4) td_device struct td_device { void *priv; struct driver *driver; PM_POWERSTATE powerstate : 8; uint8_t id; }; struct driver { int (*init)(struct td_device *dev); int (*suspend)(struct td_device *dev, PM_POWERSTATE state); int (*resume)(struct td_device *dev); }; int suspend_devices(PM_POWERSTATE state); void resume_devices(void); void init_devices(struct td_device **all_devices, uint32_t all_devices_count); void init_all_devices(void); #endif
2、驱动程序配置文件,我这里配置了WDT , CLK , TEST 三个简单的驱动程序。
soc_config.c
#include <stdio.h> #include <stddef.h> #include <stdlib.h> #include <errno.h> #include "../soc/soc_config.h" #include "../soc/device.h" #include "../driver/wdt/wdt.h" #include "../driver/clk/clk.h" #include "../driver/test/test.h" typedef enum { WDT_ID = 0, CLK_ID=1, TEST_ID =2, } DEVICE_ID; struct td_device pf_device_wdt = { .id = WDT_ID, .driver = &watchdog_driver, .priv = &(struct wdt_pm_data){ .a = 1, .b =2, }, }; struct td_device pf_device_clk = { .id = CLK_ID, .driver = &clk_driver, .priv = &(struct clk_data){ .a=5, .b=6, }, }; struct td_device pf_device_test = { .id = TEST_ID, .driver = &test_driver, .priv = &(struct test_data){ .a=3, .b=4, }, }; static struct td_device *platform_devices[] = { &pf_device_wdt, &pf_device_clk, &pf_device_test, }; #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) void init_all_devices(void) { /* Init plateform devices and buses */ init_devices(platform_devices, ARRAY_SIZE(platform_devices)); }
soc_config.h
#ifndef __SOC_CONFIG_H_ #define __SOC_CONFIG_H_ extern struct td_device pf_device_wdt; extern struct td_device pf_device_clk; extern struct td_device pf_device_test; #endif
3、以上就是驱动架构的最小系统,下面添加一个驱动程序例子test_driver
test.c
#include <stdio.h> #include <stdlib.h> #include "../../soc/soc_config.h" #include "../../soc/device.h" #include "../../driver/test/test.h" int test_init(struct td_device *dev) { return 0; } static int test_suspend(struct td_device *dev, PM_POWERSTATE state) { return 0; } static int test_resume(struct td_device *dev) { return 0; } struct driver test_driver = { .init = test_init, .suspend = test_suspend, .resume = test_resume };
test.h
#ifndef _TEST_H_ #define _TEST_H_ #include <stdint.h> extern struct driver test_driver; struct test_data { uint32_t a; uint32_t b; }; #endif
5、再写个驱动程序调用实例
main.c
#include <stdio.h> #include "../bsp/soc/device.h" #include "../bsp/soc/soc_config.h" #include "../bsp/driver/test/test.h" int main() { //driver framework test! init_all_devices(); //driver struct test! struct td_device *test_device =(struct td_device *)&pf_device_test; printf(" ===test device(%d) ok!=== ",test_device->id); //driver api test! struct driver *test_driver = (struct driver *)test_device->driver; if(test_driver->init(wdt_device)==0) printf("test init ok! "); //driver data test! struct test_data *data = (struct test_data *)test_device->priv; printf("test_data a:%d,b:%d! ",data->a,data->b); return 0; }
项目工程放在github上了https://github.com/zhoudd1/driver
用code::blocks可以直接编译运行。
6.在test driver的基础上添加driver api
首先在设备指针里添加driver api属性
struct td_device pf_device_test = { .id = TEST_ID, .driver = &test_driver, .priv = &(struct test_data){ }, };
struct test_data结构体是用户根据需求自定义的,这里仅增加了几个driver api ,留了个void *driver_data空指针备用。
struct test_data { void *driver_api; void *driver_data; };
然后更新test driver实例
test.c
#include <stdio.h> #include <stdlib.h> #include "../../soc/soc_config.h" #include "../../soc/device.h" #include "../../driver/test/test.h" static void test_open_cb(struct td_device *dev) { printf("test dev open sucss ! "); } static void test_close_cb(struct td_device *dev) { } struct test_driver_api test_funcs = { .open = test_open_cb, .close = test_close_cb, }; int test_init(struct td_device *dev) { struct test_data *data = (struct test_data *)dev->priv; data->driver_api= &test_funcs; return 0; } static int test_suspend(struct td_device *dev, PM_POWERSTATE state) { return 0; } static int test_resume(struct td_device *dev) { return 0; } struct driver test_driver = { .init = test_init, .suspend = test_suspend, .resume = test_resume };
test.h
#ifndef _TEST_H_ #define _TEST_H_ #include <stdint.h> typedef void (*test_api_open)(struct td_device *dev); typedef void (*test_api_close)(struct td_device *dev); struct test_driver_api { test_api_open open; test_api_close close; }; struct test_data { void *driver_api; void *driver_data; }; extern struct driver test_driver; #endif
测试代码main.c
#include <stdio.h> #include "../bsp/soc/device.h" #include "../bsp/soc/soc_config.h" #include "../bsp/driver/wdt/wdt.h" #include "../bsp/driver/clk/clk.h" #include "../bsp/driver/test/test.h" int main() { //device driver framework test! init_all_devices(); //device struct test! struct td_device *test_device =(struct td_device *)&pf_device_test; printf("test device(%d) ok! ",test_device->id); //driver struct test! struct driver *test_driver = (struct driver *)test_device->driver; printf("test init %d! ",test_driver->init(test_device)); //driver data test! struct test_data *data = (struct test_data *)test_device->priv; //driver api test! struct test_driver_api *b = data->driver_api; b->open(test_device); //driver api data test! int *d = (int*)data->driver_data; return 0; }
代码有些凌乱,如果哪天需要在具体的SOC上重构BSP,再好好整理一下。