diff options
| -rw-r--r-- | drivers/isdn/gigaset/capi.c | 225 | ||||
| -rw-r--r-- | drivers/isdn/gigaset/common.c | 4 | ||||
| -rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 4 |
3 files changed, 180 insertions, 53 deletions
diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 665673f4d667..6fbe8999c419 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c | |||
| @@ -70,7 +70,7 @@ | |||
| 70 | #define MAX_NUMBER_DIGITS 20 | 70 | #define MAX_NUMBER_DIGITS 20 |
| 71 | #define MAX_FMT_IE_LEN 20 | 71 | #define MAX_FMT_IE_LEN 20 |
| 72 | 72 | ||
| 73 | /* values for gigaset_capi_appl.connected */ | 73 | /* values for bcs->apconnstate */ |
| 74 | #define APCONN_NONE 0 /* inactive/listening */ | 74 | #define APCONN_NONE 0 /* inactive/listening */ |
| 75 | #define APCONN_SETUP 1 /* connecting */ | 75 | #define APCONN_SETUP 1 /* connecting */ |
| 76 | #define APCONN_ACTIVE 2 /* B channel up */ | 76 | #define APCONN_ACTIVE 2 /* B channel up */ |
| @@ -84,7 +84,6 @@ struct gigaset_capi_appl { | |||
| 84 | u16 nextMessageNumber; | 84 | u16 nextMessageNumber; |
| 85 | u32 listenInfoMask; | 85 | u32 listenInfoMask; |
| 86 | u32 listenCIPmask; | 86 | u32 listenCIPmask; |
| 87 | int connected; | ||
| 88 | }; | 87 | }; |
| 89 | 88 | ||
| 90 | /* CAPI specific controller data structure */ | 89 | /* CAPI specific controller data structure */ |
| @@ -384,7 +383,7 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) | |||
| 384 | } | 383 | } |
| 385 | 384 | ||
| 386 | /* don't send further B3 messages if disconnected */ | 385 | /* don't send further B3 messages if disconnected */ |
| 387 | if (ap->connected < APCONN_ACTIVE) { | 386 | if (bcs->apconnstate < APCONN_ACTIVE) { |
| 388 | gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); | 387 | gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); |
| 389 | return; | 388 | return; |
| 390 | } | 389 | } |
| @@ -428,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) | |||
| 428 | } | 427 | } |
| 429 | 428 | ||
| 430 | /* don't send further B3 messages if disconnected */ | 429 | /* don't send further B3 messages if disconnected */ |
| 431 | if (ap->connected < APCONN_ACTIVE) { | 430 | if (bcs->apconnstate < APCONN_ACTIVE) { |
| 432 | gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); | 431 | gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); |
| 433 | dev_kfree_skb_any(skb); | 432 | dev_kfree_skb_any(skb); |
| 434 | return; | 433 | return; |
| @@ -500,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) | |||
| 500 | u32 actCIPmask; | 499 | u32 actCIPmask; |
| 501 | struct sk_buff *skb; | 500 | struct sk_buff *skb; |
| 502 | unsigned int msgsize; | 501 | unsigned int msgsize; |
| 502 | unsigned long flags; | ||
| 503 | int i; | 503 | int i; |
| 504 | 504 | ||
| 505 | /* | 505 | /* |
| @@ -624,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state) | |||
| 624 | format_ie(iif->hcmsg.CalledPartyNumber)); | 624 | format_ie(iif->hcmsg.CalledPartyNumber)); |
| 625 | 625 | ||
| 626 | /* scan application list for matching listeners */ | 626 | /* scan application list for matching listeners */ |
| 627 | bcs->ap = NULL; | 627 | spin_lock_irqsave(&bcs->aplock, flags); |
| 628 | if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { | ||
| 629 | dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", | ||
| 630 | __func__, bcs->ap, bcs->apconnstate); | ||
| 631 | bcs->ap = NULL; | ||
| 632 | bcs->apconnstate = APCONN_NONE; | ||
| 633 | } | ||
| 634 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 628 | actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); | 635 | actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); |
| 629 | list_for_each_entry(ap, &iif->appls, ctrlist) | 636 | list_for_each_entry(ap, &iif->appls, ctrlist) |
| 630 | if (actCIPmask & ap->listenCIPmask) { | 637 | if (actCIPmask & ap->listenCIPmask) { |
| @@ -642,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state) | |||
| 642 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); | 649 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); |
| 643 | 650 | ||
| 644 | /* add to listeners on this B channel, update state */ | 651 | /* add to listeners on this B channel, update state */ |
| 652 | spin_lock_irqsave(&bcs->aplock, flags); | ||
| 645 | ap->bcnext = bcs->ap; | 653 | ap->bcnext = bcs->ap; |
| 646 | bcs->ap = ap; | 654 | bcs->ap = ap; |
| 647 | bcs->chstate |= CHS_NOTIFY_LL; | 655 | bcs->chstate |= CHS_NOTIFY_LL; |
| 648 | ap->connected = APCONN_SETUP; | 656 | bcs->apconnstate = APCONN_SETUP; |
| 657 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 649 | 658 | ||
| 650 | /* emit message */ | 659 | /* emit message */ |
| 651 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); | 660 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); |
| @@ -670,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs, | |||
| 670 | struct gigaset_capi_ctr *iif = cs->iif; | 679 | struct gigaset_capi_ctr *iif = cs->iif; |
| 671 | struct sk_buff *skb; | 680 | struct sk_buff *skb; |
| 672 | 681 | ||
| 673 | if (ap->connected == APCONN_NONE) | 682 | if (bcs->apconnstate == APCONN_NONE) |
| 674 | return; | 683 | return; |
| 675 | 684 | ||
| 676 | capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, | 685 | capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, |
| @@ -684,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs, | |||
| 684 | } | 693 | } |
| 685 | capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); | 694 | capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); |
| 686 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); | 695 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); |
| 687 | ap->connected = APCONN_NONE; | ||
| 688 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); | 696 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); |
| 689 | } | 697 | } |
| 690 | 698 | ||
| @@ -701,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs, | |||
| 701 | struct sk_buff *skb; | 709 | struct sk_buff *skb; |
| 702 | 710 | ||
| 703 | /* nothing to do if no logical connection active */ | 711 | /* nothing to do if no logical connection active */ |
| 704 | if (ap->connected < APCONN_ACTIVE) | 712 | if (bcs->apconnstate < APCONN_ACTIVE) |
| 705 | return; | 713 | return; |
| 706 | ap->connected = APCONN_SETUP; | 714 | bcs->apconnstate = APCONN_SETUP; |
| 707 | 715 | ||
| 708 | capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, | 716 | capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, |
| 709 | ap->nextMessageNumber++, | 717 | ap->nextMessageNumber++, |
| @@ -730,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs) | |||
| 730 | { | 738 | { |
| 731 | struct cardstate *cs = bcs->cs; | 739 | struct cardstate *cs = bcs->cs; |
| 732 | struct gigaset_capi_ctr *iif = cs->iif; | 740 | struct gigaset_capi_ctr *iif = cs->iif; |
| 733 | struct gigaset_capi_appl *ap = bcs->ap; | 741 | struct gigaset_capi_appl *ap; |
| 734 | struct sk_buff *skb; | 742 | struct sk_buff *skb; |
| 735 | unsigned int msgsize; | 743 | unsigned int msgsize; |
| 744 | unsigned long flags; | ||
| 736 | 745 | ||
| 746 | spin_lock_irqsave(&bcs->aplock, flags); | ||
| 747 | ap = bcs->ap; | ||
| 737 | if (!ap) { | 748 | if (!ap) { |
| 749 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 738 | dev_err(cs->dev, "%s: no application\n", __func__); | 750 | dev_err(cs->dev, "%s: no application\n", __func__); |
| 739 | return; | 751 | return; |
| 740 | } | 752 | } |
| 753 | if (bcs->apconnstate == APCONN_NONE) { | ||
| 754 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 755 | dev_warn(cs->dev, "%s: application %u not connected\n", | ||
| 756 | __func__, ap->id); | ||
| 757 | return; | ||
| 758 | } | ||
| 759 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 741 | while (ap->bcnext) { | 760 | while (ap->bcnext) { |
| 742 | /* this should never happen */ | 761 | /* this should never happen */ |
| 743 | dev_warn(cs->dev, "%s: dropping extra application %u\n", | 762 | dev_warn(cs->dev, "%s: dropping extra application %u\n", |
| @@ -746,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs) | |||
| 746 | CapiCallGivenToOtherApplication); | 765 | CapiCallGivenToOtherApplication); |
| 747 | ap->bcnext = ap->bcnext->bcnext; | 766 | ap->bcnext = ap->bcnext->bcnext; |
| 748 | } | 767 | } |
| 749 | if (ap->connected == APCONN_NONE) { | ||
| 750 | dev_warn(cs->dev, "%s: application %u not connected\n", | ||
| 751 | __func__, ap->id); | ||
| 752 | return; | ||
| 753 | } | ||
| 754 | 768 | ||
| 755 | /* prepare CONNECT_ACTIVE_IND message | 769 | /* prepare CONNECT_ACTIVE_IND message |
| 756 | * Note: LLC not supported by device | 770 | * Note: LLC not supported by device |
| @@ -788,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs) | |||
| 788 | void gigaset_isdn_hupD(struct bc_state *bcs) | 802 | void gigaset_isdn_hupD(struct bc_state *bcs) |
| 789 | { | 803 | { |
| 790 | struct gigaset_capi_appl *ap; | 804 | struct gigaset_capi_appl *ap; |
| 805 | unsigned long flags; | ||
| 791 | 806 | ||
| 792 | /* | 807 | /* |
| 793 | * ToDo: pass on reason code reported by device | 808 | * ToDo: pass on reason code reported by device |
| 794 | * (requires ev-layer state machine extension to collect | 809 | * (requires ev-layer state machine extension to collect |
| 795 | * ZCAU device reply) | 810 | * ZCAU device reply) |
| 796 | */ | 811 | */ |
| 797 | for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { | 812 | spin_lock_irqsave(&bcs->aplock, flags); |
| 813 | while (bcs->ap != NULL) { | ||
| 814 | ap = bcs->ap; | ||
| 815 | bcs->ap = ap->bcnext; | ||
| 816 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
| 798 | send_disconnect_b3_ind(bcs, ap); | 817 | send_disconnect_b3_ind(bcs, ap); |
| 799 | send_disconnect_ind(bcs, ap, 0); | 818 | send_disconnect_ind(bcs, ap, 0); |
| 819 | spin_lock_irqsave(&bcs->aplock, flags); | ||
