Merge master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* master.kernel.org:/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
[WATCHDOG] at91_wdt.c - Atmel AT91RM9200 watchdog driver
[WATCHDOG] pcwd_usb.c: fix a NULL pointer dereference
[WATCHDOG] pcwd.c sprintf/strcpy fix
[WATCHDOG] pcwd.c general clean-up after patches
[WATCHDOG] pcwd.c add debug info
[WATCHDOG] pcwd.c pcwd_cleanup_module patch
[WATCHDOG] pcwd.c firmware-info patch
[WATCHDOG] pcwd.c control status patch

+340 -36
+7
drivers/char/watchdog/Kconfig
··· 60 60 61 61 # ARM Architecture 62 62 63 + config AT91_WATCHDOG 64 + tristate "AT91RM9200 watchdog" 65 + depends on WATCHDOG && ARCH_AT91RM9200 66 + help 67 + Watchdog timer embedded into AT91RM9200 chips. This will reboot your 68 + system when the timeout is reached. 69 + 63 70 config 21285_WATCHDOG 64 71 tristate "DC21285 watchdog" 65 72 depends on WATCHDOG && FOOTBRIDGE
+1
drivers/char/watchdog/Makefile
··· 23 23 obj-$(CONFIG_USBPCWATCHDOG) += pcwd_usb.o 24 24 25 25 # ARM Architecture 26 + obj-$(CONFIG_AT91_WATCHDOG) += at91_wdt.o 26 27 obj-$(CONFIG_21285_WATCHDOG) += wdt285.o 27 28 obj-$(CONFIG_977_WATCHDOG) += wdt977.o 28 29 obj-$(CONFIG_IXP2000_WATCHDOG) += ixp2000_wdt.o
+228
drivers/char/watchdog/at91_wdt.c
··· 1 + /* 2 + * Watchdog driver for Atmel AT91RM9200 (Thunder) 3 + * 4 + * Copyright (C) 2003 SAN People (Pty) Ltd 5 + * 6 + * This program is free software; you can redistribute it and/or 7 + * modify it under the terms of the GNU General Public License 8 + * as published by the Free Software Foundation; either version 9 + * 2 of the License, or (at your option) any later version. 10 + */ 11 + 12 + #include <linux/config.h> 13 + #include <linux/errno.h> 14 + #include <linux/fs.h> 15 + #include <linux/init.h> 16 + #include <linux/kernel.h> 17 + #include <linux/miscdevice.h> 18 + #include <linux/module.h> 19 + #include <linux/moduleparam.h> 20 + #include <linux/types.h> 21 + #include <linux/watchdog.h> 22 + #include <asm/bitops.h> 23 + #include <asm/uaccess.h> 24 + 25 + 26 + #define WDT_DEFAULT_TIME 5 /* 5 seconds */ 27 + #define WDT_MAX_TIME 256 /* 256 seconds */ 28 + 29 + static int wdt_time = WDT_DEFAULT_TIME; 30 + static int nowayout = WATCHDOG_NOWAYOUT; 31 + 32 + module_param(wdt_time, int, 0); 33 + MODULE_PARM_DESC(wdt_time, "Watchdog time in seconds. (default="__MODULE_STRING(WDT_DEFAULT_TIME) ")"); 34 + 35 + module_param(nowayout, int, 0); 36 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 37 + 38 + 39 + static unsigned long at91wdt_busy; 40 + 41 + /* ......................................................................... */ 42 + 43 + /* 44 + * Disable the watchdog. 45 + */ 46 + static void inline at91_wdt_stop(void) 47 + { 48 + at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN); 49 + } 50 + 51 + /* 52 + * Enable and reset the watchdog. 53 + */ 54 + static void inline at91_wdt_start(void) 55 + { 56 + at91_sys_write(AT91_ST_WDMR, AT91_ST_EXTEN | AT91_ST_RSTEN | (((65536 * wdt_time) >> 8) & AT91_ST_WDV)); 57 + at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); 58 + } 59 + 60 + /* 61 + * Reload the watchdog timer. (ie, pat the watchdog) 62 + */ 63 + static void inline at91_wdt_reload(void) 64 + { 65 + at91_sys_write(AT91_ST_CR, AT91_ST_WDRST); 66 + } 67 + 68 + /* ......................................................................... */ 69 + 70 + /* 71 + * Watchdog device is opened, and watchdog starts running. 72 + */ 73 + static int at91_wdt_open(struct inode *inode, struct file *file) 74 + { 75 + if (test_and_set_bit(0, &at91wdt_busy)) 76 + return -EBUSY; 77 + 78 + at91_wdt_start(); 79 + return nonseekable_open(inode, file); 80 + } 81 + 82 + /* 83 + * Close the watchdog device. 84 + * If CONFIG_WATCHDOG_NOWAYOUT is NOT defined then the watchdog is also 85 + * disabled. 86 + */ 87 + static int at91_wdt_close(struct inode *inode, struct file *file) 88 + { 89 + if (!nowayout) 90 + at91_wdt_stop(); /* Disable the watchdog when file is closed */ 91 + 92 + clear_bit(0, &at91wdt_busy); 93 + return 0; 94 + } 95 + 96 + /* 97 + * Change the watchdog time interval. 98 + */ 99 + static int at91_wdt_settimeout(int new_time) 100 + { 101 + /* 102 + * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz 103 + * 104 + * Since WDV is a 16-bit counter, the maximum period is 105 + * 65536 / 0.256 = 256 seconds. 106 + */ 107 + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) 108 + return -EINVAL; 109 + 110 + /* Set new watchdog time. It will be used when at91_wdt_start() is called. */ 111 + wdt_time = new_time; 112 + return 0; 113 + } 114 + 115 + static struct watchdog_info at91_wdt_info = { 116 + .identity = "at91 watchdog", 117 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, 118 + }; 119 + 120 + /* 121 + * Handle commands from user-space. 122 + */ 123 + static int at91_wdt_ioctl(struct inode *inode, struct file *file, 124 + unsigned int cmd, unsigned long arg) 125 + { 126 + void __user *argp = (void __user *)arg; 127 + int __user *p = argp; 128 + int new_value; 129 + 130 + switch(cmd) { 131 + case WDIOC_KEEPALIVE: 132 + at91_wdt_reload(); /* pat the watchdog */ 133 + return 0; 134 + 135 + case WDIOC_GETSUPPORT: 136 + return copy_to_user(argp, &at91_wdt_info, sizeof(at91_wdt_info)) ? -EFAULT : 0; 137 + 138 + case WDIOC_SETTIMEOUT: 139 + if (get_user(new_value, p)) 140 + return -EFAULT; 141 + 142 + if (at91_wdt_settimeout(new_value)) 143 + return -EINVAL; 144 + 145 + /* Enable new time value */ 146 + at91_wdt_start(); 147 + 148 + /* Return current value */ 149 + return put_user(wdt_time, p); 150 + 151 + case WDIOC_GETTIMEOUT: 152 + return put_user(wdt_time, p); 153 + 154 + case WDIOC_GETSTATUS: 155 + case WDIOC_GETBOOTSTATUS: 156 + return put_user(0, p); 157 + 158 + case WDIOC_SETOPTIONS: 159 + if (get_user(new_value, p)) 160 + return -EFAULT; 161 + 162 + if (new_value & WDIOS_DISABLECARD) 163 + at91_wdt_stop(); 164 + if (new_value & WDIOS_ENABLECARD) 165 + at91_wdt_start(); 166 + return 0; 167 + 168 + default: 169 + return -ENOIOCTLCMD; 170 + } 171 + } 172 + 173 + /* 174 + * Pat the watchdog whenever device is written to. 175 + */ 176 + static ssize_t at91_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos) 177 + { 178 + at91_wdt_reload(); /* pat the watchdog */ 179 + return len; 180 + } 181 + 182 + /* ......................................................................... */ 183 + 184 + static struct file_operations at91wdt_fops = { 185 + .owner = THIS_MODULE, 186 + .llseek = no_llseek, 187 + .ioctl = at91_wdt_ioctl, 188 + .open = at91_wdt_open, 189 + .release = at91_wdt_close, 190 + .write = at91_wdt_write, 191 + }; 192 + 193 + static struct miscdevice at91wdt_miscdev = { 194 + .minor = WATCHDOG_MINOR, 195 + .name = "watchdog", 196 + .fops = &at91wdt_fops, 197 + }; 198 + 199 + static int __init at91_wdt_init(void) 200 + { 201 + int res; 202 + 203 + /* Check that the heartbeat value is within range; if not reset to the default */ 204 + if (at91_wdt_settimeout(wdt_time)) { 205 + at91_wdt_settimeout(WDT_DEFAULT_TIME); 206 + printk(KERN_INFO "at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time); 207 + } 208 + 209 + res = misc_register(&at91wdt_miscdev); 210 + if (res) 211 + return res; 212 + 213 + printk("AT91 Watchdog Timer enabled (%d seconds, nowayout=%d)\n", wdt_time, nowayout); 214 + return 0; 215 + } 216 + 217 + static void __exit at91_wdt_exit(void) 218 + { 219 + misc_deregister(&at91wdt_miscdev); 220 + } 221 + 222 + module_init(at91_wdt_init); 223 + module_exit(at91_wdt_exit); 224 + 225 + MODULE_AUTHOR("Andrew Victor"); 226 + MODULE_DESCRIPTION("Watchdog driver for Atmel AT91RM9200"); 227 + MODULE_LICENSE("GPL"); 228 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+102 -35
drivers/char/watchdog/pcwd.c
··· 66 66 #include <linux/fs.h> /* For file operations */ 67 67 #include <linux/ioport.h> /* For io-port access */ 68 68 #include <linux/spinlock.h> /* For spin_lock/spin_unlock/... */ 69 - #include <linux/sched.h> /* TASK_INTERRUPTIBLE, set_current_state() and friends */ 70 - #include <linux/slab.h> /* For kmalloc */ 71 69 72 70 #include <asm/uaccess.h> /* For copy_to_user/put_user/... */ 73 71 #include <asm/io.h> /* For inb/outb/... */ 74 72 75 73 /* Module and version information */ 76 - #define WATCHDOG_VERSION "1.16" 77 - #define WATCHDOG_DATE "03 Jan 2006" 74 + #define WATCHDOG_VERSION "1.17" 75 + #define WATCHDOG_DATE "12 Feb 2006" 78 76 #define WATCHDOG_DRIVER_NAME "ISA-PC Watchdog" 79 77 #define WATCHDOG_NAME "pcwd" 80 78 #define PFX WATCHDOG_NAME ": " ··· 94 96 * PCI-PC Watchdog card. 95 97 */ 96 98 /* Port 1 : Control Status #1 for the PC Watchdog card, revision A. */ 97 - #define WD_WDRST 0x01 /* Previously reset state */ 98 - #define WD_T110 0x02 /* Temperature overheat sense */ 99 - #define WD_HRTBT 0x04 /* Heartbeat sense */ 100 - #define WD_RLY2 0x08 /* External relay triggered */ 101 - #define WD_SRLY2 0x80 /* Software external relay triggered */ 99 + #define WD_WDRST 0x01 /* Previously reset state */ 100 + #define WD_T110 0x02 /* Temperature overheat sense */ 101 + #define WD_HRTBT 0x04 /* Heartbeat sense */ 102 + #define WD_RLY2 0x08 /* External relay triggered */ 103 + #define WD_SRLY2 0x80 /* Software external relay triggered */ 102 104 /* Port 1 : Control Status #1 for the PC Watchdog card, revision C. */ 103 - #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ 104 - #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ 105 - #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ 105 + #define WD_REVC_WTRP 0x01 /* Watchdog Trip status */ 106 + #define WD_REVC_HRBT 0x02 /* Watchdog Heartbeat */ 107 + #define WD_REVC_TTRP 0x04 /* Temperature Trip status */ 108 + #define WD_REVC_RL2A 0x08 /* Relay 2 activated by on-board processor */ 109 + #define WD_REVC_RL1A 0x10 /* Relay 1 active */ 110 + #define WD_REVC_R2DS 0x40 /* Relay 2 disable */ 111 + #define WD_REVC_RLY2 0x80 /* Relay 2 activated? */ 106 112 /* Port 2 : Control Status #2 */ 107 113 #define WD_WDIS 0x10 /* Watchdog Disabled */ 108 114 #define WD_ENTP 0x20 /* Watchdog Enable Temperature Trip */ ··· 124 122 #define CMD_ISA_VERSION_HUNDRETH 0x03 125 123 #define CMD_ISA_VERSION_MINOR 0x04 126 124 #define CMD_ISA_SWITCH_SETTINGS 0x05 125 + #define CMD_ISA_RESET_PC 0x06 126 + #define CMD_ISA_ARM_0 0x07 127 + #define CMD_ISA_ARM_30 0x08 128 + #define CMD_ISA_ARM_60 0x09 127 129 #define CMD_ISA_DELAY_TIME_2SECS 0x0A 128 130 #define CMD_ISA_DELAY_TIME_4SECS 0x0B 129 131 #define CMD_ISA_DELAY_TIME_8SECS 0x0C 132 + #define CMD_ISA_RESET_RELAYS 0x0D 130 133 131 134 /* 132 135 * We are using an kernel timer to do the pinging of the watchdog ··· 149 142 static char expect_close; 150 143 static int temp_panic; 151 144 static struct { /* this is private data for each ISA-PC watchdog card */ 145 + char fw_ver_str[6]; /* The cards firmware version */ 152 146 int revision; /* The card's revision */ 153 147 int supports_temp; /* Wether or not the card has a temperature device */ 154 148 int command_mode; /* Wether or not the card is in command mode */ ··· 161 153 } pcwd_private; 162 154 163 155 /* module parameters */ 156 + #define QUIET 0 /* Default */ 157 + #define VERBOSE 1 /* Verbose */ 158 + #define DEBUG 2 /* print fancy stuff too */ 159 + static int debug = QUIET; 160 + module_param(debug, int, 0); 161 + MODULE_PARM_DESC(debug, "Debug level: 0=Quiet, 1=Verbose, 2=Debug (default=0)"); 162 + 164 163 #define WATCHDOG_HEARTBEAT 60 /* 60 sec default heartbeat */ 165 164 static int heartbeat = WATCHDOG_HEARTBEAT; 166 165 module_param(heartbeat, int, 0); ··· 187 172 int control_status; 188 173 int port0, last_port0; /* Double read for stabilising */ 189 174 175 + if (debug >= DEBUG) 176 + printk(KERN_DEBUG PFX "sending following data cmd=0x%02x\n", 177 + cmd); 178 + 190 179 /* The WCMD bit must be 1 and the command is only 4 bits in size */ 191 180 control_status = (cmd & 0x0F) | WD_WCMD; 192 181 outb_p(control_status, pcwd_private.io_addr + 2); ··· 206 187 207 188 udelay (250); 208 189 } 190 + 191 + if (debug >= DEBUG) 192 + printk(KERN_DEBUG PFX "received following data for cmd=0x%02x: port0=0x%02x last_port0=0x%02x\n", 193 + cmd, port0, last_port0); 209 194 210 195 return port0; 211 196 } ··· 237 214 spin_unlock(&pcwd_private.io_lock); 238 215 pcwd_private.command_mode = found; 239 216 217 + if (debug >= DEBUG) 218 + printk(KERN_DEBUG PFX "command_mode=%d\n", 219 + pcwd_private.command_mode); 220 + 240 221 return(found); 241 222 } 242 223 ··· 253 226 spin_unlock(&pcwd_private.io_lock); 254 227 255 228 pcwd_private.command_mode = 0; 229 + 230 + if (debug >= DEBUG) 231 + printk(KERN_DEBUG PFX "command_mode=%d\n", 232 + pcwd_private.command_mode); 256 233 } 257 234 258 235 static inline void pcwd_check_temperature_support(void) ··· 265 234 pcwd_private.supports_temp = 1; 266 235 } 267 236 268 - static inline char *get_firmware(void) 237 + static inline void pcwd_get_firmware(void) 269 238 { 270 239 int one, ten, hund, minor; 271 - char *ret; 272 240 273 - ret = kmalloc(6, GFP_KERNEL); 274 - if(ret == NULL) 275 - return NULL; 241 + strcpy(pcwd_private.fw_ver_str, "ERROR"); 276 242 277 243 if (set_command_mode()) { 278 244 one = send_isa_command(CMD_ISA_VERSION_INTEGER); 279 245 ten = send_isa_command(CMD_ISA_VERSION_TENTH); 280 246 hund = send_isa_command(CMD_ISA_VERSION_HUNDRETH); 281 247 minor = send_isa_command(CMD_ISA_VERSION_MINOR); 282 - sprintf(ret, "%c.%c%c%c", one, ten, hund, minor); 248 + sprintf(pcwd_private.fw_ver_str, "%c.%c%c%c", one, ten, hund, minor); 283 249 } 284 - else 285 - sprintf(ret, "ERROR"); 286 - 287 250 unset_command_mode(); 288 - return(ret); 251 + 252 + return; 289 253 } 290 254 291 255 static inline int pcwd_get_option_switches(void) ··· 298 272 299 273 static void pcwd_show_card_info(void) 300 274 { 301 - char *firmware; 302 275 int option_switches; 303 276 304 277 /* Get some extra info from the hardware (in command/debug/diag mode) */ 305 278 if (pcwd_private.revision == PCWD_REVISION_A) 306 279 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.A) detected at port 0x%04x\n", pcwd_private.io_addr); 307 280 else if (pcwd_private.revision == PCWD_REVISION_C) { 308 - firmware = get_firmware(); 281 + pcwd_get_firmware(); 309 282 printk(KERN_INFO PFX "ISA-PC Watchdog (REV.C) detected at port 0x%04x (Firmware version: %s)\n", 310 - pcwd_private.io_addr, firmware); 311 - kfree(firmware); 283 + pcwd_private.io_addr, pcwd_private.fw_ver_str); 312 284 option_switches = pcwd_get_option_switches(); 313 285 printk(KERN_INFO PFX "Option switches (0x%02x): Temperature Reset Enable=%s, Power On Delay=%s\n", 314 286 option_switches, ··· 386 362 return -EIO; 387 363 } 388 364 } 365 + 366 + if (debug >= VERBOSE) 367 + printk(KERN_DEBUG PFX "Watchdog started\n"); 368 + 389 369 return 0; 390 370 } 391 371 ··· 414 386 return -EIO; 415 387 } 416 388 } 389 + 390 + if (debug >= VERBOSE) 391 + printk(KERN_DEBUG PFX "Watchdog stopped\n"); 392 + 417 393 return 0; 418 394 } 419 395 ··· 425 393 { 426 394 /* user land ping */ 427 395 pcwd_private.next_heartbeat = jiffies + (heartbeat * HZ); 396 + 397 + if (debug >= DEBUG) 398 + printk(KERN_DEBUG PFX "Watchdog keepalive signal send\n"); 399 + 428 400 return 0; 429 401 } 430 402 ··· 438 402 return -EINVAL; 439 403 440 404 heartbeat = t; 405 + 406 + if (debug >= VERBOSE) 407 + printk(KERN_DEBUG PFX "New heartbeat: %d\n", 408 + heartbeat); 409 + 441 410 return 0; 442 411 } 443 412 444 413 static int pcwd_get_status(int *status) 445 414 { 446 - int card_status; 415 + int control_status; 447 416 448 417 *status=0; 449 418 spin_lock(&pcwd_private.io_lock); ··· 456 415 /* Rev A cards return status information from 457 416 * the base register, which is used for the 458 417 * temperature in other cards. */ 459 - card_status = inb(pcwd_private.io_addr); 418 + control_status = inb(pcwd_private.io_addr); 460 419 else { 461 420 /* Rev C cards return card status in the base 462 421 * address + 1 register. And use different bits 463 422 * to indicate a card initiated reset, and an 464 423 * over-temperature condition. And the reboot 465 424 * status can be reset. */ 466 - card_status = inb(pcwd_private.io_addr + 1); 425 + control_status = inb(pcwd_private.io_addr + 1); 467 426 } 468 427 spin_unlock(&pcwd_private.io_lock); 469 428 470 429 if (pcwd_private.revision == PCWD_REVISION_A) { 471 - if (card_status & WD_WDRST) 430 + if (control_status & WD_WDRST) 472 431 *status |= WDIOF_CARDRESET; 473 432 474 - if (card_status & WD_T110) { 433 + if (control_status & WD_T110) { 475 434 *status |= WDIOF_OVERHEAT; 476 435 if (temp_panic) { 477 436 printk (KERN_INFO PFX "Temperature overheat trip!\n"); 478 437 kernel_power_off(); 438 + /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ 479 439 } 480 440 } 481 441 } else { 482 - if (card_status & WD_REVC_WTRP) 442 + if (control_status & WD_REVC_WTRP) 483 443 *status |= WDIOF_CARDRESET; 484 444 485 - if (card_status & WD_REVC_TTRP) { 445 + if (control_status & WD_REVC_TTRP) { 486 446 *status |= WDIOF_OVERHEAT; 487 447 if (temp_panic) { 488 448 printk (KERN_INFO PFX "Temperature overheat trip!\n"); 489 449 kernel_power_off(); 450 + /* or should we just do a: panic(PFX "Temperature overheat trip!\n"); */ 490 451 } 491 452 } 492 453 } ··· 498 455 499 456 static int pcwd_clear_status(void) 500 457 { 458 + int control_status; 459 + 501 460 if (pcwd_private.revision == PCWD_REVISION_C) { 502 461 spin_lock(&pcwd_private.io_lock); 503 - outb_p(0x00, pcwd_private.io_addr + 1); /* clear reset status */ 462 + 463 + if (debug >= VERBOSE) 464 + printk(KERN_INFO PFX "clearing watchdog trip status\n"); 465 + 466 + control_status = inb_p(pcwd_private.io_addr + 1); 467 + 468 + if (debug >= DEBUG) { 469 + printk(KERN_DEBUG PFX "status was: 0x%02x\n", control_status); 470 + printk(KERN_DEBUG PFX "sending: 0x%02x\n", 471 + (control_status & WD_REVC_R2DS)); 472 + } 473 + 474 + /* clear reset status & Keep Relay 2 disable state as it is */ 475 + outb_p((control_status & WD_REVC_R2DS), pcwd_private.io_addr + 1); 476 + 504 477 spin_unlock(&pcwd_private.io_lock); 505 478 } 506 479 return 0; ··· 539 480 spin_lock(&pcwd_private.io_lock); 540 481 *temperature = ((inb(pcwd_private.io_addr)) * 9 / 5) + 32; 541 482 spin_unlock(&pcwd_private.io_lock); 483 + 484 + if (debug >= DEBUG) { 485 + printk(KERN_DEBUG PFX "temperature is: %d F\n", 486 + *temperature); 487 + } 542 488 543 489 return 0; 544 490 } ··· 663 599 static int pcwd_open(struct inode *inode, struct file *file) 664 600 { 665 601 if (!atomic_dec_and_test(&open_allowed) ) { 602 + if (debug >= VERBOSE) 603 + printk(KERN_ERR PFX "Attempt to open already opened device.\n"); 666 604 atomic_inc( &open_allowed ); 667 605 return -EBUSY; 668 606 } ··· 988 922 { 989 923 if (pcwd_private.io_addr) 990 924 pcwatchdog_exit(); 991 - return; 925 + 926 + printk(KERN_INFO PFX "Watchdog Module Unloaded.\n"); 992 927 } 993 928 994 929 module_init(pcwd_init_module);
+2 -1
drivers/char/watchdog/pcwd_usb.c
··· 705 705 err_out_unregister_reboot: 706 706 unregister_reboot_notifier(&usb_pcwd_notifier); 707 707 error: 708 - usb_pcwd_delete (usb_pcwd); 708 + if (usb_pcwd) 709 + usb_pcwd_delete(usb_pcwd); 709 710 usb_pcwd_device = NULL; 710 711 return retval; 711 712 }