X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fsbus%2Fchar%2Fcpwatchdog.c;h=ad1c7db96cb4d8eb7bc38f561ff5535f3dd168c7;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=e383894df08ec5b26171422930cb8c104c7bbbe0;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index e383894df..ad1c7db96 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -10,8 +10,6 @@ * timer interrupts. We use a timer to periodically * reset 'stopped' watchdogs on affected platforms. * - * TODO: DevFS support (/dev/watchdogs/0 ... /dev/watchdogs/2) - * * Copyright (c) 2000 Eric Brower (ebrower@usa.net) */ @@ -26,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -118,40 +117,26 @@ * UNKNOWN, MAGICAL MYSTERY REGISTER * */ -struct wd_timer_regblk { - volatile __u16 dcntr; /* down counter - hw */ - volatile __u16 dcntr_pad; - volatile __u16 limit; /* limit register - hw */ - volatile __u16 limit_pad; - volatile __u8 status; /* status register - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; - volatile __u32 pad32; /* yet more padding */ -}; +#define WD_TIMER_REGSZ 16 +#define WD0_OFF 0 +#define WD1_OFF (WD_TIMER_REGSZ * 1) +#define WD2_OFF (WD_TIMER_REGSZ * 2) +#define PLD_OFF (WD_TIMER_REGSZ * 3) -struct wd_pld_regblk { - volatile __u8 intr_mask; /* interrupt mask - b */ - volatile __u8 intr_mask_pad; - volatile __u16 intr_mask_pad2; - volatile __u8 status; /* device status - b */ - volatile __u8 status_pad; - volatile __u16 status_pad2; -}; +#define WD_DCNTR 0x00 +#define WD_LIMIT 0x04 +#define WD_STATUS 0x08 -struct wd_regblk { - volatile struct wd_timer_regblk wd0_regs; - volatile struct wd_timer_regblk wd1_regs; - volatile struct wd_timer_regblk wd2_regs; - volatile struct wd_pld_regblk pld_regs; -}; +#define PLD_IMASK (PLD_OFF + 0x00) +#define PLD_STATUS (PLD_OFF + 0x04) /* Individual timer structure */ struct wd_timer { __u16 timeout; __u8 intr_mask; - unsigned char runstatus; - volatile struct wd_timer_regblk* regs; + unsigned char runstatus; + void __iomem *regs; }; /* Device structure @@ -165,7 +150,7 @@ struct wd_device { unsigned short opt_timeout; unsigned char initialized; struct wd_timer watchdog[WD_NUMDEVS]; - volatile struct wd_regblk* regs; + void __iomem *regs; }; static struct wd_device wd_dev = { @@ -179,11 +164,11 @@ static int wd1_timeout = 0; static int wd2_timeout = 0; #ifdef MODULE -MODULE_PARM (wd0_timeout, "i"); +module_param (wd0_timeout, int, 0); MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); -MODULE_PARM (wd1_timeout, "i"); +module_param (wd1_timeout, int, 0); MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); -MODULE_PARM (wd2_timeout, "i"); +module_param (wd2_timeout, int, 0); MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); MODULE_AUTHOR @@ -200,7 +185,7 @@ MODULE_SUPPORTED_DEVICE #ifdef WD_DEBUG static void wd_dumpregs(void); #endif -static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static irqreturn_t wd_interrupt(int irq, void *dev_id); static void wd_toggleintr(struct wd_timer* pTimer, int enable); static void wd_pingtimer(struct wd_timer* pTimer); static void wd_starttimer(struct wd_timer* pTimer); @@ -314,17 +299,17 @@ static int wd_open(struct inode *inode, struct file *f) { if (request_irq(wd_dev.irq, &wd_interrupt, - SA_SHIRQ, + IRQF_SHARED, WD_OBPNAME, (void *)wd_dev.regs)) { - printk("%s: Cannot register IRQ %s\n", - WD_OBPNAME, __irq_itoa(wd_dev.irq)); + printk("%s: Cannot register IRQ %d\n", + WD_OBPNAME, wd_dev.irq); return(-EBUSY); } wd_dev.initialized = 1; } - return(0); + return(nonseekable_open(inode, f)); } static int wd_release(struct inode *inode, struct file *file) @@ -337,6 +322,7 @@ static int wd_ioctl(struct inode *inode, struct file *file, { int setopt = 0; struct wd_timer* pTimer = (struct wd_timer*)file->private_data; + void __user *argp = (void __user *)arg; struct watchdog_info info = { 0, 0, @@ -351,22 +337,20 @@ static int wd_ioctl(struct inode *inode, struct file *file, { /* Generic Linux IOCTLs */ case WDIOC_GETSUPPORT: - if(copy_to_user((struct watchdog_info *)arg, - (struct watchdog_info *)&info, - sizeof(struct watchdog_info))) { + if(copy_to_user(argp, &info, sizeof(struct watchdog_info))) { return(-EFAULT); } break; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: - if (put_user(0, (int *) arg)) + if (put_user(0, (int __user *)argp)) return -EFAULT; break; case WDIOC_KEEPALIVE: wd_pingtimer(pTimer); break; case WDIOC_SETOPTIONS: - if(copy_from_user(&setopt, (void*) arg, sizeof(unsigned int))) { + if(copy_from_user(&setopt, argp, sizeof(unsigned int))) { return -EFAULT; } if(setopt & WDIOS_DISABLECARD) { @@ -388,7 +372,7 @@ static int wd_ioctl(struct inode *inode, struct file *file, /* Solaris-compatible IOCTLs */ case WIOCGSTAT: setopt = wd_getstatus(pTimer); - if(copy_to_user((void*)arg, &setopt, sizeof(unsigned int))) { + if(copy_to_user(argp, &setopt, sizeof(unsigned int))) { return(-EFAULT); } break; @@ -409,10 +393,32 @@ static int wd_ioctl(struct inode *inode, struct file *file, return(0); } -static ssize_t wd_write( struct file *file, - const char *buf, - size_t count, - loff_t *ppos) +static long wd_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int rval = -ENOIOCTLCMD; + + switch (cmd) { + /* solaris ioctls are specific to this driver */ + case WIOCSTART: + case WIOCSTOP: + case WIOCGSTAT: + lock_kernel(); + rval = wd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); + unlock_kernel(); + break; + /* everything else is handled by the generic compat layer */ + default: + break; + } + + return rval; +} + +static ssize_t wd_write(struct file *file, + const char __user *buf, + size_t count, + loff_t *ppos) { struct wd_timer* pTimer = (struct wd_timer*)file->private_data; @@ -420,9 +426,6 @@ static ssize_t wd_write( struct file *file, return(-EINVAL); } - if (ppos != &file->f_pos) - return -ESPIPE; - if (count) { wd_pingtimer(pTimer); return 1; @@ -430,7 +433,7 @@ static ssize_t wd_write( struct file *file, return 0; } -static ssize_t wd_read(struct file * file, char * buffer, +static ssize_t wd_read(struct file * file, char __user *buffer, size_t count, loff_t *ppos) { #ifdef WD_DEBUG @@ -441,7 +444,7 @@ static ssize_t wd_read(struct file * file, char * buffer, #endif /* ifdef WD_DEBUG */ } -static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) +static irqreturn_t wd_interrupt(int irq, void *dev_id) { /* Only WD0 will interrupt-- others are NMI and we won't * see them here.... @@ -459,6 +462,7 @@ static irqreturn_t wd_interrupt(int irq, void *dev_id, struct pt_regs *regs) static struct file_operations wd_fops = { .owner = THIS_MODULE, .ioctl = wd_ioctl, + .compat_ioctl = wd_compat_ioctl, .open = wd_open, .write = wd_write, .read = wd_read, @@ -499,12 +503,12 @@ static void wd_dumpregs(void) i, wd_getstatus(&wd_dev.watchdog[i])); } - printk("\tintr_mask at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.intr_mask), - readb(&wd_dev.regs->pld_regs.intr_mask)); - printk("\tpld_status at 0x%lx: 0x%x\n", - (unsigned long)(&wd_dev.regs->pld_regs.status), - readb(&wd_dev.regs->pld_regs.status)); + printk("\tintr_mask at %p: 0x%x\n", + wd_dev.regs + PLD_IMASK, + readb(wd_dev.regs + PLD_IMASK)); + printk("\tpld_status at %p: 0x%x\n", + wd_dev.regs + PLD_STATUS, + readb(wd_dev.regs + PLD_STATUS)); } #endif @@ -517,7 +521,7 @@ static void wd_dumpregs(void) */ static void wd_toggleintr(struct wd_timer* pTimer, int enable) { - unsigned char curregs = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char curregs = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char setregs = (NULL == pTimer) ? (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : @@ -527,7 +531,7 @@ static void wd_toggleintr(struct wd_timer* pTimer, int enable) (curregs &= ~setregs): (curregs |= setregs); - wd_writeb(curregs, &wd_dev.regs->pld_regs.intr_mask); + wd_writeb(curregs, wd_dev.regs + PLD_IMASK); return; } @@ -538,8 +542,8 @@ static void wd_toggleintr(struct wd_timer* pTimer, int enable) */ static void wd_pingtimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { - wd_readw(&pTimer->regs->dcntr); + if (wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { + wd_readw(pTimer->regs + WD_DCNTR); } } @@ -551,7 +555,7 @@ static void wd_pingtimer(struct wd_timer* pTimer) */ static void wd_stoptimer(struct wd_timer* pTimer) { - if(wd_readb(&pTimer->regs->status) & WD_S_RUNNING) { + if(wd_readb(pTimer->regs + WD_STATUS) & WD_S_RUNNING) { wd_toggleintr(pTimer, WD_INTR_OFF); if(wd_dev.isbaddoggie) { @@ -578,7 +582,7 @@ static void wd_starttimer(struct wd_timer* pTimer) } pTimer->runstatus &= ~WD_STAT_SVCD; - wd_writew(pTimer->timeout, &pTimer->regs->limit); + wd_writew(pTimer->timeout, pTimer->regs + WD_LIMIT); wd_toggleintr(pTimer, WD_INTR_ON); } @@ -588,7 +592,7 @@ static void wd_starttimer(struct wd_timer* pTimer) static void wd_resetbrokentimer(struct wd_timer* pTimer) { wd_toggleintr(pTimer, WD_INTR_ON); - wd_writew(WD_BLIMIT, &pTimer->regs->limit); + wd_writew(WD_BLIMIT, pTimer->regs + WD_LIMIT); } /* Timer device initialization helper. @@ -597,7 +601,7 @@ static void wd_resetbrokentimer(struct wd_timer* pTimer) static int wd_inittimer(int whichdog) { struct miscdevice *whichmisc; - volatile struct wd_timer_regblk *whichregs; + void __iomem *whichregs; char whichident[8]; int whichmask; __u16 whichlimit; @@ -607,7 +611,7 @@ static int wd_inittimer(int whichdog) case WD0_ID: whichmisc = &wd0_miscdev; strcpy(whichident, "RIC"); - whichregs = &wd_dev.regs->wd0_regs; + whichregs = wd_dev.regs + WD0_OFF; whichmask = WD0_INTR_MASK; whichlimit= (0 == wd0_timeout) ? (wd_dev.opt_timeout): @@ -616,7 +620,7 @@ static int wd_inittimer(int whichdog) case WD1_ID: whichmisc = &wd1_miscdev; strcpy(whichident, "XIR"); - whichregs = &wd_dev.regs->wd1_regs; + whichregs = wd_dev.regs + WD1_OFF; whichmask = WD1_INTR_MASK; whichlimit= (0 == wd1_timeout) ? (wd_dev.opt_timeout): @@ -625,7 +629,7 @@ static int wd_inittimer(int whichdog) case WD2_ID: whichmisc = &wd2_miscdev; strcpy(whichident, "POR"); - whichregs = &wd_dev.regs->wd2_regs; + whichregs = wd_dev.regs + WD2_OFF; whichmask = WD2_INTR_MASK; whichlimit= (0 == wd2_timeout) ? (wd_dev.opt_timeout): @@ -690,8 +694,8 @@ static void wd_brokentimer(unsigned long data) static int wd_getstatus(struct wd_timer* pTimer) { - unsigned char stat = wd_readb(&pTimer->regs->status); - unsigned char intr = wd_readb(&wd_dev.regs->pld_regs.intr_mask); + unsigned char stat = wd_readb(pTimer->regs + WD_STATUS); + unsigned char intr = wd_readb(wd_dev.regs + PLD_IMASK); unsigned char ret = WD_STOPPED; /* determine STOPPED */ @@ -749,7 +753,7 @@ static int __init wd_init(void) for_each_ebus(ebus) { for_each_ebusdev(edev, ebus) { - if (!strcmp(edev->prom_name, WD_OBPNAME)) + if (!strcmp(edev->ofdev.node->name, WD_OBPNAME)) goto ebus_done; } } @@ -761,7 +765,7 @@ ebus_done: } wd_dev.regs = - ioremap(edev->resource[0].start, sizeof(struct wd_regblk)); + ioremap(edev->resource[0].start, 4 * WD_TIMER_REGSZ); /* ? */ if(NULL == wd_dev.regs) { printk("%s: unable to map registers\n", WD_OBPNAME); @@ -809,7 +813,7 @@ static void __exit wd_cleanup(void) * also now eventually trip. */ for(id = WD0_ID; id < WD_NUMDEVS; ++id) { - if(WD_S_RUNNING == wd_readb(&wd_dev.watchdog[id].regs->status)) { + if(WD_S_RUNNING == wd_readb(wd_dev.watchdog[id].regs + WD_STATUS)) { if(wd_dev.opt_enable) { printk(KERN_WARNING "%s%i: timer not stopped at release\n", WD_OBPNAME, id); @@ -822,7 +826,7 @@ static void __exit wd_cleanup(void) "%s%i: defect workaround disabled at release, "\ "timer expires in ~%01i sec\n", WD_OBPNAME, id, - wd_readw(&wd_dev.watchdog[id].regs->limit) / 10); + wd_readw(wd_dev.watchdog[id].regs + WD_LIMIT) / 10); } } }