发现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("\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;
}
项目工程放在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 !\r\n");
}
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!\r\n",test_device->id);
//driver struct test!
struct driver *test_driver = (struct driver *)test_device->driver;
printf("test init %d!\n",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,再好好整理一下。
https://github.com/zhoudd1/driver