diff options
Diffstat (limited to 'drivers/isdn/gigaset')
-rw-r--r-- | drivers/isdn/gigaset/asyncdata.c | 44 | ||||
-rw-r--r-- | drivers/isdn/gigaset/capi.c | 405 | ||||
-rw-r--r-- | drivers/isdn/gigaset/common.c | 36 | ||||
-rw-r--r-- | drivers/isdn/gigaset/ev-layer.c | 4 | ||||
-rw-r--r-- | drivers/isdn/gigaset/gigaset.h | 38 | ||||
-rw-r--r-- | drivers/isdn/gigaset/i4l.c | 21 | ||||
-rw-r--r-- | drivers/isdn/gigaset/isocdata.c | 72 |
7 files changed, 381 insertions, 239 deletions
diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c5016bd2d94..c3b1dc3a13a 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -126,26 +126,6 @@ static unsigned lock_loop(unsigned numbytes, struct inbuf_t *inbuf) return numbytes; } -/* set up next receive skb for data mode - */ -static void new_rcv_skb(struct bc_state *bcs) -{ - struct cardstate *cs = bcs->cs; - unsigned short hw_hdr_len = cs->hw_hdr_len; - - if (bcs->ignore) { - bcs->skb = NULL; - return; - } - - bcs->skb = dev_alloc_skb(SBUFSIZE + hw_hdr_len); - if (bcs->skb == NULL) { - dev_warn(cs->dev, "could not allocate new skb\n"); - return; - } - skb_reserve(bcs->skb, hw_hdr_len); -} - /* process a block of received bytes in HDLC data mode * (mstate != MS_LOCKED && !(inputstate & INS_command) && proto2 == L2_HDLC) * Collect HDLC frames, undoing byte stuffing and watching for DLE escapes. @@ -159,8 +139,8 @@ static unsigned hdlc_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; - __u16 fcs = bcs->fcs; - struct sk_buff *skb = bcs->skb; + __u16 fcs = bcs->rx_fcs; + struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; @@ -245,8 +225,7 @@ byte_stuff: /* prepare reception of next frame */ inputstate &= ~INS_have_data; - new_rcv_skb(bcs); - skb = bcs->skb; + skb = gigaset_new_rx_skb(bcs); } else { /* empty frame (7E 7E) */ #ifdef CONFIG_GIGASET_DEBUG @@ -255,8 +234,7 @@ byte_stuff: if (!skb) { /* skipped (?) */ gigaset_isdn_rcv_err(bcs); - new_rcv_skb(bcs); - skb = bcs->skb; + skb = gigaset_new_rx_skb(bcs); } } @@ -279,11 +257,11 @@ byte_stuff: #endif inputstate |= INS_have_data; if (skb) { - if (skb->len == SBUFSIZE) { + if (skb->len >= bcs->rx_bufsize) { dev_warn(cs->dev, "received packet too long\n"); dev_kfree_skb_any(skb); /* skip remainder of packet */ - bcs->skb = skb = NULL; + bcs->rx_skb = skb = NULL; } else { *__skb_put(skb, 1) = c; fcs = crc_ccitt_byte(fcs, c); @@ -292,7 +270,7 @@ byte_stuff: } bcs->inputstate = inputstate; - bcs->fcs = fcs; + bcs->rx_fcs = fcs; return procbytes; } @@ -308,18 +286,18 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) struct cardstate *cs = inbuf->cs; struct bc_state *bcs = cs->bcs; int inputstate = bcs->inputstate; - struct sk_buff *skb = bcs->skb; + struct sk_buff *skb = bcs->rx_skb; unsigned char *src = inbuf->data + inbuf->head; unsigned procbytes = 0; unsigned char c; if (!skb) { /* skip this block */ - new_rcv_skb(bcs); + gigaset_new_rx_skb(bcs); return numbytes; } - while (procbytes < numbytes && skb->len < SBUFSIZE) { + while (procbytes < numbytes && skb->len < bcs->rx_bufsize) { c = *src++; procbytes++; @@ -343,7 +321,7 @@ static unsigned iraw_loop(unsigned numbytes, struct inbuf_t *inbuf) if (inputstate & INS_have_data) { gigaset_skb_rcvd(bcs, skb); inputstate &= ~INS_have_data; - new_rcv_skb(bcs); + gigaset_new_rx_skb(bcs); } bcs->inputstate = inputstate; diff --git a/drivers/isdn/gigaset/capi.c b/drivers/isdn/gigaset/capi.c index 8f78f15c8ef..6fbe8999c41 100644 --- a/drivers/isdn/gigaset/capi.c +++ b/drivers/isdn/gigaset/capi.c @@ -70,7 +70,7 @@ #define MAX_NUMBER_DIGITS 20 #define MAX_FMT_IE_LEN 20 -/* values for gigaset_capi_appl.connected */ +/* values for bcs->apconnstate */ #define APCONN_NONE 0 /* inactive/listening */ #define APCONN_SETUP 1 /* connecting */ #define APCONN_ACTIVE 2 /* B channel up */ @@ -80,10 +80,10 @@ struct gigaset_capi_appl { struct list_head ctrlist; struct gigaset_capi_appl *bcnext; u16 id; + struct capi_register_params rp; u16 nextMessageNumber; u32 listenInfoMask; u32 listenCIPmask; - int connected; }; /* CAPI specific controller data structure */ @@ -319,6 +319,39 @@ static const char *format_ie(const char *ie) return result; } +/* + * emit DATA_B3_CONF message + */ +static void send_data_b3_conf(struct cardstate *cs, struct capi_ctr *ctr, + u16 appl, u16 msgid, int channel, + u16 handle, u16 info) +{ + struct sk_buff *cskb; + u8 *msg; + + cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); + if (!cskb) { + dev_err(cs->dev, "%s: out of memory\n", __func__); + return; + } + /* frequent message, avoid _cmsg overhead */ + msg = __skb_put(cskb, CAPI_DATA_B3_CONF_LEN); + CAPIMSG_SETLEN(msg, CAPI_DATA_B3_CONF_LEN); + CAPIMSG_SETAPPID(msg, appl); + CAPIMSG_SETCOMMAND(msg, CAPI_DATA_B3); + CAPIMSG_SETSUBCOMMAND(msg, CAPI_CONF); + CAPIMSG_SETMSGID(msg, msgid); + CAPIMSG_SETCONTROLLER(msg, ctr->cnr); + CAPIMSG_SETPLCI_PART(msg, channel); + CAPIMSG_SETNCCI_PART(msg, 1); + CAPIMSG_SETHANDLE_CONF(msg, handle); + CAPIMSG_SETINFO_CONF(msg, info); + + /* emit message */ + dump_rawmsg(DEBUG_MCMD, __func__, msg); + capi_ctr_handle_message(ctr, appl, cskb); +} + /* * driver interface functions @@ -339,7 +372,6 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) struct gigaset_capi_ctr *iif = cs->iif; struct gigaset_capi_appl *ap = bcs->ap; unsigned char *req = skb_mac_header(dskb); - struct sk_buff *cskb; u16 flags; /* update statistics */ @@ -351,39 +383,22 @@ void gigaset_skb_sent(struct bc_state *bcs, struct sk_buff *dskb) } /* don't send further B3 messages if disconnected */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding ack"); return; } - /* ToDo: honor unset "delivery confirmation" bit */ + /* + * send DATA_B3_CONF if "delivery confirmation" bit was set in request; + * otherwise it has already been sent by do_data_b3_req() + */ flags = CAPIMSG_FLAGS(req); - - /* build DATA_B3_CONF message */ - cskb = alloc_skb(CAPI_DATA_B3_CONF_LEN, GFP_ATOMIC); - if (!cskb) { - dev_err(cs->dev, "%s: out of memory\n", __func__); - return; - } - /* frequent message, avoid _cmsg overhead */ - CAPIMSG_SETLEN(cskb->data, CAPI_DATA_B3_CONF_LEN); - CAPIMSG_SETAPPID(cskb->data, ap->id); - CAPIMSG_SETCOMMAND(cskb->data, CAPI_DATA_B3); - CAPIMSG_SETSUBCOMMAND(cskb->data, CAPI_CONF); - CAPIMSG_SETMSGID(cskb->data, CAPIMSG_MSGID(req)); - CAPIMSG_SETCONTROLLER(cskb->data, iif->ctr.cnr); - CAPIMSG_SETPLCI_PART(cskb->data, bcs->channel + 1); - CAPIMSG_SETNCCI_PART(cskb->data, 1); - CAPIMSG_SETHANDLE_CONF(cskb->data, CAPIMSG_HANDLE_REQ(req)); - if (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) - CAPIMSG_SETINFO_CONF(cskb->data, - CapiFlagsNotSupportedByProtocol); - else - CAPIMSG_SETINFO_CONF(cskb->data, CAPI_NOERROR); - - /* emit message */ - dump_rawmsg(DEBUG_LLDATA, "DATA_B3_CONF", cskb->data); - capi_ctr_handle_message(&iif->ctr, ap->id, cskb); + if (flags & CAPI_FLAGS_DELIVERY_CONFIRMATION) + send_data_b3_conf(cs, &iif->ctr, ap->id, CAPIMSG_MSGID(req), + bcs->channel + 1, CAPIMSG_HANDLE_REQ(req), + (flags & ~CAPI_FLAGS_DELIVERY_CONFIRMATION) ? + CapiFlagsNotSupportedByProtocol : + CAPI_NOERROR); } EXPORT_SYMBOL_GPL(gigaset_skb_sent); @@ -412,7 +427,7 @@ void gigaset_skb_rcvd(struct bc_state *bcs, struct sk_buff *skb) } /* don't send further B3 messages if disconnected */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { gig_dbg(DEBUG_LLDATA, "disconnected, discarding data"); dev_kfree_skb_any(skb); return; @@ -484,6 +499,7 @@ int gigaset_isdn_icall(struct at_state_t *at_state) u32 actCIPmask; struct sk_buff *skb; unsigned int msgsize; + unsigned long flags; int i; /* @@ -608,7 +624,14 @@ int gigaset_isdn_icall(struct at_state_t *at_state) format_ie(iif->hcmsg.CalledPartyNumber)); /* scan application list for matching listeners */ - bcs->ap = NULL; + spin_lock_irqsave(&bcs->aplock, flags); + if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) { + dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", + __func__, bcs->ap, bcs->apconnstate); + bcs->ap = NULL; + bcs->apconnstate = APCONN_NONE; + } + spin_unlock_irqrestore(&bcs->aplock, flags); actCIPmask = 1 | (1 << iif->hcmsg.CIPValue); list_for_each_entry(ap, &iif->appls, ctrlist) if (actCIPmask & ap->listenCIPmask) { @@ -626,10 +649,12 @@ int gigaset_isdn_icall(struct at_state_t *at_state) dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); /* add to listeners on this B channel, update state */ + spin_lock_irqsave(&bcs->aplock, flags); ap->bcnext = bcs->ap; bcs->ap = ap; bcs->chstate |= CHS_NOTIFY_LL; - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; + spin_unlock_irqrestore(&bcs->aplock, flags); /* emit message */ capi_ctr_handle_message(&iif->ctr, ap->id, skb); @@ -654,7 +679,7 @@ static void send_disconnect_ind(struct bc_state *bcs, struct gigaset_capi_ctr *iif = cs->iif; struct sk_buff *skb; - if (ap->connected == APCONN_NONE) + if (bcs->apconnstate == APCONN_NONE) return; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT, CAPI_IND, @@ -668,7 +693,6 @@ static void send_disconnect_ind(struct bc_state *bcs, } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, CAPI_DISCONNECT_IND_LEN)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - ap->connected = APCONN_NONE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } @@ -685,9 +709,9 @@ static void send_disconnect_b3_ind(struct bc_state *bcs, struct sk_buff *skb; /* nothing to do if no logical connection active */ - if (ap->connected < APCONN_ACTIVE) + if (bcs->apconnstate < APCONN_ACTIVE) return; - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; capi_cmsg_header(&iif->hcmsg, ap->id, CAPI_DISCONNECT_B3, CAPI_IND, ap->nextMessageNumber++, @@ -714,14 +738,25 @@ void gigaset_isdn_connD(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; + struct gigaset_capi_appl *ap; struct sk_buff *skb; unsigned int msgsize; + unsigned long flags; + spin_lock_irqsave(&bcs->aplock, flags); + ap = bcs->ap; if (!ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } + if (bcs->apconnstate == APCONN_NONE) { + spin_unlock_irqrestore(&bcs->aplock, flags); + dev_warn(cs->dev, "%s: application %u not connected\n", + __func__, ap->id); + return; + } + spin_unlock_irqrestore(&bcs->aplock, flags); while (ap->bcnext) { /* this should never happen */ dev_warn(cs->dev, "%s: dropping extra application %u\n", @@ -730,11 +765,6 @@ void gigaset_isdn_connD(struct bc_state *bcs) CapiCallGivenToOtherApplication); ap->bcnext = ap->bcnext->bcnext; } - if (ap->connected == APCONN_NONE) { - dev_warn(cs->dev, "%s: application %u not connected\n", - __func__, ap->id); - return; - } /* prepare CONNECT_ACTIVE_IND message * Note: LLC not supported by device @@ -772,17 +802,24 @@ void gigaset_isdn_connD(struct bc_state *bcs) void gigaset_isdn_hupD(struct bc_state *bcs) { struct gigaset_capi_appl *ap; + unsigned long flags; /* * ToDo: pass on reason code reported by device * (requires ev-layer state machine extension to collect * ZCAU device reply) */ - for (ap = bcs->ap; ap != NULL; ap = ap->bcnext) { + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + ap = bcs->ap; + bcs->ap = ap->bcnext; + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_b3_ind(bcs, ap); send_disconnect_ind(bcs, ap, 0); + spin_lock_irqsave(&bcs->aplock, flags); } - bcs->ap = NULL; + bcs->apconnstate = APCONN_NONE; + spin_unlock_irqrestore(&bcs->aplock, flags); } /** @@ -796,24 +833,21 @@ void gigaset_isdn_connB(struct bc_state *bcs) { struct cardstate *cs = bcs->cs; struct gigaset_capi_ctr *iif = cs->iif; - struct gigaset_capi_appl *ap = bcs->ap; + struct gigaset_capi_appl *ap; struct sk_buff *skb; + unsigned long flags; unsigned int msgsize; u8 command; + spin_lock_irqsave(&bcs->aplock, flags); + ap = bcs->ap; if (!ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: no application\n", __func__); return; } - while (ap->bcnext) { - /* this should never happen */ - dev_warn(cs->dev, "%s: dropping extra application %u\n", - __func__, ap->bcnext->id); - send_disconnect_ind(bcs, ap->bcnext, - CapiCallGivenToOtherApplication); - ap->bcnext = ap->bcnext->bcnext; - } - if (!ap->connected) { + if (!bcs->apconnstate) { + spin_unlock_irqrestore(&bcs->aplock, flags); dev_warn(cs->dev, "%s: application %u not connected\n", __func__, ap->id); return; @@ -825,13 +859,26 @@ void gigaset_isdn_connB(struct bc_state *bcs) * CONNECT_B3_ACTIVE_IND in reply to CONNECT_B3_RESP * Parameters in both cases always: NCCI = 1, NCPI empty */ - if (ap->connected >= APCONN_ACTIVE) { + if (bcs->apconnstate >= APCONN_ACTIVE) { command = CAPI_CONNECT_B3_ACTIVE; msgsize = CAPI_CONNECT_B3_ACTIVE_IND_BASELEN; } else { command = CAPI_CONNECT_B3; msgsize = CAPI_CONNECT_B3_IND_BASELEN; } + bcs->apconnstate = APCONN_ACTIVE; + + spin_unlock_irqrestore(&bcs->aplock, flags); + + while (ap->bcnext) { + /* this should never happen */ + dev_warn(cs->dev, "%s: dropping extra application %u\n", + __func__, ap->bcnext->id); + send_disconnect_ind(bcs, ap->bcnext, + CapiCallGivenToOtherApplication); + ap->bcnext = ap->bcnext->bcnext; + } + capi_cmsg_header(&iif->hcmsg, ap->id, command, CAPI_IND, ap->nextMessageNumber++, iif->ctr.cnr | ((bcs->channel + 1) << 8) | (1 << 16)); @@ -842,7 +889,6 @@ void gigaset_isdn_connB(struct bc_state *bcs) } capi_cmsg2message(&iif->hcmsg, __skb_put(skb, msgsize)); dump_cmsg(DEBUG_CMD, __func__, &iif->hcmsg); - ap->connected = APCONN_ACTIVE; capi_ctr_handle_message(&iif->ctr, ap->id, skb); } @@ -945,8 +991,64 @@ static void gigaset_register_appl(struct capi_ctr *ctr, u16 appl, return; } ap->id = appl; + ap->rp = *rp; list_add(&ap->ctrlist, &iif->appls); + dev_info(cs->dev, "application %u registered\n", ap->id); +} + +/* + * remove CAPI application from channel + * helper function to keep indentation levels down and stay in 80 columns + */ + +static inline void remove_appl_from_channel(struct bc_state *bcs, + struct gigaset_capi_appl *ap) +{ + struct cardstate *cs = bcs->cs; + struct gigaset_capi_appl *bcap; + unsigned long flags; + int prevconnstate; + + spin_lock_irqsave(&bcs->aplock, flags); + bcap = bcs->ap; + if (bcap == NULL) { + spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + + /* check first application on channel */ + if (bcap == ap) { + bcs->ap = ap->bcnext; + if (bcs->ap != NULL) { + spin_unlock_irqrestore(&bcs->aplock, flags); + return; + } + + /* none left, clear channel state */ + prevconnstate = bcs->apconnstate; + bcs->apconnstate = APCONN_NONE; + spin_unlock_irqrestore(&bcs->aplock, flags); + + if (prevconnstate == APCONN_ACTIVE) { + dev_notice(cs->dev, "%s: hanging up channel %u\n", + __func__, bcs->channel); + gigaset_add_event(cs, &bcs->at_state, + EV_HUP, NULL, 0, NULL); + gigaset_schedule_event(cs); + } + return; + } + + /* check remaining list */ + do { + if (bcap->bcnext == ap) { + bcap->bcnext = bcap->bcnext->bcnext; + return; + } + bcap = bcap->bcnext; + } while (bcap != NULL); + spin_unlock_irqrestore(&bcs->aplock, flags); } /* @@ -958,19 +1060,19 @@ static void gigaset_release_appl(struct capi_ctr *ctr, u16 appl) = container_of(ctr, struct gigaset_capi_ctr, ctr); struct cardstate *cs = iif->ctr.driverdata; struct gigaset_capi_appl *ap, *tmp; + unsigned ch; list_for_each_entry_safe(ap, tmp, &iif->appls, ctrlist) if (ap->id == appl) { - if (ap->connected != APCONN_NONE) { - dev_err(cs->dev, - "%s: application %u still connected\n", - __func__, ap->id); - /* ToDo: clear active connection */ - } + /* remove from any channels */ + for (ch = 0; ch < cs->channels; ch++) + remove_appl_from_channel(&cs->bcs[ch], ap); + + /* remove from registration list */ list_del(&ap->ctrlist); kfree(ap); + dev_info(cs->dev, "application %u released\n", appl); } - } /* @@ -1149,7 +1251,8 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, char **commands; char *s; u8 *pp; - int i, l; + unsigned long flags; + int i, l, lbc, lhlc; u16 info; /* decode message */ @@ -1164,8 +1267,18 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiNoPlciAvailable); return; } + spin_lock_irqsave(&bcs->aplock, flags); + if (bcs->ap != NULL || bcs->apconnstate != APCONN_NONE) + dev_warn(cs->dev, "%s: channel not properly cleared (%p/%d)\n", + __func__, bcs->ap, bcs->apconnstate); ap->bcnext = NULL; bcs->ap = ap; + bcs->apconnstate = APCONN_SETUP; + spin_unlock_irqrestore(&bcs->aplock, flags); + + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); cmsg->adr.adrPLCI |= (bcs->channel + 1) << 8; /* build command table */ @@ -1273,42 +1386,59 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } - /* check/encode parameter: BC */ - if (cmsg->BC && cmsg->BC[0]) { - /* explicit BC overrides CIP */ - l = 2*cmsg->BC[0] + 7; + /* + * check/encode parameters: BC & HLC + * must be encoded together as device doesn't accept HLC separately + * explicit parameters override values derived from CIP + */ + + /* determine lengths */ + if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ + lbc = 2*cmsg->BC[0]; + else if (cip2bchlc[cmsg->CIPValue].bc) /* BC derived from CIP */ + lbc = strlen(cip2bchlc[cmsg->CIPValue].bc); + else /* no BC */ + lbc = 0; + if (cmsg->HLC && cmsg->HLC[0]) /* HLC specified explicitly */ + lhlc = 2*cmsg->HLC[0]; + else if (cip2bchlc[cmsg->CIPValue].hlc) /* HLC derived from CIP */ + lhlc = strlen(cip2bchlc[cmsg->CIPValue].hlc); + else /* no HLC */ + lhlc = 0; + + if (lbc) { + /* have BC: allocate and assemble command string */ + l = lbc + 7; /* "^SBC=" + value + "\r" + null byte */ + if (lhlc) + l += lhlc + 7; /* ";^SHLC=" + value */ commands[AT_BC] = kmalloc(l, GFP_KERNEL); if (!commands[AT_BC]) goto oom; strcpy(commands[AT_BC], "^SBC="); - decode_ie(cmsg->BC, commands[AT_BC]+5); + if (cmsg->BC && cmsg->BC[0]) /* BC specified explicitly */ + decode_ie(cmsg->BC, commands[AT_BC] + 5); + else /* BC derived from CIP */ + strcpy(commands[AT_BC] + 5, + cip2bchlc[cmsg->CIPValue].bc); + if (lhlc) { + strcpy(commands[AT_BC] + lbc + 5, ";^SHLC="); + if (cmsg->HLC && cmsg->HLC[0]) + /* HLC specified explicitly */ + decode_ie(cmsg->HLC, + commands[AT_BC] + lbc + 12); + else /* HLC derived from CIP */ + strcpy(commands[AT_BC] + lbc + 12, + cip2bchlc[cmsg->CIPValue].hlc); + } strcpy(commands[AT_BC] + l - 2, "\r"); - } else if (cip2bchlc[cmsg->CIPValue].bc) { - l = strlen(cip2bchlc[cmsg->CIPValue].bc) + 7; - commands[AT_BC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_BC]) - goto oom; - snprintf(commands[AT_BC], l, "^SBC=%s\r", - cip2bchlc[cmsg->CIPValue].bc); - } - - /* check/encode parameter: HLC */ - if (cmsg->HLC && cmsg->HLC[0]) { - /* explicit HLC overrides CIP */ - l = 2*cmsg->HLC[0] + 7; - commands[AT_HLC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_HLC]) - goto oom; - strcpy(commands[AT_HLC], "^SHLC="); - decode_ie(cmsg->HLC, commands[AT_HLC]+5); - strcpy(commands[AT_HLC] + l - 2, "\r"); - } else if (cip2bchlc[cmsg->CIPValue].hlc) { - l = strlen(cip2bchlc[cmsg->CIPValue].hlc) + 7; - commands[AT_HLC] = kmalloc(l, GFP_KERNEL); - if (!commands[AT_HLC]) - goto oom; - snprintf(commands[AT_HLC], l, "^SHLC=%s\r", - cip2bchlc[cmsg->CIPValue].hlc); + } else { + /* no BC */ + if (lhlc) { + dev_notice(cs->dev, "%s: cannot set HLC without BC\n", + "CONNECT_REQ"); + info = CapiIllMessageParmCoding; /* ? */ + goto error; + } } /* check/encode parameter: B Protocol */ @@ -1322,13 +1452,13 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, @@ -1382,7 +1512,6 @@ static void do_connect_req(struct gigaset_capi_ctr *iif, goto error; } gigaset_schedule_event(cs); - ap->connected = APCONN_SETUP; send_conf(iif, ap, skb, CapiSuccess); return; @@ -1410,6 +1539,7 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, _cmsg *cmsg = &iif->acmsg; struct bc_state *bcs; struct gigaset_capi_appl *oap; + unsigned long flags; int channel; /* decode message */ @@ -1429,12 +1559,24 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, switch (cmsg->Reject) { case 0: /* Accept */ /* drop all competing applications, keep only this one */ - for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) - if (oap != ap) + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + oap = bcs->ap; + bcs->ap = oap->bcnext; + if (oap != ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); + spin_lock_irqsave(&bcs->aplock, flags); + } + } ap->bcnext = NULL; bcs->ap = ap; + spin_unlock_irqrestore(&bcs->aplock, flags); + + bcs->rx_bufsize = ap->rp.datablklen; + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); bcs->chstate |= CHS_NOTIFY_LL; /* check/encode B channel protocol */ @@ -1448,13 +1590,13 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, bcs->proto2 = L2_HDLC; break; case 1: - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; break; default: dev_warn(cs->dev, "B1 Protocol %u unsupported, using Transparent\n", cmsg->B1protocol); - bcs->proto2 = L2_BITSYNC; + bcs->proto2 = L2_VOICE; } if (cmsg->B2protocol != 1) dev_warn(cs->dev, @@ -1502,31 +1644,45 @@ static void do_connect_resp(struct gigaset_capi_ctr *iif, send_disconnect_ind(bcs, ap, 0); /* remove it from the list of listening apps */ + spin_lock_irqsave(&bcs->aplock, flags); if (bcs->ap == ap) { bcs->ap = ap->bcnext; - if (bcs->ap == NULL) + if (bcs->ap == NULL) { /* last one: stop ev-layer hupD notifications */ + bcs->apconnstate = APCONN_NONE; bcs->chstate &= ~CHS_NOTIFY_LL; + } + spin_unlock_irqrestore(&bcs->aplock, flags); return; } for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) { if (oap->bcnext == ap) { oap->bcnext = oap->bcnext->bcnext; + spin_unlock_irqrestore(&bcs->aplock, flags); return; } } + spin_unlock_irqrestore(&bcs->aplock, flags); dev_err(cs->dev, "%s: application %u not found\n", __func__, ap->id); return; default: /* Reject */ /* drop all competing applications, keep only this one */ - for (oap = bcs->ap; oap != NULL; oap = oap->bcnext) - if (oap != ap) + spin_lock_irqsave(&bcs->aplock, flags); + while (bcs->ap != NULL) { + oap = bcs->ap; + bcs->ap = oap->bcnext; + if (oap != ap) { + spin_unlock_irqrestore(&bcs->aplock, flags); send_disconnect_ind(bcs, oap, CapiCallGivenToOtherApplication); + spin_lock_irqsave(&bcs->aplock, flags); + } + } ap->bcnext = NULL; bcs->ap = ap; + spin_unlock_irqrestore(&bcs->aplock, flags); /* reject call - will trigger DISCONNECT_IND for this app */ dev_info(cs->dev, "%s: Reject=%x\n", @@ -1549,6 +1705,7 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; + struct bc_state *bcs; int channel; /* decode message */ @@ -1563,9 +1720,10 @@ static void do_connect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; /* mark logical connection active */ - ap->connected = APCONN_ACTIVE; + bcs->apconnstate = APCONN_ACTIVE; /* build NCCI: always 1 (one B3 connection only) */ cmsg->adr.adrNCCI |= 1 << 16; @@ -1611,7 +1769,7 @@ static void do_connect_b3_resp(struct gigaset_capi_ctr *iif, if (cmsg->Reject) { /* Reject: clear B3 connect received flag */ - ap->connected = APCONN_SETUP; + bcs->apconnstate = APCONN_SETUP; /* trigger hangup, causing eventual DISCONNECT_IND */ if (!gigaset_add_event(cs, &bcs->at_state, @@ -1683,11 +1841,11 @@ static void do_disconnect_req(struct gigaset_capi_ctr *iif, } /* skip if DISCONNECT_IND already sent */ - if (!ap->connected) + if (!bcs->apconnstate) return; /* check for active logical connection */ - if (ap->connected >= APCONN_ACTIVE) { + if (bcs->apconnstate >= APCONN_ACTIVE) { /* * emit DISCONNECT_B3_IND with cause 0x3301 * use separate cmsg structure, as the content of iif->acmsg @@ -1736,6 +1894,7 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, { struct cardstate *cs = iif->ctr.driverdata; _cmsg *cmsg = &iif->acmsg; + struct bc_state *bcs; int channel; /* decode message */ @@ -1751,17 +1910,17 @@ static void do_disconnect_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; /* reject if logical connection not active */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } /* trigger hangup, causing eventual DISCONNECT_B3_IND */ - if (!gigaset_add_event(cs, &cs->bcs[channel-1].at_state, - EV_HUP, NULL, 0, NULL)) { + if (!gigaset_add_event(cs, &bcs->at_state, EV_HUP, NULL, 0, NULL)) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } @@ -1782,11 +1941,14 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, struct sk_buff *skb) { struct cardstate *cs = iif->ctr.driverdata; + struct bc_state *bcs; int channel = CAPIMSG_PLCI_PART(skb->data); u16 ncci = CAPIMSG_NCCI_PART(skb->data); u16 msglen = CAPIMSG_LEN(skb->data); u16 datalen = CAPIMSG_DATALEN(skb->data); u16 flags = CAPIMSG_FLAGS(skb->data); + u16 msgid = CAPIMSG_MSGID(skb->data); + u16 handle = CAPIMSG_HANDLE_REQ(skb->data); /* frequent message, avoid _cmsg overhead */ dump_rawmsg(DEBUG_LLDATA, "DATA_B3_REQ", skb->data); @@ -1802,6 +1964,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, send_conf(iif, ap, skb, CapiIllContrPlciNcci); return; } + bcs = &cs->bcs[channel-1]; if (msglen != CAPI_DATA_B3_REQ_LEN && msglen != CAPI_DATA_B3_REQ_LEN64) dev_notice(cs->dev, "%s: unexpected length %d\n", "DATA_B3_REQ", msglen); @@ -1821,7 +1984,7 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, } /* reject if logical connection not active */ - if (ap->connected < APCONN_ACTIVE) { + if (bcs->apconnstate < APCONN_ACTIVE) { send_conf(iif, ap, skb, CapiMessageNotSupportedInCurrentState); return; } @@ -1832,17 +1995,19 @@ static void do_data_b3_req(struct gigaset_capi_ctr *iif, skb_pull(skb, msglen); /* pass to device-specific module */ - if (cs->ops->send_skb(&cs->bcs[channel-1], skb) < 0) { + if (cs->ops->send_skb(bcs, skb) < 0) { send_conf(iif, ap, skb, CAPI_MSGOSRESOURCEERR); return; } - /* DATA_B3_CONF reply will be sent by gigaset_skb_sent() */ - /* - * ToDo: honor unset "delivery confirmation" bit - * (send DATA_B3_CONF immediately?) + * DATA_B3_CONF will be sent by gigaset_skb_sent() only if "delivery + * confirmation" bit is set; otherwise we have to send it now */ + if (!(flags & CAPI_FLAGS_DELIVERY_CONFIRMATION)) + send_data_b3_conf(cs, &iif->ctr, ap->id, msgid, channel, handle, + flags ? CapiFlagsNotSupportedByProtocol + : CAPI_NOERROR); } /* diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index f6f45f22192..5d4befb8105 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -399,8 +399,8 @@ static void gigaset_freebcs(struct bc_state *bcs) gig_dbg(DEBUG_INIT, "clearing bcs[%d]->at_state", bcs->channel); clear_at_state(&bcs->at_state); gig_dbg(DEBUG_INIT, "freeing bcs[%d]->skb", bcs->channel); - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; + dev_kfree_skb(bcs->rx_skb); + bcs->rx_skb = NULL; for (i = 0; i < AT_NUM; ++i) { kfree(bcs->commands[i]); @@ -634,19 +634,10 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, bcs->emptycount = 0; #endif - gig_dbg(DEBUG_INIT, "allocating bcs[%d]->skb", channel); - bcs->fcs = PPP_INITFCS; + bcs->rx_bufsize = 0; + bcs->rx_skb = NULL; + bcs->rx_fcs = PPP_INITFCS; bcs->inputstate = 0; - if (cs->ignoreframes) { - bcs->skb = NULL; - } else { - bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (bcs->skb != NULL) - skb_reserve(bcs->skb, cs->hw_hdr_len); - else - pr_err("out of memory\n"); - } - bcs->channel = channel; bcs->cs = cs; @@ -658,16 +649,15 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, for (i = 0; i < AT_NUM; ++i) bcs->commands[i] = NULL; + spin_lock_init(&bcs->aplock); + bcs->ap = NULL; + bcs->apconnstate = 0; + gig_dbg(DEBUG_INIT, " setting up bcs[%d]->hw", channel); if (cs->ops->initbcshw(bcs)) return bcs; gig_dbg(DEBUG_INIT, " failed"); - - gig_dbg(DEBUG_INIT, " freeing bcs[%d]->skb", channel); - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; - return NULL; } @@ -839,14 +829,12 @@ void gigaset_bcs_reinit(struct bc_state *bcs) bcs->emptycount = 0; #endif - bcs->fcs = PPP_INITFCS; + bcs->rx_fcs = PPP_INITFCS; bcs->chstate = 0; bcs->ignore = cs->ignoreframes; - if (bcs->ignore) { - dev_kfree_skb(bcs->skb); - bcs->skb = NULL; - } + dev_kfree_skb(bcs->rx_skb); + bcs->rx_skb = NULL; cs->ops->reinitbcshw(bcs); } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 206c380c523..ceaef9a04a4 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -282,9 +282,7 @@ struct reply_t gigaset_tab_cid[] = /* dial */ {EV_DIAL, -1, -1, -1, -1, -1, {ACT_DIAL} }, {RSP_INIT, 0, 0, SEQ_DIAL, 601, 5, {ACT_CMD+AT_BC} }, -{RSP_OK, 601, 601, -1, 602, 5, {ACT_CMD+AT_HLC} }, -{RSP_NULL, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, -{RSP_OK, 602, 602, -1, 603, 5, {ACT_CMD+AT_PROTO} }, +{RSP_OK, 601, 601, -1, 603, 5, {ACT_CMD+AT_PROTO} }, {RSP_OK, 603, 603, -1, 604, 5, {ACT_CMD+AT_TYPE} }, {RSP_OK, 604, 604, -1, 605, 5, {ACT_CMD+AT_MSN} }, {RSP_NULL, 605, 605, -1, 606, 5, {ACT_CMD+AT_CLIP} }, diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 05947f9c184..8738b0821fc 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -45,10 +45,6 @@ #define MAX_EVENTS 64 /* size of event queue */ #define RBUFSIZE 8192 -#define SBUFSIZE 4096 /* sk_buff payload size */ - -#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ -#define MAX_BUF_SIZE (SBUFSIZE - 2) /* Max. size of a data packet from LL */ /* compile time options */ #define GIG_MAJOR 0 @@ -190,10 +186,9 @@ void gigaset_dbg_buffer(enum debuglevel level, const unsigned char *msg, #define AT_BC 3 #define AT_PROTO 4 #define AT_TYPE 5 -#define AT_HLC 6 -#define AT_CLIP 7 +#define AT_CLIP 6 /* total number */ -#define AT_NUM 8 +#define AT_NUM 7 /* variables in struct at_state_t */ #define VAR_ZSAU 0 @@ -380,8 +375,10 @@ struct bc_state { struct at_state_t at_state; - __u16 fcs; - struct sk_buff *skb; + /* receive buffer */ + unsigned rx_bufsize; /* max size accepted by application */ + struct sk_buff *rx_skb; + __u16 rx_fcs; int inputstate; /* see INS_XXXX */ int channel; @@ -406,7 +403,9 @@ struct bc_state { struct bas_bc_state *bas; /* usb hardware driver (base) */ } hw; - void *ap; /* LL application structure */ + void *ap; /* associated LL application */ + int apconnstate; /* LL application connection state */ + spinlock_t aplock; }; struct cardstate { @@ -801,8 +800,23 @@ static inline void gigaset_bchannel_up(struct bc_state *bcs) gigaset_schedule_event(bcs->cs); } -/* handling routines for sk_buff */ -/* ============================= */ +/* set up next receive skb for data mode */ +static inline struct sk_buff *gigaset_new_rx_skb(struct bc_state *bcs) +{ + struct cardstate *cs = bcs->cs; + unsigned short hw_hdr_len = cs->hw_hdr_len; + + if (bcs->ignore) { + bcs->rx_skb = NULL; + } else { + bcs->rx_skb = dev_alloc_skb(bcs->rx_bufsize + hw_hdr_len); + if (bcs->rx_skb == NULL) + dev_warn(cs->dev, "could not allocate skb\n"); + else + skb_reserve(bcs->rx_skb, hw_hdr_len); + } + return bcs->rx_skb; +} /* append received bytes to inbuf */ int gigaset_fill_inbuf(struct inbuf_t *inbuf, const unsigned char *src, diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index c22e5ace827..f01c3c2e2e4 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -16,7 +16,10 @@ #include "gigaset.h" #include <linux/isdnif.h> +#define SBUFSIZE 4096 /* sk_buff payload size */ +#define TRANSBUFSIZE 768 /* bytes per skb for transparent receive */ #define HW_HDR_LEN 2 /* Header size used to store ack info */ +#define MAX_BUF_SIZE (SBUFSIZE - HW_HDR_LEN) /* max data packet from LL */ /* == Handling of I4L IO =====================================================*/ @@ -231,6 +234,15 @@ static int command_from_LL(isdn_ctrl *cntrl) dev_err(cs->dev, "ISDN_CMD_DIAL: channel not free\n"); return -EBUSY; } + switch (bcs->proto2) { + case L2_HDLC: + bcs->rx_bufsize = SBUFSIZE; + break; + default: /* assume transparent */ + bcs->rx_bufsize = TRANSBUFSIZE; + } + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); commands = kzalloc(AT_NUM*(sizeof *commands), GFP_ATOMIC); if (!commands) { @@ -314,6 +326,15 @@ static int command_from_LL(isdn_ctrl *cntrl) return -EINVAL; } bcs = cs->bcs + ch; + switch (bcs->proto2) { + case L2_HDLC: + bcs->rx_bufsize = SBUFSIZE; + break; + default: /* assume transparent */ + bcs->rx_bufsize = TRANSBUFSIZE; + } + dev_kfree_skb(bcs->rx_skb); + gigaset_new_rx_skb(bcs); if (!gigaset_add_event(cs, &bcs->at_state, EV_ACCEPT, NULL, 0, NULL)) return -ENOMEM; diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index 16fd3bd4888..2dfd346fc88 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -500,19 +500,18 @@ int gigaset_isoc_buildframe(struct bc_state *bcs, unsigned char *in, int len) */ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) { - bcs->fcs = crc_ccitt_byte(bcs->fcs, c); - if (unlikely(bcs->skb == NULL)) { + bcs->rx_fcs = crc_ccitt_byte(bcs->rx_fcs, c); + if (bcs->rx_skb == NULL) /* skipping */ return; - } - if (unlikely(bcs->skb->len == SBUFSIZE)) { + if (bcs->rx_skb->len >= bcs->rx_bufsize) { dev_warn(bcs->cs->dev, "received oversized packet discarded\n"); bcs->hw.bas->giants++; - dev_kfree_skb_any(bcs->skb); - bcs->skb = NULL; + dev_kfree_skb_any(bcs->rx_skb); + bcs->rx_skb = NULL; return; } - *__skb_put(bcs->skb, 1) = c; + *__skb_put(bcs->rx_skb, 1) = c; } /* hdlc_flush @@ -521,18 +520,13 @@ static inline void hdlc_putbyte(unsigned char c, struct bc_state *bcs) static inline void hdlc_flush(struct bc_state *bcs) { /* clear skb or allocate new if not skipping */ - if (likely(bcs->skb != NULL)) - skb_trim(bcs->skb, 0); - else if (!bcs->ignore) { - bcs->skb = dev_alloc_skb(SBUFSIZE + bcs->cs->hw_hdr_len); - if (bcs->skb) - skb_reserve(bcs->skb, bcs->cs->hw_hdr_len); - else - dev_err(bcs->cs->dev, "could not allocate skb\n"); - } + if (bcs->rx_skb != NULL) + skb_trim(bcs->rx_skb, 0); + else + gigaset_new_rx_skb(bcs); /* reset packet state */ - bcs->fcs = PPP_INITFCS; + bcs->rx_fcs = PPP_INITFCS; } /* hdlc_done @@ -549,7 +543,7 @@ static inline void hdlc_done(struct bc_state *bcs) hdlc_flush(bcs); return; } - procskb = bcs->skb; + procskb = bcs->rx_skb; if (procskb == NULL) { /* previous error */ gig_dbg(DEBUG_ISO, "%s: skb=NULL", __func__); @@ -560,8 +554,8 @@ static inline void hdlc_done(struct bc_state *bcs) bcs->hw.bas->runts++; dev_kfree_skb_any(procskb); gigaset_isdn_rcv_err(bcs); - } else if (bcs->fcs != PPP_GOODFCS) { - dev_notice(cs->dev, "frame check error (0x%04x)\n", bcs->fcs); + } else if (bcs->rx_fcs != PPP_GOODFCS) { + dev_notice(cs->dev, "frame check error\n"); bcs->hw.bas->fcserrs++; dev_kfree_skb_any(procskb); gigaset_isdn_rcv_err(bcs); @@ -574,13 +568,8 @@ static inline void hdlc_done(struct bc_state *bcs) bcs->hw.bas->goodbytes += len; gigaset_skb_rcvd(bcs, procskb); } - - bcs->skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (bcs->skb) - skb_reserve(bcs->skb, cs->hw_hdr_len); - else - dev_err(cs->dev, "could not allocate skb\n"); - bcs->fcs = PPP_INITFCS; + gigaset_new_rx_skb(bcs); + bcs->rx_fcs = PPP_INITFCS; } /* hdlc_frag @@ -597,8 +586,8 @@ static inline void hdlc_frag(struct bc_state *bcs, unsigned inbits) dev_notice(bcs->cs->dev, "received partial byte (%d bits)\n", inbits); bcs->hw.bas->alignerrs++; gigaset_isdn_rcv_err(bcs); - __skb_trim(bcs->skb, 0); - bcs->fcs = PPP_INITFCS; + __skb_trim(bcs->rx_skb, 0); + bcs->rx_fcs = PPP_INITFCS; } /* bit counts lookup table for HDLC bit unstuffing @@ -847,7 +836,6 @@ static inline void hdlc_unpack(unsigned char *src, unsigned count, static inline void trans_receive(unsigned char *src, unsigned count, struct bc_state *bcs) { - struct cardstate *cs = bcs->cs; struct sk_buff *skb; int dobytes; unsigned char *dst; @@ -857,17 +845,11 @@ static inline void trans_receive(unsigned char *src, unsigned count, hdlc_flush(bcs); return; } - skb = bcs->skb; - if (unlikely(skb == NULL)) { - bcs->skb = skb = dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (!skb) { - dev_err(cs->dev, "could not allocate skb\n"); - return; - } - skb_reserve(skb, cs->hw_hdr_len); - } + skb = bcs->rx_skb; + if (skb == NULL) + skb = gigaset_new_rx_skb(bcs); bcs->hw.bas->goodbytes += skb->len; - dobytes = TRANSBUFSIZE - skb->len; + dobytes = bcs->rx_bufsize - skb->len; while (count > 0) { dst = skb_put(skb, count < dobytes ? count : dobytes); while (count > 0 && dobytes > 0) { @@ -879,14 +861,10 @@ static inline void trans_receive(unsigned char *src, unsigned count, dump_bytes(DEBUG_STREAM_DUMP, "rcv data", skb->data, skb->len); gigaset_skb_rcvd(bcs, skb); - bcs->skb = skb = - dev_alloc_skb(SBUFSIZE + cs->hw_hdr_len); - if (!skb) { - dev_err(cs->dev, "could not allocate skb\n"); + skb = gigaset_new_rx_skb(bcs); + if (skb == NULL) return; - } - skb_reserve(skb, cs->hw_hdr_len); - dobytes = TRANSBUFSIZE; + dobytes = bcs->rx_bufsize; } } } |