⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hc_simple.c

📁 linux客户机函数定义的实际例子
💻 C
📖 第 1 页 / 共 3 页
字号:
	struct list_head *lh;

	if (hci == NULL) {
		DBGERR ("sh_schedule_trans: hci == NULL\n");
		return 0;
	}
	if (hci->td_array == NULL) {
		DBGERR ("sh_schedule_trans: hci->td_array == NULL\n");
		return 0;
	}

	if (hci->td_array->len != 0) {
		DBGERR ("ERROR: schedule, hci->td_array->len = 0x%x, s/b: 0\n",
			hci->td_array->len);
	}

	/* schedule the next available interrupt transfer or the next
	 * stage of the interrupt transfer */

	if (hci->td_array->len == 0 && !list_empty (&hci->intr_list)) {
		units_left = sh_scan_urb_list (hci, &hci->intr_list);
	}

	/* schedule the next available control transfer or the next
	 * stage of the control transfer */

	if (hci->td_array->len == 0 && !list_empty (&hci->ctrl_list) && units_left > 0) {
		units_left = sh_scan_urb_list (hci, &hci->ctrl_list);
	}

	/* schedule the next available bulk transfer or the next
	 * stage of the bulk transfer */

	if (hci->td_array->len == 0 && !list_empty (&hci->bulk_list) && units_left > 0) {
		sh_scan_urb_list (hci, &hci->bulk_list);

		/* be fair to each BULK URB (move list head around) 
		 * only when the new SOF happens */

		lh = hci->bulk_list.next;
		list_del (&hci->bulk_list);
		list_add (&hci->bulk_list, lh);
	}
	return 0;
}

/***************************************************************************
 * Function Name : sh_add_packet
 *
 * This function forms the packet and transmit the packet. This function
 * will handle all endpoint type: isochoronus, interrupt, control, and 
 * bulk.
 * 
 * Input: hci = data structure for the host controller 
 *        urb = USB request block data structure 
 *
 * Return: 0 = unsucessful; 1 = successful   
 **************************************************************************/
static int sh_add_packet (hci_t * hci, struct urb * urb)
{
	__u8 *data = NULL;
	int len = 0;
	int toggle = 0;
	int maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));
	int endpoint = usb_pipeendpoint (urb->pipe);
	int address = usb_pipedevice (urb->pipe);
	int slow = (((urb->pipe) >> 26) & 1);
	int out = usb_pipeout (urb->pipe);
	int pid = 0;
	int ret;
	int i = 0;
	int iso = 0;

	DBGFUNC ("enter sh_add_packet\n");
	if (maxps == 0)
		maxps = 8;

	/* calculate len, toggle bit and add the transaction */
	switch (usb_pipetype (urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		pid = out ? PID_OUT : PID_IN;
		iso = 1;
		i = hci->frame_number - urb->start_frame;
		data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
		len = urb->iso_frame_desc[i].length;
		break;

	case PIPE_BULK:	/* BULK and BULK0 */
	case PIPE_INTERRUPT:
		pid = out ? PID_OUT : PID_IN;
		len = urb->transfer_buffer_length - urb->actual_length;
		data = urb->transfer_buffer + urb->actual_length;
		toggle = usb_gettoggle (urb->dev, endpoint, out);
		break;

	case PIPE_CONTROL:
		switch (qu_urbstate (urb)) {
		case US_CTRL_SETUP:
			len = 8;
			pid = PID_SETUP;
			data = urb->setup_packet;
			toggle = 0;
			break;

		case US_CTRL_DATA:
			if (!hci->last_packet_nak) {
				/* The last packet received is not a nak:
				 * reset the nak count
				 */

				hci->nakCnt = 0;
			}
			if (urb->transfer_buffer_length != 0) {
				pid = out ? PID_OUT : PID_IN;
				len = urb->transfer_buffer_length - urb->actual_length;
				data = urb->transfer_buffer + urb->actual_length;
				toggle = (urb->actual_length & maxps) ? 0 : 1;
				usb_settoggle (urb->dev,
					       usb_pipeendpoint (urb->pipe),
					       usb_pipeout (urb->pipe), toggle);
				break;
			} else {
				/* correct state and fall through */
				qu_seturbstate (urb, US_CTRL_ACK);
			}

		case US_CTRL_ACK:
			len = 0;

			/* reply in opposite direction */
			pid = !out ? PID_OUT : PID_IN;
			toggle = 1;
			usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe),
				       usb_pipeout (urb->pipe), toggle);
			break;
		}
	}

	ret =
	    hc_add_trans (hci, len, data, toggle, maxps, slow, endpoint,
			  address, pid, iso, qu_urbstate (urb));

	DBGVERBOSE ("transfer_pa: addr:%d ep:%d pid:%x tog:%x iso:%x sl:%x "
		    "max:%d\n len:%d ret:%d data:%p left:%d\n",
		    address, endpoint, pid, toggle, iso, slow,
		    maxps, len, ret, data, hci->hp.units_left);

	if (ret >= 0) {
		hci->td_array->td[hci->td_array->len].urb = urb;
		hci->td_array->td[hci->td_array->len].len = ret;
		hci->td_array->td[hci->td_array->len].iso_index = i;
		hci->td_array->len++;
		hci->active_trans = 1;
		return 1;
	}
	return 0;
}

/***************************************************************************
 * Function Name : cc_to_error
 *
 * This function maps the SL811HS hardware error code to the linux USB error
 * code.
 * 
 * Input: cc = hardware error code 
 *
 * Return: USB error code   
 **************************************************************************/
static int cc_to_error (int cc)
{
	int errCode = 0;
	if (cc & SL11H_STATMASK_ERROR) {
		errCode |= -EILSEQ;
	} else if (cc & SL11H_STATMASK_OVF) {
		errCode |= -EOVERFLOW;
	} else if (cc & SL11H_STATMASK_STALL) {
		errCode |= -EPIPE;
	}
	return errCode;
}

/***************************************************************************
 * Function Name : sh_done_list
 *
 * This function process the packet when it has done finish transfer.
 * 
 * 1) It handles hardware error
 * 2) It updates the URB state
 * 3) If the USB transaction is complete, it start the return stack path.
 * 
 * Input: hci = data structure for the host controller 
 *        isExcessNak = flag tells if there excess NAK condition occurred 
 *
 * Return:  urb_state or -1 if the transaction has complete   
 **************************************************************************/
static int sh_done_list (hci_t * hci, int *isExcessNak)
{
	int actbytes = 0;
	int active = 0;
	void *data = NULL;
	int cc;
	int maxps;
	int toggle;
	struct urb *urb;
	int urb_state = 0;
	int ret = 1;		/* -1 parse abbort, 1 parse ok, 0 last element */
	int trans = 0;
	int len;
	int iso_index = 0;
	int out;
	int pid = 0;
	int debugLen = 0;

	*isExcessNak = 0;

	DBGFUNC ("enter sh_done_list: td_array->len = 0x%x\n",
		 hci->td_array->len);

	debugLen = hci->td_array->len;
	if (debugLen > 1)
		DBGERR ("sh_done_list: td_array->len = 0x%x > 1\n",
			hci->td_array->len);

	for (trans = 0; ret && trans < hci->td_array->len && trans < MAX_TRANS;
	     trans++) {
		urb = hci->td_array->td[trans].urb;
		len = hci->td_array->td[trans].len;
		out = usb_pipeout (urb->pipe);

		if (usb_pipeisoc (urb->pipe)) {
			iso_index = hci->td_array->td[trans].iso_index;
			data = urb->transfer_buffer + urb->iso_frame_desc[iso_index].offset;
			toggle = 0;
		} else {
			data = urb->transfer_buffer + urb->actual_length;
			toggle = usb_gettoggle (urb->dev,
						usb_pipeendpoint (urb->pipe),
						usb_pipeout (urb->pipe));

		}
		urb_state = qu_urbstate (urb);
		pid = out ? PID_OUT : PID_IN;
		ret = hc_parse_trans (hci, &actbytes, data, &cc, &toggle, len,
				      pid, urb_state);
		maxps = usb_maxpacket (urb->dev, urb->pipe, usb_pipeout (urb->pipe));

		if (maxps == 0)
			maxps = 8;

		active = (urb_state != US_CTRL_SETUP) && (actbytes && !(actbytes & (maxps - 1)));

		/* If the transfer is not bulk in, then it is necessary to get all
		 * data specify by the urb->transfer_len.
		 */

		if (!(usb_pipebulk (urb->pipe) && usb_pipein (urb->pipe)))
			active = active && (urb->transfer_buffer_length != urb->actual_length + actbytes);

		if (urb->transfer_buffer_length == urb->actual_length + actbytes)
			active = 0;

		if ((cc &
		     (SL11H_STATMASK_ERROR | SL11H_STATMASK_TMOUT |
		      SL11H_STATMASK_OVF | SL11H_STATMASK_STALL))
		    && !(cc & SL11H_STATMASK_NAK)) {
			if (++urb->error_count > 3) {
				DBGERR ("done_list: excessive error: errcount = 0x%x, cc = 0x%x\n",
					urb->error_count, cc);
				urb_state = 0;
				active = 0;
			} else {
				DBGERR ("done_list: packet err, cc = 0x%x, "
					" urb->length = 0x%x, actual_len = 0x%x,"
					" urb_state =0x%x\n",
					cc, urb->transfer_buffer_length,
					urb->actual_length, urb_state);
//			if (cc & SL11H_STATMASK_STALL) {
				/* The USB function is STALLED on a control pipe (0), 
				 * then it needs to send the SETUP command again to 
				 * clear the STALL condition
				 */

//				if (usb_pipeendpoint (urb->pipe) == 0) {
//					urb_state = 2;  
//					active = 0;
//				}
//			} else   
				active = 1;
			}
		} else {
			if (cc & SL11H_STATMASK_NAK) {
				if (hci->nakCnt < 0x10000) {
					hci->nakCnt++;
					hci->last_packet_nak = 1;
					active = 1;
					*isExcessNak = 0;
				} else {
					DBGERR ("done_list: nak count exceed limit\n");
					active = 0;
					*isExcessNak = 1;
					hci->nakCnt = 0;
				}
			} else {
				hci->nakCnt = 0;
				hci->last_packet_nak = 0;
			}

			if (urb_state != US_CTRL_SETUP) {
				/* no error */
				urb->actual_length += actbytes;
				usb_settoggle (urb->dev,
					       usb_pipeendpoint (urb->pipe),
					       usb_pipeout (urb->pipe), toggle);
			}
			if (usb_pipeisoc (urb->pipe)) {
				urb->iso_frame_desc[iso_index].actual_length = actbytes;
				urb->iso_frame_desc[iso_index].status = cc_to_error (cc);
				active = (iso_index < urb->number_of_packets);
			}
		}
		if (!active) {
			if (!urb_state) {
				urb->status = cc_to_error (cc);
				if (urb->status) {
					DBGERR ("error on received packet: urb->status = 0x%x\n",
						urb->status);
				}
				hci->td_array->len = 0;
				qu_return_urb (hci, urb, 1);
				return -1;
			} else {
				/* We do not want to decrement the urb_state if exceeded nak,
				 * because we need to finish the data stage of the control 
				 * packet 
				 */

				if (!(*isExcessNak))
					urb_state--;
				qu_seturbstate (urb, urb_state);
			}
		}
	}

	if (urb_state < 0)
		DBGERR ("ERROR: done_list, urb_state = %d, suppose > 0\n",
			urb_state);
	if (debugLen != hci->td_array->len) {
		DBGERR ("ERROR: done_list, debugLen!= td_array->len,"
			"debugLen = 0x%x, hci->td_array->len = 0x%x\n",
			debugLen, hci->td_array->len);
	}

	hci->td_array->len = 0;

	return urb_state;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -