2010年就打算把linux里的驱动框架核心代码抠出来的,但是由于懒而且linux代码量大,一直下不了手。最近调试的intel curie里驱动架构也类似linux,代码就少多了,由于工作需要不得不梳理一下这一堆代码,今天花了一下午,把整个BSP部分的驱动核心抽离出来了,并且做了几个小sample。
最小驱动框架核心代码
1、设备管理
device.c
#include #include#include#include#include#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 voidresume_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;gotoerr_resume_device;
}if (dev->powerstate ==PM_RUNNING)/*Device already running*/
continue;if (dev->driver->resume && (ret = dev->driver->resume(dev)))gotoerr_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);
}intsuspend_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_#includetypedefenum{
PM_NOT_INIT= 0,
PM_SHUTDOWN,
PM_SUSPENDED,
PM_RUNNING,
PM_COUNT
} PM_POWERSTATE;structtd_device;structdriver;//struct __packed __aligned(4) td_device
structtd_device
{void *priv;struct driver *driver;
PM_POWERSTATE powerstate :8;
uint8_t id;
};structdriver
{int (*init)(struct td_device *dev);int (*suspend)(struct td_device *dev, PM_POWERSTATE state);int (*resume)(struct td_device *dev);
};intsuspend_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 #include#include#include#include"../soc/soc_config.h"#include"../soc/device.h"#include"../driver/wdt/wdt.h"#include"../driver/clk/clk.h"#include"../driver/test/test.h"typedefenum{
WDT_ID= 0,
CLK_ID=1,
TEST_ID=2,
} DEVICE_ID;struct td_device pf_device_wdt ={
.id=WDT_ID,
.driver= &watchdog_driver,
.priv= &(structwdt_pm_data){
.a= 1,
.b=2,
},
};struct td_device pf_device_clk ={
.id=CLK_ID,
.driver= &clk_driver,
.priv= &(structclk_data){
.a=5,
.b=6,
},
};struct td_device pf_device_test ={
.id=TEST_ID,
.driver= &test_driver,
.priv= &(structtest_data){
.a=3,
.b=4,
},
};static struct 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_
extern structtd_device pf_device_wdt;extern structtd_device pf_device_clk;extern structtd_device pf_device_test;#endif
3、以上就是驱动架构的最小系统,下面添加一个驱动程序例子test_driver
test.c
#include #include#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
extern structdriver test_driver;structtest_data
{
uint32_t a;
uint32_t b;
};#endif
5、再写个驱动程序调用实例
main.c
#include #include"../bsp/soc/device.h"#include"../bsp/soc/soc_config.h"#include"../bsp/driver/test/test.h"
intmain()
{//driver framework test!
init_all_devices();//driver struct test!
struct td_device *test_device =(struct td_device *)&pf_device_test;
printf("\r\n===test device(%d) ok!===\r\n",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);return 0;
}
用code::blocks可以直接编译运行。