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); | ||
800 | } | 820 | } |
801 | bcs->ap = NULL; | 821 | bcs->apconnstate = APCONN_NONE; |
822 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
802 | } | 823 | } |
803 | 824 | ||
804 | /** | 825 | /** |
@@ -812,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs) | |||
812 | { | 833 | { |
813 | struct cardstate *cs = bcs->cs; | 834 | struct cardstate *cs = bcs->cs; |
814 | struct gigaset_capi_ctr *iif = cs->iif; | 835 | struct gigaset_capi_ctr *iif = cs->iif; |
815 | struct gigaset_capi_appl *ap = bcs->ap; | 836 | struct gigaset_capi_appl *ap; |
816 | struct sk_buff *skb; | 837 | struct sk_buff *skb; |
838 | unsigned long flags; | ||
817 | unsigned int msgsize; | 839 | unsigned int msgsize; |
818 | u8 command; | 840 | u8 command; |
819 | 841 | ||
842 | spin_lock_irqsave(&bcs->aplock, flags); | ||
843 | ap = bcs->ap; | ||
820 | if (!ap) { | 844 | if (!ap) { |
845 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
821 | dev_err(cs->dev, "%s: no application\n", __func__); | 846 | dev_err(cs->dev, "%s: no application\n", __func__); |
822 | return; | 847 | return; |
823 | } | 848 | } |
824 | while (ap->bcnext) { | 849 | if (!bcs->apconnstate) { |
825 | /* this should never happen */ | 850 | spin_unlock_irqrestore(&bcs->aplock, flags); |
826 | dev_warn(cs->dev, "%s: dropping extra application %u\n", | ||
827 | __func__, ap->bcnext->id); | ||
828 | send_disconnect_ind(bcs, ap->bcnext, | ||
829 | CapiCallGivenToOtherApplication); | ||
830 | ap->bcnext = ap->bcnext->bcnext; | ||
831 | } | ||
832 | if (!ap->connected) { | ||
833 | dev_warn(cs->dev, "%s: application %u not connected\n", | 851 | dev_warn(cs->dev, "%s: application %u not connected\n", |
834 | __func__, ap->id); | 852 | __func__, ap->id); |
835 | return; | 853 | return; |
@@ -841,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs) | |||
841 | * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP | 859 | * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP |
842 | * Parameters in both cases always: NCCI = 1, NCPI empty | 860 | * Parameters in both cases always: NCCI = 1, NCPI empty |
843 | */ | 861 | */ |
844 | if (ap->connected >= APCONN_ACTIVE) { | 862 | if (bcs->apconnstate >= APCONN_ACTIVE) { |
845 | command = CAPI_CONNECT_B3_ACTIVE; | 863 | command = CAPI_CONNECT_B3_ACTIVE; |
846 | msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; | 864 | msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; |
847 | } else { | 865 | } else { |
848 | command = CAPI_CONNECT_B3; | 866 | command = CAPI_CONNECT_B3; |
849 | msgsize = CAPI_CONNECT_B3_IND_BASELEN; | 867 | msgsize = CAPI_CONNECT_B3_IND_BASELEN; |
850 | } | 868 | } |
869 | bcs->apconnstate = APCONN_ACTIVE; | ||
870 | |||
871 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
872 | |||
873 | while (ap->bcnext) { | ||
874 | /* this should never happen */ | ||
875 | dev_warn(cs->dev, "%s: dropping extra application %u\n", | ||
876 | __func__, ap->bcnext->id); | ||
877 | send_disconnect_ind(bcs, ap->bcnext, | ||
878 | CapiCallGivenToOtherApplication); | ||
879 | ap->bcnext = ap->bcnext->bcnext; | ||
880 | } | ||
881 | |||
851 | capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, | 882 | capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, |
852 | ap->nextMessageNumber++, | 883 | ap->nextMessageNumber++, |
853 | iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); | 884 | iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); |
@@ -858,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs) | |||
858 | } | 889 | } |
859 | capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); | 890 | capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); |
860 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); | 891 | dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); |
861 | ap->connected = APCONN_ACTIVE; | ||
862 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); | 892 | capi_ctr_handle_message(&iif->ctr, ap->id, skb); |
863 | } | 893 | } |
864 | 894 | ||
@@ -964,6 +994,61 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, | |||
964 | ap->rp = *rp; | 994 | ap->rp = *rp; |
965 | 995 | ||
966 | list_add(&ap->ctrlist, &iif->appls); | 996 | list_add(&ap->ctrlist, &iif->appls); |
997 | dev_info(cs->dev, "application %u registered\n", ap->id); | ||
998 | } | ||
999 | |||
1000 | /* | ||
1001 | * remove CAPI application from channel | ||
1002 | * helper function to keep indentation levels down and stay in 80 columns | ||
1003 | */ | ||
1004 | |||
1005 | static inline void remove_appl_from_channel(struct bc_state *bcs, | ||
1006 | struct gigaset_capi_appl *ap) | ||
1007 | { | ||
1008 | struct cardstate *cs = bcs->cs; | ||
1009 | struct gigaset_capi_appl *bcap; | ||
1010 | unsigned long flags; | ||
1011 | int prevconnstate; | ||
1012 | |||
1013 | spin_lock_irqsave(&bcs->aplock, flags); | ||
1014 | bcap = bcs->ap; | ||
1015 | if (bcap == NULL) { | ||
1016 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1017 | return; | ||
1018 | } | ||
1019 | |||
1020 | /* check first application on channel */ | ||
1021 | if (bcap == ap) { | ||
1022 | bcs->ap = ap->bcnext; | ||
1023 | if (bcs->ap != NULL) { | ||
1024 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1025 | return; | ||
1026 | } | ||
1027 | |||
1028 | /* none left, clear channel state */ | ||
1029 | prevconnstate = bcs->apconnstate; | ||
1030 | bcs->apconnstate = APCONN_NONE; | ||
1031 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1032 | |||
1033 | if (prevconnstate == APCONN_ACTIVE) { | ||
1034 | dev_notice(cs->dev, "%s: hanging up channel %u\n", | ||
1035 | __func__, bcs->channel); | ||
1036 | gigaset_add_event(cs, &bcs->at_state, | ||
1037 | EV_HUP, NULL, 0, NULL); | ||
1038 | gigaset_schedule_event(cs); | ||
1039 | } | ||
1040 | return; | ||
1041 | } | ||
1042 | |||
1043 | /* check remaining list */ | ||
1044 | do { | ||
1045 | if (bcap->bcnext == ap) { | ||
1046 | bcap->bcnext = bcap->bcnext->bcnext; | ||
1047 | return; | ||
1048 | } | ||
1049 | bcap = bcap->bcnext; | ||
1050 | } while (bcap != NULL); | ||
1051 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
967 | } | 1052 | } |
968 | 1053 | ||
969 | /* | 1054 | /* |
@@ -975,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) | |||
975 | = container_of(ctr, struct gigaset_capi_ctr, ctr); | 1060 | = container_of(ctr, struct gigaset_capi_ctr, ctr); |
976 | struct cardstate *cs = iif->ctr.driverdata; | 1061 | struct cardstate *cs = iif->ctr.driverdata; |
977 | struct gigaset_capi_appl *ap, *tmp; | 1062 | struct gigaset_capi_appl *ap, *tmp; |
1063 | unsigned ch; | ||
978 | 1064 | ||
979 | list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) | 1065 | list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) |
980 | if (ap->id == appl) { | 1066 | if (ap->id == appl) { |
981 | if (ap->connected != APCONN_NONE) { | 1067 | /* remove from any channels */ |
982 | dev_err(cs->dev, | 1068 | for (ch = 0; ch < cs->channels; ch++) |
983 | "%s: application %u still connected\n", | 1069 | remove_appl_from_channel(&cs->bcs[ch], ap); |
984 | __func__, ap->id); | 1070 | |
985 | /* ToDo: clear active connection */ | 1071 | /* remove from registration list */ |
986 | } | ||
987 | list_del(&ap->ctrlist); | 1072 | list_del(&ap->ctrlist); |
988 | kfree(ap); | 1073 | kfree(ap); |
1074 | dev_info(cs->dev, "application %u released\n", appl); | ||
989 | } | 1075 | } |
990 | |||
991 | } | 1076 | } |
992 | 1077 | ||
993 | /* | 1078 | /* |
@@ -1166,6 +1251,7 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, | |||
1166 | char **commands; | 1251 | char **commands; |
1167 | char *s; | 1252 | char *s; |
1168 | u8 *pp; | 1253 | u8 *pp; |
1254 | unsigned long flags; | ||
1169 | int i, l, lbc, lhlc; | 1255 | int i, l, lbc, lhlc; |
1170 | u16 info; | 1256 | u16 info; |
1171 | 1257 | ||
@@ -1181,8 +1267,15 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, | |||
1181 | send_conf(iif, ap, skb, CapiNoPlciAvailable); | 1267 | send_conf(iif, ap, skb, CapiNoPlciAvailable); |
1182 | return; | 1268 | return; |
1183 | } | 1269 | } |
1270 | spin_lock_irqsave(&bcs->aplock, flags); | ||
1271 | if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) | ||
1272 | dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", | ||
1273 | __func__, bcs->ap, bcs->apconnstate); | ||
1184 | ap->bcnext = NULL; | 1274 | ap->bcnext = NULL; |
1185 | bcs->ap = ap; | 1275 | bcs->ap = ap; |
1276 | bcs->apconnstate = APCONN_SETUP; | ||
1277 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1278 | |||
1186 | bcs->rx_bufsize = ap->rp.datablklen; | 1279 | bcs->rx_bufsize = ap->rp.datablklen; |
1187 | dev_kfree_skb(bcs->rx_skb); | 1280 | dev_kfree_skb(bcs->rx_skb); |
1188 | gigaset_new_rx_skb(bcs); | 1281 | gigaset_new_rx_skb(bcs); |
@@ -1419,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, | |||
1419 | goto error; | 1512 | goto error; |
1420 | } | 1513 | } |
1421 | gigaset_schedule_event(cs); | 1514 | gigaset_schedule_event(cs); |
1422 | ap->connected = APCONN_SETUP; | ||
1423 | send_conf(iif, ap, skb, CapiSuccess); | 1515 | send_conf(iif, ap, skb, CapiSuccess); |
1424 | return; | 1516 | return; |
1425 | 1517 | ||
@@ -1447,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, | |||
1447 | _cmsg *cmsg = &iif->acmsg; | 1539 | _cmsg *cmsg = &iif->acmsg; |
1448 | struct bc_state *bcs; | 1540 | struct bc_state *bcs; |
1449 | struct gigaset_capi_appl *oap; | 1541 | struct gigaset_capi_appl *oap; |
1542 | unsigned long flags; | ||
1450 | int channel; | 1543 | int channel; |
1451 | 1544 | ||
1452 | /* decode message */ | 1545 | /* decode message */ |
@@ -1466,12 +1559,21 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, | |||
1466 | switch (cmsg->Reject) { | 1559 | switch (cmsg->Reject) { |
1467 | case 0: /* Accept */ | 1560 | case 0: /* Accept */ |
1468 | /* drop all competing applications, keep only this one */ | 1561 | /* drop all competing applications, keep only this one */ |
1469 | for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) | 1562 | spin_lock_irqsave(&bcs->aplock, flags); |
1470 | if (oap != ap) | 1563 | while (bcs->ap != NULL) { |
1564 | oap = bcs->ap; | ||
1565 | bcs->ap = oap->bcnext; | ||
1566 | if (oap != ap) { | ||
1567 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1471 | send_disconnect_ind(bcs, oap, | 1568 | send_disconnect_ind(bcs, oap, |
1472 | CapiCallGivenToOtherApplication); | 1569 | CapiCallGivenToOtherApplication); |
1570 | spin_lock_irqsave(&bcs->aplock, flags); | ||
1571 | } | ||
1572 | } | ||
1473 | ap->bcnext = NULL; | 1573 | ap->bcnext = NULL; |
1474 | bcs->ap = ap; | 1574 | bcs->ap = ap; |
1575 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1576 | |||
1475 | bcs->rx_bufsize = ap->rp.datablklen; | 1577 | bcs->rx_bufsize = ap->rp.datablklen; |
1476 | dev_kfree_skb(bcs->rx_skb); | 1578 | dev_kfree_skb(bcs->rx_skb); |
1477 | gigaset_new_rx_skb(bcs); | 1579 | gigaset_new_rx_skb(bcs); |
@@ -1542,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, | |||
1542 | send_disconnect_ind(bcs, ap, 0); | 1644 | send_disconnect_ind(bcs, ap, 0); |
1543 | 1645 | ||
1544 | /* remove it from the list of listening apps */ | 1646 | /* remove it from the list of listening apps */ |
1647 | spin_lock_irqsave(&bcs->aplock, flags); | ||
1545 | if (bcs->ap == ap) { | 1648 | if (bcs->ap == ap) { |
1546 | bcs->ap = ap->bcnext; | 1649 | bcs->ap = ap->bcnext; |
1547 | if (bcs->ap == NULL) | 1650 | if (bcs->ap == NULL) { |
1548 | /* last one: stop ev-layer hupD notifications */ | 1651 | /* last one: stop ev-layer hupD notifications */ |
1652 | bcs->apconnstate = APCONN_NONE; | ||
1549 | bcs->chstate &= ~CHS_NOTIFY_LL; | 1653 | bcs->chstate &= ~CHS_NOTIFY_LL; |
1654 | } | ||
1655 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1550 | return; | 1656 | return; |
1551 | } | 1657 | } |
1552 | for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { | 1658 | for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { |
1553 | if (oap->bcnext == ap) { | 1659 | if (oap->bcnext == ap) { |
1554 | oap->bcnext = oap->bcnext->bcnext; | 1660 | oap->bcnext = oap->bcnext->bcnext; |
1661 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1555 | return; | 1662 | return; |
1556 | } | 1663 | } |
1557 | } | 1664 | } |
1665 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1558 | dev_err(cs->dev, "%s: application %u not found\n", | 1666 | dev_err(cs->dev, "%s: application %u not found\n", |
1559 | __func__, ap->id); | 1667 | __func__, ap->id); |
1560 | return; | 1668 | return; |
1561 | 1669 | ||
1562 | default: /* Reject */ | 1670 | default: /* Reject */ |
1563 | /* drop all competing applications, keep only this one */ | 1671 | /* drop all competing applications, keep only this one */ |
1564 | for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) | 1672 | spin_lock_irqsave(&bcs->aplock, flags); |
1565 | if (oap != ap) | 1673 | while (bcs->ap != NULL) { |
1674 | oap = bcs->ap; | ||
1675 | bcs->ap = oap->bcnext; | ||
1676 | if (oap != ap) { | ||
1677 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1566 | send_disconnect_ind(bcs, oap, | 1678 | send_disconnect_ind(bcs, oap, |
1567 | CapiCallGivenToOtherApplication); | 1679 | CapiCallGivenToOtherApplication); |
1680 | spin_lock_irqsave(&bcs->aplock, flags); | ||
1681 | } | ||
1682 | } | ||
1568 | ap->bcnext = NULL; | 1683 | ap->bcnext = NULL; |
1569 | bcs->ap = ap; | 1684 | bcs->ap = ap; |
1685 | spin_unlock_irqrestore(&bcs->aplock, flags); | ||
1570 | 1686 | ||
1571 | /* reject call - will trigger DISCONNECT_IND for this app */ | 1687 | /* reject call - will trigger DISCONNECT_IND for this app */ |
1572 | dev_info(cs->dev, "%s: Reject=%x\n", | 1688 | dev_info(cs->dev, "%s: Reject=%x\n", |
@@ -1589,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, | |||
1589 | { | 1705 | { |
1590 | struct cardstate *cs = iif->ctr.driverdata; | 1706 | struct cardstate *cs = iif->ctr.driverdata; |
1591 | _cmsg *cmsg = &iif->acmsg; | 1707 | _cmsg *cmsg = &iif->acmsg; |
1708 | struct bc_state *bcs; | ||
1592 | int channel; | 1709 | int channel; |
1593 | 1710 | ||
1594 | /* decode message */ | 1711 | /* decode message */ |
@@ -1603,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, | |||
1603 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); | 1720 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); |
1604 | return; | 1721 | return; |
1605 | } | 1722 | } |
1723 | bcs = &cs->bcs[channel-1]; | ||
1606 | 1724 | ||
1607 | /* mark logical connection active */ | 1725 | /* mark logical connection active */ |
1608 | ap->connected = APCONN_ACTIVE; | 1726 | bcs->apconnstate = APCONN_ACTIVE; |
1609 | 1727 | ||
1610 | /* build NCCI: always 1 (one B3 connection only) */ | 1728 | /* build NCCI: always 1 (one B3 connection only) */ |
1611 | cmsg->adr.adrNCCI |= 1 << 16; | 1729 | cmsg->adr.adrNCCI |= 1 << 16; |
@@ -1651,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, | |||
1651 | 1769 | ||
1652 | if (cmsg->Reject) { | 1770 | if (cmsg->Reject) { |
1653 | /* Reject: clear B3 connect received flag */ | 1771 | /* Reject: clear B3 connect received flag */ |
1654 | ap->connected = APCONN_SETUP; | 1772 | bcs->apconnstate = APCONN_SETUP; |
1655 | 1773 | ||
1656 | /* trigger hangup, causing eventual DISCONNECT_IND */ | 1774 | /* trigger hangup, causing eventual DISCONNECT_IND */ |
1657 | if (!gigaset_add_event(cs, &bcs->at_state, | 1775 | if (!gigaset_add_event(cs, &bcs->at_state, |
@@ -1723,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, | |||
1723 | } | 1841 | } |
1724 | 1842 | ||
1725 | /* skip if DISCONNECT_IND already sent */ | 1843 | /* skip if DISCONNECT_IND already sent */ |
1726 | if (!ap->connected) | 1844 | if (!bcs->apconnstate) |
1727 | return; | 1845 | return; |
1728 | 1846 | ||
1729 | /* check for active logical connection */ | 1847 | /* check for active logical connection */ |
1730 | if (ap->connected >= APCONN_ACTIVE) { | 1848 | if (bcs->apconnstate >= APCONN_ACTIVE) { |
1731 | /* | 1849 | /* |
1732 | * emit DISCONNECT_B3_IND with cause 0x3301 | 1850 | * emit DISCONNECT_B3_IND with cause 0x3301 |
1733 | * use separate cmsg structure, as the content of iif->acmsg | 1851 | * use separate cmsg structure, as the content of iif->acmsg |
@@ -1776,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, | |||
1776 | { | 1894 | { |
1777 | struct cardstate *cs = iif->ctr.driverdata; | 1895 | struct cardstate *cs = iif->ctr.driverdata; |
1778 | _cmsg *cmsg = &iif->acmsg; | 1896 | _cmsg *cmsg = &iif->acmsg; |
1897 | struct bc_state *bcs; | ||
1779 | int channel; | 1898 | int channel; |
1780 | 1899 | ||
1781 | /* decode message */ | 1900 | /* decode message */ |
@@ -1791,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, | |||
1791 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); | 1910 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); |
1792 | return; | 1911 | return; |
1793 | } | 1912 | } |
1913 | bcs = &cs->bcs[channel-1]; | ||
1794 | 1914 | ||
1795 | /* reject if logical connection not active */ | 1915 | /* reject if logical connection not active */ |
1796 | if (ap->connected < APCONN_ACTIVE) { | 1916 | if (bcs->apconnstate < APCONN_ACTIVE) { |
1797 | send_conf(iif, ap, skb, | 1917 | send_conf(iif, ap, skb, |
1798 | CapiMessageNotSupportedInCurrentState); | 1918 | CapiMessageNotSupportedInCurrentState); |
1799 | return; | 1919 | return; |
1800 | } | 1920 | } |
1801 | 1921 | ||
1802 | /* trigger hangup, causing eventual DISCONNECT_B3_IND */ | 1922 | /* trigger hangup, causing eventual DISCONNECT_B3_IND */ |
1803 | if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, | 1923 | if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { |
1804 | EV_HUP, NULL, 0, NULL)) { | ||
1805 | send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); | 1924 | send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); |
1806 | return; | 1925 | return; |
1807 | } | 1926 | } |
@@ -1822,6 +1941,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, | |||
1822 | struct sk_buff *skb) | 1941 | struct sk_buff *skb) |
1823 | { | 1942 | { |
1824 | struct cardstate *cs = iif->ctr.driverdata; | 1943 | struct cardstate *cs = iif->ctr.driverdata; |
1944 | struct bc_state *bcs; | ||
1825 | int channel = CAPIMSG_PLCI_PART(skb->data); | 1945 | int channel = CAPIMSG_PLCI_PART(skb->data); |
1826 | u16 ncci = CAPIMSG_NCCI_PART(skb->data); | 1946 | u16 ncci = CAPIMSG_NCCI_PART(skb->data); |
1827 | u16 msglen = CAPIMSG_LEN(skb->data); | 1947 | u16 msglen = CAPIMSG_LEN(skb->data); |
@@ -1844,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, | |||
1844 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); | 1964 | send_conf(iif, ap, skb, CapiIllContrPlciNcci); |
1845 | return; | 1965 | return; |
1846 | } | 1966 | } |
1967 | bcs = &cs->bcs[channel-1]; | ||
1847 | if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) | 1968 | if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) |
1848 | dev_notice(cs->dev, "%s: unexpected length %d\n", | 1969 | dev_notice(cs->dev, "%s: unexpected length %d\n", |
1849 | "DATA_B3_REQ", msglen); | 1970 | "DATA_B3_REQ", msglen); |
@@ -1863,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, | |||
1863 | } | 1984 | } |
1864 | 1985 | ||
1865 | /* reject if logical connection not active */ | 1986 | /* reject if logical connection not active */ |
1866 | if (ap->connected < APCONN_ACTIVE) { | 1987 | if (bcs->apconnstate < APCONN_ACTIVE) { |
1867 | send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); | 1988 | send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); |
1868 | return; | 1989 | return; |
1869 | } | 1990 | } |
@@ -1874,7 +1995,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, | |||
1874 | skb_pull(skb, msglen); | 1995 | skb_pull(skb, msglen); |
1875 | 1996 | ||
1876 | /* pass to device-specific module */ | 1997 | /* pass to device-specific module */ |
1877 | if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { | 1998 | if (cs->ops->send_skb(bcs, skb) < 0) { |
1878 | send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); | 1999 | send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); |
1879 | return; | 2000 | return; |
1880 | } | 2001 | } |
diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 9778fabbc488..5d4befb81057 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c | |||
@@ -649,6 +649,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, | |||
649 | for (i = 0; i < AT_NUM; ++i) | 649 | for (i = 0; i < AT_NUM; ++i) |
650 | bcs->commands[i] = NULL; | 650 | bcs->commands[i] = NULL; |
651 | 651 | ||
652 | spin_lock_init(&bcs->aplock); | ||
653 | bcs->ap = NULL; | ||
654 | bcs->apconnstate = 0; | ||
655 | |||
652 | gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); | 656 | gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); |
653 | if (cs->ops->initbcshw(bcs)) | 657 | if (cs->ops->initbcshw(bcs)) |
654 | return bcs; | 658 | return bcs; |
diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index c4e6c26897ea..8738b0821fc9 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h | |||
@@ -403,7 +403,9 @@ struct bc_state { | |||
403 | struct bas_bc_state *bas; /* usb hardware driver (base) */ | 403 | struct bas_bc_state *bas; /* usb hardware driver (base) */ |
404 | } hw; | 404 | } hw; |
405 | 405 | ||
406 | void *ap; /* LL application structure */ | 406 | void *ap; /* associated LL application */ |
407 | int apconnstate; /* LL application connection state */ | ||
408 | spinlock_t aplock; | ||
407 | }; | 409 | }; |
408 | 410 | ||
409 | struct cardstate { | 411 | struct cardstate { |