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

📄 hc_sl811.c

📁 linux下面的SL811驱动硬件平台S3C44B0
💻 C
📖 第 1 页 / 共 5 页
字号:
	else if (td->done && td->td_status) {
		urb->status = td->td_status;
reset_toggle:
		toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
		usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
		PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
		return ;
	}
	// unlink, and not do transfer yet
	else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
		urb->status = -ENOENT;
		PDEBUG(3, "unlink and not transfer!");
		return ;
	}
	// unlink, and transfer not complete yet.
	else if (td->done == 0 && urbp->unlink && td->td_status) {
		urb->status = -ENOENT;
		PDEBUG(3, "unlink and not complete!");
		goto reset_toggle;
	}
	// must be bug!!!
	else {// (td->done == 0 && urbp->unlink == 0)
		PDEBUG(1, "we should not get here!");
		urb->status = -EPIPE;
		return ;
	}
}

/*
 * Control transfers
 */
static int sl811_submit_control(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = 0;
	__u8 ctrl = 0;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	
	PDEBUG(4, "enter, urb = %p", urb);
	
	if (usb_pipeslow(urb->pipe) && !(hc->rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED))
		ctrl |= SL811_USB_CTRL_PREAMBLE;
	
	/* Build SETUP TD */
	pidep = PIDEP(USB_PID_SETUP, usb_pipeendpoint(urb->pipe));
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE | SL811_USB_CTRL_DIR_OUT;
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;
		
	sl811_fill_td(td, ctrl, SL811_DATA_START, 8, pidep, dev, urb->setup_packet);
	sl811_calc_td_time(td);
	
	urbp->cur_td = urbp->first_td = td;
	
	/*
	 * If direction is "send", change the frame from SETUP (0x2D)
	 * to OUT (0xE1). Else change it from SETUP to IN (0x69).
	 */
	pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
	else
		ctrl &= ~SL811_USB_CTRL_DIR_OUT;

	/* Build the DATA TD's */
	while (len > 0) {
		int pktsze = len;

		if (pktsze > maxsze)
			pktsze = maxsze;

		/* Alternate Data0/1 (start with Data1) */
		ctrl ^= SL811_USB_CTRL_TOGGLE_1;
	
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);	
		sl811_calc_td_time(td);
		
		data += pktsze;
		len -= pktsze;
	}

	/* Build the final TD for control status */
	td = sl811_alloc_td(urb);
	if (!td)
		return -ENOMEM;

	/* It's IN if the pipe is an output pipe or we're not expecting data back */
	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length) {
		pidep = PIDEP(USB_PID_IN, usb_pipeendpoint(urb->pipe));
		ctrl &= ~SL811_USB_CTRL_DIR_OUT;	
	} else {
		pidep = PIDEP(USB_PID_OUT, usb_pipeendpoint(urb->pipe));
		ctrl |= SL811_USB_CTRL_DIR_OUT;
	}
		
	/* End in Data1 */
	ctrl |= SL811_USB_CTRL_TOGGLE_1;

	sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
	sl811_calc_td_time(td);
	urbp->last_td = td;
/*	
// for debug
	{
		struct list_head *head, *tmp;
		struct sl811_td *td;
		int i = 0;
		head = &urbp->td_list;
		tmp = head->next;
	
		if (list_empty(&urbp->td_list)) {
			PDEBUG(1, "bug!!! td list is empty!");
			return -ENODEV;
		}
		
		while (tmp != head) {
			++i;
			td = list_entry(tmp, struct sl811_td, td_list);
			PDEBUG(3, "td = %p, i = %d", td, i);
			tmp = tmp->next;
		}
	}
*/	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Result the control urb.
 */
static void sl811_result_control(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;

	PDEBUG(4, "enter, urb = %p", urb);
	
	if (list_empty(&urbp->td_list)) {
		PDEBUG(1, "td list is empty");
		return ;
	}

	head = &urbp->td_list;

	tmp = head->next;
	td = list_entry(tmp, struct sl811_td, td_list);

	/* The first TD is the SETUP phase, check the status, but skip the count */
	if (!td->done) {
		PDEBUG(3, "setup phase error, td = %p, done = %d", td, td->done);
		goto err_done;
	}
	if (td->td_status)  {
		PDEBUG(3, "setup phase error, td = %p, td status = %d", td, td->td_status);
		goto err_status;
	}

	urb->actual_length = 0;

	/* The rest of the TD's (but the last) are data */
	tmp = tmp->next;
	while (tmp != head && tmp->next != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;
		if (!td->done) {
			PDEBUG(3, "data phase error, td = %p, done = %d", td, td->done);
			goto err_done;
		}
		if (td->td_status)  {
			PDEBUG(3, "data phase error, td = %p, td status = %d", td, td->td_status);
			goto err_status;
		}

		urb->actual_length += td->len - td->left;
		// short packet.
		if (td->left) {
			PDEBUG(3, "data phase short packet, td = %p, count = %d", td, td->len - td->left);
			break;
		}
	}

	/* The last td is status phase */
	td = urbp->last_td;
	if (!td->done) {
		PDEBUG(3, "status phase error, td = %p, done = %d", td, td->done);
		goto err_done;
	}
	if (td->td_status)  {
		PDEBUG(3, "status phase error, td = %p, td status = %d", td, td->td_status);
		goto err_status;
	}
	
	PDEBUG(4, "leave success");
	
	urb->status = 0;
	return ;

err_done:
	if (urbp->unlink)
		urb->status = -ENOENT;
	else {
		PDEBUG(1, "we should not get here! td = %p", td);
		urb->status = -EPIPE;
	}
	return ;	

err_status:
	urb->status = td->td_status;		
	return ;
}

/*
 * Bulk transfers
 */
static int sl811_submit_bulk(struct urb *urb)
{
	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
	int len = urb->transfer_buffer_length;
	__u8 *data = urb->transfer_buffer;
	__u8 dev = usb_pipedevice(urb->pipe);
	__u8 pidep = PIDEP(usb_packetid(urb->pipe), usb_pipeendpoint(urb->pipe));
	__u8 ctrl = 0;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;

	PDEBUG(4, "enter, urb = %p", urb);
		
	if (len < 0) {
		PDEBUG(1, "error, urb = %p, len = %d", urb, len);
		return -EINVAL;
	}

	/* Can't have low speed bulk transfers */
	if (usb_pipeslow(urb->pipe)) {
		PDEBUG(1, "error, urb = %p, low speed device", urb);
		return -EINVAL;
	}

	if (usb_pipeout(urb->pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
		
	ctrl |= SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
			
	/* Build the DATA TD's */
	do {	/* Allow zero length packets */
		int pktsze = len;

		if (pktsze > maxsze)
			pktsze = maxsze;

		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		/* Alternate Data0/1 (start with Data1) */
		ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));		
		
		sl811_fill_td(td, ctrl, SL811_DATA_START, pktsze, pidep, dev, data);
		sl811_calc_td_time(td);
		
		if (urbp->cur_td == NULL)
			urbp->cur_td = urbp->first_td = td;
			
		data += pktsze;
		len -= maxsze;
	} while (len > 0);

	/*
	 * USB_ZERO_PACKET means adding a 0-length packet, if
	 * direction is OUT and the transfer_length was an
	 * exact multiple of maxsze, hence
	 * (len = transfer_length - N * maxsze) == 0
	 * however, if transfer_length == 0, the zero packet
	 * was already prepared above.
	 */
	if (usb_pipeout(urb->pipe) && (urb->transfer_flags & USB_ZERO_PACKET) &&
	   !len && urb->transfer_buffer_length) {
		
		td = sl811_alloc_td(urb);
		if (!td)
			return -ENOMEM;

		/* Alternate Data0/1 (start with Data1) */
		ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
			
		sl811_fill_td(td, ctrl, SL811_DATA_START, 0, pidep, dev, 0);
		sl811_calc_td_time(td);
	}
	
	urbp->last_td = td;
	
	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Reset bulk transfers
 */
static int sl811_reset_bulk(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td;
	struct list_head *head, *tmp;

	PDEBUG(4, "enter, urb = %p", urb);
	
	
	head = &urbp->td_list;	
	tmp = head->next;
	
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);

		/* Alternate Data0/1 (start with Data1) */
		td->ctrl &= ~SL811_USB_CTRL_TOGGLE_1;
		if (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)))
			td->ctrl |= SL811_USB_CTRL_TOGGLE_1;
		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
		
		sl811_reset_td(td);
	} 

	urb->status = -EINPROGRESS;
	urb->actual_length = 0;
	urbp->cur_td = urbp->first_td;

	PDEBUG(4, "leave success");
	
	return 0;
}

/*
 * Result the bulk urb.
 */
static void sl811_result_bulk(struct urb *urb)
{
	struct list_head *tmp, *head;
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_td *td = NULL;
	int toggle;

	PDEBUG(4, "enter, urb = %p", urb);
	
	urb->actual_length = 0;

	head = &urbp->td_list;
	tmp = head->next;
	while (tmp != head) {
		td = list_entry(tmp, struct sl811_td, td_list);
		tmp = tmp->next;

		// success.
		if (td->done && td->td_status == 0) {
			urb->actual_length += td->len - td->left;
			
			// short packet
			if (td->left) {
				urb->status = 0;
				PDEBUG(3, "short packet, td = %p, count = %d", td, td->len - td->left);
				goto reset_toggle;
			}
		}
		// tranfer is done but fail, reset the toggle.
		else if (td->done && td->td_status) {
			urb->status = td->td_status;
			PDEBUG(3, "error: td = %p, td status = %d", td, td->td_status);
			goto reset_toggle;
		}
		// unlink, and not do transfer yet
		else if (td->done == 0 && urbp->unlink && td->td_status == 0) {
			urb->status = -ENOENT;
			PDEBUG(3, "unlink and not transfer!");
			return ;
		}
		// unlink, and transfer not complete yet.
		else if (td->done == 0 && urbp->unlink && td->td_status) {
			PDEBUG(3, "unlink and not complete!");
			urb->status = -ENOENT;
			goto reset_toggle;
		}
		// must be bug!!!
		else {// (td->done == 0 && urbp->unlink == 0)
			urb->status = -EPIPE;
			PDEBUG(1, "we should not get here!");
			return ;
		}
	}
	
	PDEBUG(4, "leave success");		
	urb->status = 0;
	return ;

reset_toggle:
	toggle = (td->ctrl & SL811_USB_CTRL_TOGGLE_1) ? 1 : 0;
	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe), toggle);
}

/*
 * Find the first urb have the same dev and endpoint.
 */
static inline int sl811_find_same_urb(struct list_head *head, struct urb *urb)
{
	struct list_head *tmp;
	struct urb *u;
	
	if (!head || !urb)
		return 0;
		
	tmp = head->next;
	
	while (tmp != head) {
		u = list_entry(tmp, struct urb, urb_list);
		if (u == urb)
			return 1;
		tmp = tmp->next;	
	}
	
	return 0;
}

/*
 * Find the first urb have the same dev and endpoint.
 */
static inline struct urb* sl811_find_same_devep(struct list_head *head, struct urb *urb)
{
	struct list_head *tmp;
	struct urb *u;
	
	if (!head || !urb)
		return NULL;
		
	tmp = head->next;
	
	while (tmp != head) {
		u = list_entry(tmp, struct urb, urb_list);
		if ((usb_pipe_endpdev(u->pipe)) == (usb_pipe_endpdev(urb->pipe)))
			return u;
		tmp = tmp->next;	
	}
	
	return NULL;
}

/*
 * This function is called by the USB core API when an URB is available to
 * process. 
 */
static int sl811_submit_urb(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	unsigned int pipe = urb->pipe;
	struct list_head *head = NULL;
	unsigned long flags;
	int bustime;
	int ret = 0;
	int temp = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (urb->hcpriv) {
		PDEBUG(1, "urbp is not null, urb = %p, urbp = %p", urb, urb->hcpriv);
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus || !hc)  {
		PDEBUG(1, "dev or bus or hc is null");
		return -ENODEV;
	}
	
	if (usb_endpoint_halted(urb->dev, usb_pipeendpoint(pipe), usb_pipeout(pipe))) {
		PDEBUG(2, "sl811_submit_urb: endpoint_halted");
		return -EPIPE;
	}
	
	if (usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)) > SL811_DATA_LIMIT) {
		printk(KERN_ERR "Packet size is big for SL811, should < %d!\n", SL811_DATA_LIMIT);
		return -EINVAL;
	
		printk(KERN_ERR "out packet isze = %d   in packet size = %d\n", urb->dev->epmaxpacketout[usb_pipeendpoint(pipe)], urb->dev->epmaxpacketin[usb_pipeendpoint(pipe)]);
		return -EINVAL;
	}
	
	
	/* a request to the virtual root hub */
	temp = pipe;
	//printk("righto:usb_pipedevice:%d, pipe:%d, rh.devnum:%d\n",usb_pipedevice(temp), temp, hc->rh.devnum );
 
	if ( usb_pipedevice(pipe) == hc->rh.devnum)
	{
		//printk("righto: run to usb_pipedevice(pipe), then return sl811_rh_submit_urb()\n");
		return sl811_rh_submit_urb(urb);
	}
	
 
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		head = &hc->iso_list;
		break;
	case PIPE_INTERRUPT:
		head = &hc->intr_list;
		break;
	case PIPE_CONTROL:
		head = &hc->ctrl_list;
		break;
	case PIPE_BULK:
		head = &hc->bulk_list;
		break;
	}
		
	if (sl811_find_same_devep(head, urb)) {
		list_add(&urb->urb_list, &hc->wait_list);
		PDEBUG(4, "add to wait list");
		//printk("righto: run to sl811_find_same_devep()\n");

⌨️ 快捷键说明

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