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

📄 hc_simple.c

📁 linux2.4.20下的针对三星公司的s3c2410的usb模块驱动代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	return 0;}/*************************************************************************** * Function Name : qu_next_urb * * This function removes the URB from the queue and add the next URB to  * active list.  *  * Input: hci = data structure for the host controller  *        urb = USB request block data structure  *        resub_ok = resubmit flag * * Return: pointer to the next urb   **************************************************************************/static struct urb *qu_next_urb (hci_t * hci, struct urb * urb, int resub_ok){	struct hci_device *hci_dev = usb_to_hci (urb->dev);	epd_t *ed = &hci_dev->ed[qu_pipeindex (urb->pipe)];	DBGFUNC ("enter qu_next_urb\n");	list_del (&urb->urb_list);	INIT_LIST_HEAD (&urb->urb_list);	if (ed->pipe_head == urb) {#ifdef HC_URB_TIMEOUT		if (urb->timeout)			del_timer (&ed->timeout);#endif		if (!--hci->active_urbs)			hc_stop_int (hci);		if (!list_empty (&ed->urb_queue)) {			urb = list_entry (ed->urb_queue.next, struct urb, urb_list);			list_del (&urb->urb_list);			INIT_LIST_HEAD (&urb->urb_list);			ed->pipe_head = urb;			qu_queue_active_urb (hci, urb, ed);		} else {			ed->pipe_head = NULL;			urb = NULL;		}	}	return urb;}/*************************************************************************** * Function Name : qu_return_urb * * This function is part of the return path.    *  * Input: hci = data structure for the host controller  *        urb = USB request block data structure  *        resub_ok = resubmit flag * * Return: pointer to the next urb   **************************************************************************/static struct urb *qu_return_urb (hci_t * hci, struct urb * urb, int resub_ok){	struct urb *next_urb;	DBGFUNC ("enter qu_return_rub\n");	next_urb = qu_next_urb (hci, urb, resub_ok);	hcs_return_urb (hci, urb, resub_ok);	return next_urb;}/*************************************************************************** * Function Name : sh_scan_iso_urb_list * * This function goes throught the isochronous urb list and schedule the  * the transfer.    * * Note: This function has not tested yet *  * Input: hci = data structure for the host controller  *        list_lh = pointer to the isochronous list  *        frame_number = the frame number  * * Return: 0 = unsuccessful; 1 = successful   **************************************************************************/static int sh_scan_iso_urb_list (hci_t * hci, struct list_head *list_lh,				 int frame_number){	struct list_head *lh = list_lh->next;	struct urb *urb;	DBGFUNC ("enter sh_scan_iso_urb_list\n");	hci->td_array->len = 0;	while (lh != list_lh) {		urb = list_entry (lh, struct urb, urb_list);		lh = lh->next;		if (((frame_number - urb->start_frame) & 0x7ff) <		    urb->number_of_packets) {			if (!sh_add_packet (hci, urb)) {				return 0;			} else {				if (((frame_number -				      urb->start_frame) & 0x7ff) > 0x400) {					if (qu_urbstate (urb) > 0)						urb = qu_return_urb (hci, urb, 1);					else						urb = qu_next_urb (hci, urb, 1);					if (lh == list_lh && urb)						lh = &urb->urb_list;				}			}		}	}	return 1;}/*************************************************************************** * Function Name : sh_scan_urb_list * * This function goes through the urb list and schedule the  * the transaction.    *  * Input: hci = data structure for the host controller  *        list_lh = pointer to the isochronous list  * * Return: 0 = unsuccessful; 1 = successful   **************************************************************************/static int sh_scan_urb_list (hci_t * hci, struct list_head *list_lh){	struct list_head *lh = NULL;	struct urb *urb;	if (list_lh == NULL) {		DBGERR ("sh_scan_urb_list: error, list_lh == NULL\n");	}	DBGFUNC ("enter sh_scan_urb_list: frame# \n");	list_for_each (lh, list_lh) {		urb = list_entry (lh, struct urb, urb_list);		if (urb == NULL)			return 1;		if (!usb_pipeint (urb->pipe)		    || (((hci->frame_number - urb->start_frame)			 & 0x7ff) >= urb->interval)) {			DBGVERBOSE ("sh_scan_urb_list !INT: %d fr_no: %d int: %d pint: %d\n",				    urb->start_frame, hci->frame_number, urb->interval,				    usb_pipeint (urb->pipe));			if (!sh_add_packet (hci, urb)) {				return 0;			} else {				DBGVERBOSE ("INT: start: %d fr_no: %d int: %d pint: %d\n",					    urb->start_frame, hci->frame_number,					    urb->interval, usb_pipeint (urb->pipe));				urb->start_frame = hci->frame_number;				return 0;			}		}	}	return 1;}/*************************************************************************** * Function Name : sh_shedule_trans * * This function schedule the USB transaction. * This function will process the endpoint in the following order:  * interrupt, control, and bulk.     *  * Input: hci = data structure for the host controller  *        isSOF = flag indicate if Start Of Frame has occurred  * * Return: 0    **************************************************************************/static int sh_schedule_trans (hci_t * hci, int isSOF){	int units_left = 1;	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 + -