driver.h
#ifndef _DRIVER_H
#define _DRIVER_H
#define WDT_ON 0
#define WDT_OFF 1
#define WDT_MODE 2
#define WDT_FEED 3
#endif
driver.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mm.h>
#include <linux/ioport.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include "driver.h"
struct wdt_driver {
unsigned long phys;
void __iomem *virt_base;
unsigned long wtcon;
unsigned long wtdat;
unsigned long wtcnt;
struct cdev cdev;
unsigned minor,major;
dev_t devno;
unsigned long irq;
void (*wdt_on)(struct wdt_driver *wdt);
void (*wdt_off)(struct wdt_driver *wdt);
void (*wdt_mode)(struct wdt_driver *wdt,unsigned long n);
void (*wdt_feed)(struct wdt_driver *wdt);
};
int open_wdt(struct inode *inod, struct file * filp)
{
printk("has open the wdt/n");
return 0;
}
int ioctl_wdt(struct inode *inod,struct file * filp,unsigned int cmd,unsigned long arg)
{
struct wdt_driver *wdt=container_of(inod->i_cdev,struct wdt_driver,cdev);
switch(cmd)
{
case WDT_ON:
wdt->wdt_on(wdt);
break;
case WDT_OFF:
wdt->wdt_off(wdt);
break;
case WDT_MODE:
wdt->wdt_mode(wdt,arg);
break;
case WDT_FEED:
wdt->wdt_feed(wdt);
break;
default:
return -EINVAL;
}
return 0;
}
struct wdt_driver *wdt;
struct class *myclass;
struct file_operations f_ops={
owner : THIS_MODULE,
open : open_wdt,
ioctl : ioctl_wdt,
};
void wdt_on(struct wdt_driver *wdt)
{
unsigned long ret;
ret=ioread32(wdt->wtcon);
ret|=(1<<5);
iowrite32(ret,wdt->wtcon);
}
void wdt_off(struct wdt_driver *wdt)
{
unsigned long ret;
ret=ioread32(wdt->wtcon);
ret&=~(1<<5);
iowrite32(ret,wdt->wtcon);
}
void wdt_mode(struct wdt_driver *wdt ,unsigned long reset)
{
unsigned long ret;
ret=ioread32(wdt->wtcon);
if(reset)
{
ret&=~(1<<2);
ret|=1;
iowrite32(ret,wdt->wtcon);
printk("reset mode opened/n");
}
else
{
ret&=(~1);
ret|=(1<<2);
iowrite32(ret,wdt->wtcon);
}
}
void wdt_feed(struct wdt_driver *wdt)
{
iowrite32(0x8000,wdt->wtcnt);
}
irqreturn_t irqhandled(int irqno,void *devno)
{
printk("the watchdog has interrupt/n");
return IRQ_HANDLED;
}
int init_wdt_device(struct wdt_driver *wdt)
{
wdt->irq=IRQ_S3C2440_WDT;
wdt->virt_base=ioremap(wdt->phys,SZ_4K);
if(NULL==wdt->virt_base)
{
printk("<kernel> has no virtul mem/n");
goto ERR1;
}
wdt->wtcon=(unsigned long)wdt->virt_base+(unsigned long )0x00;
wdt->wtdat=(unsigned long)wdt->virt_base+0x04;
wdt->wtcnt=(unsigned long)wdt->virt_base+0x08;
if(request_irq(wdt->irq,irqhandled,0,"watchdog",NULL))
{
printk("<kernel> request the irq failed/n");
goto ERR2;
}
wdt->wdt_on=wdt_on;
wdt->wdt_off=wdt_off;
wdt->wdt_mode=wdt_mode;
wdt->wdt_feed=wdt_feed;
iowrite32(0x8004,wdt->wtcon);
iowrite32(0x8000,wdt->wtcnt);
return 0;
ERR2:
iounmap((void __iomem*)wdt->virt_base);
ERR1:
return -EBUSY;
}
int init_wdt(struct platform_device *pdev)
{
wdt=kmalloc(sizeof(struct wdt_driver),GFP_KERNEL);
if(NULL==wdt)
{
printk("<kernel>has no enough mem/n");
goto ERR1;
}
memset(wdt,0,sizeof(struct wdt_driver));
wdt->major=0;
wdt->minor=0;
if(wdt->major)
{
wdt->devno=MKDEV(wdt->major,wdt->minor);
register_chrdev_region(wdt->devno,1,"wdt_driver");
}
else
{
alloc_chrdev_region(&wdt->devno,wdt->minor,1,"wdt_driver");
printk("<kernel alloc>major=%d,minor=%d/n",MAJOR(wdt->devno),MINOR(wdt->minor));
}
myclass = class_create(THIS_MODULE, "test-udev-class");
device_create(myclass, NULL, wdt->devno, "%s", "watchdog");
cdev_init(&wdt->cdev,&f_ops);
wdt->phys=pdev->resource->start;
if(init_wdt_device(wdt))
{
printk("<kernel>init the wdt device failed/n");
goto ERR2;
}
if(cdev_add(&wdt->cdev,wdt->devno,1))
{
printk("add the device failed/n");
goto ERR3;
}
return 0;
ERR3:
class_destroy(myclass);
device_destroy(myclass,wdt->devno);
unregister_chrdev_region(wdt->devno,1);
ERR2:
kfree(wdt);
return -ENODEV;
ERR1:
return -ENOMEM;
}
int plat_probe(struct platform_device *pdev)
{
printk("<kernel> the plat_driver has probe with the device/n");
init_wdt(pdev);
return 0;
}
int plat_remove(struct platform_device *dev)
{
iowrite32(0,wdt->wtcon);
cdev_del(&wdt->cdev);
class_destroy(myclass);
device_destroy(myclass,wdt->devno);
unregister_chrdev_region(wdt->devno,1);
iounmap((void __iomem *)wdt->virt_base);
free_irq(wdt->irq,NULL);
kfree(wdt);
return 0;
}
struct platform_driver drv={
probe : plat_probe,
remove : plat_remove,
driver : {
name : "watchdog"
}
};
int init_driver(void)
{
platform_driver_register(&drv);
return 0;
}
void exit_driver(void)
{
platform_driver_unregister(&drv);
}
module_init(init_driver);
module_exit(exit_driver);
MODULE_LICENSE("GPL");
device.c
#include <linux/module.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/device.h>
#include <linux/platform_device.h>
struct resource wdt_res ={
start :0x53000000,
end :0x530000ff,
};
void wdt_release(struct device *dev)
{
printk("has the wdt device unregister/n");
}
struct platform_device wdt={
name : "watchdog",
id : 10,
dev : {
bus_id : "wdt_dev",
release : wdt_release,
},
resource : &wdt_res,
};
int init_device(void)
{
platform_device_register(&wdt);
return 0;
}
void exit_device(void)
{
platform_device_unregister(&wdt);
}
module_init(init_device);
module_exit(exit_device);
MODULE_LICENSE("GPL");
test.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>
#include "driver.h"
int main(int argc, char **argv)
{
int fd;
unsigned cmd;
fd=open("/dev/watchdog",O_RDWR);
if(fd<0)
{
printf("has no the watchdog file/n");
return -1;
}
printf("fd=%d/n",fd);
ioctl(fd, WDT_MODE, 1);/*enable the watchdog has send the reset signal and disable the interrupt*/
// ioctl(fd,WDT_MODE,0);/*disable send reset signal*/
ioctl(fd, WDT_ON);
while(1) {
ioctl(fd, WDT_FEED);/***feed the watchdog****/
usleep(100 * 1000);
}
close(fd);
return 0;