您的位置:首页 > 其它

watchdog_dev注册过程分析(待续)

2017-06-19 01:53 211 查看
watchdog以platform的方式写的,驱动中的注册和初始化都在platform_driver结构体中的probe函数中

static int __devinit s3c2410wdt_probe(struct platform_device *pdev)
{
struct device *dev;
unsigned int wtcon;
int started = 0;
int ret;
int size;

DBG("%s: probe=%p\n", __func__, pdev);

dev = &pdev->dev;
wdt_dev = &pdev->dev;

wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (wdt_mem == NULL) {
dev_err(dev, "no memory resource specified\n");
return -ENOENT;
}

wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (wdt_irq == NULL) {
dev_err(dev, "no irq resource specified\n");
ret = -ENOENT;
goto err;
}

/* get the memory region for the watchdog timer */

size = resource_size(wdt_mem);
if (!request_mem_region(wdt_mem->start, size, pdev->name)) {
dev_err(dev, "failed to get memory region\n");
ret = -EBUSY;
goto err;
}

wdt_base = ioremap(wdt_mem->start, size);
if (wdt_base == NULL) {
dev_err(dev, "failed to ioremap() region\n");
ret = -EINVAL;
goto err_req;
}

DBG("probe: mapped wdt_base=%p\n", wdt_base);

wdt_clock = clk_get(&pdev->dev, "watchdog");
if (IS_ERR(wdt_clock)) {
dev_err(dev, "failed to find watchdog clock source\n");
ret = PTR_ERR(wdt_clock);
goto err_map;
}

clk_enable(wdt_clock);

ret = s3c2410wdt_cpufreq_register();
if (ret < 0) {
pr_err("failed to register cpufreq\n");
goto err_clk;
}

/* see if we can actually set the requested timer margin, and if
* not, try the default value */

if (s3c2410wdt_set_heartbeat(&s3c2410_wdd, tmr_margin)) {
started = s3c2410wdt_set_heartbeat(&s3c2410_wdd,
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);

if (started == 0)
dev_info(dev,
"tmr_margin value out of range, default %d used\n",
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
else
dev_info(dev, "default timer value is out of range, "
"cannot start\n");
}

ret = request_irq(wdt_irq->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0) {
dev_err(dev, "failed to install irq (%d)\n", ret);
goto err_cpufreq;
}

watchdog_set_nowayout(&s3c2410_wdd, nowayout);

ret = watchdog_register_device(&s3c2410_wdd);
if (ret) {
dev_err(dev, "cannot register watchdog (%d)\n", ret);
goto err_irq;
}

if (tmr_atboot && started == 0) {
dev_info(dev, "starting watchdog timer\n");
s3c2410wdt_start(&s3c2410_wdd);
} else if (!tmr_atboot) {
/* if we're not enabling the watchdog, then ensure it is
* disabled if it has been left running from the bootloader
* or other source */

s3c2410wdt_stop(&s3c2410_wdd);
}

/* print out a statement of readiness */

wtcon = readl(wdt_base + S3C2410_WTCON);

dev_info(dev, "watchdog %sactive, reset %sabled, irq %sabled\n",
(wtcon & S3C2410_WTCON_ENABLE) ?  "" : "in",
(wtcon & S3C2410_WTCON_RSTEN) ? "en" : "dis",
(wtcon & S3C2410_WTCON_INTEN) ? "en" : "dis");

return 0;

err_irq:
free_irq(wdt_irq->start, pdev);

err_cpufreq:
s3c2410wdt_cpufreq_deregister();

err_clk:
clk_disable(wdt_clock);
clk_put(wdt_clock);
wdt_clock = NULL;

err_map:
iounmap(wdt_base);

err_req:
release_mem_region(wdt_mem->start, size);

err:
wdt_irq = NULL;
wdt_mem = NULL;
return ret;
}

probe先进行一些初始化和寄存器的设置,最后调用watchdog_register_device注册struct watchdog_device

ret = watchdog_register_device(&s3c2410_wdd);

这个函数在watchdog.h中定义,在watchdog_core.c中实现

nt watchdog_register_device(struct watchdog_device *wdd)
{
int ret;

if (wdd == NULL || wdd->info == NULL || wdd->ops == NULL)
return -EINVAL;

/* Mandatory operations need to be supported */
if (wdd->ops->start == NULL || wdd->ops->stop == NULL)
return -EINVAL;

/*
* Check that we have valid min and max timeout values, if
* not reset them both to 0 (=not used or unknown)
*/
if (wdd->min_timeout > wdd->max_timeout) {
pr_info("Invalid min and max timeout values, resetting to 0!\n");
wdd->min_timeout = 0;
wdd->max_timeout = 0;
}

/*
* Note: now that all watchdog_device data has been verified, we
* will not check this anymore in other functions. If data gets
* corrupted in a later stage then we expect a kernel panic!
*/

/* We only support 1 watchdog device via the /dev/watchdog interface */
ret = watchdog_dev_register(wdd);
if (ret) {
pr_err("error registering /dev/watchdog (err=%d)\n", ret);
return ret;
}

return 0;
}watchdog_register_device中先判断,传入的struct watchdog_device具有info和ops结构体,且ops中有start和stop。然后调用watchdog_dev.c中的watchdog_dev_register。

ret = watchdog_dev_register(wdd);
int watchdog_dev_register(struct watchdog_device *watchdog)
{
int err;

/* Only one device can register for /dev/watchdog */
if (test_and_set_bit(0, &watchdog_dev_busy)) {
pr_err("only one watchdog can use /dev/watchdog\n");
return -EBUSY;
}

wdd = watchdog;

err = misc_register(&watchdog_miscdev);
if (err != 0) {
pr_err("%s: cannot register miscdev on minor=%d (err=%d)\n",
watchdog->info->identity, WATCHDOG_MINOR, err);
goto out;
}

return 0;

out:
wdd = NULL;
clear_bit(0, &watchdog_dev_busy);
return err;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: