/* * Watchdog driver for the IXP2400/IXP2800 based platforms * * (c) Copyright 2000 Intel Coporation * Based on SoftDog driver by Alan Cox * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide * warranty for any of this software. This material is provided * "AS-IS" and at no charge. * * Harold Yang * Stanley Wang * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MY_NAME "IXP425 Watchdog Timer" /* you must define it ,otherwise ,the timer will stop after write() ,read() */ //#define CONFIG_WATCHDOG_NOWAYOUT /* you can comment it ,if you don't debug */ #define CONFIG_IXP425_WTDEBUG #ifdef CONFIG_IXP425_WTDEBUG #define dbg(format, arg...) \ do { \ printk("<0>" "%s: " format, \ MY_NAME , ## arg); \ } while (0) #else #define dbg(format, arg...) #endif #define TIMER_FREQ 66000000 /* 66 MHZ timer */ #define TIMER_KEY 0x482e #define TIMER_MARGIN 66 /* (secs) Default is 1 minute */ static int ixp425_margin = TIMER_MARGIN; /* in seconds */ static int ixp425wdt_users; //static int pre_margin; //IXP425 CPU 's watch dog timer is 32 bit , so I define it to be unsigned int --bob static unsigned int pre_margin; /* * Allow only one person to hold it open */ static int ixp425dog_open(struct inode *inode, struct file *file) { if(test_and_set_bit(1,&ixp425wdt_users)) return -EBUSY; MOD_INC_USE_COUNT; dbg("\n\nin open () function , *IXP425_OSWT = %u\n",*IXP425_OSWT); dbg("ixp425_margin=%d\n",ixp425_margin); /* Activate IXP425 Watchdog timer */ pre_margin=TIMER_FREQ * ixp425_margin; *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWT = pre_margin; dbg("in open function pre_margin = %u\n",pre_margin); *IXP425_OSWE = 0x5; //bit 0:reset ; bit 1:interupt; bit 2:counter down enable *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 0; } static int ixp425dog_release(struct inode *inode, struct file *file) { /* * Shut off the timer. * Lock it in if it's a module and we defined ...NOWAYOUT */ *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWT = pre_margin; #ifndef CONFIG_WATCHDOG_NOWAYOUT *IXP425_OSWE = 0x0; #endif *IXP425_OSWK = 0; /* Lock the watch dog timer */ ixp425wdt_users = 0; MOD_DEC_USE_COUNT; return 0; } static ssize_t ixp425dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) { /* Can't seek (pwrite) on this device */ if (ppos != &file->f_pos) return -ESPIPE; /* Refresh OSMR3 timer. */ if(len) { dbg("has into write function len !=0 , *IXP425_OSWT = %u\n",*IXP425_OSWT); dbg("just IXP425_OSWT will set to be %u \n",pre_margin); *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWT = pre_margin; *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 1; } return 0; } /* it is only used to test the IXP425_OSWT register's value --BOB */ static ssize_t ixp425dog_read(struct file *file, char *data, size_t len, loff_t *ppos) { /* read OSMR3 timer. */ int current_timer = 0; char buffer[10] = {'\0'}; dbg("has into read() function , *IXP425_OSWT = %u\n",*IXP425_OSWT); //*IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ current_timer = *IXP425_OSWT ; //*IXP425_OSWK = 0; /* Lock the watch dog timer */ //--> snprintf(buffer,sizeof(buffer)-1,"%d",current_timer); copy_to_user(data,buffer,strlen(buffer)); } static int ixp425dog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int new_margin; int options = 0; static struct watchdog_info ident = { identity: "IXP425 Watchdog Timer", options: WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_CARDRESET, }; switch(cmd){ default: return -ENOIOCTLCMD; case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); case WDIOC_GETSTATUS: return put_user(0,(int *)arg); case WDIOC_GETBOOTSTATUS: return put_user((*IXP425_OSST & 0x00000010) ? WDIOF_CARDRESET : 0, (int *)arg); case WDIOC_GETTEMP: return -ENOIOCTLCMD; case WDIOC_SETOPTIONS: if (get_user(options, (int *)arg)) return -EFAULT; switch(options) { case WDIOS_DISABLECARD: *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWE = 0x0; *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 0; case WDIOS_ENABLECARD: *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWE = 0x5; *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 0; default: return -ENOIOCTLCMD; } case WDIOC_SETTIMEOUT: if (get_user(new_margin, (int *)arg)) return -EFAULT; if (new_margin < 1) return -EINVAL; ixp425_margin = new_margin; pre_margin=TIMER_FREQ * ixp425_margin; *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWT = pre_margin; *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 0; case WDIOC_GETTIMEOUT: put_user(ixp425_margin, (int *)arg); return 0; case WDIOC_KEEPALIVE: *IXP425_OSWK = TIMER_KEY; /* Unlock the watch dog timer */ *IXP425_OSWT = pre_margin; *IXP425_OSWK = 0; /* Lock the watch dog timer */ return 0; } } static struct file_operations ixp425dog_fops= { owner: THIS_MODULE, read: ixp425dog_read, write: ixp425dog_write, ioctl: ixp425dog_ioctl, open: ixp425dog_open, release: ixp425dog_release, }; static struct miscdevice ixp425dog_miscdev= { WATCHDOG_MINOR, "IXP425 watchdog", &ixp425dog_fops }; static int __init ixp425dog_init(void) { int ret; dbg("WATCHDOG_MINOR = %d\n",WATCHDOG_MINOR); ret = misc_register(&ixp425dog_miscdev); dbg("ret of misc_register() = %d\n",ret); if (ret) return ret; dbg("timer margin %d sec\n", ixp425_margin); return 0; } static void __exit ixp425dog_exit(void) { misc_deregister(&ixp425dog_miscdev); } module_init(ixp425dog_init); module_exit(ixp425dog_exit); MODULE_AUTHOR("Stanely Wang"); MODULE_LICENSE("GPL"); MODULE_PARM(ixp425_margin,"i"); MODULE_PARM_DESC(ixp425_margin,"IXP425 Watchdog Timer's expiring time."); MODULE_DESCRIPTION("IXP425 Watchdog Timer driver."); MODULE_SUPPORTED_DEVICE("IXCDP1100 dev board.");