Пример #1
0
static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
			      struct urb *urb,
			      gfp_t mem_flags)
{
	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
	struct device *dev = usbhs_priv_to_dev(priv);
	struct usb_host_endpoint *ep = urb->ep;
	struct usbhsh_device *new_udev = NULL;
	int is_dir_in = usb_pipein(urb->pipe);
	int ret;

	dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out");

	if (!usbhsh_is_running(hpriv)) {
		ret = -EIO;
		dev_err(dev, "host is not running\n");
		goto usbhsh_urb_enqueue_error_not_linked;
	}

	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	if (ret) {
		dev_err(dev, "urb link failed\n");
		goto usbhsh_urb_enqueue_error_not_linked;
	}

	/*
	 * attach udev if needed
	 * see [image of mod_host]
	 */
	if (!usbhsh_device_get(hpriv, urb)) {
		new_udev = usbhsh_device_attach(hpriv, urb);
		if (!new_udev) {
			ret = -EIO;
			dev_err(dev, "device attach failed\n");
			goto usbhsh_urb_enqueue_error_not_linked;
		}
	}

	/*
	 * attach endpoint if needed
	 * see [image of mod_host]
	 */
	if (!usbhsh_ep_to_uep(ep)) {
		ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags);
		if (ret < 0) {
			dev_err(dev, "endpoint attach failed\n");
			goto usbhsh_urb_enqueue_error_free_device;
		}
	}

	/*
	 * attach pipe to endpoint
	 * see [image of mod_host]
	 */
	ret = usbhsh_pipe_attach(hpriv, urb);
	if (ret < 0) {
		dev_err(dev, "pipe attach failed\n");
		goto usbhsh_urb_enqueue_error_free_endpoint;
	}

	/*
	 * push packet
	 */
	if (usb_pipecontrol(urb->pipe))
		ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags);
	else
		ret = usbhsh_queue_push(hcd, urb, mem_flags);

	return ret;

usbhsh_urb_enqueue_error_free_endpoint:
	usbhsh_endpoint_detach(hpriv, ep);
usbhsh_urb_enqueue_error_free_device:
	if (new_udev)
		usbhsh_device_detach(hpriv, new_udev);
usbhsh_urb_enqueue_error_not_linked:

	dev_dbg(dev, "%s error\n", __func__);

	return ret;
}
Пример #2
0
/*
 * queue up an urb for anything except the root hub
 */
static int admhc_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
		gfp_t mem_flags)
{
	struct admhcd	*ahcd = hcd_to_admhcd(hcd);
	struct ed	*ed;
	struct urb_priv	*urb_priv;
	unsigned int	pipe = urb->pipe;
	int		td_cnt = 0;
	unsigned long	flags;
	int		ret = 0;

#ifdef ADMHC_VERBOSE_DEBUG
	spin_lock_irqsave(&ahcd->lock, flags);
	urb_print(ahcd, urb, "ENQEUE", usb_pipein(pipe), -EINPROGRESS);
	spin_unlock_irqrestore(&ahcd->lock, flags);
#endif

	/* every endpoint has an ed, locate and maybe (re)initialize it */
	ed = ed_get(ahcd, urb->ep, urb->dev, pipe, urb->interval);
	if (!ed)
		return -ENOMEM;

	/* for the private part of the URB we need the number of TDs */
	switch (ed->type) {
	case PIPE_CONTROL:
		if (urb->transfer_buffer_length > TD_DATALEN_MAX)
			/* td_submit_urb() doesn't yet handle these */
			return -EMSGSIZE;

		/* 1 TD for setup, 1 for ACK, plus ... */
		td_cnt = 2;
		/* FALLTHROUGH */
	case PIPE_BULK:
		/* one TD for every 4096 Bytes (can be upto 8K) */
		td_cnt += urb->transfer_buffer_length / TD_DATALEN_MAX;
		/* ... and for any remaining bytes ... */
		if ((urb->transfer_buffer_length % TD_DATALEN_MAX) != 0)
			td_cnt++;
		/* ... and maybe a zero length packet to wrap it up */
		if (td_cnt == 0)
			td_cnt++;
		else if ((urb->transfer_flags & URB_ZERO_PACKET) != 0
			&& (urb->transfer_buffer_length
				% usb_maxpacket(urb->dev, pipe,
					usb_pipeout (pipe))) == 0)
			td_cnt++;
		break;
	case PIPE_INTERRUPT:
		/*
		 * for Interrupt IN/OUT transactions, each ED contains
		 * only 1 TD.
		 * TODO: check transfer_buffer_length?
		 */
		td_cnt = 1;
		break;
	case PIPE_ISOCHRONOUS:
		/* number of packets from URB */
		td_cnt = urb->number_of_packets;
		break;
	}

	urb_priv = urb_priv_alloc(ahcd, td_cnt, mem_flags);
	if (!urb_priv)
		return -ENOMEM;

	urb_priv->ed = ed;

	spin_lock_irqsave(&ahcd->lock, flags);
	/* don't submit to a dead HC */
	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
		ret = -ENODEV;
		goto fail;
	}
	if (!HC_IS_RUNNING(hcd->state)) {
		ret = -ENODEV;
		goto fail;
	}

	ret = usb_hcd_link_urb_to_ep(hcd, urb);
	if (ret)
		goto fail;

	/* schedule the ed if needed */
	if (ed->state == ED_IDLE) {
		ret = ed_schedule(ahcd, ed);
		if (ret < 0) {
			usb_hcd_unlink_urb_from_ep(hcd, urb);
			goto fail;
		}
		if (ed->type == PIPE_ISOCHRONOUS) {
			u16	frame = admhc_frame_no(ahcd);

			/* delay a few frames before the first TD */
			frame += max_t (u16, 8, ed->interval);
			frame &= ~(ed->interval - 1);
			frame |= ed->branch;
			urb->start_frame = frame;

			/* yes, only URB_ISO_ASAP is supported, and
			 * urb->start_frame is never used as input.
			 */
		}
	} else if (ed->type == PIPE_ISOCHRONOUS)
		urb->start_frame = ed->last_iso + ed->interval;

	/* fill the TDs and link them to the ed; and
	 * enable that part of the schedule, if needed
	 * and update count of queued periodic urbs
	 */
	urb->hcpriv = urb_priv;
	td_submit_urb(ahcd, urb);

#ifdef ADMHC_VERBOSE_DEBUG
	admhc_dump_ed(ahcd, "admhc_urb_enqueue", urb_priv->ed, 1);
#endif

fail:
	if (ret)
		urb_priv_free(ahcd, urb_priv);

	spin_unlock_irqrestore(&ahcd->lock, flags);
	return ret;
}