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

   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)封装性

  1. struct _Device_data;  
  2.   
  3. typedef  void (*process)(struct  _Device_data* pData);  
  4.   
  5. typedef struct  _Device_data  
  6. {  
  7.     int value;  
  8.     process pProcess;  
  9.       
  10. }Data;  
    封装性的意义在于,函数和数据是绑在一起的,数据和数据是绑在一起的。这样,我们就可以通过简单的一个结构指针访问到所有的数据,遍历所有的函数。封装性,这是类拥有的属性,当然也是数据结构体拥有的属性。

(2)继承性

  1. typedef struct _parent  
  2. {  
  3.     int data_parent;  
  4.   
  5. }Parent;  
  6.   
  7. typedef struct _Child  
  8. {  
  9.     struct _parent parent;  
  10.     int data_child;  
  11.   
  12. }Child;  
    在设计C语言继承性的时候,我们需要做的就是把基础数据放在继承的结构的首位置即可。这样,不管是数据的访问、数据的强转、数据的访问都不会有什么问题。

(3)多态

  1. typedef struct _Play  
  2. {  
  3.     void* pData;  
  4.     void (*start_play)(struct _Play* pPlay);  
  5. }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);
}

展开阅读全文

没有更多推荐了,返回首页