diff options
author | Alexey Khoroshilov <khoroshilov@ispras.ru> | 2013-02-06 19:00:34 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2013-02-08 15:21:19 -0500 |
commit | d34138d057628211b1c835e13a64d0cc2423c969 (patch) | |
tree | df6748f0f35437ceb4e3d0fdd49e8f6db2957cb4 | |
parent | b95d788ac72b86515842a4eb92bb58a8da76a975 (diff) |
pcmcia: synclink_cs: fix error handling in mgslpc_probe()
mgslpc_probe() ignores errors in mgslpc_add_device() and
does not release all resource if mgslpc_config() failed.
The patch adds returned code to mgslpc_add_device()
and fixes the both issues.
Found by Linux Driver Verification project (linuxtesting.org).
Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r-- | drivers/char/pcmcia/synclink_cs.c | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/drivers/char/pcmcia/synclink_cs.c b/drivers/char/pcmcia/synclink_cs.c index b66eaa04f8cb..56e4e940fa19 100644 --- a/drivers/char/pcmcia/synclink_cs.c +++ b/drivers/char/pcmcia/synclink_cs.c | |||
@@ -397,7 +397,7 @@ static int adapter_test(MGSLPC_INFO *info); | |||
397 | 397 | ||
398 | static int claim_resources(MGSLPC_INFO *info); | 398 | static int claim_resources(MGSLPC_INFO *info); |
399 | static void release_resources(MGSLPC_INFO *info); | 399 | static void release_resources(MGSLPC_INFO *info); |
400 | static void mgslpc_add_device(MGSLPC_INFO *info); | 400 | static int mgslpc_add_device(MGSLPC_INFO *info); |
401 | static void mgslpc_remove_device(MGSLPC_INFO *info); | 401 | static void mgslpc_remove_device(MGSLPC_INFO *info); |
402 | 402 | ||
403 | static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); | 403 | static bool rx_get_frame(MGSLPC_INFO *info, struct tty_struct *tty); |
@@ -549,14 +549,21 @@ static int mgslpc_probe(struct pcmcia_device *link) | |||
549 | /* Initialize the struct pcmcia_device structure */ | 549 | /* Initialize the struct pcmcia_device structure */ |
550 | 550 | ||
551 | ret = mgslpc_config(link); | 551 | ret = mgslpc_config(link); |
552 | if (ret) { | 552 | if (ret != 0) |
553 | tty_port_destroy(&info->port); | 553 | goto failed; |
554 | return ret; | ||
555 | } | ||
556 | 554 | ||
557 | mgslpc_add_device(info); | 555 | ret = mgslpc_add_device(info); |
556 | if (ret != 0) | ||
557 | goto failed_release; | ||
558 | 558 | ||
559 | return 0; | 559 | return 0; |
560 | |||
561 | failed_release: | ||
562 | mgslpc_release((u_long)link); | ||
563 | failed: | ||
564 | tty_port_destroy(&info->port); | ||
565 | kfree(info); | ||
566 | return ret; | ||
560 | } | 567 | } |
561 | 568 | ||
562 | /* Card has been inserted. | 569 | /* Card has been inserted. |
@@ -2706,8 +2713,12 @@ static void release_resources(MGSLPC_INFO *info) | |||
2706 | * | 2713 | * |
2707 | * Arguments: info pointer to device instance data | 2714 | * Arguments: info pointer to device instance data |
2708 | */ | 2715 | */ |
2709 | static void mgslpc_add_device(MGSLPC_INFO *info) | 2716 | static int mgslpc_add_device(MGSLPC_INFO *info) |
2710 | { | 2717 | { |
2718 | MGSLPC_INFO *current_dev = NULL; | ||
2719 | struct device *tty_dev; | ||
2720 | int ret; | ||
2721 | |||
2711 | info->next_device = NULL; | 2722 | info->next_device = NULL; |
2712 | info->line = mgslpc_device_count; | 2723 | info->line = mgslpc_device_count; |
2713 | sprintf(info->device_name,"ttySLP%d",info->line); | 2724 | sprintf(info->device_name,"ttySLP%d",info->line); |
@@ -2722,7 +2733,7 @@ static void mgslpc_add_device(MGSLPC_INFO *info) | |||
2722 | if (!mgslpc_device_list) | 2733 | if (!mgslpc_device_list) |
2723 | mgslpc_device_list = info; | 2734 | mgslpc_device_list = info; |
2724 | else { | 2735 | else { |
2725 | MGSLPC_INFO *current_dev = mgslpc_device_list; | 2736 | current_dev = mgslpc_device_list; |
2726 | while( current_dev->next_device ) | 2737 | while( current_dev->next_device ) |
2727 | current_dev = current_dev->next_device; | 2738 | current_dev = current_dev->next_device; |
2728 | current_dev->next_device = info; | 2739 | current_dev->next_device = info; |
@@ -2737,10 +2748,30 @@ static void mgslpc_add_device(MGSLPC_INFO *info) | |||
2737 | info->device_name, info->io_base, info->irq_level); | 2748 | info->device_name, info->io_base, info->irq_level); |
2738 | 2749 | ||
2739 | #if SYNCLINK_GENERIC_HDLC | 2750 | #if SYNCLINK_GENERIC_HDLC |
2740 | hdlcdev_init(info); | 2751 | ret = hdlcdev_init(info); |
2752 | if (ret != 0) | ||
2753 | goto failed; | ||
2741 | #endif | 2754 | #endif |
2742 | tty_port_register_device(&info->port, serial_driver, info->line, | 2755 | |
2756 | tty_dev = tty_port_register_device(&info->port, serial_driver, info->line, | ||
2743 | &info->p_dev->dev); | 2757 | &info->p_dev->dev); |
2758 | if (IS_ERR(tty_dev)) { | ||
2759 | ret = PTR_ERR(tty_dev); | ||
2760 | #if SYNCLINK_GENERIC_HDLC | ||
2761 | hdlcdev_exit(info); | ||
2762 | #endif | ||
2763 | goto failed; | ||
2764 | } | ||
2765 | |||
2766 | return 0; | ||
2767 | |||
2768 | failed: | ||
2769 | if (current_dev) | ||
2770 | current_dev->next_device = NULL; | ||
2771 | else | ||
2772 | mgslpc_device_list = NULL; | ||
2773 | mgslpc_device_count--; | ||
2774 | return ret; | ||
2744 | } | 2775 | } |
2745 | 2776 | ||
2746 | static void mgslpc_remove_device(MGSLPC_INFO *remove_info) | 2777 | static void mgslpc_remove_device(MGSLPC_INFO *remove_info) |