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

📄 hc_sl811.c

📁 linux下面的SL811驱动硬件平台S3C44B0
💻 C
📖 第 1 页 / 共 5 页
字号:
		goto out_unlock;
	}
	
	if (!sl811_alloc_urb_priv(urb)) {
		ret = -ENOMEM;
		//printk("righto: run to sl811_alloc_urb_priv()\n");
		goto out_unlock;
	}
	
	switch (usb_pipetype(urb->pipe)) 
	{
	case PIPE_ISOCHRONOUS:
		if (urb->number_of_packets <= 0) {
			ret = -EINVAL;
			break;
		}
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0) {
			ret = bustime;
			break;
		}
		if (!(ret = sl811_submit_isochronous(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
		
		//printk("righto: run to PIPE_ISOCHRONOUS\n");
		break;
	case PIPE_INTERRUPT:
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0)
			ret = bustime;
		else if (!(ret = sl811_submit_interrupt(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 0);
		//printk("righto: run to PIPE_INTERRUPT\n");
		break;
	case PIPE_CONTROL:
		ret = sl811_submit_control(urb);
		//printk("righto: run to PIPE_CONTOL\n");
		break;
	case PIPE_BULK:
		ret = sl811_submit_bulk(urb);
		//printk("righto: run to PIPE_BULK\n");
		break;
	}
	
	if (!ret) {
		((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
		list_add(&urb->urb_list, head);
		PDEBUG(4, "add to type list");
		urb->status = -EINPROGRESS;
		if (++hc->active_urbs == 1)
		{
			//printk("righto: sl811_enable_interrupt()\n");
			sl811_enable_interrupt(hc);
		}
		//printk("righto: run to ret\n");
		goto out_unlock;	
	} else {
		PDEBUG(2, "submit urb fail! error = %d", ret);
		//printk("righto: run to else");
		sl811_free_urb_priv(urb);
	}
	
out_unlock:	
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);

	return ret;
}

/*
 * Submit the urb the wait list.
 */
static int sl811_submit_urb_with_lock(struct urb *urb)
{
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct list_head *head = NULL;
	int bustime;
	int ret = 0;
	
	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_alloc_urb_priv(urb)) {
		ret = -ENOMEM;
		goto out_unlock;
	}
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		if (urb->number_of_packets <= 0) {
			ret = -EINVAL;
			break;
		}
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0) {
			ret = bustime;
			break;
		}
		if (!(ret = sl811_submit_isochronous(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
		break;
	case PIPE_INTERRUPT:
		bustime = usb_check_bandwidth(urb->dev, urb);
		if (bustime < 0)
			ret = bustime;
		else if (!(ret = sl811_submit_interrupt(urb)))
			usb_claim_bandwidth(urb->dev, urb, bustime, 0);
		break;
	case PIPE_CONTROL:
		ret = sl811_submit_control(urb);
		break;
	case PIPE_BULK:
		ret = sl811_submit_bulk(urb);
		break;
	}
	
	if (ret == 0) {
		((struct sl811_urb_priv *)urb->hcpriv)->inserttime = jiffies;
		list_add(&urb->urb_list, head);
		PDEBUG(4, "add to type list");
		urb->status = -EINPROGRESS;
		if (++hc->active_urbs == 1)
			sl811_enable_interrupt(hc);
		goto out_unlock;	
	} else {
		PDEBUG(2, "submit urb fail! error = %d", ret);
		sl811_free_urb_priv(urb);
	}
	
out_unlock:	
	spin_unlock(&urb->lock);

	return ret;
}

/*
 * Reset the urb
 */
static void sl811_reset_urb(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;

	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		sl811_reset_isochronous(urb);
		break;
	case PIPE_INTERRUPT:
		sl811_reset_interrupt(urb);
		break;
	case PIPE_CONTROL:
		return;
	case PIPE_BULK:
		sl811_reset_bulk(urb);
		break;
	}
	urbp->inserttime = jiffies;
}

/*
 * Return the result of a transfer
 */
static void sl811_result_urb(struct urb *urb)
{
	struct sl811_urb_priv *urbp = urb->hcpriv;
	struct sl811_hc *hc = urb->dev->bus->hcpriv;
	struct list_head *head = NULL;
	struct urb *u = NULL;
	int reset = 0;
	int ring = 0;

	if (urb->status != -EINPROGRESS) {
		PDEBUG(1, "urb status is not EINPROGRESS!");
		return ;
	}
	
	spin_lock(&urb->lock);
	
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_ISOCHRONOUS:
		head = &hc->iso_list;
		sl811_result_isochronous(urb);
		
		// if the urb is not unlink and is in a urb "ring", we reset it
		if (!urbp->unlink && urb->next) 
			ring = 1;
		break;
	case PIPE_INTERRUPT:
		head = &hc->intr_list;
		sl811_result_interrupt(urb);
		
		// if the urb is not unlink and not "once" query, we reset.
		if (!urbp->unlink && urb->interval)
			reset = 1;
		break;
	case PIPE_CONTROL:
		head = &hc->ctrl_list;
		sl811_result_control(urb);
		break;
	case PIPE_BULK:
		head = &hc->bulk_list;
		sl811_result_bulk(urb);
		
		// if the urb is not unlink and is in a urb "ring", we reset it
		if (!urbp->unlink && urb->next)
			ring = 1;
		break;
	}
	
	PDEBUG(4, "result urb status = %d", urb->status);
	
	if (ring && urb->next == urb)
		reset = 1;
	
	if (!reset) {
		switch (usb_pipetype(urb->pipe)) {
		case PIPE_ISOCHRONOUS:
			usb_release_bandwidth(urb->dev, urb, 1);
			break;
		case PIPE_INTERRUPT:
			usb_release_bandwidth(urb->dev, urb, 0);
			break;
		}
		sl811_free_urb_priv(urb);
	}
	
	spin_unlock(&urb->lock);
	
	if (urb->complete)
		urb->complete(urb);
	
	if (reset) {
		spin_lock(&urb->lock);
		sl811_reset_urb(urb);
		if (usb_pipeint(urb->pipe))
			list_add(&urb->urb_list, &hc->idle_intr_list);
		else
			list_add(&urb->urb_list, head);
		spin_unlock(&urb->lock);
	} else {
		if (--hc->active_urbs <= 0) {
			hc->active_urbs = 0;
			sl811_disable_interrupt(hc);
		}
		
		if (ring) 
			u = urb->next;
		else
			u = sl811_find_same_devep(&hc->wait_list, urb);
			
		if (u) {
			if (!list_empty(&u->urb_list))
				list_del(&u->urb_list);
			if (sl811_submit_urb_with_lock(u))
				list_add(&u->urb_list, &hc->wait_list);
		}
	}
}


#ifdef SL811_TIMEOUT

/*
 * Unlink the urb from the urb list
 */
static int sl811_unlink_urb(struct urb *urb)
{
	unsigned long flags;
	struct sl811_hc *hc;
	struct sl811_urb_priv *urbp;
	int call = 0;
	int schedule = 0;
	int count = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus) {
		PDEBUG(1, "dev or bus is null");
		return -ENODEV;
	}
	
	hc = urb->dev->bus->hcpriv; 
	urbp = urb->hcpriv;
	
	/* a request to the virtual root hub */
	if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
		return sl811_rh_unlink_urb(urb); 
	
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);

	// in wait list
	if (sl811_find_same_urb(&hc->wait_list, urb)) {	
		PDEBUG(4, "unlink urb in wait list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		call = 1;
		goto out;
	}
	
	// in intr idle list.
	if (sl811_find_same_urb(&hc->idle_intr_list, urb)) {	
		PDEBUG(4, "unlink urb in idle intr list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		sl811_free_urb_priv(urb);
		usb_release_bandwidth(urb->dev, urb, 0);
		if (--hc->active_urbs <= 0) {
			hc->active_urbs = 0;
			sl811_disable_interrupt(hc);
		}
		call = 1;
		goto out;
	}

	if (urb->status == -EINPROGRESS) {  
		PDEBUG(3, "urb is still in progress");
		urbp->unlink = 1;

re_unlink:
		// Is it in progress?
		urbp = urb->hcpriv;
		if (urbp && hc->cur_td == urbp->cur_td) {
			++count;
			if (sl811_read(hc, 0) & SL811_USB_CTRL_ARM) {
				PDEBUG(3, "unlink: cur td is still in progress! count = %d", count);
re_schedule:				
				schedule = 1;
				spin_unlock(&urb->lock);
				spin_unlock_irqrestore(&hc->hc_lock, flags);
				schedule_timeout(HZ/50);
				spin_lock_irqsave(&hc->hc_lock, flags);
				spin_lock(&urb->lock);
			} else {
				PDEBUG(3, "unlink: lost of interrupt? do parse! count = %d", count);
				spin_unlock(&urb->lock);
				sl811_transfer_done(hc, 0);
				spin_lock(&urb->lock);
			}
			goto re_unlink;
		}
		
		if (list_empty(&urb->urb_list)) {
			PDEBUG(3, "unlink: list empty!");
			goto out;
		}
			
		if (urb->transfer_flags & USB_TIMEOUT_KILLED) { 
			PDEBUG(3, "unlink: time out killed");
			// it is timeout killed by us 
			goto result;
		} else if (urb->transfer_flags & USB_ASYNC_UNLINK) { 
			// we do nothing, just let it be processing later
			PDEBUG(3, "unlink async, do nothing");
			goto out;
		} else {
			// synchron without callback
			PDEBUG(3, "unlink synchron, we wait the urb complete or timeout");
			if (schedule == 0) {
				PDEBUG(3, "goto re_schedule");
				goto re_schedule;
			} else {
				PDEBUG(3, "already scheduled");
				goto result;
			}
		}
	} else if (!list_empty(&urb->urb_list)) {
		PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
		//list_del_init(&urb->urb_list);
		//call = 1;
	}

out:
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	if (call && urb->complete)
		urb->complete(urb);
	
	return 0;
	
result:
	spin_unlock(&urb->lock);
	
	list_del_init(&urb->urb_list);
	sl811_result_urb(urb);	
	
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	return 0;
}

#else

/*
 * Unlink the urb from the urb list
 */
static int sl811_unlink_urb(struct urb *urb)
{
	unsigned long flags;
	struct sl811_hc *hc;
	struct sl811_urb_priv *urbp;
	int call = 0;
	
	if (!urb) {
		PDEBUG(1, "urb is null");
		return -EINVAL;
	}
	
	if (!urb->dev || !urb->dev->bus) {
		PDEBUG(1, "dev or bus is null");
		return -ENODEV;
	}
	
	hc = urb->dev->bus->hcpriv; 
	urbp = urb->hcpriv;
	
	/* a request to the virtual root hub */
	if (usb_pipedevice(urb->pipe) == hc->rh.devnum)
		return sl811_rh_unlink_urb(urb); 
	
	spin_lock_irqsave(&hc->hc_lock, flags);
	spin_lock(&urb->lock);

	// in wait list
	if (sl811_find_same_urb(&hc->wait_list, urb)) {	
		PDEBUG(2, "unlink urb in wait list");
		list_del_init(&urb->urb_list);
		urb->status = -ENOENT;
		call = 1;
		goto out;
	}
	
	if (urb->status == -EINPROGRESS) {  
		PDEBUG(2, "urb is still in progress");
		urbp->unlink = 1;

		// Is it in progress?
		urbp = urb->hcpriv;
		if (urbp && hc->cur_td == urbp->cur_td) {
			// simple, let it out
			PDEBUG(2, "unlink: cur td is still in progress!");
			hc->cur_td = NULL;
		}
		
		goto result;
	} else if (!list_empty(&urb->urb_list)) {
		PDEBUG(1, "urb = %p, status = %d is in a list, why?", urb, urb->status);
		list_del_init(&urb->urb_list);
		if (urbp)
			goto result;
		else
			call = 1;
	}

out:
	spin_unlock(&urb->lock);
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	if (call && urb->complete)
		urb->complete(urb);
			
	return 0;
	
result:
	spin_unlock(&urb->lock);
	
	list_del_init(&urb->urb_list);
	sl811_result_urb(urb);	
	
	spin_unlock_irqrestore(&hc->hc_lock, flags);
	
	return 0;
}

#endif

static int sl811_get_current_frame_number(struct usb_device *usb_dev)
{
	return ((struct sl811_hc *)(usb_dev->bus->hcpriv))->frame_number;
}

static struct usb_operations sl811_device_operations = 
{
	sl811_alloc_dev_priv,
	sl811_free_dev_priv,
	sl811_get_current_frame_number,
	sl811_submit_urb,
	sl811_unlink_urb
};

/*
 * This	functions transmit a td.
 */
static inline void sl811_trans_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
	sl811_print_td(4, td);
	sl811_write_buf(hc, SL811_ADDR_A,  &td->addr, 4);
	if (td->len && (td->ctrl & SL811_USB_CTRL_DIR_OUT))
		sl811_write_buf(hc, td->addr,  td->buf, td->len);

	sl811_write(hc,	SL811_CTRL_A, td->ctrl);
}

		
/*
 * This	function checks	the status of the transmitted or received packet
 * and copy the	data from the SL811HS register into a buffer.
 */
static void sl811_parse_cur_td(struct sl811_hc *hc, struct sl811_td *td)
{
	struct urb *urb = td->urb;
#ifdef SL811_DEBUG
	int dev = usb_pipedevice(td->urb->pipe);
	int ep = usb_pipeendpoint(td->urb->pipe);
#endif

	sl811_read_buf(hc, SL811_STS_A, &td->status, 2);
	
	if (td->status & SL811_USB_STS_ACK) {
		td->done = 1;
		

⌨️ 快捷键说明

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