Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  National Semiconductor PC87307/PC97307 (ala SC1200) WDT driver
0004  *  (c) Copyright 2002 Zwane Mwaikambo <zwane@commfireservices.com>,
0005  *          All Rights Reserved.
0006  *  Based on wdt.c and wdt977.c by Alan Cox and Woody Suwalski respectively.
0007  *
0008  *  The author(s) of this software shall not be held liable for damages
0009  *  of any nature resulting due to the use of this software. This
0010  *  software is provided AS-IS with no warranties.
0011  *
0012  *  Changelog:
0013  *  20020220 Zwane Mwaikambo    Code based on datasheet, no hardware.
0014  *  20020221 Zwane Mwaikambo    Cleanups as suggested by Jeff Garzik
0015  *                  and Alan Cox.
0016  *  20020222 Zwane Mwaikambo    Added probing.
0017  *  20020225 Zwane Mwaikambo    Added ISAPNP support.
0018  *  20020412 Rob Radez      Broke out start/stop functions
0019  *       <rob@osinvestor.com>   Return proper status instead of
0020  *                  temperature warning
0021  *                  Add WDIOC_GETBOOTSTATUS and
0022  *                  WDIOC_SETOPTIONS ioctls
0023  *                  Fix CONFIG_WATCHDOG_NOWAYOUT
0024  *  20020530 Joel Becker        Add Matt Domsch's nowayout module
0025  *                  option
0026  *  20030116 Adam Belay     Updated to the latest pnp code
0027  */
0028 
0029 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0030 
0031 #include <linux/module.h>
0032 #include <linux/moduleparam.h>
0033 #include <linux/miscdevice.h>
0034 #include <linux/watchdog.h>
0035 #include <linux/ioport.h>
0036 #include <linux/spinlock.h>
0037 #include <linux/notifier.h>
0038 #include <linux/reboot.h>
0039 #include <linux/init.h>
0040 #include <linux/pnp.h>
0041 #include <linux/fs.h>
0042 #include <linux/semaphore.h>
0043 #include <linux/io.h>
0044 #include <linux/uaccess.h>
0045 
0046 #define SC1200_MODULE_VER   "build 20020303"
0047 #define SC1200_MODULE_NAME  "sc1200wdt"
0048 
0049 #define MAX_TIMEOUT 255 /* 255 minutes */
0050 #define PMIR        (io)    /* Power Management Index Register */
0051 #define PMDR        (io+1)  /* Power Management Data Register */
0052 
0053 /* Data Register indexes */
0054 #define FER1        0x00    /* Function enable register 1 */
0055 #define FER2        0x01    /* Function enable register 2 */
0056 #define PMC1        0x02    /* Power Management Ctrl 1 */
0057 #define PMC2        0x03    /* Power Management Ctrl 2 */
0058 #define PMC3        0x04    /* Power Management Ctrl 3 */
0059 #define WDTO        0x05    /* Watchdog timeout register */
0060 #define WDCF        0x06    /* Watchdog config register */
0061 #define WDST        0x07    /* Watchdog status register */
0062 
0063 /* WDCF bitfields - which devices assert WDO */
0064 #define KBC_IRQ     0x01    /* Keyboard Controller */
0065 #define MSE_IRQ     0x02    /* Mouse */
0066 #define UART1_IRQ   0x03    /* Serial0 */
0067 #define UART2_IRQ   0x04    /* Serial1 */
0068 /* 5 -7 are reserved */
0069 
0070 static int timeout = 1;
0071 static int io = -1;
0072 static int io_len = 2;      /* for non plug and play */
0073 static unsigned long open_flag;
0074 static char expect_close;
0075 static DEFINE_SPINLOCK(sc1200wdt_lock); /* io port access serialisation */
0076 
0077 #if defined CONFIG_PNP
0078 static int isapnp = 1;
0079 static struct pnp_dev *wdt_dev;
0080 
0081 module_param(isapnp, int, 0);
0082 MODULE_PARM_DESC(isapnp,
0083     "When set to 0 driver ISA PnP support will be disabled");
0084 #endif
0085 
0086 module_param_hw(io, int, ioport, 0);
0087 MODULE_PARM_DESC(io, "io port");
0088 module_param(timeout, int, 0);
0089 MODULE_PARM_DESC(timeout, "range is 0-255 minutes, default is 1");
0090 
0091 static bool nowayout = WATCHDOG_NOWAYOUT;
0092 module_param(nowayout, bool, 0);
0093 MODULE_PARM_DESC(nowayout,
0094     "Watchdog cannot be stopped once started (default="
0095                 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
0096 
0097 
0098 
0099 /* Read from Data Register */
0100 static inline void __sc1200wdt_read_data(unsigned char index,
0101                         unsigned char *data)
0102 {
0103     outb_p(index, PMIR);
0104     *data = inb(PMDR);
0105 }
0106 
0107 static void sc1200wdt_read_data(unsigned char index, unsigned char *data)
0108 {
0109     spin_lock(&sc1200wdt_lock);
0110     __sc1200wdt_read_data(index, data);
0111     spin_unlock(&sc1200wdt_lock);
0112 }
0113 
0114 /* Write to Data Register */
0115 static inline void __sc1200wdt_write_data(unsigned char index,
0116                         unsigned char data)
0117 {
0118     outb_p(index, PMIR);
0119     outb(data, PMDR);
0120 }
0121 
0122 static inline void sc1200wdt_write_data(unsigned char index,
0123                         unsigned char data)
0124 {
0125     spin_lock(&sc1200wdt_lock);
0126     __sc1200wdt_write_data(index, data);
0127     spin_unlock(&sc1200wdt_lock);
0128 }
0129 
0130 
0131 static void sc1200wdt_start(void)
0132 {
0133     unsigned char reg;
0134     spin_lock(&sc1200wdt_lock);
0135 
0136     __sc1200wdt_read_data(WDCF, &reg);
0137     /* assert WDO when any of the following interrupts are triggered too */
0138     reg |= (KBC_IRQ | MSE_IRQ | UART1_IRQ | UART2_IRQ);
0139     __sc1200wdt_write_data(WDCF, reg);
0140     /* set the timeout and get the ball rolling */
0141     __sc1200wdt_write_data(WDTO, timeout);
0142 
0143     spin_unlock(&sc1200wdt_lock);
0144 }
0145 
0146 static void sc1200wdt_stop(void)
0147 {
0148     sc1200wdt_write_data(WDTO, 0);
0149 }
0150 
0151 /* This returns the status of the WDO signal, inactive high. */
0152 static inline int sc1200wdt_status(void)
0153 {
0154     unsigned char ret;
0155 
0156     sc1200wdt_read_data(WDST, &ret);
0157     /* If the bit is inactive, the watchdog is enabled, so return
0158      * KEEPALIVEPING which is a bit of a kludge because there's nothing
0159      * else for enabled/disabled status
0160      */
0161     return (ret & 0x01) ? 0 : WDIOF_KEEPALIVEPING;
0162 }
0163 
0164 static int sc1200wdt_open(struct inode *inode, struct file *file)
0165 {
0166     /* allow one at a time */
0167     if (test_and_set_bit(0, &open_flag))
0168         return -EBUSY;
0169 
0170     if (timeout > MAX_TIMEOUT)
0171         timeout = MAX_TIMEOUT;
0172 
0173     sc1200wdt_start();
0174     pr_info("Watchdog enabled, timeout = %d min(s)", timeout);
0175 
0176     return stream_open(inode, file);
0177 }
0178 
0179 
0180 static long sc1200wdt_ioctl(struct file *file, unsigned int cmd,
0181                         unsigned long arg)
0182 {
0183     int new_timeout;
0184     void __user *argp = (void __user *)arg;
0185     int __user *p = argp;
0186     static const struct watchdog_info ident = {
0187         .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
0188                             WDIOF_MAGICCLOSE,
0189         .firmware_version = 0,
0190         .identity = "PC87307/PC97307",
0191     };
0192 
0193     switch (cmd) {
0194     case WDIOC_GETSUPPORT:
0195         if (copy_to_user(argp, &ident, sizeof(ident)))
0196             return -EFAULT;
0197         return 0;
0198 
0199     case WDIOC_GETSTATUS:
0200         return put_user(sc1200wdt_status(), p);
0201 
0202     case WDIOC_GETBOOTSTATUS:
0203         return put_user(0, p);
0204 
0205     case WDIOC_SETOPTIONS:
0206     {
0207         int options, retval = -EINVAL;
0208 
0209         if (get_user(options, p))
0210             return -EFAULT;
0211 
0212         if (options & WDIOS_DISABLECARD) {
0213             sc1200wdt_stop();
0214             retval = 0;
0215         }
0216 
0217         if (options & WDIOS_ENABLECARD) {
0218             sc1200wdt_start();
0219             retval = 0;
0220         }
0221 
0222         return retval;
0223     }
0224     case WDIOC_KEEPALIVE:
0225         sc1200wdt_write_data(WDTO, timeout);
0226         return 0;
0227 
0228     case WDIOC_SETTIMEOUT:
0229         if (get_user(new_timeout, p))
0230             return -EFAULT;
0231         /* the API states this is given in secs */
0232         new_timeout /= 60;
0233         if (new_timeout < 0 || new_timeout > MAX_TIMEOUT)
0234             return -EINVAL;
0235         timeout = new_timeout;
0236         sc1200wdt_write_data(WDTO, timeout);
0237         fallthrough;    /* and return the new timeout */
0238 
0239     case WDIOC_GETTIMEOUT:
0240         return put_user(timeout * 60, p);
0241 
0242     default:
0243         return -ENOTTY;
0244     }
0245 }
0246 
0247 
0248 static int sc1200wdt_release(struct inode *inode, struct file *file)
0249 {
0250     if (expect_close == 42) {
0251         sc1200wdt_stop();
0252         pr_info("Watchdog disabled\n");
0253     } else {
0254         sc1200wdt_write_data(WDTO, timeout);
0255         pr_crit("Unexpected close!, timeout = %d min(s)\n", timeout);
0256     }
0257     clear_bit(0, &open_flag);
0258     expect_close = 0;
0259 
0260     return 0;
0261 }
0262 
0263 
0264 static ssize_t sc1200wdt_write(struct file *file, const char __user *data,
0265                         size_t len, loff_t *ppos)
0266 {
0267     if (len) {
0268         if (!nowayout) {
0269             size_t i;
0270 
0271             expect_close = 0;
0272 
0273             for (i = 0; i != len; i++) {
0274                 char c;
0275 
0276                 if (get_user(c, data + i))
0277                     return -EFAULT;
0278                 if (c == 'V')
0279                     expect_close = 42;
0280             }
0281         }
0282 
0283         sc1200wdt_write_data(WDTO, timeout);
0284         return len;
0285     }
0286 
0287     return 0;
0288 }
0289 
0290 
0291 static int sc1200wdt_notify_sys(struct notifier_block *this,
0292                     unsigned long code, void *unused)
0293 {
0294     if (code == SYS_DOWN || code == SYS_HALT)
0295         sc1200wdt_stop();
0296 
0297     return NOTIFY_DONE;
0298 }
0299 
0300 
0301 static struct notifier_block sc1200wdt_notifier = {
0302     .notifier_call =    sc1200wdt_notify_sys,
0303 };
0304 
0305 static const struct file_operations sc1200wdt_fops = {
0306     .owner      = THIS_MODULE,
0307     .llseek     = no_llseek,
0308     .write      = sc1200wdt_write,
0309     .unlocked_ioctl = sc1200wdt_ioctl,
0310     .compat_ioctl   = compat_ptr_ioctl,
0311     .open       = sc1200wdt_open,
0312     .release    = sc1200wdt_release,
0313 };
0314 
0315 static struct miscdevice sc1200wdt_miscdev = {
0316     .minor      = WATCHDOG_MINOR,
0317     .name       = "watchdog",
0318     .fops       = &sc1200wdt_fops,
0319 };
0320 
0321 
0322 static int __init sc1200wdt_probe(void)
0323 {
0324     /* The probe works by reading the PMC3 register's default value of 0x0e
0325      * there is one caveat, if the device disables the parallel port or any
0326      * of the UARTs we won't be able to detect it.
0327      * NB. This could be done with accuracy by reading the SID registers,
0328      * but we don't have access to those io regions.
0329      */
0330 
0331     unsigned char reg;
0332 
0333     sc1200wdt_read_data(PMC3, &reg);
0334     reg &= 0x0f;        /* we don't want the UART busy bits */
0335     return (reg == 0x0e) ? 0 : -ENODEV;
0336 }
0337 
0338 
0339 #if defined CONFIG_PNP
0340 
0341 static const struct pnp_device_id scl200wdt_pnp_devices[] = {
0342     /* National Semiconductor PC87307/PC97307 watchdog component */
0343     {.id = "NSC0800", .driver_data = 0},
0344     {.id = ""},
0345 };
0346 
0347 static int scl200wdt_pnp_probe(struct pnp_dev *dev,
0348                     const struct pnp_device_id *dev_id)
0349 {
0350     /* this driver only supports one card at a time */
0351     if (wdt_dev || !isapnp)
0352         return -EBUSY;
0353 
0354     wdt_dev = dev;
0355     io = pnp_port_start(wdt_dev, 0);
0356     io_len = pnp_port_len(wdt_dev, 0);
0357 
0358     if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
0359         pr_err("Unable to register IO port %#x\n", io);
0360         return -EBUSY;
0361     }
0362 
0363     pr_info("PnP device found at io port %#x/%d\n", io, io_len);
0364     return 0;
0365 }
0366 
0367 static void scl200wdt_pnp_remove(struct pnp_dev *dev)
0368 {
0369     if (wdt_dev) {
0370         release_region(io, io_len);
0371         wdt_dev = NULL;
0372     }
0373 }
0374 
0375 static struct pnp_driver scl200wdt_pnp_driver = {
0376     .name       = "scl200wdt",
0377     .id_table   = scl200wdt_pnp_devices,
0378     .probe      = scl200wdt_pnp_probe,
0379     .remove     = scl200wdt_pnp_remove,
0380 };
0381 
0382 #endif /* CONFIG_PNP */
0383 
0384 
0385 static int __init sc1200wdt_init(void)
0386 {
0387     int ret;
0388 
0389     pr_info("%s\n", SC1200_MODULE_VER);
0390 
0391 #if defined CONFIG_PNP
0392     if (isapnp) {
0393         ret = pnp_register_driver(&scl200wdt_pnp_driver);
0394         if (ret)
0395             goto out_clean;
0396     }
0397 #endif
0398 
0399     if (io == -1) {
0400         pr_err("io parameter must be specified\n");
0401         ret = -EINVAL;
0402         goto out_pnp;
0403     }
0404 
0405 #if defined CONFIG_PNP
0406     /* now that the user has specified an IO port and we haven't detected
0407      * any devices, disable pnp support */
0408     if (isapnp)
0409         pnp_unregister_driver(&scl200wdt_pnp_driver);
0410     isapnp = 0;
0411 #endif
0412 
0413     if (!request_region(io, io_len, SC1200_MODULE_NAME)) {
0414         pr_err("Unable to register IO port %#x\n", io);
0415         ret = -EBUSY;
0416         goto out_pnp;
0417     }
0418 
0419     ret = sc1200wdt_probe();
0420     if (ret)
0421         goto out_io;
0422 
0423     ret = register_reboot_notifier(&sc1200wdt_notifier);
0424     if (ret) {
0425         pr_err("Unable to register reboot notifier err = %d\n", ret);
0426         goto out_io;
0427     }
0428 
0429     ret = misc_register(&sc1200wdt_miscdev);
0430     if (ret) {
0431         pr_err("Unable to register miscdev on minor %d\n",
0432                WATCHDOG_MINOR);
0433         goto out_rbt;
0434     }
0435 
0436     /* ret = 0 */
0437 
0438 out_clean:
0439     return ret;
0440 
0441 out_rbt:
0442     unregister_reboot_notifier(&sc1200wdt_notifier);
0443 
0444 out_io:
0445     release_region(io, io_len);
0446 
0447 out_pnp:
0448 #if defined CONFIG_PNP
0449     if (isapnp)
0450         pnp_unregister_driver(&scl200wdt_pnp_driver);
0451 #endif
0452     goto out_clean;
0453 }
0454 
0455 
0456 static void __exit sc1200wdt_exit(void)
0457 {
0458     misc_deregister(&sc1200wdt_miscdev);
0459     unregister_reboot_notifier(&sc1200wdt_notifier);
0460 
0461 #if defined CONFIG_PNP
0462     if (isapnp)
0463         pnp_unregister_driver(&scl200wdt_pnp_driver);
0464     else
0465 #endif
0466     release_region(io, io_len);
0467 }
0468 
0469 module_init(sc1200wdt_init);
0470 module_exit(sc1200wdt_exit);
0471 
0472 MODULE_AUTHOR("Zwane Mwaikambo <zwane@commfireservices.com>");
0473 MODULE_DESCRIPTION(
0474     "Driver for National Semiconductor PC87307/PC97307 watchdog component");
0475 MODULE_LICENSE("GPL");