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

📄 sl811.c

📁 在LINUX下驱动USB芯片SL811的程序源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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;}#endifstatic 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;		/*		if ((td->ctrl & SL811_USB_CTRL_TOGGLE_1) != (td->status & SL811_USB_STS_TOGGLE_1)) {			PDEBUG(2, "dev %d endpoint %d unexpect data toggle!", dev, ep);			td->td_status = -EILSEQ;		}*/				if (!(td->ctrl & SL811_USB_CTRL_DIR_OUT) && td->len > 0)			sl811_read_buf(hc, td->addr, td->buf, td->len - td->left);					if (td->left && (urb->transfer_flags & USB_DISABLE_SPD)) {			PDEBUG(2, "dev %d endpoint %d unexpect short packet! td = %p", dev, ep, td);			td->td_status = -EREMOTEIO;		} else			td->td_status = 0;	} else if (td->status & SL811_USB_STS_STALL) {		PDEBUG(2, "dev %d endpoint %d halt, td = %p", dev, ep, td);		td->td_status = -EPIPE;		if (urb->dev)			usb_endpoint_halt(td->urb->dev, usb_pipeendpoint(td->urb->pipe), usb_pipeout(td->urb->pipe));		td->done = 1;	} else if (td->status & SL811_USB_STS_OVERFLOW) {		PDEBUG(1, "dev %d endpoint %d overflow, sl811 only support packet less than %d", dev, ep, SL811_DATA_LIMIT);			td->td_status = -EOVERFLOW;		td->done = 1;	} else if (td->status & SL811_USB_STS_TIMEOUT ) {		PDEBUG(2, "dev %d endpoint %d timeout, td = %p", dev, ep, td);			td->td_status = -ETIMEDOUT;		if (--td->errcnt == 0)			td->done = 1;	} else if (td->status & SL811_USB_STS_ERROR) {		PDEBUG(2, "dev %d endpoint %d error, td = %p", dev, ep, td);		td->td_status = -EILSEQ;		if (--td->errcnt == 0)			td->done = 1;	} else if (td->status & SL811_USB_STS_NAK) {		++td->nakcnt;		PDEBUG(3, "dev %d endpoint %d nak, td = %p, count = %d", dev, ep, td, td->nakcnt);		td->td_status = -EINPROGRESS;		if (!usb_pipeslow(td->urb->pipe) && td->nakcnt > 1024) {			PDEBUG(2, "too many naks, td = %p, count = %d", td, td->nakcnt);			td->td_status = -ETIMEDOUT;			td->done = 1;		} 	} 		sl811_print_td(4, td);}/* * This	function checks	the status of current urb. */static int sl811_parse_cur_urb(struct urb *urb){	struct sl811_urb_priv *urbp = urb->hcpriv;	struct sl811_td *td = urbp->cur_td;	struct list_head *tmp;		sl811_print_td(5, td);		// this td not done yet.	if (!td->done)		return 0;		// the last ld, so the urb is done.	if (td == urbp->last_td) {		PDEBUG(4, "urb = %p is done success", td->urb);		if (usb_pipeisoc(td->urb->pipe))			PDEBUG(4, "ISO URB DONE, td = %p", td);		return 1;	}		// iso transfer, we always advance to next td 	if (usb_pipeisoc(td->urb->pipe)) {		tmp = &td->td_list;		tmp = tmp->next;		urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);		PDEBUG(4, "ISO NEXT, td = %p", urbp->cur_td);			return 0;	}			// some error occur, so the urb is done.	if (td->td_status) {		PDEBUG(3, "urb = %p is done error, td status is = %d", td->urb, td->td_status);		return 1;	}			// short packet.	if (td->left) {		if (usb_pipecontrol(td->urb->pipe)) {			// control packet, we advance to the last td			PDEBUG(3, "ctrl short packet, advance to last td");			urbp->cur_td = urbp->last_td;			return 0;		} else {			// interrut and bulk packet, urb is over.			PDEBUG(3, "bulk or intr short packet, urb is over");			return 1;		}	}	// we advance to next td.		tmp = &td->td_list;	tmp = tmp->next;	urbp->cur_td = list_entry(tmp, struct sl811_td, td_list);#ifdef SL811_DEBUG	PDEBUG(4, "advance to the next td, urb = %p, td = %p", urb, urbp->cur_td);	sl811_print_td(5, urbp->cur_td);	if (td == urbp->cur_td)

⌨️ 快捷键说明

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