/* * st5481_b_l2l1 is the entry point for upper layer routines that want to * transmit on the B channel. PH_DATA | REQUEST is a normal packet that * we either start transmitting (if idle) or queue (if busy). * PH_PULL | REQUEST can be called to request a callback message * (PH_PULL | CONFIRM) * once the link is idle. After a "pull" callback, the upper layer * routines can use PH_PULL | INDICATION to send data. */ void st5481_b_l2l1(struct hisax_if *ifc, int pr, void *arg) { struct st5481_bcs *bcs = ifc->priv; struct sk_buff *skb = arg; int mode; DBG(4, ""); switch (pr) { case PH_DATA | REQUEST: if (bcs->b_out.tx_skb) BUG(); bcs->b_out.tx_skb = skb; break; case PH_ACTIVATE | REQUEST: mode = (int) arg; DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); st5481B_mode(bcs, mode); B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); break; case PH_DEACTIVATE | REQUEST: DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); st5481B_mode(bcs, L1_MODE_NULL); B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); break; default: WARN("pr %#x\n", pr); } }
static void fritz_b_l2l1(struct hisax_if *ifc, int pr, void *arg) { struct fritz_bcs *bcs = ifc->priv; struct sk_buff *skb = arg; int mode; DBG(0x10, "pr %#x", pr); switch (pr) { case PH_DATA | REQUEST: if (bcs->tx_skb) BUG(); bcs->tx_skb = skb; DBG_SKB(1, skb); hdlc_fill_fifo(bcs); break; case PH_ACTIVATE | REQUEST: mode = (int) arg; DBG(4,"B%d,PH_ACTIVATE_REQUEST %d", bcs->channel + 1, mode); modehdlc(bcs, mode); B_L1L2(bcs, PH_ACTIVATE | INDICATION, NULL); break; case PH_DEACTIVATE | REQUEST: DBG(4,"B%d,PH_DEACTIVATE_REQUEST", bcs->channel + 1); modehdlc(bcs, L1_MODE_NULL); B_L1L2(bcs, PH_DEACTIVATE | INDICATION, NULL); break; } }
static inline void hdlc_xpr_irq(struct fritz_bcs *bcs) { struct sk_buff *skb; skb = bcs->tx_skb; if (!skb) return; if (skb->len) { hdlc_fill_fifo(bcs); return; } bcs->tx_cnt = 0; bcs->tx_skb = NULL; B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); dev_kfree_skb_irq(skb); }
static inline void hdlc_rpr_irq(struct fritz_bcs *bcs, u32 stat) { struct fritz_adapter *adapter = bcs->adapter; struct sk_buff *skb; int len; if (stat & HDLC_STAT_RDO) { DBG(0x10, "RDO"); bcs->ctrl.sr.xml = 0; bcs->ctrl.sr.cmd |= HDLC_CMD_RRS; adapter->write_ctrl(bcs, 1); bcs->ctrl.sr.cmd &= ~HDLC_CMD_RRS; adapter->write_ctrl(bcs, 1); bcs->rcvidx = 0; return; } len = (stat & HDLC_STAT_RML_MASK) >> 8; if (len == 0) len = 32; hdlc_empty_fifo(bcs, len); if ((stat & HDLC_STAT_RME) || (bcs->mode == L1_MODE_TRANS)) { if (((stat & HDLC_STAT_CRCVFRRAB)== HDLC_STAT_CRCVFR) || (bcs->mode == L1_MODE_TRANS)) { skb = dev_alloc_skb(bcs->rcvidx); if (!skb) { printk(KERN_WARNING "HDLC: receive out of memory\n"); } else { memcpy(skb_put(skb, bcs->rcvidx), bcs->rcvbuf, bcs->rcvidx); DBG_SKB(1, skb); B_L1L2(bcs, PH_DATA | INDICATION, skb); } bcs->rcvidx = 0; } else { DBG(0x10, "ch%d invalid frame %#x", bcs->channel, stat); bcs->rcvidx = 0; } } }
/* * Encode and transmit next frame. */ static void usb_b_out(struct st5481_bcs *bcs,int buf_nr) { struct st5481_b_out *b_out = &bcs->b_out; struct st5481_adapter *adapter = bcs->adapter; struct urb *urb; unsigned int packet_size,offset; int len,buf_size,bytes_sent; int i; struct sk_buff *skb; if (test_and_set_bit(buf_nr, &b_out->busy)) { DBG(4,"ep %d urb %d busy",(bcs->channel+1)*2,buf_nr); return; } urb = b_out->urb[buf_nr]; // Adjust isoc buffer size according to flow state if(b_out->flow_event & (OUT_DOWN | OUT_UNDERRUN)) { buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; packet_size = SIZE_ISO_PACKETS_B_OUT + B_FLOW_ADJUST; DBG(4,"B%d,adjust flow,add %d bytes",bcs->channel+1,B_FLOW_ADJUST); } else if(b_out->flow_event & OUT_UP){ buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; packet_size = SIZE_ISO_PACKETS_B_OUT - B_FLOW_ADJUST; DBG(4,"B%d,adjust flow,remove %d bytes",bcs->channel+1,B_FLOW_ADJUST); } else { buf_size = NUM_ISO_PACKETS_B*SIZE_ISO_PACKETS_B_OUT; packet_size = 8; } b_out->flow_event = 0; len = 0; while (len < buf_size) { if ((skb = b_out->tx_skb)) { DBG_SKB(0x100, skb); DBG(4,"B%d,len=%d",bcs->channel+1,skb->len); if (bcs->mode == L1_MODE_TRANS) { bytes_sent = buf_size - len; if (skb->len < bytes_sent) bytes_sent = skb->len; { /* swap tx bytes to get hearable audio data */ register unsigned char *src = skb->data; register unsigned char *dest = urb->transfer_buffer+len; register unsigned int count; for (count = 0; count < bytes_sent; count++) *dest++ = isdnhdlc_bit_rev_tab[*src++]; } len += bytes_sent; } else { len += isdnhdlc_encode(&b_out->hdlc_state, skb->data, skb->len, &bytes_sent, urb->transfer_buffer+len, buf_size-len); } skb_pull(skb, bytes_sent); if (!skb->len) { // Frame sent b_out->tx_skb = NULL; B_L1L2(bcs, PH_DATA | CONFIRM, (void *) skb->truesize); dev_kfree_skb_any(skb); /* if (!(bcs->tx_skb = skb_dequeue(&bcs->sq))) { */ /* st5481B_sched_event(bcs, B_XMTBUFREADY); */ /* } */ } } else { if (bcs->mode == L1_MODE_TRANS) { memset(urb->transfer_buffer+len, 0xff, buf_size-len); len = buf_size; } else { // Send flags len += isdnhdlc_encode(&b_out->hdlc_state, NULL, 0, &bytes_sent, urb->transfer_buffer+len, buf_size-len); } } } // Prepare the URB for (i = 0, offset = 0; offset < len; i++) { urb->iso_frame_desc[i].offset = offset; urb->iso_frame_desc[i].length = packet_size; offset += packet_size; packet_size = SIZE_ISO_PACKETS_B_OUT; } urb->transfer_buffer_length = len; urb->number_of_packets = i; urb->dev = adapter->usb_dev; DBG_ISO_PACKET(0x200,urb); SUBMIT_URB(urb, GFP_NOIO); }