Ejemplo n.º 1
0
/* This is a version of usb_clear_halt() that allows early termination and
 * doesn't read the status from the device -- this is because some devices
 * crash their internal firmware when the status is requested after a halt.
 *
 * A definitive list of these 'bad' devices is too difficult to maintain or
 * make complete enough to be useful.  This problem was first observed on the
 * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
 * MacOS nor Windows checks the status after clearing a halt.
 *
 * Since many vendors in this space limit their testing to interoperability
 * with these two OSes, specification violations like this one are common.
 */
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe);

	if (usb_pipein (pipe))
		endp |= USB_DIR_IN;

	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
		USB_ENDPOINT_HALT, endp,
		NULL, 0, 3*HZ);

	if (result >= 0)
		usb_reset_endpoint(us->pusb_dev, endp);

	usb_stor_dbg(us, "result = %d\n", result);
	return result;
}
Ejemplo n.º 2
0
static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
    int len, char ev_type)
{
	int pipe = urb->pipe;

	if (len <= 0)
		return 'L';
	if (len >= DATA_MAX)
		len = DATA_MAX;

	/*
	 * Bulk is easy to shortcut reliably. 
	 * XXX Other pipe types need consideration. Currently, we overdo it
	 * and collect garbage for them: better more than less.
	 */
	if (usb_pipebulk(pipe) || usb_pipecontrol(pipe)) {
		if (usb_pipein(pipe)) {
			if (ev_type == 'S')
				return '<';
		} else {
			if (ev_type == 'C')
				return '>';
		}
	}

	/*
	 * The check to see if it's safe to poke at data has an enormous
	 * number of corner cases, but it seems that the following is
	 * more or less safe.
	 *
	 * We do not even try to look transfer_buffer, because it can
	 * contain non-NULL garbage in case the upper level promised to
	 * set DMA for the HCD.
	 */
	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
		return mon_dmapeek(ep->data, urb->transfer_dma, len);

	if (urb->transfer_buffer == NULL)
		return 'Z';	/* '0' would be not as pretty. */

	memcpy(ep->data, urb->transfer_buffer, len);
	return 0;
}
Ejemplo n.º 3
0
/* This is a version of usb_clear_halt() that doesn't read the status from
 * the device -- this is because some devices crash their internal firmware
 * when the status is requested after a halt
 */
int usb_stor_clear_halt(struct usb_device *dev, int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);

	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
				 USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
				 endp, NULL, 0, HZ * 3);

	/* this is a failure case */
	if (result < 0)
		return result;

	/* reset the toggles and endpoint flags */
	usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
	usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);

	return 0;
}
Ejemplo n.º 4
0
void usb_buffer_unmap(struct urb *urb)
{
	struct usb_bus		*bus;
	struct device		*controller;

	if (!urb
			|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
			|| !urb->dev
			|| !(bus = urb->dev->bus)
			|| !(controller = bus->controller))
		return;

	if (controller->dma_mask) {
		dma_unmap_single(controller,
			urb->transfer_dma, urb->transfer_buffer_length,
			usb_pipein(urb->pipe)
				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
	}
	urb->transfer_flags &= ~URB_NO_TRANSFER_DMA_MAP;
}
Ejemplo n.º 5
0
/* This is a version of usb_clear_halt() that allows early termination and
 * doesn't read the status from the device -- this is because some devices
 * crash their internal firmware when the status is requested after a halt.
 *
 * A definitive list of these 'bad' devices is too difficult to maintain or
 * make complete enough to be useful.  This problem was first observed on the
 * Hagiwara FlashGate DUAL unit.  However, bus traces reveal that neither
 * MacOS nor Windows checks the status after clearing a halt.
 *
 * Since many vendors in this space limit their testing to interoperability
 * with these two OSes, specification violations like this one are common.
 */
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe);

	if (usb_pipein (pipe))
		endp |= USB_DIR_IN;

	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
		USB_ENDPOINT_HALT, endp,
		NULL, 0, 3*HZ);

	/* reset the endpoint toggle */
	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
		usb_pipeout(pipe), 0);

	US_DEBUGP("%s: result = %d\n", __FUNCTION__, result);
	return result;
}
Ejemplo n.º 6
0
//----- usb_stor_clear_halt() ---------------------
int usb_stor_clear_halt(struct us_data *us, unsigned int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe);

	//printk("transport --- usb_stor_clear_halt\n");
	if (usb_pipein (pipe))
		endp |= USB_DIR_IN;

	result = usb_stor_control_msg(us, us->send_ctrl_pipe,
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT,
		USB_ENDPOINT_HALT, endp,
		NULL, 0, 3*HZ);

	/* reset the endpoint toggle */
	if (result >= 0)
		//usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0);
                usb_reset_endpoint(us->pusb_dev, endp);

	return result;
}
Ejemplo n.º 7
0
//transfer buffer must be aligned on an 8 bytes boundary
static int hci_submit_urb (urb_t * urb)
{
	hci_t * hci;
	unsigned int pipe = urb->pipe;
	unsigned long flags;
	int ret;

	if (!urb->dev || !urb->dev->bus || urb->hcpriv) return -EINVAL;
#if BURST_TRANSFER_SIZE >= 8
	if ( ((int)urb->transfer_buffer) & 7) {
		if ( (urb->transfer_buffer_length >8) ||
		     ( ( ((int)urb->transfer_buffer) & 1 ) && (urb->transfer_buffer_length >1) ) ) {
			printk(KERN_ERR __FILE__  ": improper alignment, size %d bytes\n",urb->transfer_buffer_length);
			return -EINVAL;
		}
	}
#endif
	if (usb_endpoint_halted (urb->dev,
				usb_pipeendpoint (pipe), usb_pipeout (pipe)))
		return -EPIPE;

	hci = (hci_t *) urb->dev->bus->hcpriv;

	/* a request to the virtual root hub */
	if (usb_pipedevice (pipe) == hci->rh.devnum) {
		return rh_submit_urb (urb);
	}

	if (urb_debug)
		urb_print (urb, "SUB", usb_pipein (pipe));

	/* queue the URB to its endpoint-queue */

	spin_lock_irqsave (&hci->urb_list_lock, flags);
	ret = hcs_urb_queue (hci, urb);
	spin_unlock_irqrestore (&hci->urb_list_lock, flags);

	return ret;

}
Ejemplo n.º 8
0
/* This is a version of usb_clear_halt() that doesn't read the status from
 * the device -- this is because some devices crash their internal firmware
 * when the status is requested after a halt
 */
static int  clear_halt(USB_DEV_T *dev, int pipe)
{
    int    result;
    int    endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);

    UMAS_DEBUG("clear_halt!\n");
    result = USBH_SendCtrlMsg(dev, usb_sndctrlpipe(dev, 0),
                              USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
                              endp, NULL, 0, 0);
    /* this is a failure case */
    if(result < 0)
    {
        UMAS_DEBUG("clear_halt failed!!\n");
        return result;
    }

    /* reset the toggles and endpoint flags */
    usb_endpoint_running(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));
    usb_settoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe), 0x1000);

    return 0;
}
/* some members of urb must be substituted before. */
int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
{
	int ret;
	int size;

	if (ud->side == USBIP_STUB) {
		/* stub_rx.c */
		/* the direction of urb must be OUT. */
		if (usb_pipein(urb->pipe))
			return 0;

		size = urb->transfer_buffer_length;
	} else {
		/* vhci_rx.c */
		/* the direction of urb must be IN. */
		if (usb_pipeout(urb->pipe))
			return 0;

		size = urb->actual_length;
	}

	/* no need to recv xbuff */
	if (!(size > 0))
		return 0;

	ret = usbip_xmit(0, ud->tcp_socket, (char *)urb->transfer_buffer,
			 size, 0);
	if (ret != size) {
		dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
		if (ud->side == USBIP_STUB) {
			usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
		} else {
			usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
			return -EPIPE;
		}
	}

	return ret;
}
Ejemplo n.º 10
0
static int dump_urbs(struct list_head *list, char *buf, unsigned max)
{
	int count = 0;
	int tmp;
	struct urb *urb;

	if (list_empty(list))
		return snprintf(buf, max, "\t(queue empty)\n");

	list_for_each_entry(urb, list, urb_list) {
		const unsigned pipe = urb->pipe;

		/* for non-multipoint, urb->dev never changes */
		tmp = snprintf(buf, max,
			       "\turb %p dev%d ep%d%s-%s %d/%d\n",
			       urb, urb->dev->devnum,
			       usb_pipeendpoint(pipe),
			       usb_pipein(pipe) ? "in" : "out", ( {
								 char *s;
								 switch
								 (usb_pipetype
								  (pipe)) {
case PIPE_BULK:
s = "bulk"; break; case PIPE_INTERRUPT:
s = "int"; break; case PIPE_CONTROL:
s = "control"; break; default:
								 s = "iso";
								 break;}; s;}
			       ),
			       urb->actual_length,
			       urb->transfer_buffer_length) ;
		if (tmp < 0)
			break;
		tmp = min(tmp, (int)max);
		count += tmp;
		buf += tmp;
		max -= tmp;
	}
int usbip_recv_xbuff(struct usbip_device *ud, struct urb *urb)
{
	int ret;
	int size;

	if (ud->side == USBIP_STUB) {
		
		
		if (usb_pipein(urb->pipe))
			return 0;

		size = urb->transfer_buffer_length;
	} else {
		
		
		if (usb_pipeout(urb->pipe))
			return 0;

		size = urb->actual_length;
	}

	
	if (!(size > 0))
		return 0;

	ret = usbip_recv(ud->tcp_socket, urb->transfer_buffer, size);
	if (ret != size) {
		dev_err(&urb->dev->dev, "recv xbuf, %d\n", ret);
		if (ud->side == USBIP_STUB) {
			usbip_event_add(ud, SDEV_EVENT_ERROR_TCP);
		} else {
			usbip_event_add(ud, VDEV_EVENT_ERROR_TCP);
			return -EPIPE;
		}
	}

	return ret;
}
Ejemplo n.º 12
0
static void ehci_urb_complete (
	struct ehci_hcd		*ehci,
	dma_addr_t		addr,
	struct urb		*urb
) {
	if (urb->transfer_buffer_length && usb_pipein (urb->pipe))
		pci_dma_sync_single (ehci->hcd.pdev, addr,
			urb->transfer_buffer_length,
			PCI_DMA_FROMDEVICE);

	/* cleanse status if we saw no error */
	if (likely (urb->status == -EINPROGRESS)) {
		if (urb->actual_length != urb->transfer_buffer_length
				&& (urb->transfer_flags & USB_DISABLE_SPD))
			urb->status = -EREMOTEIO;
		else
			urb->status = 0;
	}

	/* only report unlinks once */
	if (likely (urb->status != -ENOENT && urb->status != -ENOTCONN))
		urb->complete (urb);
}
Ejemplo n.º 13
0
struct urb *usb_buffer_map(struct urb *urb)
{
	struct usb_bus		*bus;
	struct device		*controller;

	if (!urb
			|| !urb->dev
			|| !(bus = urb->dev->bus)
			|| !(controller = bus->controller))
		return NULL;

	if (controller->dma_mask) {
		urb->transfer_dma = dma_map_single(controller,
			urb->transfer_buffer, urb->transfer_buffer_length,
			usb_pipein(urb->pipe)
				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
	/* FIXME generic api broken like pci, can't report errors */
	/* if (urb->transfer_dma == DMA_ADDR_INVALID) return 0; */
	} else
		urb->transfer_dma = ~0;
	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
	return urb;
}
Ejemplo n.º 14
0
/* This is a version of usb_clear_halt() that doesn't read the status from
 * the device -- this is because some devices crash their internal firmware
 * when the status is requested after a halt
 */
int usb_stor_clear_halt(struct us_data *us, int pipe)
{
	int result;
	int endp = usb_pipeendpoint(pipe) | (usb_pipein(pipe) << 7);

	result = usb_stor_control_msg(us,
		usb_sndctrlpipe(us->pusb_dev, 0),
		USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0,
		endp, NULL, 0);		/* note: no 3*HZ timeout */
	US_DEBUGP("usb_stor_clear_halt: result=%d\n", result);

	/* this is a failure case */
	if (result < 0)
		return result;

	/* reset the toggles and endpoint flags */
	usb_endpoint_running(us->pusb_dev, usb_pipeendpoint(pipe),
		usb_pipeout(pipe));
	usb_settoggle(us->pusb_dev, usb_pipeendpoint(pipe),
		usb_pipeout(pipe), 0);

	return 0;
}
Ejemplo n.º 15
0
static int vstusb_fill_and_send_urb(struct urb *urb,
				    struct usb_device *usb_dev,
				    unsigned int pipe, void *data,
				    unsigned int len, struct completion *done)
{
	struct usb_host_endpoint *ep;
	struct usb_host_endpoint **hostep;
	unsigned int pipend;

	int status;

	hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out;
	pipend = usb_pipeendpoint(pipe);
	ep = hostep[pipend];

	if (!ep || (len == 0))
		return -EINVAL;

	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
	    == USB_ENDPOINT_XFER_INT) {
		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
		usb_fill_int_urb(urb, usb_dev, pipe, data, len,
				 (usb_complete_t)usb_api_blocking_completion,
				 NULL, ep->desc.bInterval);
	} else
		usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
				  (usb_complete_t)usb_api_blocking_completion,
				  NULL);

	init_completion(done);
	urb->context = done;
	urb->actual_length = 0;
	status = usb_submit_urb(urb, GFP_KERNEL);

	return status;
}
Ejemplo n.º 16
0
/**
 * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
 * @urb: urb whose transfer_buffer/setup_packet will be synchronized
 */
void usb_buffer_dmasync(struct urb *urb)
{
	struct usb_bus		*bus;
	struct device		*controller;

	if (!urb
			|| !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP)
			|| !urb->dev
			|| !(bus = urb->dev->bus)
			|| !(controller = bus->controller))
		return;

	if (controller->dma_mask) {
		dma_sync_single(controller,
			urb->transfer_dma, urb->transfer_buffer_length,
			usb_pipein(urb->pipe)
				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
		if (usb_pipecontrol(urb->pipe))
			dma_sync_single(controller,
					urb->setup_dma,
					sizeof(struct usb_ctrlrequest),
					DMA_TO_DEVICE);
	}
}
Ejemplo n.º 17
0
/**
 * usb_sg_init - initializes scatterlist-based bulk/interrupt I/O request
 * @io: request block being initialized.  until usb_sg_wait() returns,
 *	treat this as a pointer to an opaque block of memory,
 * @dev: the usb device that will send or receive the data
 * @pipe: endpoint "pipe" used to transfer the data
 * @period: polling rate for interrupt endpoints, in frames or
 * 	(for high speed endpoints) microframes; ignored for bulk
 * @sg: scatterlist entries
 * @nents: how many entries in the scatterlist
 * @length: how many bytes to send from the scatterlist, or zero to
 * 	send every byte identified in the list.
 * @mem_flags: SLAB_* flags affecting memory allocations in this call
 *
 * Returns zero for success, else a negative errno value.  This initializes a
 * scatter/gather request, allocating resources such as I/O mappings and urb
 * memory (except maybe memory used by USB controller drivers).
 *
 * The request must be issued using usb_sg_wait(), which waits for the I/O to
 * complete (or to be canceled) and then cleans up all resources allocated by
 * usb_sg_init().
 *
 * The request may be canceled with usb_sg_cancel(), either before or after
 * usb_sg_wait() is called.
 */
int usb_sg_init (
	struct usb_sg_request	*io,
	struct usb_device	*dev,
	unsigned		pipe, 
	unsigned		period,
	struct scatterlist	*sg,
	int			nents,
	size_t			length,
	int			mem_flags
)
{
	int			i;
	int			urb_flags;
	int			dma;

	if (!io || !dev || !sg
			|| usb_pipecontrol (pipe)
			|| usb_pipeisoc (pipe)
			|| nents <= 0)
		return -EINVAL;

	spin_lock_init (&io->lock);
	io->dev = dev;
	io->pipe = pipe;
	io->sg = sg;
	io->nents = nents;

	/* not all host controllers use DMA (like the mainstream pci ones);
	 * they can use PIO (sl811) or be software over another transport.
	 */
	dma = (dev->dev.dma_mask != 0);
	if (dma)
		io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
	else
		io->entries = nents;

	/* initialize all the urbs we'll use */
	if (io->entries <= 0)
		return io->entries;

	io->count = 0;
	io->urbs = kmalloc (io->entries * sizeof *io->urbs, mem_flags);
	if (!io->urbs)
		goto nomem;

	urb_flags = URB_ASYNC_UNLINK | URB_NO_TRANSFER_DMA_MAP
			| URB_NO_INTERRUPT;
	if (usb_pipein (pipe))
		urb_flags |= URB_SHORT_NOT_OK;

	for (i = 0; i < io->entries; i++, io->count = i) {
		unsigned		len;

		io->urbs [i] = usb_alloc_urb (0, mem_flags);
		if (!io->urbs [i]) {
			io->entries = i;
			goto nomem;
		}

		io->urbs [i]->dev = NULL;
		io->urbs [i]->pipe = pipe;
		io->urbs [i]->interval = period;
		io->urbs [i]->transfer_flags = urb_flags;

		io->urbs [i]->complete = sg_complete;
		io->urbs [i]->context = io;
		io->urbs [i]->status = -EINPROGRESS;
		io->urbs [i]->actual_length = 0;

		if (dma) {
			/* hc may use _only_ transfer_dma */
			io->urbs [i]->transfer_dma = sg_dma_address (sg + i);
			len = sg_dma_len (sg + i);
		} else {
			/* hc may use _only_ transfer_buffer */
			io->urbs [i]->transfer_buffer =
				page_address (sg [i].page) + sg [i].offset;
			len = sg [i].length;
		}

		if (length) {
			len = min_t (unsigned, len, length);
			length -= len;
			if (length == 0)
				io->entries = i + 1;
		}
		io->urbs [i]->transfer_buffer_length = len;
	}
	io->urbs [--i]->transfer_flags &= ~URB_NO_INTERRUPT;

	/* transaction state */
	io->status = 0;
	io->bytes = 0;
	init_completion (&io->complete);
	return 0;

nomem:
	sg_clean (io);
	return -ENOMEM;
}
Ejemplo n.º 18
0
static void sg_complete (struct urb *urb, struct pt_regs *regs)
{
	struct usb_sg_request	*io = (struct usb_sg_request *) urb->context;

	spin_lock (&io->lock);

	/* In 2.5 we require hcds' endpoint queues not to progress after fault
	 * reports, until the completion callback (this!) returns.  That lets
	 * device driver code (like this routine) unlink queued urbs first,
	 * if it needs to, since the HC won't work on them at all.  So it's
	 * not possible for page N+1 to overwrite page N, and so on.
	 *
	 * That's only for "hard" faults; "soft" faults (unlinks) sometimes
	 * complete before the HCD can get requests away from hardware,
	 * though never during cleanup after a hard fault.
	 */
	if (io->status
			&& (io->status != -ECONNRESET
				|| urb->status != -ECONNRESET)
			&& urb->actual_length) {
		dev_err (io->dev->bus->controller,
			"dev %s ep%d%s scatterlist error %d/%d\n",
			io->dev->devpath,
			usb_pipeendpoint (urb->pipe),
			usb_pipein (urb->pipe) ? "in" : "out",
			urb->status, io->status);
		// BUG ();
	}

	if (urb->status && urb->status != -ECONNRESET) {
		int		i, found, status;

		io->status = urb->status;

		/* the previous urbs, and this one, completed already.
		 * unlink pending urbs so they won't rx/tx bad data.
		 */
		for (i = 0, found = 0; i < io->entries; i++) {
			if (!io->urbs [i])
				continue;
			if (found) {
				status = usb_unlink_urb (io->urbs [i]);
				if (status != -EINPROGRESS && status != -EBUSY)
				{
					dev_err (&io->dev->dev,
						"%s, unlink --> %d\n",
						__FUNCTION__, status);
					if(status == -19)
					{
					    printk("sg_complete====will do softreset\n");
                                            kerSysMipsSoftReset();
                                        }
			        }
			} else if (urb == io->urbs [i])
				found = 1;
		}
	}
	urb->dev = NULL;

	/* on the last completion, signal usb_sg_wait() */
	io->bytes += urb->actual_length;
	io->count--;
	if (!io->count)
		complete (&io->complete);

	spin_unlock (&io->lock);
}
Ejemplo n.º 19
0
static int
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
		   int length, struct devrequest *req)
{
	struct QH *qh;
	struct qTD *td;
	volatile struct qTD *vtd;
	unsigned long ts;
	uint32_t *tdp;
	uint32_t endpt, token, usbsts;
	uint32_t c, toggle;
	uint32_t cmd;
	int timeout;
	int ret = 0;

	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
	      buffer, length, req);
	if (req != NULL)
		debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
		      req->request, req->request,
		      req->requesttype, req->requesttype,
		      le16_to_cpu(req->value), le16_to_cpu(req->value),
		      le16_to_cpu(req->index));

	qh = ehci_alloc(sizeof(struct QH), 32);
	if (qh == NULL) {
		debug("unable to allocate QH\n");
		return -1;
	}
	qh->qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);
	c = (usb_pipespeed(pipe) != USB_SPEED_HIGH &&
	     usb_pipeendpoint(pipe) == 0) ? 1 : 0;
	endpt = (8 << 28) |
	    (c << 27) |
	    (usb_maxpacket(dev, pipe) << 16) |
	    (0 << 15) |
	    (1 << 14) |
	    (usb_pipespeed(pipe) << 12) |
	    (usb_pipeendpoint(pipe) << 8) |
	    (0 << 7) | (usb_pipedevice(pipe) << 0);
	qh->qh_endpt1 = cpu_to_hc32(endpt);
	endpt = (1 << 30) |
	    (dev->portnr << 23) |
	    (dev->parent->devnum << 16) | (0 << 8) | (0 << 0);
	qh->qh_endpt2 = cpu_to_hc32(endpt);
	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);

	td = NULL;
	tdp = &qh->qh_overlay.qt_next;

	toggle =
	    usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));

	if (req != NULL) {
		td = ehci_alloc(sizeof(struct qTD), 32);
		if (td == NULL) {
			debug("unable to allocate SETUP td\n");
			goto fail;
		}
		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (0 << 31) |
		    (sizeof(*req) << 16) |
		    (0 << 15) | (0 << 12) | (3 << 10) | (2 << 8) | (0x80 << 0);
		td->qt_token = cpu_to_hc32(token);
		if (ehci_td_buffer(td, req, sizeof(*req)) != 0) {
			debug("unable construct SETUP td\n");
			ehci_free(td, sizeof(*td));
			goto fail;
		}
		*tdp = cpu_to_hc32((uint32_t) td);
		tdp = &td->qt_next;
		toggle = 1;
	}

	if (length > 0 || req == NULL) {
		td = ehci_alloc(sizeof(struct qTD), 32);
		if (td == NULL) {
			debug("unable to allocate DATA td\n");
			goto fail;
		}
		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (toggle << 31) |
		    (length << 16) |
		    ((req == NULL ? 1 : 0) << 15) |
		    (0 << 12) |
		    (3 << 10) |
		    ((usb_pipein(pipe) ? 1 : 0) << 8) | (0x80 << 0);
		td->qt_token = cpu_to_hc32(token);
		if (ehci_td_buffer(td, buffer, length) != 0) {
			debug("unable construct DATA td\n");
			ehci_free(td, sizeof(*td));
			goto fail;
		}
		*tdp = cpu_to_hc32((uint32_t) td);
		tdp = &td->qt_next;
	}

	if (req != NULL) {
		td = ehci_alloc(sizeof(struct qTD), 32);
		if (td == NULL) {
			debug("unable to allocate ACK td\n");
			goto fail;
		}
		td->qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		td->qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = (toggle << 31) |
		    (0 << 16) |
		    (1 << 15) |
		    (0 << 12) |
		    (3 << 10) |
		    ((usb_pipein(pipe) ? 0 : 1) << 8) | (0x80 << 0);
		td->qt_token = cpu_to_hc32(token);
		*tdp = cpu_to_hc32((uint32_t) td);
		tdp = &td->qt_next;
	}

	qh_list.qh_link = cpu_to_hc32((uint32_t) qh | QH_LINK_TYPE_QH);

	/* Flush dcache */
	ehci_flush_dcache(&qh_list);

	usbsts = ehci_readl(&hcor->or_usbsts);
	ehci_writel(&hcor->or_usbsts, (usbsts & 0x3f));

	/* Enable async. schedule. */
	cmd = ehci_readl(&hcor->or_usbcmd);
	cmd |= CMD_ASE;
	ehci_writel(&hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, STD_ASS,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STD_ASS set\n");
		goto fail;
	}

	/* Wait for TDs to be processed. */
	ts = get_timer(0);
	vtd = td;
	timeout = USB_TIMEOUT_MS(pipe);
	do {
		/* Invalidate dcache */
		ehci_invalidate_dcache(&qh_list);
		token = hc32_to_cpu(vtd->qt_token);
		if (!(token & 0x80))
			break;
		WATCHDOG_RESET();
	} while (get_timer(ts) < timeout);

	/* Check that the TD processing happened */
	if (token & 0x80) {
		printf("EHCI timed out on TD - token=%#x\n", token);
		goto fail;
	}

	/* Disable async schedule. */
	cmd = ehci_readl(&hcor->or_usbcmd);
	cmd &= ~CMD_ASE;
	ehci_writel(&hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&hcor->or_usbsts, STD_ASS, 0,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STD_ASS reset\n");
		goto fail;
	}

	qh_list.qh_link = cpu_to_hc32((uint32_t)&qh_list | QH_LINK_TYPE_QH);

	token = hc32_to_cpu(qh->qh_overlay.qt_token);
	if (!(token & 0x80)) {
		debug("TOKEN=%#x\n", token);
		switch (token & 0xfc) {
		case 0:
			toggle = token >> 31;
			usb_settoggle(dev, usb_pipeendpoint(pipe),
				       usb_pipeout(pipe), toggle);
			dev->status = 0;
			break;
		case 0x40:
			dev->status = USB_ST_STALLED;
			break;
		case 0xa0:
		case 0x20:
			dev->status = USB_ST_BUF_ERR;
			break;
		case 0x50:
		case 0x10:
			dev->status = USB_ST_BABBLE_DET;
			break;
		default:
			dev->status = USB_ST_CRC_ERR;
			if ((token & 0x40) == 0x40)
				dev->status |= USB_ST_STALLED;
			break;
		}
		dev->act_len = length - ((token >> 16) & 0x7fff);
	} else {
/** Initializes a QH structure.
 *
 * @param[in] _hcd The HCD state structure for the DWC OTG controller.
 * @param[in] _qh The QH to init.
 * @param[in] _urb Holds the information about the device/endpoint that we need
 * to initialize the QH. */
#define SCHEDULE_SLOP 10
#define SCHEDULE_SPLIT_SLOP	10  /* 1 == 125us,  10 -> 1.25ms, 20 -> 2.5ms, */
void dwc_otg_hcd_qh_init(dwc_otg_hcd_t * _hcd, dwc_otg_qh_t * _qh,
			 struct urb *_urb)
{
	memset(_qh, 0, sizeof(dwc_otg_qh_t));

	/* Initialize QH */
	switch (usb_pipetype(_urb->pipe)) {
	case PIPE_CONTROL:
		_qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
		break;
	case PIPE_BULK:
		_qh->ep_type = USB_ENDPOINT_XFER_BULK;
		break;
	case PIPE_ISOCHRONOUS:
		_qh->ep_type = USB_ENDPOINT_XFER_ISOC;
		break;
	case PIPE_INTERRUPT:
		_qh->ep_type = USB_ENDPOINT_XFER_INT;
		break;
	}

	_qh->ep_is_in = usb_pipein(_urb->pipe) ? 1 : 0;

	_qh->data_toggle = DWC_OTG_HC_PID_DATA0;
	_qh->maxp =
	    usb_maxpacket(_urb->dev, _urb->pipe, !(usb_pipein(_urb->pipe)));
	INIT_LIST_HEAD(&_qh->qtd_list);
	INIT_LIST_HEAD(&_qh->qh_list_entry);
	_qh->channel = NULL;

	/* FS/LS Enpoint on HS Hub 
	 * NOT virtual root hub */
	_qh->do_split = 0;
	if (((_urb->dev->speed == USB_SPEED_LOW) ||
	     (_urb->dev->speed == USB_SPEED_FULL)) &&
	    (_urb->dev->tt) && (_urb->dev->tt->hub)
	    && (_urb->dev->tt->hub->devnum != 1)) {
		DWC_DEBUGPL(DBG_HCD,
			    "QH init: EP %d: TT found at hub addr %d, for port %d\n",
			    usb_pipeendpoint(_urb->pipe),
			    _urb->dev->tt->hub->devnum, _urb->dev->ttport);
		_qh->do_split = 1;
	}

	if (_qh->ep_type == USB_ENDPOINT_XFER_INT ||
	    _qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
		/* Compute scheduling parameters once and save them. */
		hprt0_data_t hprt;

		/** @todo Account for split transfers in the bus time. */
		int bytecount =
		    dwc_hb_mult(_qh->maxp) * dwc_max_packet(_qh->maxp);
		int usecs = /*FIXME: hardcode to highspeed, to fix Full/Low speed device via Hub*/
		    usb_calc_bus_time(/*_urb->dev->speed*/USB_SPEED_HIGH, usb_pipein(_urb->pipe),
				      (_qh->ep_type == USB_ENDPOINT_XFER_ISOC),
				      bytecount);
		_qh->usecs = NS_TO_US(usecs);
		/* Start in a slightly future (micro)frame. */
		_qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number,
						     SCHEDULE_SLOP);
		_qh->interval = _urb->interval;
#if 0
		/* Increase interrupt polling rate for debugging. */
		if (_qh->ep_type == USB_ENDPOINT_XFER_INT) {
			_qh->interval = 8;
		}
#endif
		hprt.d32 = dwc_read_reg32(_hcd->core_if->host_if->hprt0);
		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
		    ((_urb->dev->speed == USB_SPEED_LOW) ||
		     (_urb->dev->speed == USB_SPEED_FULL))) {
			_qh->interval *= 8;
			_qh->sched_frame |= 0x7;
			_qh->start_split_frame = _qh->sched_frame;
		}

	}else{
		if(_qh->do_split){
			_qh->interval = SCHEDULE_SPLIT_SLOP;
			_qh->sched_frame = dwc_frame_num_inc(_hcd->frame_number,
						     _qh->interval);

		};
	}

	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", _qh);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
		    _urb->dev->devnum);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
		    usb_pipeendpoint(_urb->pipe),
		    usb_pipein(_urb->pipe) == USB_DIR_IN ? "IN" : "OUT");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", ( {
			 char *speed;
			 switch(_urb->dev->speed) {
				case USB_SPEED_LOW:
					speed = "low"; break; 
				case USB_SPEED_FULL:
					speed = "full"; break; 
				case USB_SPEED_HIGH:
					speed = "high"; break; 
				default:
					 speed = "?"; break;};
			 speed;})) ;
Ejemplo n.º 21
0
static int
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
		   int length, struct devrequest *req)
{
	ALLOC_ALIGN_BUFFER(struct QH, qh, 1, USB_DMA_MINALIGN);
	struct qTD *qtd;
	int qtd_count = 0;
	int qtd_counter = 0;
	volatile struct qTD *vtd;
	unsigned long ts;
	uint32_t *tdp;
	uint32_t endpt, maxpacket, token, usbsts;
	uint32_t c, toggle;
	uint32_t cmd;
	int timeout;
	int ret = 0;
	struct ehci_ctrl *ctrl = ehci_get_ctrl(dev);

	debug("dev=%p, pipe=%lx, buffer=%p, length=%d, req=%p\n", dev, pipe,
	      buffer, length, req);
	if (req != NULL)
		debug("req=%u (%#x), type=%u (%#x), value=%u (%#x), index=%u\n",
		      req->request, req->request,
		      req->requesttype, req->requesttype,
		      le16_to_cpu(req->value), le16_to_cpu(req->value),
		      le16_to_cpu(req->index));

#define PKT_ALIGN	512
	/*
	 * The USB transfer is split into qTD transfers. Eeach qTD transfer is
	 * described by a transfer descriptor (the qTD). The qTDs form a linked
	 * list with a queue head (QH).
	 *
	 * Each qTD transfer starts with a new USB packet, i.e. a packet cannot
	 * have its beginning in a qTD transfer and its end in the following
	 * one, so the qTD transfer lengths have to be chosen accordingly.
	 *
	 * Each qTD transfer uses up to QT_BUFFER_CNT data buffers, mapped to
	 * single pages. The first data buffer can start at any offset within a
	 * page (not considering the cache-line alignment issues), while the
	 * following buffers must be page-aligned. There is no alignment
	 * constraint on the size of a qTD transfer.
	 */
	if (req != NULL)
		/* 1 qTD will be needed for SETUP, and 1 for ACK. */
		qtd_count += 1 + 1;
	if (length > 0 || req == NULL) {
		/*
		 * Determine the qTD transfer size that will be used for the
		 * data payload (not considering the first qTD transfer, which
		 * may be longer or shorter, and the final one, which may be
		 * shorter).
		 *
		 * In order to keep each packet within a qTD transfer, the qTD
		 * transfer size is aligned to PKT_ALIGN, which is a multiple of
		 * wMaxPacketSize (except in some cases for interrupt transfers,
		 * see comment in submit_int_msg()).
		 *
		 * By default, i.e. if the input buffer is aligned to PKT_ALIGN,
		 * QT_BUFFER_CNT full pages will be used.
		 */
		int xfr_sz = QT_BUFFER_CNT;
		/*
		 * However, if the input buffer is not aligned to PKT_ALIGN, the
		 * qTD transfer size will be one page shorter, and the first qTD
		 * data buffer of each transfer will be page-unaligned.
		 */
		if ((unsigned long)buffer & (PKT_ALIGN - 1))
			xfr_sz--;
		/* Convert the qTD transfer size to bytes. */
		xfr_sz *= EHCI_PAGE_SIZE;
		/*
		 * Approximate by excess the number of qTDs that will be
		 * required for the data payload. The exact formula is way more
		 * complicated and saves at most 2 qTDs, i.e. a total of 128
		 * bytes.
		 */
		qtd_count += 2 + length / xfr_sz;
	}
/*
 * Threshold value based on the worst-case total size of the allocated qTDs for
 * a mass-storage transfer of 65535 blocks of 512 bytes.
 */
#if CONFIG_SYS_MALLOC_LEN <= 64 + 128 * 1024
#warning CONFIG_SYS_MALLOC_LEN may be too small for EHCI
#endif
	qtd = memalign(USB_DMA_MINALIGN, qtd_count * sizeof(struct qTD));
	if (qtd == NULL) {
		printf("unable to allocate TDs\n");
		return -1;
	}

	memset(qh, 0, sizeof(struct QH));
	memset(qtd, 0, qtd_count * sizeof(*qtd));

	toggle = usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe));

	/*
	 * Setup QH (3.6 in ehci-r10.pdf)
	 *
	 *   qh_link ................. 03-00 H
	 *   qh_endpt1 ............... 07-04 H
	 *   qh_endpt2 ............... 0B-08 H
	 * - qh_curtd
	 *   qh_overlay.qt_next ...... 13-10 H
	 * - qh_overlay.qt_altnext
	 */
	qh->qh_link = cpu_to_hc32((unsigned long)&ctrl->qh_list | QH_LINK_TYPE_QH);
	c = (dev->speed != USB_SPEED_HIGH) && !usb_pipeendpoint(pipe);
	maxpacket = usb_maxpacket(dev, pipe);
	endpt = QH_ENDPT1_RL(8) | QH_ENDPT1_C(c) |
		QH_ENDPT1_MAXPKTLEN(maxpacket) | QH_ENDPT1_H(0) |
		QH_ENDPT1_DTC(QH_ENDPT1_DTC_DT_FROM_QTD) |
		QH_ENDPT1_EPS(ehci_encode_speed(dev->speed)) |
		QH_ENDPT1_ENDPT(usb_pipeendpoint(pipe)) | QH_ENDPT1_I(0) |
		QH_ENDPT1_DEVADDR(usb_pipedevice(pipe));
	qh->qh_endpt1 = cpu_to_hc32(endpt);
	endpt = QH_ENDPT2_MULT(1) | QH_ENDPT2_UFCMASK(0) | QH_ENDPT2_UFSMASK(0);
	qh->qh_endpt2 = cpu_to_hc32(endpt);
	ehci_update_endpt2_dev_n_port(dev, qh);
	qh->qh_overlay.qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
	qh->qh_overlay.qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);

	tdp = &qh->qh_overlay.qt_next;

	if (req != NULL) {
		/*
		 * Setup request qTD (3.5 in ehci-r10.pdf)
		 *
		 *   qt_next ................ 03-00 H
		 *   qt_altnext ............. 07-04 H
		 *   qt_token ............... 0B-08 H
		 *
		 *   [ buffer, buffer_hi ] loaded with "req".
		 */
		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = QT_TOKEN_DT(0) | QT_TOKEN_TOTALBYTES(sizeof(*req)) |
			QT_TOKEN_IOC(0) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
			QT_TOKEN_PID(QT_TOKEN_PID_SETUP) |
			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
		if (ehci_td_buffer(&qtd[qtd_counter], req, sizeof(*req))) {
			printf("unable to construct SETUP TD\n");
			goto fail;
		}
		/* Update previous qTD! */
		*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
		tdp = &qtd[qtd_counter++].qt_next;
		toggle = 1;
	}

	if (length > 0 || req == NULL) {
		uint8_t *buf_ptr = buffer;
		int left_length = length;

		do {
			/*
			 * Determine the size of this qTD transfer. By default,
			 * QT_BUFFER_CNT full pages can be used.
			 */
			int xfr_bytes = QT_BUFFER_CNT * EHCI_PAGE_SIZE;
			/*
			 * However, if the input buffer is not page-aligned, the
			 * portion of the first page before the buffer start
			 * offset within that page is unusable.
			 */
			xfr_bytes -= (unsigned long)buf_ptr & (EHCI_PAGE_SIZE - 1);
			/*
			 * In order to keep each packet within a qTD transfer,
			 * align the qTD transfer size to PKT_ALIGN.
			 */
			xfr_bytes &= ~(PKT_ALIGN - 1);
			/*
			 * This transfer may be shorter than the available qTD
			 * transfer size that has just been computed.
			 */
			xfr_bytes = min(xfr_bytes, left_length);

			/*
			 * Setup request qTD (3.5 in ehci-r10.pdf)
			 *
			 *   qt_next ................ 03-00 H
			 *   qt_altnext ............. 07-04 H
			 *   qt_token ............... 0B-08 H
			 *
			 *   [ buffer, buffer_hi ] loaded with "buffer".
			 */
			qtd[qtd_counter].qt_next =
					cpu_to_hc32(QT_NEXT_TERMINATE);
			qtd[qtd_counter].qt_altnext =
					cpu_to_hc32(QT_NEXT_TERMINATE);
			token = QT_TOKEN_DT(toggle) |
				QT_TOKEN_TOTALBYTES(xfr_bytes) |
				QT_TOKEN_IOC(req == NULL) | QT_TOKEN_CPAGE(0) |
				QT_TOKEN_CERR(3) |
				QT_TOKEN_PID(usb_pipein(pipe) ?
					QT_TOKEN_PID_IN : QT_TOKEN_PID_OUT) |
				QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
			qtd[qtd_counter].qt_token = cpu_to_hc32(token);
			if (ehci_td_buffer(&qtd[qtd_counter], buf_ptr,
						xfr_bytes)) {
				printf("unable to construct DATA TD\n");
				goto fail;
			}
			/* Update previous qTD! */
			*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
			tdp = &qtd[qtd_counter++].qt_next;
			/*
			 * Data toggle has to be adjusted since the qTD transfer
			 * size is not always an even multiple of
			 * wMaxPacketSize.
			 */
			if ((xfr_bytes / maxpacket) & 1)
				toggle ^= 1;
			buf_ptr += xfr_bytes;
			left_length -= xfr_bytes;
		} while (left_length > 0);
	}

	if (req != NULL) {
		/*
		 * Setup request qTD (3.5 in ehci-r10.pdf)
		 *
		 *   qt_next ................ 03-00 H
		 *   qt_altnext ............. 07-04 H
		 *   qt_token ............... 0B-08 H
		 */
		qtd[qtd_counter].qt_next = cpu_to_hc32(QT_NEXT_TERMINATE);
		qtd[qtd_counter].qt_altnext = cpu_to_hc32(QT_NEXT_TERMINATE);
		token = QT_TOKEN_DT(1) | QT_TOKEN_TOTALBYTES(0) |
			QT_TOKEN_IOC(1) | QT_TOKEN_CPAGE(0) | QT_TOKEN_CERR(3) |
			QT_TOKEN_PID(usb_pipein(pipe) ?
				QT_TOKEN_PID_OUT : QT_TOKEN_PID_IN) |
			QT_TOKEN_STATUS(QT_TOKEN_STATUS_ACTIVE);
		qtd[qtd_counter].qt_token = cpu_to_hc32(token);
		/* Update previous qTD! */
		*tdp = cpu_to_hc32((unsigned long)&qtd[qtd_counter]);
		tdp = &qtd[qtd_counter++].qt_next;
	}

	ctrl->qh_list.qh_link = cpu_to_hc32((unsigned long)qh | QH_LINK_TYPE_QH);

	/* Flush dcache */
	flush_dcache_range((unsigned long)&ctrl->qh_list,
		ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
	flush_dcache_range((unsigned long)qh, ALIGN_END_ADDR(struct QH, qh, 1));
	flush_dcache_range((unsigned long)qtd,
			   ALIGN_END_ADDR(struct qTD, qtd, qtd_count));

	/* Set async. queue head pointer. */
	ehci_writel(&ctrl->hcor->or_asynclistaddr, (unsigned long)&ctrl->qh_list);

	usbsts = ehci_readl(&ctrl->hcor->or_usbsts);
	ehci_writel(&ctrl->hcor->or_usbsts, (usbsts & 0x3f));

	/* Enable async. schedule. */
	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
	cmd |= CMD_ASE;
	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, STS_ASS,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STS_ASS set\n");
		goto fail;
	}

	/* Wait for TDs to be processed. */
	ts = get_timer(0);
	vtd = &qtd[qtd_counter - 1];
	timeout = USB_TIMEOUT_MS(pipe);
	do {
		/* Invalidate dcache */
		invalidate_dcache_range((unsigned long)&ctrl->qh_list,
			ALIGN_END_ADDR(struct QH, &ctrl->qh_list, 1));
		invalidate_dcache_range((unsigned long)qh,
			ALIGN_END_ADDR(struct QH, qh, 1));
		invalidate_dcache_range((unsigned long)qtd,
			ALIGN_END_ADDR(struct qTD, qtd, qtd_count));

		token = hc32_to_cpu(vtd->qt_token);
		if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE))
			break;
		WATCHDOG_RESET();
	} while (get_timer(ts) < timeout);

	/*
	 * Invalidate the memory area occupied by buffer
	 * Don't try to fix the buffer alignment, if it isn't properly
	 * aligned it's upper layer's fault so let invalidate_dcache_range()
	 * vow about it. But we have to fix the length as it's actual
	 * transfer length and can be unaligned. This is potentially
	 * dangerous operation, it's responsibility of the calling
	 * code to make sure enough space is reserved.
	 */
	invalidate_dcache_range((unsigned long)buffer,
		ALIGN((unsigned long)buffer + length, ARCH_DMA_MINALIGN));

	/* Check that the TD processing happened */
	if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)
		printf("EHCI timed out on TD - token=%#x\n", token);

	/* Disable async schedule. */
	cmd = ehci_readl(&ctrl->hcor->or_usbcmd);
	cmd &= ~CMD_ASE;
	ehci_writel(&ctrl->hcor->or_usbcmd, cmd);

	ret = handshake((uint32_t *)&ctrl->hcor->or_usbsts, STS_ASS, 0,
			100 * 1000);
	if (ret < 0) {
		printf("EHCI fail timeout STS_ASS reset\n");
		goto fail;
	}

	token = hc32_to_cpu(qh->qh_overlay.qt_token);
	if (!(QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_ACTIVE)) {
		debug("TOKEN=%#x\n", token);
		switch (QT_TOKEN_GET_STATUS(token) &
			~(QT_TOKEN_STATUS_SPLITXSTATE | QT_TOKEN_STATUS_PERR)) {
		case 0:
			toggle = QT_TOKEN_GET_DT(token);
			usb_settoggle(dev, usb_pipeendpoint(pipe),
				       usb_pipeout(pipe), toggle);
			dev->status = 0;
			break;
		case QT_TOKEN_STATUS_HALTED:
			dev->status = USB_ST_STALLED;
			break;
		case QT_TOKEN_STATUS_ACTIVE | QT_TOKEN_STATUS_DATBUFERR:
		case QT_TOKEN_STATUS_DATBUFERR:
			dev->status = USB_ST_BUF_ERR;
			break;
		case QT_TOKEN_STATUS_HALTED | QT_TOKEN_STATUS_BABBLEDET:
		case QT_TOKEN_STATUS_BABBLEDET:
			dev->status = USB_ST_BABBLE_DET;
			break;
		default:
			dev->status = USB_ST_CRC_ERR;
			if (QT_TOKEN_GET_STATUS(token) & QT_TOKEN_STATUS_HALTED)
				dev->status |= USB_ST_STALLED;
			break;
		}
		dev->act_len = length - QT_TOKEN_GET_TOTALBYTES(token);
	} else {
		dev->act_len = 0;
#ifndef CONFIG_USB_EHCI_FARADAY
		debug("dev=%u, usbsts=%#x, p[1]=%#x, p[2]=%#x\n",
		      dev->devnum, ehci_readl(&ctrl->hcor->or_usbsts),
		      ehci_readl(&ctrl->hcor->or_portsc[0]),
		      ehci_readl(&ctrl->hcor->or_portsc[1]));
#endif
	}

	free(qtd);
	return (dev->status != USB_ST_NOT_PROC) ? 0 : -1;

fail:
	free(qtd);
	return -1;
}
Ejemplo n.º 22
0
int usbpn_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
	static const char ifname[] = "usbpn%d";
	const struct usb_cdc_union_desc *union_header = NULL;
	const struct usb_host_interface *data_desc;
	struct usb_interface *data_intf;
	struct usb_device *usbdev = interface_to_usbdev(intf);
	struct net_device *dev;
	struct usbpn_dev *pnd;
	u8 *data;
	int phonet = 0;
	int len, err;

	data = intf->altsetting->extra;
	len = intf->altsetting->extralen;
	while (len >= 3) {
		u8 dlen = data[0];
		if (dlen < 3)
			return -EINVAL;

		/* bDescriptorType */
		if (data[1] == USB_DT_CS_INTERFACE) {
			/* bDescriptorSubType */
			switch (data[2]) {
			case USB_CDC_UNION_TYPE:
				if (union_header || dlen < 5)
					break;
				union_header =
					(struct usb_cdc_union_desc *)data;
				break;
			case 0xAB:
				phonet = 1;
				break;
			}
		}
		data += dlen;
		len -= dlen;
	}

	if (!union_header || !phonet)
		return -EINVAL;

	data_intf = usb_ifnum_to_if(usbdev, union_header->bSlaveInterface0);
	if (data_intf == NULL)
		return -ENODEV;
	/* Data interface has one inactive and one active setting */
	if (data_intf->num_altsetting != 2)
		return -EINVAL;
	if (data_intf->altsetting[0].desc.bNumEndpoints == 0
	 && data_intf->altsetting[1].desc.bNumEndpoints == 2)
		data_desc = data_intf->altsetting + 1;
	else
	if (data_intf->altsetting[0].desc.bNumEndpoints == 2
	 && data_intf->altsetting[1].desc.bNumEndpoints == 0)
		data_desc = data_intf->altsetting;
	else
		return -EINVAL;

	dev = alloc_netdev(sizeof(*pnd) + sizeof(pnd->urbs[0]) * rxq_size,
				ifname, usbpn_setup);
	if (!dev)
		return -ENOMEM;

	pnd = netdev_priv(dev);
	SET_NETDEV_DEV(dev, &intf->dev);
	netif_stop_queue(dev);

	pnd->dev = dev;
	pnd->usb = usb_get_dev(usbdev);
	pnd->intf = intf;
	pnd->data_intf = data_intf;
	spin_lock_init(&pnd->tx_lock);
	spin_lock_init(&pnd->rx_lock);
	/* Endpoints */
	if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
			data_desc->endpoint[0].desc.bEndpointAddress);
		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
			data_desc->endpoint[1].desc.bEndpointAddress);
	} else {
		pnd->rx_pipe = usb_rcvbulkpipe(usbdev,
			data_desc->endpoint[1].desc.bEndpointAddress);
		pnd->tx_pipe = usb_sndbulkpipe(usbdev,
			data_desc->endpoint[0].desc.bEndpointAddress);
	}
	pnd->active_setting = data_desc - data_intf->altsetting;

	err = usb_driver_claim_interface(&usbpn_driver, data_intf, pnd);
	if (err)
		goto out;

	/* Force inactive mode until the network device is brought UP */
	usb_set_interface(usbdev, union_header->bSlaveInterface0,
				!pnd->active_setting);
	usb_set_intfdata(intf, pnd);

	err = register_netdev(dev);
	if (err) {
		usb_driver_release_interface(&usbpn_driver, data_intf);
		goto out;
	}

	dev_dbg(&dev->dev, "USB CDC Phonet device found\n");
	return 0;

out:
	usb_set_intfdata(intf, NULL);
	free_netdev(dev);
	return err;
}
Ejemplo n.º 23
0
static int __devinit if_usb_probe(struct usb_interface *intf,
					const struct usb_device_id *id)
{
	struct usb_host_interface *data_desc;
	struct usb_link_device *usb_ld =
			(struct usb_link_device *)id->driver_info;
	struct link_device *ld = &usb_ld->ld;
	struct usb_interface *data_intf;
	struct usb_device *usbdev = interface_to_usbdev(intf);
	struct device *dev, *ehci_dev, *root_hub;
	struct if_usb_devdata *pipe;
	struct urb *urb;
	int i;
	int j;
	int dev_id;
	int err;

	/* To detect usb device order probed */
	dev_id = intf->cur_altsetting->desc.bInterfaceNumber;

	if (dev_id >= IF_USB_DEVNUM_MAX) {
		dev_err(&intf->dev, "Device id %d cannot support\n",
								dev_id);
		return -EINVAL;
	}

	if (!usb_ld) {
		dev_err(&intf->dev,
		"if_usb device doesn't be allocated\n");
		err = ENOMEM;
		goto out;
	}

	mif_info("probe dev_id=%d usb_device_id(0x%p), usb_ld (0x%p)\n",
				dev_id, id, usb_ld);

	usb_ld->usbdev = usbdev;
	usb_get_dev(usbdev);

	for (i = 0; i < IF_USB_DEVNUM_MAX; i++) {
		data_intf = usb_ifnum_to_if(usbdev, i);

		/* remap endpoint of RAW to no.1 for LTE modem */
		if (i == 0)
			pipe = &usb_ld->devdata[1];
		else if (i == 1)
			pipe = &usb_ld->devdata[0];
		else
			pipe = &usb_ld->devdata[i];

		pipe->disconnected = 0;
		pipe->data_intf = data_intf;
		data_desc = data_intf->cur_altsetting;

		/* Endpoints */
		if (usb_pipein(data_desc->endpoint[0].desc.bEndpointAddress)) {
			pipe->rx_pipe = usb_rcvbulkpipe(usbdev,
				data_desc->endpoint[0].desc.bEndpointAddress);
			pipe->tx_pipe = usb_sndbulkpipe(usbdev,
				data_desc->endpoint[1].desc.bEndpointAddress);
			pipe->rx_buf_size = 1024*4;
		} else {
			pipe->rx_pipe = usb_rcvbulkpipe(usbdev,
				data_desc->endpoint[1].desc.bEndpointAddress);
			pipe->tx_pipe = usb_sndbulkpipe(usbdev,
				data_desc->endpoint[0].desc.bEndpointAddress);
			pipe->rx_buf_size = 1024*4;
		}

		if (i == 0) {
			dev_info(&usbdev->dev, "USB IF USB device found\n");
		} else {
			err = usb_driver_claim_interface(&if_usb_driver,
					data_intf, usb_ld);
			if (err < 0) {
				mif_err("failed to cliam usb interface\n");
				goto out;
			}
		}

		usb_set_intfdata(data_intf, usb_ld);
		usb_ld->dev_count++;
		pm_suspend_ignore_children(&data_intf->dev, true);

		for (j = 0; j < URB_COUNT; j++) {
			urb = usb_alloc_urb(0, GFP_KERNEL);
			if (!urb) {
				mif_err("alloc urb fail\n");
				err = -ENOMEM;
				goto out2;
			}

			urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
			urb->transfer_buffer = usb_alloc_coherent(usbdev,
				pipe->rx_buf_size, GFP_KERNEL,
				&urb->transfer_dma);
			if (!urb->transfer_buffer) {
				mif_err(
				"Failed to allocate transfer buffer\n");
				usb_free_urb(urb);
				err = -ENOMEM;
				goto out2;
			}

			usb_fill_bulk_urb(urb, usbdev, pipe->rx_pipe,
				urb->transfer_buffer, pipe->rx_buf_size,
				usb_rx_complete, pipe);
			usb_anchor_urb(urb, &pipe->urbs);
		}
	}

	/* temporary call reset_resume */
	atomic_set(&usb_ld->suspend_count, 1);
	if_usb_reset_resume(data_intf);
	atomic_set(&usb_ld->suspend_count, 0);

	SET_HOST_ACTIVE(usb_ld->pdata, 1);
	usb_ld->host_wake_timeout_flag = 0;

	if (gpio_get_value(usb_ld->pdata->gpio_phone_active)) {
		struct link_pm_data *pm_data = usb_ld->link_pm_data;
		int delay = pm_data->autosuspend_delay_ms ?:
				DEFAULT_AUTOSUSPEND_DELAY_MS;
		pm_runtime_set_autosuspend_delay(&usbdev->dev, delay);
		dev = &usbdev->dev;
		if (dev->parent) {
			dev_dbg(&usbdev->dev, "if_usb Runtime PM Start!!\n");
			usb_enable_autosuspend(usb_ld->usbdev);
			/* s5p-ehci runtime pm allow - usb phy suspend mode */
			root_hub = &usbdev->bus->root_hub->dev;
			ehci_dev = root_hub->parent;
			mif_debug("ehci device = %s, %s\n",
					dev_driver_string(ehci_dev),
					dev_name(ehci_dev));
			pm_runtime_allow(ehci_dev);

			if (!pm_data->autosuspend)
				pm_runtime_forbid(dev);

			if (has_hub(usb_ld))
				link_pm_preactive(pm_data);

			pm_data->root_hub = root_hub;
		}

		usb_ld->flow_suspend = 0;
		/* Queue work if skbs were pending before a disconnect/probe */
		if (ld->sk_fmt_tx_q.qlen || ld->sk_raw_tx_q.qlen)
			queue_delayed_work(ld->tx_wq, &ld->tx_delayed_work, 0);

		usb_ld->if_usb_connected = 1;
		/*USB3503*/
		mif_debug("hub active complete\n");

		usb_change_modem_state(usb_ld, STATE_ONLINE);
	} else {
Ejemplo n.º 24
0
static int vhcd_urb_enqueue(struct usb_hcd *hcd,
                            struct usb_host_endpoint *ep,
                            struct urb *urb,
                            gfp_t mem_flags)
{
	int ret = 0;
	unsigned int transfer_flags = 0 ;

	struct usb_device * udev = urb->dev;

	/* FIXME Check for non existent device */

	if (!HC_IS_RUNNING(hcd->state)) {
		LOG("HC is not running\n");
		return -ENODEV;
	}

	/* we have to trap some control messages, i.e. USB_REQ_SET_ADDRESS... */
	/* TODO we don't have to do it here, but in the server */

	if (usb_pipedevice(urb->pipe) == 0) {
		__u8 type = usb_pipetype(urb->pipe);
		struct usb_ctrlrequest *ctrlreq = (struct usb_ctrlrequest *) urb->setup_packet;

		if (type != PIPE_CONTROL || !ctrlreq ) {
			LOG("invalid request to devnum 0\n");
			ret = -EINVAL;
			goto no_need_xmit;
		}

		switch (ctrlreq->bRequest) {

		case USB_REQ_SET_ADDRESS:
			LOG("SetAddress Request (%d) to port %d\n",
			          ctrlreq->wValue, urb->dev->portnum);

			spin_lock (&urb->lock);
			if (urb->status == -EINPROGRESS) {
				/* This request is successfully completed. */
				/* If not -EINPROGRESS, possibly unlinked. */
				urb->status = 0;
			}
			spin_unlock (&urb->lock);

			goto no_need_xmit;

		case USB_REQ_GET_DESCRIPTOR:
			if (ctrlreq->wValue == (USB_DT_DEVICE << 8))
				LOG("Get_Descriptor to device 0 (get max pipe size)\n");
			goto out;

		default:
			/* NOT REACHED */
			LOG("invalid request to devnum 0 bRequest %u, wValue %u\n",
			          ctrlreq->bRequest, ctrlreq->wValue);
			ret = -EINVAL;
			goto no_need_xmit;
		}
	}

out:
	if (urb->status != -EINPROGRESS) {
		LOG("URB already unlinked!, status %d\n", urb->status);
		return urb->status;
	}

	if (usb_pipeisoc(urb->pipe)) {
		LOG("ISO URBs not supported");
		ret = -EINVAL;
		goto no_need_xmit;
	}

	urb->hcpriv = (void *) hcd_to_vhcd(hcd);
	LOG("hcpriv %p", urb->hcpriv);

	transfer_flags = urb->transfer_flags;
	usb_get_urb(urb);

#if 0
	d_urb->type              = usb_pipetype(urb->pipe);
	d_urb->dev_id            = data->gadget[urb->dev->portnum-1].id;
	d_urb->endpoint          = usb_pipeendpoint(urb->pipe);
	d_urb->direction         = 0 || usb_pipein(urb->pipe);
	d_urb->interval          = urb->interval;
	d_urb->transfer_flags    = urb->transfer_flags;
	d_urb->number_of_packets = urb->number_of_packets;
	d_urb->priv              = priv;
	d_urb->size              = urb->transfer_buffer_length; 
	d_urb->data			     = urb->transfer_buffer;
	d_urb->phys_addr	     = d_urb->data?virt_to_phys(d_urb->data):0;


	if (urb->setup_packet) {
		memcpy(d_urb->setup_packet, urb->setup_packet, 8);
	}

	/* XXX ISO ? */
//	if (urb->number_of_packets)
//		memcpy(d_urb->iso_desc, urb->iso_frame_desc, urb->number_of_packets*sizeof(struct usb_iso_packet_descriptor));

	ret = libddeusb_submit_d_urb(d_urb);
#else
	unsigned port_num = urb->dev->portnum;

	switch (usb_pipetype(urb->pipe)) {

	case PIPE_CONTROL:
		{
			struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)
			                               urb->setup_packet;
			dde_linux26_usb_vhcd_submit_control_urb_cb(port_num,
			                                           usb_pipeendpoint(urb->pipe),
			                                           usb_pipein(urb->pipe),
			                                           urb, /* handle */
			                                           sizeof(*req), req);
		}
		break;

	case PIPE_INTERRUPT:
		printk(" int\n");
//	dde_linux26_usb_vhcd_submit_urb(urb->transfer_buffer,
//	                                urb->transfer_buffer_length);
		return -EINVAL;
		break;

	/* unsupported transfer types */
	case PIPE_BULK:
		printk(" bulk\n");
		return -EINVAL;
	case PIPE_ISOCHRONOUS:
		printk(" isoc\n");
		return -EINVAL;
	}
#endif

//	if (ret) {
//		LOG("URB SUBMIT FAILED (%d).",ret);
//		/* s.t. went wrong. */	
//		spin_lock_irqsave(&data->lock, flags);  
//		data->rcv_buf[i]=NULL;
//		spin_unlock_irqrestore(&data->lock, flags);
//		down(&data->rcv_buf_free);
//		kmem_cache_free(priv_cache, urb->hcpriv);
//		usb_put_urb(urb);
//		urb->status = ret;
//		urb->hcpriv = NULL;
//		libddeusb_free_d_urb(d_urb);
//		return ret;
//	}

	LOG("URB %p submitted", urb);

	return 0;

no_need_xmit:
	usb_hcd_giveback_urb(hcd, urb);
	return 0;
}
Ejemplo n.º 25
0
/**
 * usb_submit_urb - issue an asynchronous transfer request for an endpoint
 * @urb: pointer to the urb describing the request
 * @mem_flags: the type of memory to allocate, see kmalloc() for a list
 *	of valid options for this.
 *
 * This submits a transfer request, and transfers control of the URB
 * describing that request to the USB subsystem.  Request completion will
 * be indicated later, asynchronously, by calling the completion handler.
 * The three types of completion are success, error, and unlink
 * (a software-induced fault, also called "request cancellation").
 *
 * URBs may be submitted in interrupt context.
 *
 * The caller must have correctly initialized the URB before submitting
 * it.  Functions such as usb_fill_bulk_urb() and usb_fill_control_urb() are
 * available to ensure that most fields are correctly initialized, for
 * the particular kind of transfer, although they will not initialize
 * any transfer flags.
 *
 * Successful submissions return 0; otherwise this routine returns a
 * negative error number.  If the submission is successful, the complete()
 * callback from the URB will be called exactly once, when the USB core and
 * Host Controller Driver (HCD) are finished with the URB.  When the completion
 * function is called, control of the URB is returned to the device
 * driver which issued the request.  The completion handler may then
 * immediately free or reuse that URB.
 *
 * With few exceptions, USB device drivers should never access URB fields
 * provided by usbcore or the HCD until its complete() is called.
 * The exceptions relate to periodic transfer scheduling.  For both
 * interrupt and isochronous urbs, as part of successful URB submission
 * urb->interval is modified to reflect the actual transfer period used
 * (normally some power of two units).  And for isochronous urbs,
 * urb->start_frame is modified to reflect when the URB's transfers were
 * scheduled to start.  Not all isochronous transfer scheduling policies
 * will work, but most host controller drivers should easily handle ISO
 * queues going from now until 10-200 msec into the future.
 *
 * For control endpoints, the synchronous usb_control_msg() call is
 * often used (in non-interrupt context) instead of this call.
 * That is often used through convenience wrappers, for the requests
 * that are standardized in the USB 2.0 specification.  For bulk
 * endpoints, a synchronous usb_bulk_msg() call is available.
 *
 * Request Queuing:
 *
 * URBs may be submitted to endpoints before previous ones complete, to
 * minimize the impact of interrupt latencies and system overhead on data
 * throughput.  With that queuing policy, an endpoint's queue would never
 * be empty.  This is required for continuous isochronous data streams,
 * and may also be required for some kinds of interrupt transfers. Such
 * queuing also maximizes bandwidth utilization by letting USB controllers
 * start work on later requests before driver software has finished the
 * completion processing for earlier (successful) requests.
 *
 * As of Linux 2.6, all USB endpoint transfer queues support depths greater
 * than one.  This was previously a HCD-specific behavior, except for ISO
 * transfers.  Non-isochronous endpoint queues are inactive during cleanup
 * after faults (transfer errors or cancellation).
 *
 * Reserved Bandwidth Transfers:
 *
 * Periodic transfers (interrupt or isochronous) are performed repeatedly,
 * using the interval specified in the urb.  Submitting the first urb to
 * the endpoint reserves the bandwidth necessary to make those transfers.
 * If the USB subsystem can't allocate sufficient bandwidth to perform
 * the periodic request, submitting such a periodic request should fail.
 *
 * Device drivers must explicitly request that repetition, by ensuring that
 * some URB is always on the endpoint's queue (except possibly for short
 * periods during completion callacks).  When there is no longer an urb
 * queued, the endpoint's bandwidth reservation is canceled.  This means
 * drivers can use their completion handlers to ensure they keep bandwidth
 * they need, by reinitializing and resubmitting the just-completed urb
 * until the driver longer needs that periodic bandwidth.
 *
 * Memory Flags:
 *
 * The general rules for how to decide which mem_flags to use
 * are the same as for kmalloc.  There are four
 * different possible values; GFP_KERNEL, GFP_NOFS, GFP_NOIO and
 * GFP_ATOMIC.
 *
 * GFP_NOFS is not ever used, as it has not been implemented yet.
 *
 * GFP_ATOMIC is used when
 *   (a) you are inside a completion handler, an interrupt, bottom half,
 *       tasklet or timer, or
 *   (b) you are holding a spinlock or rwlock (does not apply to
 *       semaphores), or
 *   (c) current->state != TASK_RUNNING, this is the case only after
 *       you've changed it.
 *
 * GFP_NOIO is used in the block io path and error handling of storage
 * devices.
 *
 * All other situations use GFP_KERNEL.
 *
 * Some more specific rules for mem_flags can be inferred, such as
 *  (1) start_xmit, timeout, and receive methods of network drivers must
 *      use GFP_ATOMIC (they are called with a spinlock held);
 *  (2) queuecommand methods of scsi drivers must use GFP_ATOMIC (also
 *      called with a spinlock held);
 *  (3) If you use a kernel thread with a network driver you must use
 *      GFP_NOIO, unless (b) or (c) apply;
 *  (4) after you have done a down() you can use GFP_KERNEL, unless (b) or (c)
 *      apply or your are in a storage driver's block io path;
 *  (5) USB probe and disconnect can use GFP_KERNEL unless (b) or (c) apply; and
 *  (6) changing firmware on a running storage or net device uses
 *      GFP_NOIO, unless b) or c) apply
 *
 */
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
{
	int				xfertype, max;
	struct usb_device		*dev;
	struct usb_host_endpoint	*ep;
	int				is_out;

	if (!urb || urb->hcpriv || !urb->complete)
		return -EINVAL;
	dev = urb->dev;
	if ((!dev) || (dev->state < USB_STATE_DEFAULT))
		return -ENODEV;

	/* For now, get the endpoint from the pipe.  Eventually drivers
	 * will be required to set urb->ep directly and we will eliminate
	 * urb->pipe.
	 */
	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
			[usb_pipeendpoint(urb->pipe)];
	if (!ep)
		return -ENOENT;

	urb->ep = ep;
	urb->status = -EINPROGRESS;
	urb->actual_length = 0;

	/* Lots of sanity checks, so HCDs can rely on clean data
	 * and don't need to duplicate tests
	 */
	xfertype = usb_endpoint_type(&ep->desc);
	if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
		struct usb_ctrlrequest *setup =
				(struct usb_ctrlrequest *) urb->setup_packet;

		if (!setup)
			return -ENOEXEC;
		is_out = !(setup->bRequestType & USB_DIR_IN) ||
				!setup->wLength;
	} else {
		is_out = usb_endpoint_dir_out(&ep->desc);
	}

	/* Cache the direction for later use */
	urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
			(is_out ? URB_DIR_OUT : URB_DIR_IN);

	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
			dev->state < USB_STATE_CONFIGURED)
		return -ENODEV;

	max = le16_to_cpu(ep->desc.wMaxPacketSize);
	if (max <= 0) {
		dev_dbg(&dev->dev,
			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
			usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
			__func__, max);
		return -EMSGSIZE;
	}

	/* periodic transfers limit size per frame/uframe,
	 * but drivers only control those sizes for ISO.
	 * while we're checking, initialize return status.
	 */
	if (xfertype == USB_ENDPOINT_XFER_ISOC) {
		int	n, len;

		/* "high bandwidth" mode, 1-3 packets/uframe? */
		if (dev->speed == USB_SPEED_HIGH) {
			int	mult = 1 + ((max >> 11) & 0x03);
			max &= 0x07ff;
			max *= mult;
		}
Ejemplo n.º 26
0
static int sl811_send_packet(struct usb_device *dev, unsigned long pipe, __u8 *buffer, int len)
{
	__u8 ctrl = SL811_USB_CTRL_ARM | SL811_USB_CTRL_ENABLE;
	__u16 status = 0;
	int err = 0, time_start = get_timer(0);
	int need_preamble = !(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
		(dev->speed == USB_SPEED_LOW);

	if (len > 239)
		return -1;

	if (usb_pipeout(pipe))
		ctrl |= SL811_USB_CTRL_DIR_OUT;
	if (usb_gettoggle(dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
		ctrl |= SL811_USB_CTRL_TOGGLE_1;
	if (need_preamble)
		ctrl |= SL811_USB_CTRL_PREAMBLE;

	sl811_write(SL811_INTRSTS, 0xff);

	while (err < 3) {
		sl811_write(SL811_ADDR_A, 0x10);
		sl811_write(SL811_LEN_A, len);
		if (usb_pipeout(pipe) && len)
			sl811_write_buf(0x10, buffer, len);

		if (!(rh_status.wPortStatus & USB_PORT_STAT_LOW_SPEED) &&
		    sl811_read(SL811_SOFCNTDIV)*64 < calc_needed_buswidth(len, need_preamble))
			ctrl |= SL811_USB_CTRL_SOF;
		else
			ctrl &= ~SL811_USB_CTRL_SOF;

		sl811_write(SL811_CTRL_A, ctrl);
		while (!(sl811_read(SL811_INTRSTS) & SL811_INTR_DONE_A)) {
			if (5*CONFIG_SYS_HZ < get_timer(time_start)) {
				printf("USB transmit timed out\n");
				return -USB_ST_CRC_ERR;
			}
		}

		sl811_write(SL811_INTRSTS, 0xff);
		status = sl811_read(SL811_STS_A);

		if (status & SL811_USB_STS_ACK) {
			int remainder = sl811_read(SL811_CNT_A);
			if (remainder) {
				PDEBUG(0, "usb transfer remainder = %d\n", remainder);
				len -= remainder;
			}
			if (usb_pipein(pipe) && len)
				sl811_read_buf(0x10, buffer, len);
			return len;
		}

		if ((status & SL811_USB_STS_NAK) == SL811_USB_STS_NAK)
			continue;

		PDEBUG(0, "usb transfer error %#x\n", (int)status);
		err++;
	}

	err = 0;

	if (status & SL811_USB_STS_ERROR)
		err |= USB_ST_BUF_ERR;
	if (status & SL811_USB_STS_TIMEOUT)
		err |= USB_ST_CRC_ERR;
	if (status & SL811_USB_STS_STALL)
		err |= USB_ST_STALLED;

	return -err;
}
Ejemplo n.º 27
0
void dwc_otg_hcd_qh_init(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh, struct urb *urb)
{
	char *speed, *type;
	memset (qh, 0, sizeof (dwc_otg_qh_t));

	/* Initialize QH */
	switch (usb_pipetype(urb->pipe)) {
	case PIPE_CONTROL:
		qh->ep_type = USB_ENDPOINT_XFER_CONTROL;
		break;
	case PIPE_BULK:
		qh->ep_type = USB_ENDPOINT_XFER_BULK;
		break;
	case PIPE_ISOCHRONOUS:
		qh->ep_type = USB_ENDPOINT_XFER_ISOC;
		break;
	case PIPE_INTERRUPT:
		qh->ep_type = USB_ENDPOINT_XFER_INT;
		break;
	}

	qh->ep_is_in = usb_pipein(urb->pipe) ? 1 : 0;

	qh->data_toggle = DWC_OTG_HC_PID_DATA0;
	qh->maxp = usb_maxpacket(urb->dev, urb->pipe, !(usb_pipein(urb->pipe)));
	INIT_LIST_HEAD(&qh->qtd_list);
	INIT_LIST_HEAD(&qh->qh_list_entry);
	qh->channel = NULL;

	/* FS/LS Enpoint on HS Hub
	 * NOT virtual root hub */
	qh->do_split = 0;
	if (((urb->dev->speed == USB_SPEED_LOW) ||
	     (urb->dev->speed == USB_SPEED_FULL)) &&
	     (urb->dev->tt) && (urb->dev->tt->hub) && (urb->dev->tt->hub->devnum != 1))
	{
		DWC_DEBUGPL(DBG_HCD, "QH init: EP %d: TT found at hub addr %d, for port %d\n",
			   usb_pipeendpoint(urb->pipe), urb->dev->tt->hub->devnum,
			   urb->dev->ttport);
		qh->do_split = 1;
	}

	if (qh->ep_type == USB_ENDPOINT_XFER_INT ||
	    qh->ep_type == USB_ENDPOINT_XFER_ISOC) {
		/* Compute scheduling parameters once and save them. */
		hprt0_data_t hprt;

		/** @todo Account for split transfers in the bus time. */
		int bytecount = dwc_hb_mult(qh->maxp) * dwc_max_packet(qh->maxp);

		/* FIXME: work-around patch by Steven */
		qh->usecs = NS_TO_US(usb_calc_bus_time(urb->dev->speed,
					       usb_pipein(urb->pipe),
					       (qh->ep_type == USB_ENDPOINT_XFER_ISOC),
					       bytecount));

		/* Start in a slightly future (micro)frame. */
		qh->sched_frame = dwc_frame_num_inc(hcd->frame_number,
						     SCHEDULE_SLOP);
		qh->interval = urb->interval;
#if 0
		/* Increase interrupt polling rate for debugging. */
		if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
			qh->interval = 8;
		}
#endif
		hprt.d32 = dwc_read_reg32(hcd->core_if->host_if->hprt0);
		if ((hprt.b.prtspd == DWC_HPRT0_PRTSPD_HIGH_SPEED) &&
		    ((urb->dev->speed == USB_SPEED_LOW) ||
		     (urb->dev->speed == USB_SPEED_FULL))) {
			qh->interval *= 8;
			qh->sched_frame |= 0x7;
			qh->start_split_frame = qh->sched_frame;
		}

	}

	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD QH Initialized\n");
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - qh = %p\n", qh);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Device Address = %d\n",
		    urb->dev->devnum);
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Endpoint %d, %s\n",
		    usb_pipeendpoint(urb->pipe),
		    usb_pipein(urb->pipe) == USB_DIR_IN ? "IN" : "OUT");

	switch(urb->dev->speed) {
	case USB_SPEED_LOW:
		speed = "low";
		break;
	case USB_SPEED_FULL:
		speed = "full";
		break;
	case USB_SPEED_HIGH:
		speed = "high";
		break;
	default:
		speed = "?";
		break;
	}
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Speed = %s\n", speed);

	switch (qh->ep_type) {
	case USB_ENDPOINT_XFER_ISOC:
		type = "isochronous";
		break;
	case USB_ENDPOINT_XFER_INT:
		type = "interrupt";
		break;
	case USB_ENDPOINT_XFER_CONTROL:
		type = "control";
		break;
	case USB_ENDPOINT_XFER_BULK:
		type = "bulk";
		break;
	default:
		type = "?";
		break;
	}
	DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH  - Type = %s\n",type);

#ifdef DEBUG
	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - usecs = %d\n",
			    qh->usecs);
		DWC_DEBUGPL(DBG_HCDV, "DWC OTG HCD QH - interval = %d\n",
			    qh->interval);
	}
#endif
	qh->dw_align_buf = NULL;
	return;
}
Ejemplo n.º 28
0
int submit_control_msg(struct usb_device *dev, unsigned long pipe, void *buffer,
		       int len,struct devrequest *setup)
{
	int done = 0;
	int devnum = usb_pipedevice(pipe);
	int ep = usb_pipeendpoint(pipe);

	dev->status = 0;

	if (devnum == root_hub_devnum)
		return sl811_rh_submit_urb(dev, pipe, buffer, len, setup);

	PDEBUG(7, "dev = %d pipe = %ld buf = %p size = %d rt = %#x req = %#x bus = %i\n",
	       devnum, ep, buffer, len, (int)setup->requesttype,
	       (int)setup->request, sl811_read(SL811_SOFCNTDIV)*64);

	sl811_write(SL811_DEV_A, devnum);
	sl811_write(SL811_PIDEP_A, PIDEP(USB_PID_SETUP, ep));
	/* setup phase */
	usb_settoggle(dev, ep, 1, 0);
	if (sl811_send_packet(dev, usb_sndctrlpipe(dev, ep),
			      (__u8*)setup, sizeof(*setup)) == sizeof(*setup)) {
		int dir_in = usb_pipein(pipe);
		int max = usb_maxpacket(dev, pipe);

		/* data phase */
		sl811_write(SL811_PIDEP_A,
			    PIDEP(dir_in ? USB_PID_IN : USB_PID_OUT, ep));
		usb_settoggle(dev, ep, usb_pipeout(pipe), 1);
		while (done < len) {
			int res = sl811_send_packet(dev, pipe, (__u8*)buffer+done,
						    max > len - done ? len - done : max);
			if (res < 0) {
				PDEBUG(0, "status data failed!\n");
				dev->status = -res;
				return 0;
			}
			done += res;
			usb_dotoggle(dev, ep, usb_pipeout(pipe));
			if (dir_in && res < max) /* short packet */
				break;
		}

		/* status phase */
		sl811_write(SL811_PIDEP_A,
			    PIDEP(!dir_in ? USB_PID_IN : USB_PID_OUT, ep));
		usb_settoggle(dev, ep, !usb_pipeout(pipe), 1);
		if (sl811_send_packet(dev,
				      !dir_in ? usb_rcvctrlpipe(dev, ep) :
				      usb_sndctrlpipe(dev, ep),
				      0, 0) < 0) {
			PDEBUG(0, "status phase failed!\n");
			dev->status = -1;
		}
	} else {
		PDEBUG(0, "setup phase failed!\n");
		dev->status = -1;
	}

	dev->act_len = done;

	return done;
}
Ejemplo n.º 29
0
static int
ehci_submit_async(struct usb_device *dev, unsigned long pipe, void *buffer,
		   int length, struct devrequest *req)
{
	struct dwc_ctrl *ctrl = dev->controller;
	pUSB_OTG_REG otgReg = ctrl->otgReg;
	uint32_t channel_num = usb_pipeendpoint(pipe);
	uint32_t eptype;
	HOST_RET ret = HOST_OK;

	HCTSIZ_DATA hctsiz;
	HCCHAR_DATA hcchar;
	uint32_t hcStat;
	uint32_t errCnt;
	uint32_t packet_size;
	uint32_t datatoggle;

	eptype = usb_pipetype(pipe);
	// ep tye definition is different in pipe and dwc hcchar
	if(eptype == 2 )
		eptype = 0;
	else if (eptype == 3)
		eptype = 2;
    
	debug("ehci_submit_async channel pipe %lx req %p, len %x\n", pipe, req, length);
	if(req == NULL)
		packet_size = 0x200;
	else
		packet_size = 0x40;
	if (req != NULL) {  // setup for control
		hctsiz.d32 = 0;
		hctsiz.b.pid =  DWC_HCTSIZ_SETUP;
		hctsiz.b.pktcnt =  1;
		hctsiz.b.xfersize =  8;
		hcchar.d32 = 0;
		hcchar.b.mps = packet_size; 
		hcchar.b.epnum = channel_num; // use the same channel number as endpoint number
		hcchar.b.epdir = DWC_EPDIR_OUT;
		hcchar.b.eptype = eptype;
		hcchar.b.multicnt = 1;
		hcchar.b.devaddr = usb_pipedevice(pipe);
		hcchar.b.chdis = 0;
		hcchar.b.chen = 1;
		hcStat = HCSTAT_SETUP;
		errCnt = 0;
		dwc_init_channel(dev, hctsiz.d32, hcchar, (uint32_t)req);
		if(dwc_wait_for_complete(dev, channel_num, &hcStat, &errCnt)){
			ret = HOST_ERR;
			goto out;
		}
		if(hcStat != HCSTAT_DONE){
			ret = HOST_ERR;
			goto out;
		}
	}
	
	if (length || (req == NULL)) {    // data for bulk & control
		if(req)
			datatoggle = DWC_HCTSIZ_DATA1;
		else
			datatoggle = ctrl->datatoggle[usb_pipein(pipe)];
		debug("dwc_hcd data len %x toggle %x\n", length, datatoggle);
		hctsiz.d32 = 0;
		hctsiz.b.pid =  datatoggle;
		hctsiz.b.pktcnt =  (length+packet_size - 1)/packet_size;
		hctsiz.b.xfersize =  length;
		hcchar.d32 = 0;
		hcchar.b.mps = packet_size; 
		hcchar.b.epnum = channel_num; // use the same channel number as endpoint number
		hcchar.b.epdir = (req == NULL) ? usb_pipein(pipe) : DWC_EPDIR_IN;
		hcchar.b.eptype = eptype;
		hcchar.b.multicnt = 1;
		hcchar.b.devaddr = usb_pipedevice(pipe);
		hcchar.b.chdis = 0;
		hcchar.b.chen = 1;
		hcStat = HCSTAT_DATA;
		errCnt = 0;
        
		if((req == NULL)&&(hctsiz.b.pktcnt&0x01))
		{
			ctrl->datatoggle[usb_pipein(pipe)] ^= 0x02;
		}
		dwc_init_channel(dev, hctsiz.d32, hcchar, (uint32_t)buffer);
		if(dwc_wait_for_complete(dev, channel_num, &hcStat, &errCnt)){
			ret = HOST_ERR;
			goto out;
		}
		if(hcStat == HCSTAT_STALL)
			ctrl->datatoggle[usb_pipein(pipe)] = 0;
	}
	if (req != NULL) {  // status for control
		debug("status len %x\n", length);
		hctsiz.d32 = 0;
		hctsiz.b.dopng = 0;
		hctsiz.b.pid =  DWC_HCTSIZ_DATA1;
		hctsiz.b.pktcnt =  1;
		hctsiz.b.xfersize =  0;
		hcchar.d32 = 0;
		hcchar.b.mps = packet_size; 
		hcchar.b.epnum = channel_num; // use the same channel number as endpoint number
		hcchar.b.epdir = (length) ? DWC_EPDIR_OUT : DWC_EPDIR_IN;
		hcchar.b.eptype = eptype;
		hcchar.b.multicnt = 1;
		hcchar.b.devaddr = usb_pipedevice(pipe);
		hcchar.b.chdis = 0;
		hcchar.b.chen = 1;
		hcStat = HCSTAT_DATA;
		errCnt = 0;
		dwc_init_channel(dev, hctsiz.d32, hcchar, 0);
		if(dwc_wait_for_complete(dev, channel_num, &hcStat, &errCnt)){
			ret = HOST_ERR;
			goto out;
		}
	}
	
out:
	if(ret){
		debug("dwc_init channel hcziz %x, hcdma %x, hcchar %x\n", 
			otgReg->Host.hchn[channel_num].hctsizn, 
			otgReg->Host.hchn[channel_num].hcdman,
			otgReg->Host.hchn[channel_num].hccharn);
	}
	dev->act_len = length;
	dev->status = 0;
	return (ret);
}
Ejemplo n.º 30
0
/**
 * Sets the final status of an URB and returns it to the device driver. Any
 * required cleanup of the URB is performed.
 */
static int _complete(dwc_otg_hcd_t * hcd, void *urb_handle,
		     dwc_otg_hcd_urb_t * dwc_otg_urb, uint32_t status)
{
	struct urb *urb = (struct urb *)urb_handle;
#ifdef DEBUG
	if (CHK_DEBUG_LEVEL(DBG_HCDV | DBG_HCD_URB)) {
		DWC_PRINTF("%s: urb %p, device %d, ep %d %s, status=%d\n",
			   __func__, urb, usb_pipedevice(urb->pipe),
			   usb_pipeendpoint(urb->pipe),
			   usb_pipein(urb->pipe) ? "IN" : "OUT", status);
		if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
			int i;
			for (i = 0; i < urb->number_of_packets; i++) {
				DWC_PRINTF("  ISO Desc %d status: %d\n",
					   i, urb->iso_frame_desc[i].status);
			}
		}
	}
#endif

	urb->actual_length = dwc_otg_hcd_urb_get_actual_length(dwc_otg_urb);
	/* Convert status value. */
	switch (status) {
	case -DWC_E_PROTOCOL:
		status = -EPROTO;
		break;
	case -DWC_E_IN_PROGRESS:
		status = -EINPROGRESS;
		break;
	case -DWC_E_PIPE:
		status = -EPIPE;
		break;
	case -DWC_E_IO:
		status = -EIO;
		break;
	case -DWC_E_TIMEOUT:
		status = -ETIMEDOUT;
		break;
	default:
		if (status) {
			/* alan.K
			 * DWC_OTG IP don't know this status, so assumed to be a DWC_E_PROTOCOL. 
			 */
			DWC_WARN("Unknown urb status %d, but assumed to be an EPROTO\n", status);
			status = -EPROTO;
		}
	}

	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
		int i;

		urb->error_count = dwc_otg_hcd_urb_get_error_count(dwc_otg_urb);
		for (i = 0; i < urb->number_of_packets; ++i) {
			urb->iso_frame_desc[i].actual_length =
			    dwc_otg_hcd_urb_get_iso_desc_actual_length
			    (dwc_otg_urb, i);
			urb->iso_frame_desc[i].status =
			    dwc_otg_hcd_urb_get_iso_desc_actual_length
			    (dwc_otg_urb, i);
		}
	}

	urb->status = status;
	urb->hcpriv = NULL;
	if (!status) {
		if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
		    (urb->actual_length < urb->transfer_buffer_length)) {
			urb->status = -EREMOTEIO;
		}
	}

	if ((usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) ||
	    (usb_pipetype(urb->pipe) == PIPE_INTERRUPT)) {
		struct usb_host_endpoint *ep = dwc_urb_to_endpoint(urb);
		if (ep) {
			free_bus_bandwidth(dwc_otg_hcd_to_hcd(hcd),
					   dwc_otg_hcd_get_ep_bandwidth(hcd, ep->hcpriv),
					   urb);
		}
	}

	dwc_free(dwc_otg_urb);
	usb_hcd_giveback_urb(dwc_otg_hcd_to_hcd(hcd), urb, status);
	return 0;
}