hfc_usb.c
来自「linux 内核源代码」· C语言 代码 · 共 1,609 行 · 第 1/3 页
C
1,609 行
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};static voidtx_iso_complete(struct urb *urb){ 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; fifon = fifo->fifonum; status = urb->status; tx_offset = 0; /* ISO transfer only partially completed, look at individual frame status for details */ if (status == -EXDEV) { DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete with -EXDEV" ", urb->status %d, fifonum %d\n", status, fifon); for (k = 0; k < iso_packets[fifon]; ++k) { errcode = urb->iso_frame_desc[k].status; if (errcode) DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: tx_iso_complete " "packet %i, status: %i\n", k, errcode); } // clear status, so go on with ISO transfers status = 0; } if (fifo->active && !status) { transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) transp_mode = 1; /* is FifoFull-threshold set for our channel? */ threshbit = (hfc->threshold_mask & (1 << fifon)); 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 = 0; /* 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 = 1; } 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 = 1; fifo->hif->l1l2(fifo->hif, PH_DATA | CONFIRM, (void *) (unsigned long) fifo->skbuff-> truesize); if (fifo->skbuff && fifo->delete_flg) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; fifo->delete_flg = 0; } frame_complete = 0; } } 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: error(%i): '%s', fifonum=%d\n", status, symbolic(urb_errlist, status), fifon); } }}static voidrx_iso_complete(struct urb *urb){ 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]; fifon = fifo->fifonum; status = urb->status; if (urb->status == -EOVERFLOW) { DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-USB: ignoring USB DATAOVERRUN fifo(%i)", fifon); status = 0; } /* ISO transfer only partially completed, look at individual frame status for details */ if (status == -EXDEV) { DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete with -EXDEV " "urb->status %d, fifonum %d\n", status, fifon); 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; if (iso_status && !hfc->disc_flag) DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: rx_iso_complete " "ISO packet %i, status: %i\n", k, iso_status); if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: ISO-D-RX lst_urblen:%2d " "act_urblen:%2d max-urblen:%2d EOF:0x%0x", fifo->last_urblen, len, maxlen, eof[5]); DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); } 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 == HFCUSB_D_RX) { /* the S0 state is in the upper half of the 1st status byte */ s0_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_ERR "HFC-S USB: error submitting ISO URB: %d\n", errcode); } } else { if (status && !hfc->disc_flag) { printk(KERN_ERR "HFC-S USB: rx_iso_complete : " "urb->status %d, fifonum %d\n", status, fifon); } }}/* collect rx data from INT- and ISO-URBs */static voidcollect_rx_frame(usb_fifo * fifo, __u8 * data, int len, int finish){ hfcusb_data *hfc = fifo->hfc; int transp_mode, fifon; fifon = fifo->fifonum; transp_mode = 0; if (fifon < 4 && hfc->b_mode[fifon / 2] == L1_MODE_TRANS) transp_mode = 1; if (!fifo->skbuff) { fifo->skbuff = dev_alloc_skb(fifo->max_size + 3); if (!fifo->skbuff) { printk(KERN_ERR "HFC-S USB: cannot allocate buffer for fifo(%d)\n", fifon); return; } } if (len) { if (fifo->skbuff->len + len < fifo->max_size) { memcpy(skb_put(fifo->skbuff, len), data, len); } else { DBG(HFCUSB_DBG_FIFO_ERR, "HCF-USB: got frame exceeded fifo->max_size(%d) fifo(%d)", fifo->max_size, fifon); DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); skb_trim(fifo->skbuff, 0); } } 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)) { if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_DCHANNEL, "HFC-S USB: D-RX len(%d)", fifo->skbuff->len); DBG_SKB(HFCUSB_DBG_DCHANNEL, fifo->skbuff); } /* remove CRC & status */ skb_trim(fifo->skbuff, fifo->skbuff->len - 3); if (fifon == HFCUSB_PCM_RX) { fifo->hif->l1l2(fifo->hif, PH_DATA_E | INDICATION, fifo->skbuff); } else fifo->hif->l1l2(fifo->hif, PH_DATA | INDICATION, fifo->skbuff); fifo->skbuff = NULL; /* buffer was freed from upper layer */ } else { DBG(HFCUSB_DBG_FIFO_ERR, "HFC-S USB: ERROR frame len(%d) fifo(%d)", fifo->skbuff->len, fifon); DBG_SKB(HFCUSB_DBG_VERBOSE_USB, fifo->skbuff); skb_trim(fifo->skbuff, 0); } }}static voidrx_int_complete(struct urb *urb){ int len; int status; __u8 *buf, maxlen, fifon; usb_fifo *fifo = (usb_fifo *) urb->context; hfcusb_data *hfc = fifo->hfc; static __u8 eof[8]; urb->dev = hfc->dev; /* security init */ fifon = fifo->fifonum; if ((!fifo->active) || (urb->status)) { DBG(HFCUSB_DBG_INIT, "HFC-S USB: RX-Fifo %i is going down (%i)", fifon, urb->status); fifo->urb->interval = 0; /* cancel automatic rescheduling */ if (fifo->skbuff) { dev_kfree_skb_any(fifo->skbuff); fifo->skbuff = NULL; } return; } len = urb->actual_length; buf = fifo->buffer; maxlen = fifo->usb_packet_maxlen; if (fifon == HFCUSB_D_RX) { DBG(HFCUSB_DBG_VERBOSE_USB, "HFC-S USB: INT-D-RX lst_urblen:%2d " "act_urblen:%2d max-urblen:%2d EOF:0x%0x", fifo->last_urblen, len, maxlen, eof[5]); DBG_PACKET(HFCUSB_DBG_VERBOSE_USB, buf, len); } if (fifo->last_urblen != fifo->usb_packet_maxlen) { /* the threshold mask is in the 2nd status byte */ hfc->threshold_mask = buf[1]; /* the S0 state is in the upper half of the 1st status byte */ s0_state_handler(hfc, buf[0] >> 4); eof[fifon] = buf[0] & 1; /* if we have more than the 2 status bytes -> collect data */ if (len > 2) collect_rx_frame(fifo, buf + 2, urb->actual_length - 2, (len < maxlen) ? eof[fifon] : 0); } else { collect_rx_frame(fifo, buf, urb->actual_length, (len < maxlen) ? eof[fifon] : 0); } fifo->last_urblen = urb->actual_length; status = usb_submit_urb(urb, GFP_ATOMIC); if (status) { printk(KERN_INFO "HFC-S USB: %s error resubmitting URB fifo(%d)\n", __FUNCTION__, fifon); }}/* start initial INT-URB for certain fifo */static voidstart_int_fifo(usb_fifo * fifo){ int errcode; DBG(HFCUSB_DBG_INIT, "HFC-S USB: starting RX INT-URB for fifo:%d\n", fifo->fifonum); if (!fifo->urb) { fifo->urb = usb_alloc_urb(0, GFP_KERNEL); if (!fifo->urb) return; } usb_fill_int_urb(fifo->urb, fifo->hfc->dev, fifo->pipe, fifo->buffer, fifo->usb_packet_maxlen, rx_int_complete, fifo, fifo->intervall); fifo->active = 1; /* must be marked active */ errcode = usb_submit_urb(fifo->urb, GFP_KERNEL); if (errcode) { printk(KERN_ERR "HFC-S USB: submit URB error(start_int_info): status:%i\n", errcode); fifo->active = 0; fifo->skbuff = NULL; }}static voidsetup_bchannel(hfcusb_data * hfc, int channel, int mode){ __u8 val, idx_table[2] = { 0, 2 }; if (hfc->disc_flag) { return; } DBG(HFCUSB_DBG_STATES, "HFC-S USB: setting channel %d to mode %d", channel, mode); hfc->b_mode[channel] = mode; /* setup CON_HDLC */ val = 0; if (mode != L1_MODE_NULL) val = 8; /* enable fifo? */ if (mode == L1_MODE_TRANS) val |= 2; /* set transparent bit */ /* set FIFO to transmit register */ queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel], 1); queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); /* reset fifo */ queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); /* set FIFO to receive register */ queue_control_request(hfc, HFCUSB_FIFO, idx_table[channel] + 1, 1); queue_control_request(hfc, HFCUSB_CON_HDLC, val, 1); /* reset fifo */ queue_control_request(hfc, HFCUSB_INC_RES_F, 2, 1); val = 0x40; if (hfc->b_mode[0]) val |= 1; if (hfc->b_mode[1]) val |= 2; queue_control_request(hfc, HFCUSB_SCTRL, val, 1); val = 0; if (hfc->b_mode[0]) val |= 1; if (hfc->b_mode[1]) val |= 2; queue_control_request(hfc, HFCUSB_SCTRL_R, val, 1); if (mode == L1_MODE_NULL) { if (channel) handle_led(hfc, LED_B2_OFF); else handle_led(hfc, LED_B1_OFF); } else { if (channel) handle_led(hfc, LED_B2_ON); else handle_led(hfc, LED_B1_ON); }}static voidhfc_usb_l2l1(struct hisax_if *my_hisax_if, int pr, void *arg){ usb_fifo *fifo = my_hisax_if->priv; hfcusb_data *hfc = fifo->hfc; switch (pr) { case PH_ACTIVATE | REQUEST: if (fifo->fifonum == HFCUSB_D_TX) { DBG(HFCUSB_DBG_STATES, "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_ACTIVATE | REQUEST"); if (hfc->l1_state != 3 && hfc->l1_state != 7) { hfc->d_if.ifc.l1l2(&hfc->d_if.ifc, PH_DEACTIVATE | INDICATION, NULL); DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_DEACTIVATE | INDICATION sent (not state 3 or 7)"); } else { if (hfc->l1_state == 7) { /* l1 already active */ hfc->d_if.ifc.l1l2(&hfc-> d_if. ifc, PH_ACTIVATE | INDICATION, NULL); DBG(HFCUSB_DBG_STATES, "HFC-S USB: PH_ACTIVATE | INDICATION sent again ;)"); } else { /* force sending sending INFO1 */ queue_control_request(hfc, HFCUSB_STATES, 0x14, 1); mdelay(1); /* start l1 activation */ queue_control_request(hfc, HFCUSB_STATES, 0x04, 1); if (!timer_pending (&hfc->t3_timer)) { hfc->t3_timer. expires = jiffies + (HFC_TIMER_T3 * HZ) / 1000; add_timer(&hfc-> t3_timer); } } } } else { DBG(HFCUSB_DBG_STATES, "HFC_USB: hfc_usb_d_l2l1 B-chan: PH_ACTIVATE | REQUEST"); setup_bchannel(hfc, (fifo->fifonum == HFCUSB_B1_TX) ? 0 : 1, (long) arg); fifo->hif->l1l2(fifo->hif, PH_ACTIVATE | INDICATION, NULL); } break; case PH_DEACTIVATE | REQUEST: if (fifo->fifonum == HFCUSB_D_TX) { DBG(HFCUSB_DBG_STATES, "HFC_USB: hfc_usb_d_l2l1 D-chan: PH_DEACTIVATE | REQUEST"); } else { DBG(HFCUSB_DBG_STATES, "HFC_USB: hfc_usb_d_l2l1 Bx-chan: PH_DEACTIVATE | REQUEST"); setup_bchannel(hfc, (fifo->fifonum == HFCUSB_B1_TX) ? 0 : 1, (int) L1_MODE_NULL);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?