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

📄 uhci-q.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	if ((!(urb->transfer_flags & URB_NO_FSBR)) && !urbp->fsbr) {		urbp->fsbr = 1;		if (!uhci->fsbr++ && !uhci->fsbrtimeout)			uhci->skel_term_qh->link = cpu_to_le32(uhci->skel_fs_control_qh->dma_handle) | UHCI_PTR_QH;	}}static void uhci_dec_fsbr(struct uhci_hcd *uhci, struct urb *urb){	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	if ((!(urb->transfer_flags & URB_NO_FSBR)) && urbp->fsbr) {		urbp->fsbr = 0;		if (!--uhci->fsbr)			uhci->fsbrtimeout = jiffies + FSBR_DELAY;	}}/* * Map status to standard result codes * * <status> is (td_status(td) & 0xF60000), a.k.a. * uhci_status_bits(td_status(td)). * Note: <status> does not include the TD_CTRL_NAK bit. * <dir_out> is True for output TDs and False for input TDs. */static int uhci_map_status(int status, int dir_out){	if (!status)		return 0;	if (status & TD_CTRL_BITSTUFF)			/* Bitstuff error */		return -EPROTO;	if (status & TD_CTRL_CRCTIMEO) {		/* CRC/Timeout */		if (dir_out)			return -EPROTO;		else			return -EILSEQ;	}	if (status & TD_CTRL_BABBLE)			/* Babble */		return -EOVERFLOW;	if (status & TD_CTRL_DBUFERR)			/* Buffer error */		return -ENOSR;	if (status & TD_CTRL_STALLED)			/* Stalled */		return -EPIPE;	WARN_ON(status & TD_CTRL_ACTIVE);		/* Active */	return 0;}/* * Control transfers */static int uhci_submit_control(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb){	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	struct uhci_td *td;	struct uhci_qh *qh, *skelqh;	unsigned long destination, status;	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));	int len = urb->transfer_buffer_length;	dma_addr_t data = urb->transfer_dma;	/* The "pipe" thing contains the destination in bits 8--18 */	destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;	/* 3 errors */	status = TD_CTRL_ACTIVE | uhci_maxerr(3);	if (urb->dev->speed == USB_SPEED_LOW)		status |= TD_CTRL_LS;	/*	 * Build the TD for the control request setup packet	 */	td = uhci_alloc_td(uhci);	if (!td)		return -ENOMEM;	uhci_add_td_to_urb(urb, td);	uhci_fill_td(td, status, destination | uhci_explen(7),		urb->setup_dma);	/*	 * If direction is "send", change the packet ID from SETUP (0x2D)	 * to OUT (0xE1).  Else change it from SETUP to IN (0x69) and	 * set Short Packet Detect (SPD) for all data packets.	 */	if (usb_pipeout(urb->pipe))		destination ^= (USB_PID_SETUP ^ USB_PID_OUT);	else {		destination ^= (USB_PID_SETUP ^ USB_PID_IN);		status |= TD_CTRL_SPD;	}	/*	 * Build the DATA TD's	 */	while (len > 0) {		int pktsze = len;		if (pktsze > maxsze)			pktsze = maxsze;		td = uhci_alloc_td(uhci);		if (!td)			return -ENOMEM;		/* Alternate Data0/1 (start with Data1) */		destination ^= TD_TOKEN_TOGGLE;			uhci_add_td_to_urb(urb, td);		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1),			data);		data += pktsze;		len -= pktsze;	}	/*	 * Build the final TD for control status 	 */	td = uhci_alloc_td(uhci);	if (!td)		return -ENOMEM;	/*	 * It's IN if the pipe is an output pipe or we're not expecting	 * data back.	 */	destination &= ~TD_TOKEN_PID_MASK;	if (usb_pipeout(urb->pipe) || !urb->transfer_buffer_length)		destination |= USB_PID_IN;	else		destination |= USB_PID_OUT;	destination |= TD_TOKEN_TOGGLE;		/* End in Data1 */	status &= ~TD_CTRL_SPD;	uhci_add_td_to_urb(urb, td);	uhci_fill_td(td, status | TD_CTRL_IOC,		destination | uhci_explen(UHCI_NULL_DATA_SIZE), 0);	qh = uhci_alloc_qh(uhci);	if (!qh)		return -ENOMEM;	urbp->qh = qh;	qh->urbp = urbp;	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);	/* Low-speed transfers get a different queue, and won't hog the bus.	 * Also, some devices enumerate better without FSBR; the easiest way	 * to do that is to put URBs on the low-speed queue while the device	 * is in the DEFAULT state. */	if (urb->dev->speed == USB_SPEED_LOW ||			urb->dev->state == USB_STATE_DEFAULT)		skelqh = uhci->skel_ls_control_qh;	else {		skelqh = uhci->skel_fs_control_qh;		uhci_inc_fsbr(uhci, urb);	}	if (eurb)		uhci_append_queued_urb(uhci, eurb, urb);	else		uhci_insert_qh(uhci, skelqh, urb);	return -EINPROGRESS;}/* * If control-IN transfer was short, the status packet wasn't sent. * This routine changes the element pointer in the QH to point at the * status TD.  It's safe to do this even while the QH is live, because * the hardware only updates the element pointer following a successful * transfer.  The inactive TD for the short packet won't cause an update, * so the pointer won't get overwritten.  The next time the controller * sees this QH, it will send the status packet. */static int usb_control_retrigger_status(struct uhci_hcd *uhci, struct urb *urb){	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	struct uhci_td *td;	urbp->short_control_packet = 1;	td = list_entry(urbp->td_list.prev, struct uhci_td, list);	urbp->qh->element = cpu_to_le32(td->dma_handle);	return -EINPROGRESS;}static int uhci_result_control(struct uhci_hcd *uhci, struct urb *urb){	struct list_head *tmp, *head;	struct urb_priv *urbp = urb->hcpriv;	struct uhci_td *td;	unsigned int status;	int ret = 0;	if (list_empty(&urbp->td_list))		return -EINVAL;	head = &urbp->td_list;	if (urbp->short_control_packet) {		tmp = head->prev;		goto status_stage;	}	tmp = head->next;	td = list_entry(tmp, struct uhci_td, list);	/* The first TD is the SETUP stage, check the status, but skip */	/*  the count */	status = uhci_status_bits(td_status(td));	if (status & TD_CTRL_ACTIVE)		return -EINPROGRESS;	if (status)		goto td_error;	urb->actual_length = 0;	/* The rest of the TD's (but the last) are data */	tmp = tmp->next;	while (tmp != head && tmp->next != head) {		unsigned int ctrlstat;		td = list_entry(tmp, struct uhci_td, list);		tmp = tmp->next;		ctrlstat = td_status(td);		status = uhci_status_bits(ctrlstat);		if (status & TD_CTRL_ACTIVE)			return -EINPROGRESS;		urb->actual_length += uhci_actual_length(ctrlstat);		if (status)			goto td_error;		/* Check to see if we received a short packet */		if (uhci_actual_length(ctrlstat) <				uhci_expected_length(td_token(td))) {			if (urb->transfer_flags & URB_SHORT_NOT_OK) {				ret = -EREMOTEIO;				goto err;			}			if (uhci_packetid(td_token(td)) == USB_PID_IN)				return usb_control_retrigger_status(uhci, urb);			else				return 0;		}	}status_stage:	td = list_entry(tmp, struct uhci_td, list);	/* Control status stage */	status = td_status(td);#ifdef I_HAVE_BUGGY_APC_BACKUPS	/* APC BackUPS Pro kludge */	/* It tries to send all of the descriptor instead of the amount */	/*  we requested */	if (status & TD_CTRL_IOC &&	/* IOC is masked out by uhci_status_bits */	    status & TD_CTRL_ACTIVE &&	    status & TD_CTRL_NAK)		return 0;#endif	status = uhci_status_bits(status);	if (status & TD_CTRL_ACTIVE)		return -EINPROGRESS;	if (status)		goto td_error;	return 0;td_error:	ret = uhci_map_status(status, uhci_packetout(td_token(td)));err:	if ((debug == 1 && ret != -EPIPE) || debug > 1) {		/* Some debugging code */		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",				__FUNCTION__, status);		if (errbuf) {			/* Print the chain for debugging purposes */			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);			lprintk(errbuf);		}	}	return ret;}/* * Common submit for bulk and interrupt */static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb, struct uhci_qh *skelqh){	struct uhci_td *td;	struct uhci_qh *qh;	unsigned long destination, status;	int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));	int len = urb->transfer_buffer_length;	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;	dma_addr_t data = urb->transfer_dma;	if (len < 0)		return -EINVAL;	/* The "pipe" thing contains the destination in bits 8--18 */	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);	status = uhci_maxerr(3) | TD_CTRL_ACTIVE;	if (urb->dev->speed == USB_SPEED_LOW)		status |= TD_CTRL_LS;	if (usb_pipein(urb->pipe))		status |= TD_CTRL_SPD;	/*	 * Build the DATA TD's	 */	do {	/* Allow zero length packets */		int pktsze = maxsze;		if (pktsze >= len) {			pktsze = len;			if (!(urb->transfer_flags & URB_SHORT_NOT_OK))				status &= ~TD_CTRL_SPD;		}		td = uhci_alloc_td(uhci);		if (!td)			return -ENOMEM;		uhci_add_td_to_urb(urb, td);		uhci_fill_td(td, status, destination | uhci_explen(pktsze - 1) |			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),			data);		data += pktsze;		len -= maxsze;		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),			usb_pipeout(urb->pipe));	} while (len > 0);	/*	 * URB_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 & URB_ZERO_PACKET) &&	    !len && urb->transfer_buffer_length) {		td = uhci_alloc_td(uhci);		if (!td)			return -ENOMEM;		uhci_add_td_to_urb(urb, td);		uhci_fill_td(td, status, destination | uhci_explen(UHCI_NULL_DATA_SIZE) |			(usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),			 usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE_SHIFT),			data);		usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),			usb_pipeout(urb->pipe));	}	/* Set the interrupt-on-completion flag on the last packet.	 * A more-or-less typical 4 KB URB (= size of one memory page)	 * will require about 3 ms to transfer; that's a little on the	 * fast side but not enough to justify delaying an interrupt	 * more than 2 or 3 URBs, so we will ignore the URB_NO_INTERRUPT	 * flag setting. */	td->status |= cpu_to_le32(TD_CTRL_IOC);	qh = uhci_alloc_qh(uhci);	if (!qh)		return -ENOMEM;	urbp->qh = qh;	qh->urbp = urbp;	/* Always breadth first */	uhci_insert_tds_in_qh(qh, urb, UHCI_PTR_BREADTH);	if (eurb)		uhci_append_queued_urb(uhci, eurb, urb);	else		uhci_insert_qh(uhci, skelqh, urb);	return -EINPROGRESS;}/* * Common result for bulk and interrupt */static int uhci_result_common(struct uhci_hcd *uhci, struct urb *urb){	struct urb_priv *urbp = urb->hcpriv;	struct uhci_td *td;	unsigned int status = 0;	int ret = 0;	urb->actual_length = 0;	list_for_each_entry(td, &urbp->td_list, list) {		unsigned int ctrlstat = td_status(td);		status = uhci_status_bits(ctrlstat);		if (status & TD_CTRL_ACTIVE)			return -EINPROGRESS;		urb->actual_length += uhci_actual_length(ctrlstat);		if (status)			goto td_error;		if (uhci_actual_length(ctrlstat) <				uhci_expected_length(td_token(td))) {			if (urb->transfer_flags & URB_SHORT_NOT_OK) {				ret = -EREMOTEIO;				goto err;			} else				return 0;		}	}	return 0;td_error:	ret = uhci_map_status(status, uhci_packetout(td_token(td)));err:	/* 	 * Enable this chunk of code if you want to see some more debugging.	 * But be careful, it has the tendancy to starve out khubd and prevent	 * disconnects from happening successfully if you have a slow debug	 * log interface (like a serial console.	 */#if 0	if ((debug == 1 && ret != -EPIPE) || debug > 1) {		/* Some debugging code */		dev_dbg(uhci_dev(uhci), "%s: failed with status %x\n",				__FUNCTION__, status);		if (errbuf) {			/* Print the chain for debugging purposes */			uhci_show_qh(urbp->qh, errbuf, ERRBUF_LEN, 0);			lprintk(errbuf);		}	}#endif	return ret;}static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb){	int ret;	/* Can't have low-speed bulk transfers */	if (urb->dev->speed == USB_SPEED_LOW)		return -EINVAL;	ret = uhci_submit_common(uhci, urb, eurb, uhci->skel_bulk_qh);	if (ret == -EINPROGRESS)		uhci_inc_fsbr(uhci, urb);	return ret;}static inline int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb, struct urb *eurb){	/* USB 1.1 interrupt transfers only involve one packet per interval;	 * that's the uhci_submit_common() "breadth first" policy.  Drivers	 * can submit urbs of any length, but longer ones might need many	 * intervals to complete.	 */	return uhci_submit_common(uhci, urb, eurb, uhci->skelqh[__interval_to_skel(urb->interval)]);}/* * Isochronous transfers */static int isochronous_find_limits(struct uhci_hcd *uhci, struct urb *urb, unsigned int *start, unsigned int *end){	struct urb *last_urb = NULL;	struct urb_priv *up;	int ret = 0;	list_for_each_entry(up, &uhci->urb_list, urb_list) {		struct urb *u = up->urb;		/* look for pending URB's with identical pipe handle */		if ((urb->pipe == u->pipe) && (urb->dev == u->dev) &&		    (u->status == -EINPROGRESS) && (u != urb)) {			if (!last_urb)				*start = u->start_frame;			last_urb = u;		}	}	if (last_urb) {		*end = (last_urb->start_frame + last_urb->number_of_packets *				last_urb->interval) & (UHCI_NUMFRAMES-1);		ret = 0;	} else		ret = -1;	/* no previous urb found */

⌨️ 快捷键说明

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