diff options
Diffstat (limited to 'drivers/isdn/gigaset/common.c')
-rw-r--r-- | drivers/isdn/gigaset/common.c | 61 |
1 files changed, 33 insertions, 28 deletions
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 95eff3b2917a..4f75cce6fdff 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -356,16 +356,17 @@ static struct cardstate *alloc_cs(struct gigaset_driver *drv) | |||
356 | { | 356 | { |
357 | unsigned long flags; | 357 | unsigned long flags; |
358 | unsigned i; | 358 | unsigned i; |
359 | static struct cardstate *ret = NULL; | 359 | struct cardstate *ret = NULL; |
360 | 360 | ||
361 | spin_lock_irqsave(&drv->lock, flags); | 361 | spin_lock_irqsave(&drv->lock, flags); |
362 | for (i = 0; i < drv->minors; ++i) { | 362 | for (i = 0; i < drv->minors; ++i) { |
363 | if (!(drv->flags[i] & VALID_MINOR)) { | 363 | if (!(drv->flags[i] & VALID_MINOR)) { |
364 | drv->flags[i] = VALID_MINOR; | 364 | if (try_module_get(drv->owner)) { |
365 | ret = drv->cs + i; | 365 | drv->flags[i] = VALID_MINOR; |
366 | } | 366 | ret = drv->cs + i; |
367 | if (ret) | 367 | } |
368 | break; | 368 | break; |
369 | } | ||
369 | } | 370 | } |
370 | spin_unlock_irqrestore(&drv->lock, flags); | 371 | spin_unlock_irqrestore(&drv->lock, flags); |
371 | return ret; | 372 | return ret; |
@@ -376,6 +377,8 @@ static void free_cs(struct cardstate *cs) | |||
376 | unsigned long flags; | 377 | unsigned long flags; |
377 | struct gigaset_driver *drv = cs->driver; | 378 | struct gigaset_driver *drv = cs->driver; |
378 | spin_lock_irqsave(&drv->lock, flags); | 379 | spin_lock_irqsave(&drv->lock, flags); |
380 | if (drv->flags[cs->minor_index] & VALID_MINOR) | ||
381 | module_put(drv->owner); | ||
379 | drv->flags[cs->minor_index] = 0; | 382 | drv->flags[cs->minor_index] = 0; |
380 | spin_unlock_irqrestore(&drv->lock, flags); | 383 | spin_unlock_irqrestore(&drv->lock, flags); |
381 | } | 384 | } |
@@ -579,7 +582,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, | |||
579 | } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) | 582 | } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) |
580 | skb_reserve(bcs->skb, HW_HDR_LEN); | 583 | skb_reserve(bcs->skb, HW_HDR_LEN); |
581 | else { | 584 | else { |
582 | warn("could not allocate skb\n"); | 585 | warn("could not allocate skb"); |
583 | bcs->inputstate |= INS_skip_frame; | 586 | bcs->inputstate |= INS_skip_frame; |
584 | } | 587 | } |
585 | 588 | ||
@@ -632,17 +635,25 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
632 | int i; | 635 | int i; |
633 | 636 | ||
634 | gig_dbg(DEBUG_INIT, "allocating cs"); | 637 | gig_dbg(DEBUG_INIT, "allocating cs"); |
635 | cs = alloc_cs(drv); | 638 | if (!(cs = alloc_cs(drv))) { |
636 | if (!cs) | 639 | err("maximum number of devices exceeded"); |
637 | goto error; | 640 | return NULL; |
641 | } | ||
642 | mutex_init(&cs->mutex); | ||
643 | mutex_lock(&cs->mutex); | ||
644 | |||
638 | gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); | 645 | gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); |
639 | cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); | 646 | cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); |
640 | if (!cs->bcs) | 647 | if (!cs->bcs) { |
648 | err("out of memory"); | ||
641 | goto error; | 649 | goto error; |
650 | } | ||
642 | gig_dbg(DEBUG_INIT, "allocating inbuf"); | 651 | gig_dbg(DEBUG_INIT, "allocating inbuf"); |
643 | cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); | 652 | cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); |
644 | if (!cs->inbuf) | 653 | if (!cs->inbuf) { |
654 | err("out of memory"); | ||
645 | goto error; | 655 | goto error; |
656 | } | ||
646 | 657 | ||
647 | cs->cs_init = 0; | 658 | cs->cs_init = 0; |
648 | cs->channels = channels; | 659 | cs->channels = channels; |
@@ -654,8 +665,6 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
654 | spin_lock_init(&cs->ev_lock); | 665 | spin_lock_init(&cs->ev_lock); |
655 | cs->ev_tail = 0; | 666 | cs->ev_tail = 0; |
656 | cs->ev_head = 0; | 667 | cs->ev_head = 0; |
657 | mutex_init(&cs->mutex); | ||
658 | mutex_lock(&cs->mutex); | ||
659 | 668 | ||
660 | tasklet_init(&cs->event_tasklet, &gigaset_handle_event, | 669 | tasklet_init(&cs->event_tasklet, &gigaset_handle_event, |
661 | (unsigned long) cs); | 670 | (unsigned long) cs); |
@@ -684,8 +693,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
684 | 693 | ||
685 | for (i = 0; i < channels; ++i) { | 694 | for (i = 0; i < channels; ++i) { |
686 | gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); | 695 | gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); |
687 | if (!gigaset_initbcs(cs->bcs + i, cs, i)) | 696 | if (!gigaset_initbcs(cs->bcs + i, cs, i)) { |
697 | err("could not allocate channel %d data", i); | ||
688 | goto error; | 698 | goto error; |
699 | } | ||
689 | } | 700 | } |
690 | 701 | ||
691 | ++cs->cs_init; | 702 | ++cs->cs_init; |
@@ -720,8 +731,10 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
720 | make_valid(cs, VALID_ID); | 731 | make_valid(cs, VALID_ID); |
721 | ++cs->cs_init; | 732 | ++cs->cs_init; |
722 | gig_dbg(DEBUG_INIT, "setting up hw"); | 733 | gig_dbg(DEBUG_INIT, "setting up hw"); |
723 | if (!cs->ops->initcshw(cs)) | 734 | if (!cs->ops->initcshw(cs)) { |
735 | err("could not allocate device specific data"); | ||
724 | goto error; | 736 | goto error; |
737 | } | ||
725 | 738 | ||
726 | ++cs->cs_init; | 739 | ++cs->cs_init; |
727 | 740 | ||
@@ -743,8 +756,8 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, | |||
743 | mutex_unlock(&cs->mutex); | 756 | mutex_unlock(&cs->mutex); |
744 | return cs; | 757 | return cs; |
745 | 758 | ||
746 | error: if (cs) | 759 | error: |
747 | mutex_unlock(&cs->mutex); | 760 | mutex_unlock(&cs->mutex); |
748 | gig_dbg(DEBUG_INIT, "failed"); | 761 | gig_dbg(DEBUG_INIT, "failed"); |
749 | gigaset_freecs(cs); | 762 | gigaset_freecs(cs); |
750 | return NULL; | 763 | return NULL; |
@@ -1040,7 +1053,6 @@ void gigaset_freedriver(struct gigaset_driver *drv) | |||
1040 | spin_unlock_irqrestore(&driver_lock, flags); | 1053 | spin_unlock_irqrestore(&driver_lock, flags); |
1041 | 1054 | ||
1042 | gigaset_if_freedriver(drv); | 1055 | gigaset_if_freedriver(drv); |
1043 | module_put(drv->owner); | ||
1044 | 1056 | ||
1045 | kfree(drv->cs); | 1057 | kfree(drv->cs); |
1046 | kfree(drv->flags); | 1058 | kfree(drv->flags); |
@@ -1072,10 +1084,6 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | |||
1072 | if (!drv) | 1084 | if (!drv) |
1073 | return NULL; | 1085 | return NULL; |
1074 | 1086 | ||
1075 | if (!try_module_get(owner)) | ||
1076 | goto out1; | ||
1077 | |||
1078 | drv->cs = NULL; | ||
1079 | drv->have_tty = 0; | 1087 | drv->have_tty = 0; |
1080 | drv->minor = minor; | 1088 | drv->minor = minor; |
1081 | drv->minors = minors; | 1089 | drv->minors = minors; |
@@ -1087,11 +1095,11 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | |||
1087 | 1095 | ||
1088 | drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); | 1096 | drv->cs = kmalloc(minors * sizeof *drv->cs, GFP_KERNEL); |
1089 | if (!drv->cs) | 1097 | if (!drv->cs) |
1090 | goto out2; | 1098 | goto error; |
1091 | 1099 | ||
1092 | drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); | 1100 | drv->flags = kmalloc(minors * sizeof *drv->flags, GFP_KERNEL); |
1093 | if (!drv->flags) | 1101 | if (!drv->flags) |
1094 | goto out3; | 1102 | goto error; |
1095 | 1103 | ||
1096 | for (i = 0; i < minors; ++i) { | 1104 | for (i = 0; i < minors; ++i) { |
1097 | drv->flags[i] = 0; | 1105 | drv->flags[i] = 0; |
@@ -1108,11 +1116,8 @@ struct gigaset_driver *gigaset_initdriver(unsigned minor, unsigned minors, | |||
1108 | 1116 | ||
1109 | return drv; | 1117 | return drv; |
1110 | 1118 | ||
1111 | out3: | 1119 | error: |
1112 | kfree(drv->cs); | 1120 | kfree(drv->cs); |
1113 | out2: | ||
1114 | module_put(owner); | ||
1115 | out1: | ||
1116 | kfree(drv); | 1121 | kfree(drv); |
1117 | return NULL; | 1122 | return NULL; |
1118 | } | 1123 | } |