Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[pandora-kernel.git] / drivers / char / watchdog / pcwd_usb.c
index 2da5ac9..0f3fd6c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     Berkshire USB-PC Watchdog Card Driver
  *
- *     (c) Copyright 2004 Wim Van Sebroeck <wim@iguana.be>.
+ *     (c) Copyright 2004-2007 Wim Van Sebroeck <wim@iguana.be>.
  *
  *     Based on source code of the following authors:
  *       Ken Hollis <kenji@bitgate.com>,
  *     http://www.berkprod.com/ or http://www.pcwatchdog.com/
  */
 
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/types.h>
-#include <linux/delay.h>
-#include <linux/miscdevice.h>
-#include <linux/watchdog.h>
-#include <linux/notifier.h>
-#include <linux/reboot.h>
-#include <linux/fs.h>
-#include <linux/smp_lock.h>
-#include <linux/completion.h>
-#include <asm/uaccess.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
+#include <linux/module.h>      /* For module specific items */
+#include <linux/moduleparam.h> /* For new moduleparam's */
+#include <linux/types.h>       /* For standard types (like size_t) */
+#include <linux/errno.h>       /* For the -ENODEV/... values */
+#include <linux/kernel.h>      /* For printk/panic/... */
+#include <linux/delay.h>       /* For mdelay function */
+#include <linux/miscdevice.h>  /* For MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR) */
+#include <linux/watchdog.h>    /* For the watchdog specific items */
+#include <linux/notifier.h>    /* For notifier support */
+#include <linux/reboot.h>      /* For reboot_notifier stuff */
+#include <linux/init.h>                /* For __init/__exit/... */
+#include <linux/fs.h>          /* For file operations */
+#include <linux/usb.h>         /* For USB functions */
+#include <linux/slab.h>                /* For kmalloc, ... */
+#include <linux/mutex.h>       /* For mutex locking */
 #include <linux/hid.h>         /* For HID_REQ_SET_REPORT & HID_DT_REPORT */
 
+#include <asm/uaccess.h>       /* For copy_to_user/put_user/... */
+
 
 #ifdef CONFIG_USB_DEBUG
        static int debug = 1;
@@ -57,8 +56,8 @@
 
 
 /* Module and Version Information */
-#define DRIVER_VERSION "1.01"
-#define DRIVER_DATE "15 Mar 2005"
+#define DRIVER_VERSION "1.02"
+#define DRIVER_DATE "21 Jan 2007"
 #define DRIVER_AUTHOR "Wim Van Sebroeck <wim@iguana.be>"
 #define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
 #define DRIVER_LICENSE "GPL"
@@ -75,14 +74,14 @@ MODULE_ALIAS_MISCDEV(TEMP_MINOR);
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 
-#define WATCHDOG_HEARTBEAT 2   /* 2 sec default heartbeat */
+#define WATCHDOG_HEARTBEAT 0   /* default heartbeat = delay-time from dip-switches */
 static int heartbeat = WATCHDOG_HEARTBEAT;
 module_param(heartbeat, int, 0);
-MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<65536 or 0=delay-time from dip-switches, default=" __MODULE_STRING(WATCHDOG_HEARTBEAT) ")");
 
 static int nowayout = WATCHDOG_NOWAYOUT;
 module_param(nowayout, int, 0);
-MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
 /* The vendor and product id's for the USB-PC Watchdog card */
 #define USB_PCWD_VENDOR_ID     0x0c98
@@ -110,6 +109,18 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table);
 #define CMD_ENABLE_WATCHDOG            0x30    /* Enable / Disable Watchdog */
 #define CMD_DISABLE_WATCHDOG           CMD_ENABLE_WATCHDOG
 
+/* Watchdog's Dip Switch heartbeat values */
+static const int heartbeat_tbl [] = {
+       5,      /* OFF-OFF-OFF  =  5 Sec  */
+       10,     /* OFF-OFF-ON   = 10 Sec  */
+       30,     /* OFF-ON-OFF   = 30 Sec  */
+       60,     /* OFF-ON-ON    =  1 Min  */
+       300,    /* ON-OFF-OFF   =  5 Min  */
+       600,    /* ON-OFF-ON    = 10 Min  */
+       1800,   /* ON-ON-OFF    = 30 Min  */
+       3600,   /* ON-ON-ON     =  1 hour */
+};
+
 /* We can only use 1 card due to the /dev/watchdog restriction */
 static int cards_found;
 
@@ -135,7 +146,7 @@ struct usb_pcwd_private {
        atomic_t                cmd_received;           /* true if we received a report after a command */
 
        int                     exists;                 /* Wether or not the device exists */
-       struct semaphore        sem;                    /* locks this structure */
+       struct mutex            mtx;                    /* locks this structure */
 };
 static struct usb_pcwd_private *usb_pcwd_device;
 
@@ -615,16 +626,15 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
        maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
 
        /* allocate memory for our device and initialize it */
-       usb_pcwd = kmalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
+       usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL);
        if (usb_pcwd == NULL) {
                printk(KERN_ERR PFX "Out of memory\n");
                goto error;
        }
-       memset (usb_pcwd, 0x00, sizeof (*usb_pcwd));
 
        usb_pcwd_device = usb_pcwd;
 
-       init_MUTEX (&usb_pcwd->sem);
+       mutex_init(&usb_pcwd->mtx);
        usb_pcwd->udev = udev;
        usb_pcwd->interface = interface;
        usb_pcwd->interface_number = iface_desc->desc.bInterfaceNumber;
@@ -682,6 +692,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi
                ((option_switches & 0x10) ? "ON" : "OFF"),
                ((option_switches & 0x08) ? "ON" : "OFF"));
 
+       /* If heartbeat = 0 then we use the heartbeat from the dip-switches */
+       if (heartbeat == 0)
+               heartbeat = heartbeat_tbl[(option_switches & 0x07)];
+
        /* Check that the heartbeat value is within it's range ; if not reset to the default */
        if (usb_pcwd_set_heartbeat(usb_pcwd, heartbeat)) {
                usb_pcwd_set_heartbeat(usb_pcwd, WATCHDOG_HEARTBEAT);
@@ -748,7 +762,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
        usb_pcwd = usb_get_intfdata (interface);
        usb_set_intfdata (interface, NULL);
 
-       down (&usb_pcwd->sem);
+       mutex_lock(&usb_pcwd->mtx);
 
        /* Stop the timer before we leave */
        if (!nowayout)
@@ -762,7 +776,7 @@ static void usb_pcwd_disconnect(struct usb_interface *interface)
        misc_deregister(&usb_pcwd_temperature_miscdev);
        unregister_reboot_notifier(&usb_pcwd_notifier);
 
-       up (&usb_pcwd->sem);
+       mutex_unlock(&usb_pcwd->mtx);
 
        /* Delete the USB PCWD device */
        usb_pcwd_delete(usb_pcwd);