您的位置:首页 > 运维架构 > Linux

Zephyr Kernel 设备驱动和设备模型(二)

2017-04-26 14:22 344 查看
   C++语言有封装、继承、多态的特点。C语言也可以面向对象和应用设计模式,关键就在于如何实现面向对象语言的三个重要属性,下面以watdog为例分析Zephyr设备驱动和设备模型。

struct device;

/**

 * @brief Static device information (In ROM) Per driver instance

 * @param name name of the device

 * @param init init function for the driver

 * @param config_info address of driver instance config information

 */

struct device_config {

    char    *name;

    int (*init)(struct device *device);

    void *config_info;

};

/**

 * @brief Runtime device structure (In memory) Per driver instance

 * @param device_config Build time config information

 * @param driver_api pointer to structure containing the API functions for

 * the device type. This pointer is filled in by the driver at init time.

 * @param driver_data river instance data. For driver use only

 */

struct device {

    struct device_config *config;

    void *driver_api;

    void *driver_data;

};

#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \

    \

    static struct device_config __config_##dev_name __used \

    __attribute__((__section__(".devconfig.init"))) = { \

        .name = drv_name, .init = (init_fn), \

        .config_info = (cfg_info) \

    }; \

    \

    static struct device (__device_##dev_name) __used \

    __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \

         .config = &(__config_##dev_name), \

         .driver_data = data \

    }

(1)封装性

[cpp]
view plain
copy

struct _Device_data;  
  
typedef  void (*process)(struct  _Device_data* pData);  
  
typedef struct  _Device_data  
{  
    int value;  
    process pProcess;  
      
}Data;  

    封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个结构指针访问到所有的数据,遍历所有的函数。封装性,这是类拥有的属性,当然也是数据结构体拥有的属性。

(2)继承性

[cpp]
view plain
copy

typedef struct _parent  
{  
    int data_parent;  
  
}Parent;  
  
typedef struct _Child  
{  
    struct _parent parent;  
    int data_child;  
  
}Child;  

    在设计C语言继承性的时候,我们需要做的就是把基础数据放在继承的结构的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么问题。

(3)多态

[cpp]
view plain
copy

typedef struct _Play  
{  
    void* pData;  
    void (*start_play)(struct _Play* pPlay);  
}Play;  

    多态,就是说用同一的接口代码处理不同的数据。比如说,这里的Play结构就是一个通用的数据结构,我们也不清楚pData是什么数据,start_play是什么处理函数?但是,我们处理的时候只要调用pPlay->start_play(pPlay)就可以了。剩下来的事情我们不需要管,因为不同的接口会有不同的函数去处理,我们只要学会调用就可以了。

#include <nanokernel.h>

#include <init.h>

#include <clock_control.h>

#include "wdt_dw.h"

#ifdef WDT_DW_INT_MASK

static inline void _wdt_dw_int_unmask(void)

{

    sys_write32(sys_read32(WDT_DW_INT_MASK) & INT_UNMASK_IA,

                        WDT_DW_INT_MASK);

}

#else

#define _wdt_dw_int_unmask()

#endif

#ifdef CONFIG_WDT_DW_CLOCK_GATE

static inline void _wdt_dw_clock_config(struct device *dev)

{

    char *drv = CONFIG_WDT_DW_CLOCK_GATE_DRV_NAME;

    struct device *clk;

    clk = device_get_binding(drv);

    if (clk) {

        struct wdt_dw_runtime *context = dev->driver_data;

        context->clock = clk;

    }

}

static inline void _wdt_dw_clock_on(struct device *dev)

{

    struct wdt_dw_dev_config *config = dev->config->config_info;

    struct wdt_dw_runtime *context = dev->driver_data;

    clock_control_on(context->clock, config->clock_data);

}

static inline void _wdt_dw_clock_off(struct device *dev)

{

    struct wdt_dw_dev_config *config = dev->config->config_info;

    struct wdt_dw_runtime *context = dev->driver_data;

    clock_control_off(context->clock, config->clock_data);

}

#else

#define _wdt_dw_clock_config(...)

#define _wdt_dw_clock_on(...)

#define _wdt_dw_clock_off(...)

#endif

/**

 * Enables the clock for the peripheral watchdog

 */

static void wdt_dw_enable(struct device *dev)

{

    _wdt_dw_clock_on(dev);

#if defined(CONFIG_SOC_QUARK_SE) || defined(CONFIG_SOC_QUARK_D2000)

    sys_set_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1);

#endif

}

static void wdt_dw_disable(struct device *dev)

{

    _wdt_dw_clock_off(dev);

#if defined(CONFIG_SOC_QUARK_SE) || defined(CONFIG_SOC_QUARK_D2000)

    sys_clear_bit(SCSS_PERIPHERAL_BASE + SCSS_PERIPH_CFG0, 1);

#endif

}

void wdt_dw_isr(void *arg)

{

    struct device *dev = arg;

    struct wdt_dw_runtime *context = dev->driver_data;

    if (context->cb_fn) {

        context->cb_fn(dev);

    }

}

static void wdt_dw_get_config(struct device *dev, struct wdt_config *config)

{

    struct wdt_dw_dev_config *wdt_dev = dev->config->config_info;

    struct wdt_dw_runtime *context = dev->driver_data;

    config->timeout = sys_read32(wdt_dev->base_address + WDT_TORR) &

                            WDT_TIMEOUT_MASK;

    config->mode = (sys_read32(wdt_dev->base_address + WDT_CR) & WDT_MODE)

                            >> WDT_MODE_OFFSET;

    config->interrupt_fn = context->cb_fn;

}

static void wdt_dw_reload(struct device *dev)

{

    struct wdt_dw_dev_config *wdt_dev = dev->config->config_info;

    sys_write32(WDT_CRR_VAL, wdt_dev->base_address + WDT_CRR);

}

static int wdt_dw_set_config(struct device *dev, struct wdt_config *config)

{
    struct wdt_dw_dev_config *wdt_dev = dev->config->config_info;

    struct wdt_dw_runtime *context = dev->driver_data;

    sys_write32(config->timeout, wdt_dev->base_address + WDT_TORR);

    /* Set response mode */

    if (WDT_MODE_RESET == config->mode) {

        sys_clear_bit(wdt_dev->base_address + WDT_CR, 1);

    } else {

        if (!config->interrupt_fn) {

            return DEV_FAIL;

        }

        context->cb_fn = config->interrupt_fn;

        sys_set_bit(wdt_dev->base_address + WDT_CR, 1);

    }

    /* Enable WDT, cannot be disabled until soc reset */

    sys_set_bit(wdt_dev->base_address + WDT_CR, 0);

    wdt_dw_reload(dev);

    return DEV_OK;

}

static struct wdt_driver_api wdt_dw_funcs = {

    .set_config = wdt_dw_set_config,

    .get_config = wdt_dw_get_config,

    .enable = wdt_dw_enable,

    .disable = wdt_dw_disable,

    .reload = wdt_dw_reload,

};

#if   0
#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \

    \

    static struct device_config __config_##dev_name __used \

    __attribute__((__section__(".devconfig.init"))) = { \

        .name = drv_name, .init = (init_fn), \

        .config_info = (cfg_info) \

    }; \

    \

    static struct device (__device_##dev_name) __used \

    __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \

         .config = &(__config_##dev_name), \

         .driver_data = data \

    }

#endif

int wdt_dw_init(struct device *dev);

struct wdt_dw_runtime wdt_runtime;

struct wdt_dw_dev_config wdt_dev = {

    .base_address = CONFIG_WDT_DW_BASE_ADDR,

#ifdef CONFIG_WDT_DW_CLOCK_GATE

    .clock_data = UINT_TO_POINTER(CONFIG_WDT_DW_CLOCK_GATE_SUBSYS),

#endif

};

DEVICE_INIT(wdt, CONFIG_WDT_DW_DRV_NAME, &wdt_dw_init,

            &wdt_runtime, &wdt_dev,

            SECONDARY, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);

int wdt_dw_init(struct device *dev)

{

    dev->driver_api = &wdt_dw_funcs;

    IRQ_CONNECT(CONFIG_WDT_DW_IRQ, CONFIG_WDT_DW_IRQ_PRI, wdt_dw_isr,

            DEVICE_GET(wdt), 0);

    irq_enable(CONFIG_WDT_DW_IRQ);

    _wdt_dw_int_unmask();

    _wdt_dw_clock_config(dev);

    return 0;
}

=========================================================================================

application sample:

#include <zephyr.h>

#include <device.h>

#include <watchdog.h>

#include "board.h"

#include <misc/printk.h>

uint32_t wdt_fired;

#define WDT_DRIVER CONFIG_WDT_DW_DRV_NAME

/* WDT Requires a callback, there is no interrupt enable / disable. */

void wdt_example_cb(struct device *dev)

{

    wdt_fired++;

    printk("watchdog fired\n");

    wdt_reload(dev);

}

void main(void)

{

    struct wdt_config wr_cfg;

    struct wdt_config cfg;

    struct device *wdt_dev;

    printk("Start watchdog test\n");

    wr_cfg.timeout = WDT_2_27_CYCLES;

    wr_cfg.mode = WDT_MODE_INTERRUPT_RESET;

    wr_cfg.interrupt_fn = wdt_example_cb;

    wdt_fired = 0;

    wdt_dev = device_get_binding(WDT_DRIVER);

    wdt_enable(wdt_dev);

    wdt_set_config(wdt_dev, &wr_cfg);

    wdt_get_config(wdt_dev, &cfg);

    printk("timeout: %d\n", cfg.timeout);

    printk("mode: %d\n", cfg.mode);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息