2010年就打算把linux里的驱动框架核心代码抠出来的,但是由于懒而且linux代码量大,一直下不了手。最近调试的intel curie里驱动架构也类似linux,代码就少多了,由于工作需要不得不梳理一下这一堆代码,今天花了一下午,把整个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"staticstruct 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; } } staticvoid 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 suspendedif (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) return0; /* 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_devicestruct 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, }, }; staticstruct td_device *qrk_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(qrk_platform_devices, ARRAY_SIZE(qrk_platform_devices)); }
soc_config.h
#ifndef __SOC_CONFIG_H_
#define __SOC_CONFIG_H_
externstruct td_device pf_device_wdt;
externstruct td_device pf_device_clk;
externstruct 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) { return0; } staticint test_suspend(struct td_device *dev, PM_POWERSTATE state) { return0; } staticint test_resume(struct td_device *dev) { return0; } struct driver test_driver = { .init = test_init, .suspend = test_suspend, .resume = test_resume };
test.h
#ifndef _TEST_H_
#define _TEST_H_
#include <stdint.h>
externstruct 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("rn===test device(%d) ok!===rn",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!n"); //driver data test!struct test_data *data = (struct test_data *)test_device->priv; printf("test_data a:%d,b:%d!n",data->a,data->b); return0; }
附件包下载http://files.cnblogs.com/files/dong1/mini_embed_driver_framework.zip
用code::blocks可以直接编译运行。
原文:http://www.cnblogs.com/dong1/p/6786056.html
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!