分析一个看门狗驱动程序
creator
sz111@126.com
http://creatorwu.cublog.cn/
1.首先wdt是一个platform设备,注册的时候采用platform_driver_register。
用platform_driver_register 向系统注册这个驱动程序.而这个函数会在
s3c2410wdt_driver的信息里提取name为搜索内容,搜索系统注册的device
中有没有这个 platform_device。 如果有注册,那么接着会执行platform_driver
里probe函数.在这里显然是s3c2410wdt_probe函数 在probe函数里,用的最多和刚
才platform_device有关的语句是platform_get_resource,这条语句用于获取
platform_device里的resource资料.例如映射的IO地址,中断等.剩下等得就是
ioremap,和 request_irq等的事情了。
而如果调用platform_driver_unregister也会去调用remov了。
2.在wdt驱动里面设定name为s3c2410-wdt,而在devs.c中有定义
struct platform_device s3c_device_wdt = {
.name = "s3c2410-wdt",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_wdt_resource),
.resource = s3c_wdt_resource,
};
/* Watchdog */
static struct resource s3c_wdt_resource[] = {
[0] = {
.start = S3C24XX_PA_WATCHDOG,
.end = S3C24XX_PA_WATCHDOG + S3C24XX_SZ_WATCHDOG - 1,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_WDT,
.end = IRQ_WDT,
.flags = IORESOURCE_IRQ,
}
};
所以可以找到系统里面有这个platform_device,接着就会执行
s3c2410wdt_probe。
static int s3c2410wdt_probe(struct platform_device *pdev)
{
struct resource *res;
int started = 0;
int ret;
int size;
DBG("%s: probe=%p\n", __FUNCTION__, pdev);
/* get the memory region for the watchdog timer */
/**
* platform_get_resource - get a resource for a device
* @dev: platform device
* @type: resource type
* @num: resource index
*/
//获得特殊寄存器占用的mem资源
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
printk(KERN_INFO PFX "failed to get memory region resouce\n");
return -ENOENT;
}
size = (res->end-res->start)+1;
wdt_mem = request_mem_region(res->start, size, pdev->name);
if (wdt_mem == NULL) {
printk(KERN_INFO PFX "failed to get memory region\n");
return -ENOENT;
}
//获得ioremap的地址,这样就可以方便的操作寄存器了。
wdt_base = ioremap(res->start, size);
if (wdt_base == 0) {
printk(KERN_INFO PFX "failed to ioremap() region\n");
return -EINVAL;
}
DBG("probe: mapped wdt_base=%p\n", wdt_base);
//获得中断的地址
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
printk(KERN_INFO PFX "failed to get irq resource\n");
iounmap(wdt_base);
return -ENOENT;
}
/**
* request_irq - allocate an interrupt line
* @irq: Interrupt line to allocate
* @handler: Function to be called when the IRQ occurs
* @irqflags: Interrupt type flags
* @devname: An ascii name for the claiming device
* @dev_id: A cookie passed back to the handler function
*
* This call allocates interrupt resources and enables the
* interrupt line and IRQ handling. From the point this
* call is made your handler function may be invoked. Since
* your handler function must clear any interrupt the board
* raises, you must take care both to initialise your hardware
* and to set up the interrupt handler in the right order.
*
* Dev_id must be globally unique. Normally the address of the
* device data structure is used as the cookie. Since the handler
* receives this value it makes sense to use it.
*
* If your interrupt is shared you must pass a non NULL dev_id
* as this is required when freeing the interrupt.
*
* Flags:
*
* IRQF_SHARED Interrupt is shared
* IRQF_DISABLED Disable local interrupts while processing
* IRQF_SAMPLE_RANDOM The interrupt can be used for entropy
*
*/
//根据获得的中断向量号申请中断。
ret = request_irq(res->start, s3c2410wdt_irq, 0, pdev->name, pdev);
if (ret != 0) {
printk(KERN_INFO PFX "failed to install irq (%d)\n", ret);
iounmap(wdt_base);
return ret;
}
/* Clock API calls */
//struct clk *clk_get(struct device *dev, const char *id)
//获得wdt的clock
wdt_clock = clk_get(&pdev->dev, "watchdog");
if (wdt_clock == NULL) {
printk(KERN_INFO PFX "failed to watchdog clock source\n");
iounmap(wdt_base);
return -ENOENT;
}
//使能wdt clock
clk_enable(wdt_clock);
/* see if we can actually set the requested timer margin, and if
* not, try the default value */
//对wdt 进行配置
if (s3c2410wdt_set_heartbeat(tmr_margin)) {
started = s3c2410wdt_set_heartbeat(CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
if (started == 0) {
printk(KERN_INFO PFX "tmr_margin value out of range, default %d used\n",
CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME);
} else {
printk(KERN_INFO PFX "default timer value is out of range, cannot start\n");
}
}
//把wdt注册为一个杂项设备
ret = misc_register(&s3c2410wdt_miscdev);
if (ret) {
printk (KERN_ERR PFX "cannot register miscdev on minor=%d (%d)\n",
WATCHDOG_MINOR, ret);
iounmap(wdt_base);
return ret;
}
if (tmr_atboot && started == 0) {
printk(KERN_INFO PFX "Starting Watchdog Timer\n");
s3c2410wdt_start();
} 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();
}
return 0;
}
阅读(878) | 评论(0) | 转发(0) |