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

📄 sl811.c

📁 在LINUX下驱动USB芯片SL811的程序源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		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);			PDEBUG(1, "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);//		printk("setup phase error, td = %p, addr = %d, dev = %d\n", td, td->addr, td->dev);		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;		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;	}		/* a request to the virtual root hub */ 	if (usb_pipedevice(pipe) == hc->rh.devnum)		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");		goto out_unlock;	}		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) {		((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);	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:

⌨️ 快捷键说明

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