📄 hfc_usb.c
字号:
if (state >= 7) { if (timer_pending(&hfc->t4_timer)) del_timer(&hfc->t4_timer);#ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: T4 deactivated");#endif } if (state == 7 && !hfc->l1_activated) { hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_ACTIVATE | INDICATION, NULL);#ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_ACTIVATE | INDICATION sent");#endif hfc->l1_activated = TRUE; handle_led(hfc, LED_S0_ON); } else if (state <= 3 /* && activated */ ) { if (old_state == 7 || old_state == 8) {#ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: T4 activated");#endif if (!timer_pending(&hfc->t4_timer)) { hfc->t4_timer.expires = jiffies + (HFC_TIMER_T4 * HZ) / 1000; add_timer(&hfc->t4_timer); } } else { hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, NULL);#ifdef CONFIG_HISAX_DEBUG DBG(ISDN_DBG, "HFC-S USB: PH_DEACTIVATE | INDICATION sent");#endif hfc->l1_activated = FALSE; handle_led(hfc, LED_S0_OFF); } } hfc->l1_state = state;}/* prepare iso urb */static voidfill_isoc_urb(struct urb *urb, struct usb_device *dev, unsigned int pipe, void *buf, int num_packets, int packet_size, int interval, usb_complete_t complete, void *context){ int k; spin_lock_init(&urb->lock); urb->dev = dev; urb->pipe = pipe; urb->complete = complete; urb->number_of_packets = num_packets; urb->transfer_buffer_length = packet_size * num_packets; urb->context = context; urb->transfer_buffer = buf; urb->transfer_flags = URB_ISO_ASAP; urb->actual_length = 0; urb->interval = interval; for (k = 0; k < num_packets; k++) { urb->iso_frame_desc[k].offset = packet_size * k; urb->iso_frame_desc[k].length = packet_size; urb->iso_frame_desc[k].actual_length = 0; }}/* allocs urbs and start isoc transfer with two pending urbs to avoid gaps in the transfer chain */static intstart_isoc_chain(usb_fifo * fifo, int num_packets_per_urb, usb_complete_t complete, int packet_size){ int i, k, errcode; printk(KERN_INFO "HFC-S USB: starting ISO-chain for Fifo %i\n", fifo->fifonum); /* allocate Memory for Iso out Urbs */ for (i = 0; i < 2; i++) { if (!(fifo->iso[i].purb)) { fifo->iso[i].purb = usb_alloc_urb(num_packets_per_urb, GFP_KERNEL); if (!(fifo->iso[i].purb)) { printk(KERN_INFO "alloc urb for fifo %i failed!!!", fifo->fifonum); } fifo->iso[i].owner_fifo = (struct usb_fifo *) fifo; /* Init the first iso */ if (ISO_BUFFER_SIZE >= (fifo->usb_packet_maxlen * num_packets_per_urb)) { fill_isoc_urb(fifo->iso[i].purb, fifo->hfc->dev, fifo->pipe, fifo->iso[i].buffer, num_packets_per_urb, fifo->usb_packet_maxlen, fifo->intervall, complete, &fifo->iso[i]); memset(fifo->iso[i].buffer, 0, sizeof(fifo->iso[i].buffer)); /* defining packet delimeters in fifo->buffer */ for (k = 0; k < num_packets_per_urb; k++) { fifo->iso[i].purb-> iso_frame_desc[k].offset = k * packet_size; fifo->iso[i].purb-> iso_frame_desc[k].length = packet_size; } } else { printk(KERN_INFO "HFC-S USB: ISO Buffer size to small!\n"); } } fifo->bit_line = BITLINE_INF; errcode = usb_submit_urb(fifo->iso[i].purb, GFP_KERNEL); fifo->active = (errcode >= 0) ? 1 : 0; if (errcode < 0) { printk(KERN_INFO "HFC-S USB: %s URB nr:%d\n", symbolic(urb_errlist, errcode), i); }; } return (fifo->active);}/* stops running iso chain and frees their pending urbs */static voidstop_isoc_chain(usb_fifo * fifo){ int i; for (i = 0; i < 2; i++) { if (fifo->iso[i].purb) {#ifdef CONFIG_HISAX_DEBUG DBG(USB_DBG, "HFC-S USB: Stopping iso chain for fifo %i.%i", fifo->fifonum, i);#endif usb_unlink_urb(fifo->iso[i].purb); usb_free_urb(fifo->iso[i].purb); fifo->iso[i].purb = NULL; } } if (fifo->urb) { usb_unlink_urb(fifo->urb); usb_free_urb(fifo->urb); fifo->urb = NULL; } fifo->active = 0;}/* defines how much ISO packets are handled in one URB */static int iso_packets[8] = { ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_B, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D, ISOC_PACKETS_D};/*****************************************************//* transmit completion routine for all ISO tx fifos *//*****************************************************/static voidtx_iso_complete(struct urb *urb, struct pt_regs *regs){ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; usb_fifo *fifo = context_iso_urb->owner_fifo; hfcusb_data *hfc = fifo->hfc; int k, tx_offset, num_isoc_packets, sink, len, current_len, errcode; int frame_complete, transp_mode, fifon, status; __u8 threshbit; __u8 threshtable[8] = { 1, 2, 4, 8, 0x10, 0x20, 0x40, 0x80 }; fifon = fifo->fifonum; status = urb->status; tx_offset = 0; if (fifo->active && !status) { transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) transp_mode = TRUE; /* is FifoFull-threshold set for our channel? */ threshbit = threshtable[fifon] & hfc->threshold_mask; num_isoc_packets = iso_packets[fifon]; /* predict dataflow to avoid fifo overflow */ if (fifon >= HFCUSB_D_TX) { sink = (threshbit) ? SINK_DMIN : SINK_DMAX; } else { sink = (threshbit) ? SINK_MIN : SINK_MAX; } fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, context_iso_urb->buffer, num_isoc_packets, fifo->usb_packet_maxlen, fifo->intervall, tx_iso_complete, urb->context); memset(context_iso_urb->buffer, 0, sizeof(context_iso_urb->buffer)); frame_complete = FALSE; /* Generate next Iso Packets */ for (k = 0; k < num_isoc_packets; ++k) { if (fifo->skbuff) { len = fifo->skbuff->len; /* we lower data margin every msec */ fifo->bit_line -= sink; current_len = (0 - fifo->bit_line) / 8; /* maximum 15 byte for every ISO packet makes our life easier */ if (current_len > 14) current_len = 14; current_len = (len <= current_len) ? len : current_len; /* how much bit do we put on the line? */ fifo->bit_line += current_len * 8; context_iso_urb->buffer[tx_offset] = 0; if (current_len == len) { if (!transp_mode) { /* here frame completion */ context_iso_urb-> buffer[tx_offset] = 1; /* add 2 byte flags and 16bit CRC at end of ISDN frame */ fifo->bit_line += 32; } frame_complete = TRUE; } memcpy(context_iso_urb->buffer + tx_offset + 1, fifo->skbuff->data, current_len); skb_pull(fifo->skbuff, current_len); /* define packet delimeters within the URB buffer */ urb->iso_frame_desc[k].offset = tx_offset; urb->iso_frame_desc[k].length = current_len + 1; tx_offset += (current_len + 1); } else { urb->iso_frame_desc[k].offset = tx_offset++; urb->iso_frame_desc[k].length = 1; fifo->bit_line -= sink; /* we lower data margin every msec */ if (fifo->bit_line < BITLINE_INF) { fifo->bit_line = BITLINE_INF; } } if (frame_complete) { fifo->delete_flg = TRUE; fifo->hif->l1l2(fifo->hif, PH_DATA | CONFIRM, (void *) fifo->skbuff-> truesize); if (fifo->skbuff && fifo->delete_flg) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; fifo->delete_flg = FALSE; } frame_complete = FALSE; } } errcode = usb_submit_urb(urb, GFP_ATOMIC); if (errcode < 0) { printk(KERN_INFO "HFC-S USB: error submitting ISO URB: %d \n", errcode); } } else { if (status && !hfc->disc_flag) { printk(KERN_INFO "HFC-S USB: tx_iso_complete : urb->status %s (%i), fifonum=%d\n", symbolic(urb_errlist, status), status, fifon); } }} /* tx_iso_complete *//*****************************************************//* receive completion routine for all ISO tx fifos *//*****************************************************/static voidrx_iso_complete(struct urb *urb, struct pt_regs *regs){ iso_urb_struct *context_iso_urb = (iso_urb_struct *) urb->context; usb_fifo *fifo = context_iso_urb->owner_fifo; hfcusb_data *hfc = fifo->hfc; int k, len, errcode, offset, num_isoc_packets, fifon, maxlen, status; unsigned int iso_status; __u8 *buf; static __u8 eof[8];#ifdef CONFIG_HISAX_DEBUG __u8 i;#endif fifon = fifo->fifonum; status = urb->status; if (urb->status == -EOVERFLOW) {#ifdef CONFIG_HISAX_DEBUG DBG(USB_DBG, "HFC-USB: ignoring USB DATAOVERRUN for fifo %i \n", fifon);#endif status = 0; } if (fifo->active && !status) { num_isoc_packets = iso_packets[fifon]; maxlen = fifo->usb_packet_maxlen; for (k = 0; k < num_isoc_packets; ++k) { len = urb->iso_frame_desc[k].actual_length; offset = urb->iso_frame_desc[k].offset; buf = context_iso_urb->buffer + offset; iso_status = urb->iso_frame_desc[k].status;#ifdef CONFIG_HISAX_DEBUG if (iso_status && !hfc->disc_flag) DBG(USB_DBG, "HFC-S USB: ISO packet failure - status:%x", iso_status); if ((fifon == 5) && (debug > 1)) { printk(KERN_INFO "HFC-S USB: ISO-D-RX lst_urblen:%2d " "act_urblen:%2d max-urblen:%2d " "EOF:0x%0x DATA: ", fifo->last_urblen, len, maxlen, eof[5]); for (i = 0; i < len; i++) printk("%.2x ", buf[i]); printk("\n"); }#endif if (fifo->last_urblen != maxlen) { /* the threshold mask is in the 2nd status byte */ hfc->threshold_mask = buf[1]; /* care for L1 state only for D-Channel to avoid overlapped iso completions */ if (fifon == 5) { /* the S0 state is in the upper half of the 1st status byte */ state_handler(hfc, buf[0] >> 4); } eof[fifon] = buf[0] & 1; if (len > 2) collect_rx_frame(fifo, buf + 2, len - 2, (len < maxlen) ? eof[fifon] : 0); } else { collect_rx_frame(fifo, buf, len, (len < maxlen) ? eof[fifon] : 0); } fifo->last_urblen = len; } fill_isoc_urb(urb, fifo->hfc->dev, fifo->pipe, context_iso_urb->buffer, num_isoc_packets, fifo->usb_packet_maxlen, fifo->intervall, rx_iso_complete, urb->context); errcode = usb_submit_urb(urb, GFP_ATOMIC); if (errcode < 0) { printk(KERN_INFO "HFC-S USB: error submitting ISO URB: %d \n", errcode); } } else { if (status && !hfc->disc_flag) { printk(KERN_INFO "HFC-S USB: rx_iso_complete : " "urb->status %d, fifonum %d\n", status, fifon); } }} /* rx_iso_complete *//*****************************************************//* collect data from interrupt or isochron in *//*****************************************************/static voidcollect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish){ hfcusb_data *hfc = fifo->hfc; int transp_mode, fifon;#ifdef CONFIG_HISAX_DEBUG int i;#endif fifon = fifo->fifonum; transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) transp_mode = TRUE; if (!fifo->skbuff) { fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); if (!fifo->skbuff) { printk(KERN_INFO "HFC-S USB: cannot allocate buffer (dev_alloc_skb) fifo:%d\n", fifon); return; } } if (len) { if (fifo->skbuff->len + len < fifo->max_size) { memcpy(skb_put(fifo->skbuff, len), data, len); } else {#ifdef CONFIG_HISAX_DEBUG printk(KERN_INFO "HFC-S USB: "); for (i = 0; i < 15; i++) printk("%.2x ", fifo->skbuff->data[fifo->skbuff-> len - 15 + i]); printk("\n");#endif printk(KERN_INFO "HCF-USB: got frame exceeded fifo->max_size:%d on fifo:%d\n", fifo->max_size, fifon); } } if (transp_mode && fifo->skbuff->len >= 128) { fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION, fifo->skbuff); fifo->skbuff = NULL; return; } /* we have a complete hdlc packet */ if (finish) { if ((!fifo->skbuff->data[fifo->skbuff->len - 1]) && (fifo->skbuff->len > 3)) { /* remove CRC & status */ skb_trim(fifo->skbuff, fifo->skbuff->len - 3); if (fifon == HFCUSB_PCM_RX) { fifo->hif->l1l2(fifo->hif,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -