27 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
29 #include <linux/module.h>
31 #include <linux/types.h>
32 #include <linux/errno.h>
33 #include <linux/kernel.h>
36 #include <linux/watchdog.h>
38 #include <linux/reboot.h>
42 #include <linux/slab.h>
44 #include <linux/hid.h>
47 #ifdef CONFIG_USB_DEBUG
59 #define dbg(format, ...) \
62 pr_debug(format "\n", ##__VA_ARGS__); \
66 #define DRIVER_VERSION "1.02"
68 #define DRIVER_DESC "Berkshire USB-PC Watchdog driver"
69 #define DRIVER_LICENSE "GPL"
70 #define DRIVER_NAME "pcwd_usb"
82 #define WATCHDOG_HEARTBEAT 0
87 "(0<heartbeat<65536 or 0=delay-time from dip-switches, default="
92 MODULE_PARM_DESC(nowayout,
"Watchdog cannot be stopped once started (default="
96 #define USB_PCWD_VENDOR_ID 0x0c98
97 #define USB_PCWD_PRODUCT_ID 0x1140
108 #define USB_COMMAND_TIMEOUT 250
111 #define CMD_READ_TEMP 0x02
113 #define CMD_TRIGGER CMD_READ_TEMP
114 #define CMD_GET_STATUS 0x04
115 #define CMD_GET_FIRMWARE_VERSION 0x08
116 #define CMD_GET_DIP_SWITCH_SETTINGS 0x0c
117 #define CMD_READ_WATCHDOG_TIMEOUT 0x18
118 #define CMD_WRITE_WATCHDOG_TIMEOUT 0x19
119 #define CMD_ENABLE_WATCHDOG 0x30
120 #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG
123 static const int heartbeat_tbl[] = {
135 static int cards_found;
139 static char expect_release;
185 static struct usb_driver usb_pcwd_driver = {
187 .probe = usb_pcwd_probe,
188 .disconnect = usb_pcwd_disconnect,
189 .id_table = usb_pcwd_table,
193 static void usb_pcwd_intr_done(
struct urb *
urb)
200 switch (urb->status) {
207 dbg(
"%s - urb shutting down with status: %d", __func__,
212 dbg(
"%s - nonzero urb status received: %d", __func__,
217 dbg(
"received following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
230 pr_err(
"can't resubmit intr, usb_submit_urb failed with result %d\n",
235 unsigned char cmd,
unsigned char *
msb,
unsigned char *
lsb)
237 int got_response,
count;
238 unsigned char buf[6];
242 if ((!usb_pcwd) || (!usb_pcwd->
exists))
250 buf[3] = buf[4] = buf[5] = 0;
252 dbg(
"sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x",
253 buf[0], buf[1], buf[2]);
261 dbg(
"usb_pcwd_send_command: error in usb_control_msg for "
262 "cmd 0x%x 0x%x 0x%x\n", cmd, *msb, *lsb);
274 if ((got_response) && (cmd == usb_pcwd->
cmd_command)) {
285 unsigned char msb = 0x00;
286 unsigned char lsb = 0x00;
293 if ((retval == 0) || (lsb == 0)) {
294 pr_err(
"Card did not acknowledge enable attempt\n");
303 unsigned char msb = 0xA5;
304 unsigned char lsb = 0xC3;
311 if ((retval == 0) || (lsb != 0)) {
312 pr_err(
"Card did not acknowledge disable attempt\n");
324 usb_pcwd_send_command(usb_pcwd,
CMD_TRIGGER, &dummy, &dummy);
331 unsigned char msb = t / 256;
332 unsigned char lsb = t % 256;
334 if ((t < 0x0001) || (t > 0xFFFF))
355 *temperature = (lsb * 9 / 5) + 32;
369 *time_left = (msb << 8) + lsb;
379 size_t len, loff_t *ppos)
392 for (i = 0; i != len; i++) {
402 usb_pcwd_keepalive(usb_pcwd_device);
407 static long usb_pcwd_ioctl(
struct file *file,
unsigned int cmd,
416 .firmware_version = 1,
432 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
440 int new_options, retval = -
EINVAL;
446 usb_pcwd_stop(usb_pcwd_device);
451 usb_pcwd_start(usb_pcwd_device);
459 usb_pcwd_keepalive(usb_pcwd_device);
469 if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat))
472 usb_pcwd_keepalive(usb_pcwd_device);
483 if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left))
494 static int usb_pcwd_open(
struct inode *
inode,
struct file *file)
501 usb_pcwd_start(usb_pcwd_device);
502 usb_pcwd_keepalive(usb_pcwd_device);
506 static int usb_pcwd_release(
struct inode *inode,
struct file *file)
511 if (expect_release == 42) {
512 usb_pcwd_stop(usb_pcwd_device);
514 pr_crit(
"Unexpected close, not stopping watchdog!\n");
515 usb_pcwd_keepalive(usb_pcwd_device);
526 static ssize_t usb_pcwd_temperature_read(
struct file *file,
char __user *data,
527 size_t len, loff_t *ppos)
531 if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature))
540 static int usb_pcwd_temperature_open(
struct inode *inode,
struct file *file)
545 static int usb_pcwd_temperature_release(
struct inode *inode,
struct file *file)
558 usb_pcwd_stop(usb_pcwd_device);
570 .write = usb_pcwd_write,
571 .unlocked_ioctl = usb_pcwd_ioctl,
572 .open = usb_pcwd_open,
573 .release = usb_pcwd_release,
579 .fops = &usb_pcwd_fops,
585 .read = usb_pcwd_temperature_read,
586 .open = usb_pcwd_temperature_open,
587 .release = usb_pcwd_temperature_release,
590 static struct miscdevice usb_pcwd_temperature_miscdev = {
592 .name =
"temperature",
593 .fops = &usb_pcwd_temperature_fops,
597 .notifier_call = usb_pcwd_notify_sys,
621 struct usb_device *
udev = interface_to_usbdev(interface);
622 struct usb_host_interface *iface_desc;
628 unsigned char fw_rev_major, fw_rev_minor;
630 unsigned char option_switches,
dummy;
633 if (cards_found > 1) {
634 pr_err(
"This driver only supports 1 device\n");
639 iface_desc = interface->cur_altsetting;
643 pr_err(
"The device isn't a Human Interface Device\n");
648 endpoint = &iface_desc->endpoint[0].desc;
650 if (!usb_endpoint_is_int_in(endpoint)) {
652 pr_err(
"Couldn't find an INTR & IN endpoint\n");
658 maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
662 if (usb_pcwd ==
NULL) {
663 pr_err(
"Out of memory\n");
667 usb_pcwd_device = usb_pcwd;
680 pr_err(
"Out of memory\n");
687 pr_err(
"Out of memory\n");
692 usb_fill_int_urb(usb_pcwd->
intr_urb, udev, pipe,
694 usb_pcwd_intr_done, usb_pcwd, endpoint->
bInterval);
696 usb_pcwd->
intr_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
700 pr_err(
"Problem registering interrupt URB\n");
709 usb_pcwd_stop(usb_pcwd);
713 &fw_rev_major, &fw_rev_minor);
715 sprintf(fw_ver_str,
"%u.%02u", fw_rev_major, fw_rev_minor);
717 sprintf(fw_ver_str,
"<card no answer>");
719 pr_info(
"Found card (Firmware: %s) with temp option\n", fw_ver_str);
725 pr_info(
"Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n",
727 ((option_switches & 0x10) ?
"ON" :
"OFF"),
728 ((option_switches & 0x08) ?
"ON" :
"OFF"));
732 heartbeat = heartbeat_tbl[(option_switches & 0x07)];
736 if (usb_pcwd_set_heartbeat(usb_pcwd,
heartbeat)) {
738 pr_info(
"heartbeat value must be 0<heartbeat<65536, using %d\n",
744 pr_err(
"cannot register reboot notifier (err=%d)\n", retval);
750 pr_err(
"cannot register miscdev on minor=%d (err=%d)\n",
752 goto err_out_unregister_reboot;
757 pr_err(
"cannot register miscdev on minor=%d (err=%d)\n",
759 goto err_out_misc_deregister;
763 usb_set_intfdata(interface, usb_pcwd);
765 pr_info(
"initialized. heartbeat=%d sec (nowayout=%d)\n",
770 err_out_misc_deregister:
772 err_out_unregister_reboot:
776 usb_pcwd_delete(usb_pcwd);
777 usb_pcwd_device =
NULL;
790 static void usb_pcwd_disconnect(
struct usb_interface *interface)
797 usb_pcwd = usb_get_intfdata(interface);
798 usb_set_intfdata(interface,
NULL);
804 usb_pcwd_stop(usb_pcwd);
817 usb_pcwd_delete(usb_pcwd);
823 pr_info(
"USB PC Watchdog disconnected\n");