Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / drivers / sbus / char / cpwatchdog.c
index ad870a3..fd2cc77 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
+#include <linux/smp_lock.h>
 #include <asm/irq.h>
 #include <asm/ebus.h>
 #include <asm/oplib.h>
  * 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 +152,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 +166,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
@@ -408,6 +395,28 @@ static int wd_ioctl(struct inode *inode, struct file *file,
        return(0);
 }
 
+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_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, 
@@ -455,6 +464,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,
@@ -495,12 +505,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
 
@@ -513,7 +523,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) : 
@@ -523,7 +533,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;
 }
 
@@ -534,8 +544,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);
        }
 }
 
@@ -547,7 +557,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) {
@@ -574,7 +584,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);
 }
 
@@ -584,7 +594,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.
@@ -593,7 +603,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;
@@ -603,7 +613,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): 
@@ -612,7 +622,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): 
@@ -621,7 +631,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): 
@@ -686,8 +696,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 */
@@ -757,7 +767,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);
@@ -805,7 +815,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);
@@ -818,7 +828,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);
                                }
                        }
                }