diff options
Diffstat (limited to 'drivers/watchdog/pcwd_usb.c')
-rw-r--r-- | drivers/watchdog/pcwd_usb.c | 168 |
1 files changed, 82 insertions, 86 deletions
diff --git a/drivers/watchdog/pcwd_usb.c b/drivers/watchdog/pcwd_usb.c index bf443d077a1e..c1685c942de6 100644 --- a/drivers/watchdog/pcwd_usb.c +++ b/drivers/watchdog/pcwd_usb.c | |||
@@ -40,8 +40,7 @@ | |||
40 | #include <linux/slab.h> /* For kmalloc, ... */ | 40 | #include <linux/slab.h> /* For kmalloc, ... */ |
41 | #include <linux/mutex.h> /* For mutex locking */ | 41 | #include <linux/mutex.h> /* For mutex locking */ |
42 | #include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ | 42 | #include <linux/hid.h> /* For HID_REQ_SET_REPORT & HID_DT_REPORT */ |
43 | 43 | #include <linux/uaccess.h> /* For copy_to_user/put_user/... */ | |
44 | #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ | ||
45 | 44 | ||
46 | 45 | ||
47 | #ifdef CONFIG_USB_DEBUG | 46 | #ifdef CONFIG_USB_DEBUG |
@@ -88,7 +87,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" _ | |||
88 | #define USB_PCWD_PRODUCT_ID 0x1140 | 87 | #define USB_PCWD_PRODUCT_ID 0x1140 |
89 | 88 | ||
90 | /* table of devices that work with this driver */ | 89 | /* table of devices that work with this driver */ |
91 | static struct usb_device_id usb_pcwd_table [] = { | 90 | static struct usb_device_id usb_pcwd_table[] = { |
92 | { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) }, | 91 | { USB_DEVICE(USB_PCWD_VENDOR_ID, USB_PCWD_PRODUCT_ID) }, |
93 | { } /* Terminating entry */ | 92 | { } /* Terminating entry */ |
94 | }; | 93 | }; |
@@ -110,7 +109,7 @@ MODULE_DEVICE_TABLE (usb, usb_pcwd_table); | |||
110 | #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG | 109 | #define CMD_DISABLE_WATCHDOG CMD_ENABLE_WATCHDOG |
111 | 110 | ||
112 | /* Watchdog's Dip Switch heartbeat values */ | 111 | /* Watchdog's Dip Switch heartbeat values */ |
113 | static const int heartbeat_tbl [] = { | 112 | static const int heartbeat_tbl[] = { |
114 | 5, /* OFF-OFF-OFF = 5 Sec */ | 113 | 5, /* OFF-OFF-OFF = 5 Sec */ |
115 | 10, /* OFF-OFF-ON = 10 Sec */ | 114 | 10, /* OFF-OFF-ON = 10 Sec */ |
116 | 30, /* OFF-ON-OFF = 30 Sec */ | 115 | 30, /* OFF-ON-OFF = 30 Sec */ |
@@ -130,15 +129,15 @@ static char expect_release; | |||
130 | 129 | ||
131 | /* Structure to hold all of our device specific stuff */ | 130 | /* Structure to hold all of our device specific stuff */ |
132 | struct usb_pcwd_private { | 131 | struct usb_pcwd_private { |
133 | struct usb_device * udev; /* save off the usb device pointer */ | 132 | struct usb_device *udev; /* save off the usb device pointer */ |
134 | struct usb_interface * interface; /* the interface for this device */ | 133 | struct usb_interface *interface; /* the interface for this device */ |
135 | 134 | ||
136 | unsigned int interface_number; /* the interface number used for cmd's */ | 135 | unsigned int interface_number; /* the interface number used for cmd's */ |
137 | 136 | ||
138 | unsigned char * intr_buffer; /* the buffer to intr data */ | 137 | unsigned char *intr_buffer; /* the buffer to intr data */ |
139 | dma_addr_t intr_dma; /* the dma address for the intr buffer */ | 138 | dma_addr_t intr_dma; /* the dma address for the intr buffer */ |
140 | size_t intr_size; /* the size of the intr buffer */ | 139 | size_t intr_size; /* the size of the intr buffer */ |
141 | struct urb * intr_urb; /* the urb used for the intr pipe */ | 140 | struct urb *intr_urb; /* the urb used for the intr pipe */ |
142 | 141 | ||
143 | unsigned char cmd_command; /* The command that is reported back */ | 142 | unsigned char cmd_command; /* The command that is reported back */ |
144 | unsigned char cmd_data_msb; /* The data MSB that is reported back */ | 143 | unsigned char cmd_data_msb; /* The data MSB that is reported back */ |
@@ -154,8 +153,8 @@ static struct usb_pcwd_private *usb_pcwd_device; | |||
154 | static DEFINE_MUTEX(disconnect_mutex); | 153 | static DEFINE_MUTEX(disconnect_mutex); |
155 | 154 | ||
156 | /* local function prototypes */ | 155 | /* local function prototypes */ |
157 | static int usb_pcwd_probe (struct usb_interface *interface, const struct usb_device_id *id); | 156 | static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_device_id *id); |
158 | static void usb_pcwd_disconnect (struct usb_interface *interface); | 157 | static void usb_pcwd_disconnect(struct usb_interface *interface); |
159 | 158 | ||
160 | /* usb specific object needed to register this driver with the usb subsystem */ | 159 | /* usb specific object needed to register this driver with the usb subsystem */ |
161 | static struct usb_driver usb_pcwd_driver = { | 160 | static struct usb_driver usb_pcwd_driver = { |
@@ -195,10 +194,10 @@ static void usb_pcwd_intr_done(struct urb *urb) | |||
195 | usb_pcwd->cmd_data_lsb = data[2]; | 194 | usb_pcwd->cmd_data_lsb = data[2]; |
196 | 195 | ||
197 | /* notify anyone waiting that the cmd has finished */ | 196 | /* notify anyone waiting that the cmd has finished */ |
198 | atomic_set (&usb_pcwd->cmd_received, 1); | 197 | atomic_set(&usb_pcwd->cmd_received, 1); |
199 | 198 | ||
200 | resubmit: | 199 | resubmit: |
201 | retval = usb_submit_urb (urb, GFP_ATOMIC); | 200 | retval = usb_submit_urb(urb, GFP_ATOMIC); |
202 | if (retval) | 201 | if (retval) |
203 | printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n", | 202 | printk(KERN_ERR PFX "can't resubmit intr, usb_submit_urb failed with result %d\n", |
204 | retval); | 203 | retval); |
@@ -224,7 +223,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha | |||
224 | dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x", | 223 | dbg("sending following data cmd=0x%02x msb=0x%02x lsb=0x%02x", |
225 | buf[0], buf[1], buf[2]); | 224 | buf[0], buf[1], buf[2]); |
226 | 225 | ||
227 | atomic_set (&usb_pcwd->cmd_received, 0); | 226 | atomic_set(&usb_pcwd->cmd_received, 0); |
228 | 227 | ||
229 | if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0), | 228 | if (usb_control_msg(usb_pcwd->udev, usb_sndctrlpipe(usb_pcwd->udev, 0), |
230 | HID_REQ_SET_REPORT, HID_DT_REPORT, | 229 | HID_REQ_SET_REPORT, HID_DT_REPORT, |
@@ -237,7 +236,7 @@ static int usb_pcwd_send_command(struct usb_pcwd_private *usb_pcwd, unsigned cha | |||
237 | got_response = 0; | 236 | got_response = 0; |
238 | for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) { | 237 | for (count = 0; (count < USB_COMMAND_TIMEOUT) && (!got_response); count++) { |
239 | mdelay(1); | 238 | mdelay(1); |
240 | if (atomic_read (&usb_pcwd->cmd_received)) | 239 | if (atomic_read(&usb_pcwd->cmd_received)) |
241 | got_response = 1; | 240 | got_response = 1; |
242 | } | 241 | } |
243 | 242 | ||
@@ -356,7 +355,7 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data, | |||
356 | /* scan to see whether or not we got the magic character */ | 355 | /* scan to see whether or not we got the magic character */ |
357 | for (i = 0; i != len; i++) { | 356 | for (i = 0; i != len; i++) { |
358 | char c; | 357 | char c; |
359 | if(get_user(c, data+i)) | 358 | if (get_user(c, data + i)) |
360 | return -EFAULT; | 359 | return -EFAULT; |
361 | if (c == 'V') | 360 | if (c == 'V') |
362 | expect_release = 42; | 361 | expect_release = 42; |
@@ -369,8 +368,8 @@ static ssize_t usb_pcwd_write(struct file *file, const char __user *data, | |||
369 | return len; | 368 | return len; |
370 | } | 369 | } |
371 | 370 | ||
372 | static int usb_pcwd_ioctl(struct inode *inode, struct file *file, | 371 | static long usb_pcwd_ioctl(struct file *file, unsigned int cmd, |
373 | unsigned int cmd, unsigned long arg) | 372 | unsigned long arg) |
374 | { | 373 | { |
375 | void __user *argp = (void __user *)arg; | 374 | void __user *argp = (void __user *)arg; |
376 | int __user *p = argp; | 375 | int __user *p = argp; |
@@ -383,77 +382,76 @@ static int usb_pcwd_ioctl(struct inode *inode, struct file *file, | |||
383 | }; | 382 | }; |
384 | 383 | ||
385 | switch (cmd) { | 384 | switch (cmd) { |
386 | case WDIOC_GETSUPPORT: | 385 | case WDIOC_GETSUPPORT: |
387 | return copy_to_user(argp, &ident, | 386 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
388 | sizeof (ident)) ? -EFAULT : 0; | ||
389 | 387 | ||
390 | case WDIOC_GETSTATUS: | 388 | case WDIOC_GETSTATUS: |
391 | case WDIOC_GETBOOTSTATUS: | 389 | case WDIOC_GETBOOTSTATUS: |
392 | return put_user(0, p); | 390 | return put_user(0, p); |
393 | 391 | ||
394 | case WDIOC_GETTEMP: | 392 | case WDIOC_GETTEMP: |
395 | { | 393 | { |
396 | int temperature; | 394 | int temperature; |
397 | 395 | ||
398 | if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature)) | 396 | if (usb_pcwd_get_temperature(usb_pcwd_device, &temperature)) |
399 | return -EFAULT; | 397 | return -EFAULT; |
400 | 398 | ||
401 | return put_user(temperature, p); | 399 | return put_user(temperature, p); |
402 | } | 400 | } |
403 | 401 | ||
404 | case WDIOC_KEEPALIVE: | 402 | case WDIOC_SETOPTIONS: |
405 | usb_pcwd_keepalive(usb_pcwd_device); | 403 | { |
406 | return 0; | 404 | int new_options, retval = -EINVAL; |
407 | 405 | ||
408 | case WDIOC_SETOPTIONS: | 406 | if (get_user(new_options, p)) |
409 | { | 407 | return -EFAULT; |
410 | int new_options, retval = -EINVAL; | ||
411 | 408 | ||
412 | if (get_user (new_options, p)) | 409 | if (new_options & WDIOS_DISABLECARD) { |
413 | return -EFAULT; | 410 | usb_pcwd_stop(usb_pcwd_device); |
411 | retval = 0; | ||
412 | } | ||
414 | 413 | ||
415 | if (new_options & WDIOS_DISABLECARD) { | 414 | if (new_options & WDIOS_ENABLECARD) { |
416 | usb_pcwd_stop(usb_pcwd_device); | 415 | usb_pcwd_start(usb_pcwd_device); |
417 | retval = 0; | 416 | retval = 0; |
418 | } | 417 | } |
419 | 418 | ||
420 | if (new_options & WDIOS_ENABLECARD) { | 419 | return retval; |
421 | usb_pcwd_start(usb_pcwd_device); | 420 | } |
422 | retval = 0; | ||
423 | } | ||
424 | 421 | ||
425 | return retval; | 422 | case WDIOC_KEEPALIVE: |
426 | } | 423 | usb_pcwd_keepalive(usb_pcwd_device); |
424 | return 0; | ||
427 | 425 | ||
428 | case WDIOC_SETTIMEOUT: | 426 | case WDIOC_SETTIMEOUT: |
429 | { | 427 | { |
430 | int new_heartbeat; | 428 | int new_heartbeat; |
431 | 429 | ||
432 | if (get_user(new_heartbeat, p)) | 430 | if (get_user(new_heartbeat, p)) |
433 | return -EFAULT; | 431 | return -EFAULT; |
434 | 432 | ||
435 | if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat)) | 433 | if (usb_pcwd_set_heartbeat(usb_pcwd_device, new_heartbeat)) |
436 | return -EINVAL; | 434 | return -EINVAL; |
437 | 435 | ||
438 | usb_pcwd_keepalive(usb_pcwd_device); | 436 | usb_pcwd_keepalive(usb_pcwd_device); |
439 | /* Fall */ | 437 | /* Fall */ |
440 | } | 438 | } |
441 | 439 | ||
442 | case WDIOC_GETTIMEOUT: | 440 | case WDIOC_GETTIMEOUT: |
443 | return put_user(heartbeat, p); | 441 | return put_user(heartbeat, p); |
444 | 442 | ||
445 | case WDIOC_GETTIMELEFT: | 443 | case WDIOC_GETTIMELEFT: |
446 | { | 444 | { |
447 | int time_left; | 445 | int time_left; |
448 | 446 | ||
449 | if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left)) | 447 | if (usb_pcwd_get_timeleft(usb_pcwd_device, &time_left)) |
450 | return -EFAULT; | 448 | return -EFAULT; |
451 | 449 | ||
452 | return put_user(time_left, p); | 450 | return put_user(time_left, p); |
453 | } | 451 | } |
454 | 452 | ||
455 | default: | 453 | default: |
456 | return -ENOTTY; | 454 | return -ENOTTY; |
457 | } | 455 | } |
458 | } | 456 | } |
459 | 457 | ||
@@ -519,10 +517,8 @@ static int usb_pcwd_temperature_release(struct inode *inode, struct file *file) | |||
519 | 517 | ||
520 | static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) | 518 | static int usb_pcwd_notify_sys(struct notifier_block *this, unsigned long code, void *unused) |
521 | { | 519 | { |
522 | if (code==SYS_DOWN || code==SYS_HALT) { | 520 | if (code == SYS_DOWN || code == SYS_HALT) |
523 | /* Turn the WDT off */ | 521 | usb_pcwd_stop(usb_pcwd_device); /* Turn the WDT off */ |
524 | usb_pcwd_stop(usb_pcwd_device); | ||
525 | } | ||
526 | 522 | ||
527 | return NOTIFY_DONE; | 523 | return NOTIFY_DONE; |
528 | } | 524 | } |
@@ -535,7 +531,7 @@ static const struct file_operations usb_pcwd_fops = { | |||
535 | .owner = THIS_MODULE, | 531 | .owner = THIS_MODULE, |
536 | .llseek = no_llseek, | 532 | .llseek = no_llseek, |
537 | .write = usb_pcwd_write, | 533 | .write = usb_pcwd_write, |
538 | .ioctl = usb_pcwd_ioctl, | 534 | .unlocked_ioctl = usb_pcwd_ioctl, |
539 | .open = usb_pcwd_open, | 535 | .open = usb_pcwd_open, |
540 | .release = usb_pcwd_release, | 536 | .release = usb_pcwd_release, |
541 | }; | 537 | }; |
@@ -567,13 +563,13 @@ static struct notifier_block usb_pcwd_notifier = { | |||
567 | /** | 563 | /** |
568 | * usb_pcwd_delete | 564 | * usb_pcwd_delete |
569 | */ | 565 | */ |
570 | static inline void usb_pcwd_delete (struct usb_pcwd_private *usb_pcwd) | 566 | static inline void usb_pcwd_delete(struct usb_pcwd_private *usb_pcwd) |
571 | { | 567 | { |
572 | usb_free_urb(usb_pcwd->intr_urb); | 568 | usb_free_urb(usb_pcwd->intr_urb); |
573 | if (usb_pcwd->intr_buffer != NULL) | 569 | if (usb_pcwd->intr_buffer != NULL) |
574 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, | 570 | usb_buffer_free(usb_pcwd->udev, usb_pcwd->intr_size, |
575 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); | 571 | usb_pcwd->intr_buffer, usb_pcwd->intr_dma); |
576 | kfree (usb_pcwd); | 572 | kfree(usb_pcwd); |
577 | } | 573 | } |
578 | 574 | ||
579 | /** | 575 | /** |
@@ -626,7 +622,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
626 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); | 622 | maxp = usb_maxpacket(udev, pipe, usb_pipeout(pipe)); |
627 | 623 | ||
628 | /* allocate memory for our device and initialize it */ | 624 | /* allocate memory for our device and initialize it */ |
629 | usb_pcwd = kzalloc (sizeof(struct usb_pcwd_private), GFP_KERNEL); | 625 | usb_pcwd = kzalloc(sizeof(struct usb_pcwd_private), GFP_KERNEL); |
630 | if (usb_pcwd == NULL) { | 626 | if (usb_pcwd == NULL) { |
631 | printk(KERN_ERR PFX "Out of memory\n"); | 627 | printk(KERN_ERR PFX "Out of memory\n"); |
632 | goto error; | 628 | goto error; |
@@ -641,7 +637,8 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
641 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); | 637 | usb_pcwd->intr_size = (le16_to_cpu(endpoint->wMaxPacketSize) > 8 ? le16_to_cpu(endpoint->wMaxPacketSize) : 8); |
642 | 638 | ||
643 | /* set up the memory buffer's */ | 639 | /* set up the memory buffer's */ |
644 | if (!(usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma))) { | 640 | usb_pcwd->intr_buffer = usb_buffer_alloc(udev, usb_pcwd->intr_size, GFP_ATOMIC, &usb_pcwd->intr_dma); |
641 | if (!usb_pcwd->intr_buffer) { | ||
645 | printk(KERN_ERR PFX "Out of memory\n"); | 642 | printk(KERN_ERR PFX "Out of memory\n"); |
646 | goto error; | 643 | goto error; |
647 | } | 644 | } |
@@ -675,11 +672,10 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
675 | 672 | ||
676 | /* Get the Firmware Version */ | 673 | /* Get the Firmware Version */ |
677 | got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); | 674 | got_fw_rev = usb_pcwd_send_command(usb_pcwd, CMD_GET_FIRMWARE_VERSION, &fw_rev_major, &fw_rev_minor); |
678 | if (got_fw_rev) { | 675 | if (got_fw_rev) |
679 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); | 676 | sprintf(fw_ver_str, "%u.%02u", fw_rev_major, fw_rev_minor); |
680 | } else { | 677 | else |
681 | sprintf(fw_ver_str, "<card no answer>"); | 678 | sprintf(fw_ver_str, "<card no answer>"); |
682 | } | ||
683 | 679 | ||
684 | printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n", | 680 | printk(KERN_INFO PFX "Found card (Firmware: %s) with temp option\n", |
685 | fw_ver_str); | 681 | fw_ver_str); |
@@ -725,7 +721,7 @@ static int usb_pcwd_probe(struct usb_interface *interface, const struct usb_devi | |||
725 | } | 721 | } |
726 | 722 | ||
727 | /* we can register the device now, as it is ready */ | 723 | /* we can register the device now, as it is ready */ |
728 | usb_set_intfdata (interface, usb_pcwd); | 724 | usb_set_intfdata(interface, usb_pcwd); |
729 | 725 | ||
730 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", | 726 | printk(KERN_INFO PFX "initialized. heartbeat=%d sec (nowayout=%d)\n", |
731 | heartbeat, nowayout); | 727 | heartbeat, nowayout); |
@@ -759,8 +755,8 @@ static void usb_pcwd_disconnect(struct usb_interface *interface) | |||
759 | /* prevent races with open() */ | 755 | /* prevent races with open() */ |
760 | mutex_lock(&disconnect_mutex); | 756 | mutex_lock(&disconnect_mutex); |
761 | 757 | ||
762 | usb_pcwd = usb_get_intfdata (interface); | 758 | usb_pcwd = usb_get_intfdata(interface); |
763 | usb_set_intfdata (interface, NULL); | 759 | usb_set_intfdata(interface, NULL); |
764 | 760 | ||
765 | mutex_lock(&usb_pcwd->mtx); | 761 | mutex_lock(&usb_pcwd->mtx); |
766 | 762 | ||
@@ -820,5 +816,5 @@ static void __exit usb_pcwd_exit(void) | |||
820 | } | 816 | } |
821 | 817 | ||
822 | 818 | ||
823 | module_init (usb_pcwd_init); | 819 | module_init(usb_pcwd_init); |
824 | module_exit (usb_pcwd_exit); | 820 | module_exit(usb_pcwd_exit); |