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 + -
显示快捷键?