Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1613711
  • 博文数量: 197
  • 博客积分: 10046
  • 博客等级: 上将
  • 技术积分: 1983
  • 用 户 组: 普通用户
  • 注册时间: 2006-08-07 12:36
个人简介

在外企做服务器开发, 目前是项目经理, 管理两个server开发的项目。不做嵌入式好久了。

文章分类
文章存档

2011年(2)

2010年(6)

2009年(18)

2008年(30)

2007年(100)

2006年(41)

分类: LINUX

2007-11-11 11:42:02

 

完整的信息 可以看到这里: =

 

 

自己写了一个的简单的 for smdk2410 的watchdog driver (完全依照datasheet ,并没有抄袭
s3c2410-wdt.c ) , 可是运行的时候 ,有问题:


# ./wdt_tt
in wdt_disable
readw ok ,tmp=0x0000
COUNTER_VALUE=18300
S3C2410_WTCNT address = c5000008
the value written S3C2410_WTCON=0xff00
Unable to handle kernel NULL pointer dereference at virtual address 00000032
pgd = c3d60000
[00000032] *pgd=338e9031, *pte=00000000, *ppte=00000000
Internal error: Oops: 13 [#1]
Modules linked in: wdt_s3c
CPU: 0
PC is at do_sys_open+0x70/0xe0
LR is at mntput_no_expire+0x24/0x84
pc : [] lr : [] Not tainted
sp : c38e7f70 ip : c38e7ea8 fp : c38e7f94
r10: 4014f60c r9 : c38e6000 r8 : c38e0000
r7 : 00000003 r6 : 0000002a r5 : beb4feec r4 : 00000000
r3 : 00000000 r2 : a0000013 r1 : a0000093 r0 : 0000002a
Flags: nzcv IRQs on FIQs on Mode SVC_32 Segment user
Control: 717F
Table: 33D60000 DAC: 00000015
Process wdt_tt (pid: 263, stack limit = 0xc38e6250)
Stack: (0xc38e7f70 to 0xc38e8000)
7f60: 00008550 beb4fee4 000085e4 00000001
7f80: 00000005 c0026f44 c38e7fa4 c38e7f98 c007d7d8 c007d6d0 00000000 c38e7fa8
7fa0: c0026da0 c007d7c4 beb4fee4 000085e4 000086f8 00000000 beb4feec 00000000
7fc0: beb4fee4 000085e4 00000001 00008648 00008550 00000000 4014f60c beb4feb8
7fe0: 00000000 beb4fe94 00002680 400ee830 60000010 000086f8 fbffff7f ffffffff
Backtrace:
[] (do_sys_open+0x0/0xe0) from []
(sys_open+0x24/0x28)
r8 = C0026F44 r7 = 00000005 r6 = 00000001 r5 = 000085E4
r4 = BEB4FEE4
[] (sys_open+0x0/0x28) from []
(ret_fast_syscall+0x0/0x2c)
Code: e1a00007 ebfffe9e e1a07006 ea000014 (e5900008)
Segmentation fault
#



----
上面的wdt_tt的源码是:



#include
#include
#include
#include
#include
#include
#include

int main(int argc,char **argv)
{

int fd = 0;
int n =0;

fd = open("/dev/wdt",O_RDONLY );
printf("fd=%d\n",fd);
if(fd < 0) {
perror("/dev/wdt");
return -1;
}

sleep(10);

close(fd);

return 0;
}




dirver的源码是


/* S3C2410-wdt.c
* CopyRight reserved by BobZhang
*/


#include
#include
#include
#include
#include
#include
#include
#include
#include

#include
#include
#include
#include
#include

#include //一定要有这个

#include

#include //专门定义smdk2410 watchdog 寄存器的header
file


#undef S3C24XX_VA_WATCHDOG
#define S3C24XX_VA_WATCHDOG s3c_wdt_base


static u32 heartbeat = 12; //自己定义的心跳值,这个value应该会有个上限
#define PCLK 50000000
#define PRESCALER 255
#define DIVISION_FACTOR 128 //最最大的

//#define COUNTER_VALUE heartbeat * ( 50000000 / (PRESCALER + 1) / DIVISION_FACTOR )



static unsigned long wdt_status;

#define WDT_IN_USE 0



static void __iomem *s3c_wdt_base;
static struct resource *s3c_wdt_mem;

/* 这个是一定要的,因为在regs-watchdog.h 里面都定义 ,把S3C24XX_VA_WATCHDOG 定义成
这里得到的实际的 s3c_wdt_base ,就可以实际控制硬件了。
#define S3C2410_WDOGREG(x) ((x) + S3C24XX_VA_WATCHDOG)

#define S3C2410_WTCON S3C2410_WDOGREG(0x00)
#define S3C2410_WTDAT S3C2410_WDOGREG(0x04)
#define S3C2410_WTCNT S3C2410_WDOGREG(0x08)
*/


//#define S3C2410_WTCON_RSTEN (0x01)
//#define S3C2410_WTCON_INTEN (1<<2)
//#define S3C2410_WTCON_ENABLE (1<<5)


struct resource *platform_get_resource(struct platform_device *dev, unsigned int
type,unsigned int num);

static void wdt_disable(void)
{

u32 tmp;

printk("in wdt_disable \n");
tmp = readl(S3C2410_WTCON); //only 低6bit是起作用的,其他的无用,所以用readl
printk("readl ok ,tmp=0x%04x\n",tmp);
writel(tmp & ~S3C2410_WTCON_ENABLE, S3C2410_WTCON);

}


static void wdt_enable(void)
{
u32 tmp; //255 //128
u16 COUNTER_VALUE = heartbeat * ( 50000000 / (PRESCALER + 1) / DIVISION_FACTOR );

wdt_disable();

printk("COUNTER_VALUE=%hu\n",COUNTER_VALUE);
printk("S3C2410_WTCNT address = %p\n",S3C2410_WTCNT);
//写入 S3C2410_WTDAT
writel(COUNTER_VALUE, S3C2410_WTDAT);
//写入S3C2410_WTCNT
writel(COUNTER_VALUE, S3C2410_WTCNT);

tmp = readl(S3C2410_WTCON);
tmp &= ~0xff00; //bit8~bit15 清零,然后写入PRESCALER
tmp |= (PRESCALER << 8);
printk("the value written S3C2410_WTCON=0x%04x\n",tmp);
writel(tmp, S3C2410_WTCON);

//重新eanble reset
tmp = readl(S3C2410_WTCON);
writel(tmp |S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN , S3C2410_WTCON);
}


static int s3c_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;

wdt_enable();
}



static int s3c_wdt_release(struct inode *inode, struct file *file)
{
clear_bit(WDT_IN_USE, &wdt_status);
wdt_disable();

return 0;
}



//
//static struct watchdog_info ident = {
// .options = WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
// WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
// .identity = "s3c Watchdog",
//};


static const struct file_operations s3c_wdt_fops =
{
.owner = THIS_MODULE,
// .write = s3c_wdt_write,
// .ioctl = s3c_wdt_ioctl,
.open = s3c_wdt_open,
.release = s3c_wdt_release,
};

static struct miscdevice s3c_wdt_miscdev =
{
.minor = WATCHDOG_MINOR, //130
.name = "watchdog_s3c_bob",
.fops = &s3c_wdt_fops,
};



//probe函数很简单, 就是
// 1>取得resource_wdt
// 2> request_mem_region
// 3> ioremap()
// 失败不要紧,关键要作好错误处理
static int s3c_wdt_probe(struct platform_device *pdev)
{
struct resource *res;
int ret = 0;

//#define IORESOURCE_MEM 0x00000200


/* get the memory region */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); //根据watchdog的情况作特殊处理
if (res == NULL) {
printk("failed to get memory region resource\n");
return -ENOENT;
}

s3c_wdt_mem = request_mem_region(res->start, res->end-res->start+1,
pdev->name);

if (s3c_wdt_mem == NULL) {
printk("failed to reserve memory region\n");
ret = -ENOENT;
goto err_nores;
}

s3c_wdt_base = ioremap(res->start, res->end - res->start + 1);
if (s3c_wdt_base == NULL) {
printk("WDT s3c2410 failed ioremap()\n");
ret = -EINVAL;
goto err_nomap;
}

/* 可能要作一些s3c2410 WDT 的初始化的一些动作 */

/* 开始注册watchdog 相应的函数, 是作为misc设备进行注册 */
ret = misc_register(&s3c_wdt_miscdev);
if (ret == 0)
printk("S3C2410_bob Watchdog Timer: heartbeat %d sec\n", heartbeat);
else
printk("S3C2410_bob Watchdog Timer misc_register failure ,error=%d\n",ret);

return ret;

err_nomap:
release_resource(s3c_wdt_mem);

err_nores:
return ret;
}




static struct platform_driver s3c_wdtdrv = {
.probe = s3c_wdt_probe,
// .remove = s3c_wdt_remove,
// .suspend = s3c_wdt_suspend,
// .resume = s3c_wdt_resume,
.driver = {
.name = "s3c2410-wdt",
.owner = THIS_MODULE,
},
};

static char __initdata banner[] = "S3C2410a Watchdog, (c) 2007 BobZhang\n";

static int __init s3c_wdt_init(void)
{
printk(banner);
return platform_driver_register(&s3c_wdtdrv);
}

static void __exit s3c_wdt_exit(void)
{
platform_driver_unregister(&s3c_wdtdrv);
}

module_init(s3c_wdt_init);
module_exit(s3c_wdt_exit);

MODULE_DESCRIPTION("Samsung S3C Watchdog Driver , BobZhang write , only for
testing");
MODULE_AUTHOR("BobZhang
MODULE_LICENSE("GPL");

 

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

我是这样计算watchdog到底支持几秒的: 


t_watchdog = 1/( PCLK / (Prescaler value + 1) / Division_factor )

其实 ,最后的 要写入寄存器的counter = ( PCLK / (Prescaler value + 1) / Division_factor ) * 用户要求的秒数Tmax

设用户想要设置的秒数为Tmax

则满足关系式:

Tmax * counter < 2^16

即: Tmax * ( PCLK / (Prescaler value + 1) / Division_factor ) <2^16

Tmax < 2^16 / ( PCLK / (Prescaler value + 1) / Division_factor )

即 Tmax < (2^16 * (Prescaler value + 1) * Division_factor) / PCLK

要想求出 Tmax的最大的值 , 即让 Prescaler value 和 Division_factor 取最大值即可。

而PCLK式常数 = 50000000

Tmax < (2^16 * (255 + 1) * 128) / 50000000

Tmax < 42.9

所以最终用户能设置的最大的值是42 秒, 而且 Prescaler 寄存器要设置成 255


 
+++++++++++++++++++++++++++++++++++++++++++++++++++++++

找到原因了,

原来


static int s3c_wdt_open(struct inode *inode, struct file *file)
{
if (test_and_set_bit(WDT_IN_USE, &wdt_status))
return -EBUSY;

wdt_enable();

return 0; //之前忘记 return 了。 ^_^。
}




static void wdt_enable(void)
{
u32 tmp; //255 //128
u16 COUNTER_VALUE = heartbeat * ( 50000000 / (PRESCALER + 1) / DIVISION_FACTOR );
//u16 COUNTER_VALUE = (1 << 16) -10;

printk("COUNTER_VALUE=%hu\n",COUNTER_VALUE);
printk("S3C2410_WTCNT address = %p\n",S3C2410_WTCNT);
writel(COUNTER_VALUE, S3C2410_WTDAT);
writel(COUNTER_VALUE, S3C2410_WTCNT);

tmp = readl(S3C2410_WTCON);
tmp &= ~0xff00; //bit8~bit15
tmp |= (PRESCALER << 8);

//这里是后加的,

tmp &= ~(0x03 << 3);
tmp |= 0x03 << 3; //11b is 128 division

printk("the value written S3C2410_WTCON=0x%04x\n",tmp);
writel(tmp, S3C2410_WTCON);

//ÖØÐÂeanble reset
tmp = readl(S3C2410_WTCON);
writel(tmp |S3C2410_WTCON_ENABLE | S3C2410_WTCON_RSTEN , S3C2410_WTCON);


//test,
tmp = readl(S3C2410_WTCNT);
printk("S3C2410_WTCNT value = %hu\n",tmp);
}






--------------------
watchdog的datasheet还是最简单的, 所以就安排新人 完全靠自己的理解, 不要看原有的c code 自己写, 只有这样才能真正自己写出一个driver来 。 但是这样安排还是要有个前期铺垫 , 之前仔细的领 新人 分析了 RTC的代码和datasheet ,其实RTC的datasheet 还是比Watchdog 复杂的, 是driver新手入门的好突破口。

正好自己也从来没有看过现有的watchdog的实现c 代码, 也自己写写看 , 其实也是挺锻炼人的 。 都说写driver 是天下文章一大抄 , 不过 终归还是 要培养逼着眼睛自己写的能力啊。


写driver ,看懂datasheet确实是很高的要求, 哪怕是最简单的datasheet 也要有第一次的仔细看 , 看明白了, 以后看别的datasheet 就彻底容易了。

 
阅读(3222) | 评论(1) | 转发(1) |
给主人留下些什么吧!~~

chinaunix网友2008-08-01 03:37:29

SAP99,支持下,也欢迎访问我的博客, SAP资料多多 http://sap99.cublog.cn PA系列教材 web_dynpro_for_java Web_Dynpro_for_abap abap资料-在SAP中查询TABL SAP实施顾问宝典 SAP配置(录像)-维护供应 SAP配置(录像)-定义税务 sap全面概述中文