コード例 #1
0
/**
 * This function unregisters a gadget driver
 *
 * @param driver The driver being unregistered
 */
static int dwc_usb_gadget_stop(struct usb_gadget *gadget, struct usb_gadget_driver *driver)
{
	//DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);

	if (gadget_wrapper == 0) {
		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
				-ENODEV);
		return -ENODEV;
	}
	if (driver == 0 || driver != gadget_wrapper->driver) {
		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
				-EINVAL);
		return -EINVAL;
	}

	gadget_wrapper->driver = 0;
	gadget_wrapper->enabled = 0;

	DWC_DEBUGPL(DBG_ANY, "unregistered driver '%s'\n", driver->driver.name);
	return 0;
}
コード例 #2
0
/**
 * This function unregisters a gadget driver
 *
 * @param driver The driver being unregistered
 */
int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
{
	//DWC_DEBUGPL(DBG_PCDV,"%s(%p)\n", __func__, _driver);

	if (gadget_wrapper == 0) {
		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): s_pcd==0\n", __func__,
			    -ENODEV);
		return -ENODEV;
	}
	if (driver == 0 || driver != gadget_wrapper->driver) {
		DWC_DEBUGPL(DBG_ANY, "%s Return(%d): driver?\n", __func__,
			    -EINVAL);
		return -EINVAL;
	}

	driver->unbind(&gadget_wrapper->gadget);
	gadget_wrapper->driver = 0;

	DWC_DEBUGPL(DBG_ANY, "unregistered driver \n");
	return 0;
}
コード例 #3
0
/**
 * This function frees a request object.
 *
 * @param ep The endpoint associated with the request
 * @param req The request being freed
 */
static void dwc_otg_pcd_free_request(struct usb_ep *ep, struct usb_request *req)
{
	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, ep, req);

	if (0 == ep || 0 == req) {
		DWC_WARN("%s() %s\n", __func__,
			 "Invalid ep or req argument!\n");
		return;
	}

	kfree(req);
}
コード例 #4
0
/** Initializes the DWC_otg controller and its root hub and prepares it for host
 * mode operation. Activates the root port. Returns 0 on success and a negative
 * error code on failure. */
int hcd_start(struct usb_hcd *hcd)
{
	dwc_otg_hcd_t *dwc_otg_hcd = hcd_to_dwc_otg_hcd(hcd);
	struct usb_bus *bus;

	DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD START\n");
	bus = hcd_to_bus(hcd);

	hcd->state = HC_STATE_RUNNING;
	if (dwc_otg_hcd_start(dwc_otg_hcd, &hcd_fops)) {
		return 0;
	}

	/* Initialize and connect root hub if one is not already attached */
	if (bus->root_hub) {
		DWC_DEBUGPL(DBG_HCD, "DWC OTG HCD Has Root Hub\n");
		/* Inform the HUB driver to resume. */
		usb_hcd_resume_root_hub(hcd);
	}

	return 0;
}
コード例 #5
0
/**
 *Gets the USB Frame number of the last SOF.
 */
static int get_frame_number(struct usb_gadget *gadget)
{
	struct gadget_wrapper *d;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);

	if (gadget == 0) {
		return -ENODEV;
	}

	d = container_of(gadget, struct gadget_wrapper, gadget);
	return dwc_otg_pcd_get_frame_number(d->pcd);
}
コード例 #6
0
/**
 * This function completes a request.  It call's the request call back.
 */
void request_done(dwc_otg_pcd_ep_t * _ep, dwc_otg_pcd_request_t * _req,
		  int _status)
{
	unsigned stopped = _ep->stopped;
	dwc_otg_core_if_t *core_if = GET_CORE_IF(_ep->pcd);

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _ep);

	if(_ep->dwc_ep.num && _ep->dwc_ep.is_in)
		list_del_init(&_req->pcd_queue);

	list_del_init(&_req->queue);

	if (_req->req.status == -EINPROGRESS) {
		_req->req.status = _status;
	} else {
		_status = _req->req.status;
	}

	/* don't modify queue heads during completion callback */
	_ep->stopped = 1;
	SPIN_UNLOCK(&_ep->pcd->lock);
	_req->req.complete(&_ep->ep, &_req->req);
	SPIN_LOCK(&_ep->pcd->lock);

	if (_ep->pcd->request_pending > 0) {
		--_ep->pcd->request_pending;
	}

	_ep->stopped = stopped;
	if(_ep->dwc_ep.is_in && _ep->dwc_ep.num){
		DWC_DEBUGPL(DBG_PCDV, "ep%d,len=%d\n",_ep->dwc_ep.num,_req->req.actual);
		_ep->pcd->ep_in_sync = 0;
	}

	if(core_if->dma_enable)
		dwc_otg_pcd_dma_unmap(&_ep->dwc_ep);
}
コード例 #7
0
ファイル: dwc_otg_hcd_queue.c プロジェクト: 4pao/openwrt
/**
 * Removes an interrupt or isochronous transfer from the periodic schedule.
 *
 * @param hcd The HCD state structure for the DWC OTG controller.
 * @param qh QH for the periodic transfer.
 */
static void deschedule_periodic(dwc_otg_hcd_t *hcd, dwc_otg_qh_t *qh)
{
	list_del_init(&qh->qh_list_entry);

	/* Release the periodic channel reservation. */
	hcd->periodic_channels--;

	/* Update claimed usecs per (micro)frame. */
	hcd->periodic_usecs -= qh->usecs;

	/* Update average periodic bandwidth claimed and # periodic reqs for usbfs. */
	hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_allocated -= qh->usecs / qh->interval;

	if (qh->ep_type == USB_ENDPOINT_XFER_INT) {
		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_int_reqs--;
		DWC_DEBUGPL(DBG_HCD, "Descheduled intr: qh %p, usecs %d, period %d\n",
			    qh, qh->usecs, qh->interval);
	} else {
		hcd_to_bus(dwc_otg_hcd_to_hcd(hcd))->bandwidth_isoc_reqs--;
		DWC_DEBUGPL(DBG_HCD, "Descheduled isoc: qh %p, usecs %d, period %d\n",
			    qh, qh->usecs, qh->interval);
	}
}
コード例 #8
0
/**
 * Initiates Session Request Protocol (SRP) to wakeup the host if no
 * session is in progress. If a session is already in progress, but
 * the device is suspended, remote wakeup signaling is started.
 *
 */
static int wakeup(struct usb_gadget *gadget)
{
	struct gadget_wrapper *d;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, gadget);

	if (gadget == 0) {
		return -ENODEV;
	} else {
		d = container_of(gadget, struct gadget_wrapper, gadget);
	}
	dwc_otg_pcd_wakeup(d->pcd);
	return 0;
}
コード例 #9
0
/**
 * This function is used to submit an I/O Request to an EP.
 *
 *	- When the request completes the request's completion callback
 *	  is called to return the request to the driver.
 *	- An EP, except control EPs, may have multiple requests
 *	  pending.
 *	- Once submitted the request cannot be examined or modified.
 *	- Each request is turned into one or more packets.
 *	- A BULK EP can queue any amount of data; the transfer is
 *	  packetized.
 *	- Zero length Packets are specified with the request 'zero'
 *	  flag.
 */
static int ep_queue(struct usb_ep *usb_ep, struct usb_request *usb_req,
		    gfp_t gfp_flags)
{
	dwc_otg_pcd_t *pcd;
	int retval = 0;

	//trace_printk("(%p,%p,%d)\n",
	//	    usb_ep, usb_req, gfp_flags);

	if (!usb_req || !usb_req->complete ||
		(!gadget_wrapper->gadget.sg_supported &&
			!usb_req->buf)) {
		DWC_WARN("bad params\n");
		return -EINVAL;
	}

	if (!usb_ep) {
		DWC_WARN("bad ep\n");
		return -EINVAL;
	}

	pcd = gadget_wrapper->pcd;
	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
			    gadget_wrapper->gadget.speed);
		DWC_WARN("bogus device state\n");
		return -ESHUTDOWN;
	}

	//trace_printk( "%s queue req %p, len %d buf %p\n",
	//	    usb_ep->name, usb_req, usb_req->length, usb_req->buf);

	usb_req->status = -EINPROGRESS;
	usb_req->actual = 0;

	retval = dwc_otg_pcd_ep_queue(pcd, usb_ep, usb_req->buf, usb_req->dma/*dma_addr*/,
				      usb_req->length, usb_req->zero, usb_req->num_sgs,
				      usb_req->sg, usb_req, gfp_flags == GFP_ATOMIC ? 1 : 0);
	if (retval) {
		pr_err("%s, cannot enqueue a renquest, err :%d\n", __func__,
			retval);
		pr_info( "%s queue req %p, len %d buf %p\n",
			    usb_ep->name, usb_req, usb_req->length, usb_req->buf);
		return -EINVAL;
	}

	return 0;
}
コード例 #10
0
ファイル: dwc_otg_pcd.c プロジェクト: odit/rv042
/**
 * This function frees a request object.
 *
 * @param _ep The endpoint associated with the request
 * @param _req The request being freed
 */
static void dwc_otg_pcd_free_request(struct usb_ep *_ep,
                                     struct usb_request *_req)
{
        dwc_otg_pcd_request_t *req;
        DWC_DEBUGPL(DBG_PCDV,"%s(%p,%p)\n", __func__, _ep, _req);

	if (0 == _ep || 0 == _req) {
                DWC_WARN("%s() %s\n", __func__,
                         "Invalid ep or req argument!\n");
		return;
        }

	req = container_of(_req, dwc_otg_pcd_request_t, req);
	kfree(req);
}
コード例 #11
0
/**
 * This function is called when an EP is disabled due to disconnect or
 * change in configuration. Any pending requests will terminate with a
 * status of -ESHUTDOWN.
 *
 * This function modifies the dwc_otg_ep_t data structure for this EP,
 * and then calls dwc_otg_ep_deactivate.
 */
static int dwc_otg_pcd_ep_disable(struct usb_ep *_ep)
{
	dwc_otg_pcd_ep_t * ep;
	unsigned long flags;
	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _ep);
	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
	if (!_ep || !ep->desc) {
		DWC_DEBUGPL(DBG_PCD, "%s, %s not enabled\n", __func__,
			     _ep ? ep->ep.name : NULL);
		return -EINVAL;
	}
	SPIN_LOCK_IRQSAVE(&ep->pcd->lock, flags);
	request_nuke(ep);
	dwc_otg_ep_deactivate(GET_CORE_IF(ep->pcd), &ep->dwc_ep);
	ep->desc = 0;
	ep->stopped = 1;
	if (ep->dwc_ep.is_in) {
		release_perio_tx_fifo(GET_CORE_IF(ep->pcd),ep->dwc_ep.tx_fifo_num);
		release_tx_fifo(GET_CORE_IF(ep->pcd), ep->dwc_ep.tx_fifo_num);
	}
	SPIN_UNLOCK_IRQRESTORE(&ep->pcd->lock, flags);
	DWC_DEBUGPL(DBG_PCD, "%s disabled\n", _ep->name);
	return 0;
}
コード例 #12
0
/**
 * This function completes a request.  It call's the request call back.
 */
void request_done(dwc_otg_pcd_ep_t * _ep, dwc_otg_pcd_request_t * _req,
		  int _status)
{
	unsigned stopped = _ep->stopped;
	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _ep);

	if (_req->mapped) {
		dma_unmap_single(_ep->pcd->gadget.dev.parent,
			_req->req.dma, _req->req.length,
			_ep->dwc_ep.is_in
				? DMA_TO_DEVICE
				: DMA_FROM_DEVICE);
		_req->req.dma = DMA_ADDR_INVALID;
		_req->mapped = 0;
	} else
		dma_sync_single_for_cpu(_ep->pcd->gadget.dev.parent,
			_req->req.dma, _req->req.length,
			_ep->dwc_ep.is_in
				? DMA_TO_DEVICE
				: DMA_FROM_DEVICE);

	list_del_init(&_req->queue);
	if (_req->req.status == -EINPROGRESS) {
		_req->req.status = _status;
	} else {
		_status = _req->req.status;
	}

	/* don't modify queue heads during completion callback */
	_ep->stopped = 1;
	SPIN_UNLOCK(&_ep->pcd->lock);
	_req->req.complete(&_ep->ep, &_req->req);
	SPIN_LOCK(&_ep->pcd->lock);
	if (_ep->pcd->request_pending > 0) {
		--_ep->pcd->request_pending;
	}
	_ep->stopped = stopped;

#ifdef CONFIG_405EZ
	/*
	 * Added-sr: 2007-07-26
	 *
	 * Finally, when the current request is done, mark this endpoint
	 * as not active, so that new requests can be processed.
	 */
	_ep->dwc_ep.active = 0;
#endif
}
コード例 #13
0
void pcd_remove(
	struct dwc_otg_device *_dev

	)
{
       dwc_otg_device_t *otg_dev = _dev;
	dwc_otg_pcd_t *pcd = otg_dev->pcd;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);

	/*
	 * Free the IRQ
	 */
	//free_irq(_dev->irq, pcd);
	dwc_otg_pcd_remove(otg_dev->pcd);
	free_wrapper(gadget_wrapper);
	otg_dev->pcd = 0;
}
コード例 #14
0
/**
 * This function frees an I/O buffer that was allocated by alloc_buffer.
 *
 * @param _ep the endpoint associated with the buffer
 * @param _buf address of the buffer
 * @param _dma The buffer's DMA address
 * @param _bytes The number of bytes of the buffer
 */
static void dwc_otg_pcd_free_buffer(struct usb_ep *_ep, void *_buf,
				    dma_addr_t _dma, unsigned _bytes)
{
	dwc_otg_pcd_ep_t *ep;
	dwc_otg_pcd_t *pcd = 0;

	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
	pcd = ep->pcd;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p,%0x,%d)\n", __func__, _ep, _buf, _dma,
		    _bytes);

	if (GET_CORE_IF(pcd)->dma_enable) {
		dma_free_coherent(NULL, _bytes, _buf, _dma);
	} else {
		kfree(_buf);
	}
}
コード例 #15
0
/**
 * This function cancels an I/O request from an EP.
 */
static int ep_dequeue(struct usb_ep *usb_ep, struct usb_request *usb_req)
{
	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, usb_req);

	if (!usb_ep || !usb_req) {
		DWC_WARN("bad argument\n");
		return -EINVAL;
	}
	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_WARN("bogus device state\n");
		return -ESHUTDOWN;
	}
	if (dwc_otg_pcd_ep_dequeue(gadget_wrapper->pcd, usb_ep, usb_req)) {
		return -EINVAL;
	}

	return 0;
}
コード例 #16
0
/**
 * This function allocates a request object to use with the specified
 * endpoint.
 *
 * @param _ep The endpoint to be used with with the request
 * @param _gfp_flags the GFP_* flags to use.
 */
static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *_ep,
						     gfp_t _gfp_flags)
{
	dwc_otg_pcd_request_t * req;
	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, _ep, _gfp_flags);
	if (0 == _ep) {
		DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
		return 0;
	}
	req = kmalloc(sizeof(dwc_otg_pcd_request_t), _gfp_flags);
	if (0 == req) {
		DWC_WARN("%s() %s\n", __func__,"request allocation failed!\n");
		return 0;
	}
	memset(req, 0, sizeof(dwc_otg_pcd_request_t));
	req->req.dma = DMA_ADDR_INVALID;
	INIT_LIST_HEAD(&req->queue);
	return &req->req;
}
コード例 #17
0
/**
 * usb_ep_set_halt stalls an endpoint.
 *
 * usb_ep_clear_halt clears an endpoint halt and resets its data
 * toggle.
 *
 * Both of these functions are implemented with the same underlying
 * function. The behavior depends on the value argument.
 *
 * @param[in] usb_ep the Endpoint to halt or clear halt.
 * @param[in] value
 *	- 0 means clear_halt.
 *	- 1 means set_halt,
 *	- 2 means clear stall lock flag.
 *	- 3 means set  stall lock flag.
 */
static int ep_halt(struct usb_ep *usb_ep, int value)
{
	int retval = 0;

	DWC_DEBUGPL(DBG_PCD, "HALT %s %d\n", usb_ep->name, value);

	if (!usb_ep) {
		DWC_WARN("bad ep\n");
		return -EINVAL;
	}

	retval = dwc_otg_pcd_ep_halt(gadget_wrapper->pcd, usb_ep, value);
	if (retval == -DWC_E_AGAIN) {
		return -EAGAIN;
	} else if (retval) {
		retval = -EINVAL;
	}

	return retval;
}
コード例 #18
0
/**
 * Cleanup the PCD.
 */
void pcd_remove(struct platform_device *_dev)
{
	dwc_otg_device_t *otg_dev = platform_get_otgdata(_dev);
	dwc_otg_pcd_t *pcd = otg_dev->pcd;
	int irq;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);

	/*
	 * Free the IRQ
	 */
	irq = platform_get_irq(_dev, 0);
	if(irq >= 0) {
		free_irq(irq, pcd);
	}

	dwc_otg_pcd_remove(otg_dev->pcd);
	free_wrapper(gadget_wrapper);
	otg_dev->pcd = 0;
}
コード例 #19
0
/**
 * ep_wedge: sets the halt feature and ignores clear requests
 *
 * @usb_ep: the endpoint being wedged
 *
 * Use this to stall an endpoint and ignore CLEAR_FEATURE(HALT_ENDPOINT)
 * requests. If the gadget driver clears the halt status, it will
 * automatically unwedge the endpoint.
 *
 * Returns zero on success, else negative errno. *
 * Check usb_ep_set_wedge() at "usb_gadget.h" for details
 */
static int ep_wedge(struct usb_ep *usb_ep)
{
    int retval = 0;

    DWC_DEBUGPL(DBG_PCD, "WEDGE %s\n", usb_ep->name);

    if (!usb_ep) {
        DWC_WARN("bad ep\n");
        return -EINVAL;
    }

    retval = dwc_otg_pcd_ep_wedge(gadget_wrapper->pcd, usb_ep);
    if (retval == -DWC_E_AGAIN) {
        retval = -EAGAIN;
    } else if (retval) {
        retval = -EINVAL;
    }

    return retval;
}
コード例 #20
0
/**
 * This function allocates a request object to use with the specified
 * endpoint.
 *
 * @param ep The endpoint to be used with with the request
 * @param gfp_flags the GFP_* flags to use.
 */
static struct usb_request *dwc_otg_pcd_alloc_request(struct usb_ep *ep,
						     gfp_t gfp_flags)
{
	struct usb_request *usb_req;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%d)\n", __func__, ep, gfp_flags);
	if (0 == ep) {
		DWC_WARN("%s() %s\n", __func__, "Invalid EP!\n");
		return 0;
	}
	usb_req = kmalloc(sizeof(*usb_req), gfp_flags);
	if (0 == usb_req) {
		DWC_WARN("%s() %s\n", __func__, "request allocation failed!\n");
		return 0;
	}
	memset(usb_req, 0, sizeof(*usb_req));
	usb_req->dma = DWC_INVALID_DMA_ADDR;

	return usb_req;
}
コード例 #21
0
/**
 * This function stops ISO EP Periodic Data Transfer.
 */
static int iso_ep_stop(struct usb_ep *usb_ep, struct usb_iso_request *req)
{
	int retval = 0;
	if (!usb_ep) {
		DWC_WARN("bad ep\n");
	}

	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_DEBUGPL(DBG_PCDV, "gadget.speed=%d\n",
			    gadget_wrapper->gadget.speed);
		DWC_WARN("bogus device state\n");
	}

	dwc_otg_pcd_iso_ep_stop(gadget_wrapper->pcd, usb_ep, req);
	if (retval) {
		retval = -EINVAL;
	}

	return retval;
}
コード例 #22
0
/**
 * This function is called by the Gadget Driver for each EP to be
 * configured for the current configuration (SET_CONFIGURATION).
 *
 * This function initializes the dwc_otg_ep_t data structure, and then
 * calls dwc_otg_ep_activate.
 */
static int ep_enable(struct usb_ep *usb_ep,
		     const struct usb_endpoint_descriptor *ep_desc)
{
	int retval;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p,%p)\n", __func__, usb_ep, ep_desc);

	if (!usb_ep || !ep_desc || ep_desc->bDescriptorType != USB_DT_ENDPOINT) {
		DWC_WARN("%s, bad ep or descriptor\n", __func__);
		return -EINVAL;
	}
	if (usb_ep == &gadget_wrapper->ep0) {
		DWC_WARN("%s, bad ep(0)\n", __func__);
		return -EINVAL;
	}

	/* Check FIFO size? */
	if (!ep_desc->wMaxPacketSize) {
		DWC_WARN("%s, bad %s maxpacket\n", __func__, usb_ep->name);
		return -ERANGE;
	}

	if (!gadget_wrapper->driver ||
	    gadget_wrapper->gadget.speed == USB_SPEED_UNKNOWN) {
		DWC_WARN("%s, bogus device state\n", __func__);
		return -ESHUTDOWN;
	}

	retval = dwc_otg_pcd_ep_enable(gadget_wrapper->pcd,
				       (const uint8_t *)ep_desc,
				       (void *)usb_ep);
	if (retval) {
		DWC_WARN("dwc_otg_pcd_ep_enable failed\n");
		return -EINVAL;
	}

	usb_ep->maxpacket = le16_to_cpu(ep_desc->wMaxPacketSize);

	return 0;
}
コード例 #23
0
static int _isoc_complete(dwc_otg_pcd_t * pcd, void *ep_handle,
			  void *req_handle, int proc_buf_num)
{
	int i, packet_count;
	struct usb_gadget_iso_packet_descriptor *iso_packet = 0;
	struct usb_iso_request *iso_req = req_handle;

	if (proc_buf_num) {
		iso_packet = iso_req->iso_packet_desc1;
	} else {
		iso_packet = iso_req->iso_packet_desc0;
	}
	packet_count =
	    dwc_otg_pcd_get_iso_packet_count(pcd, ep_handle, req_handle);
	for (i = 0; i < packet_count; ++i) {
		int status;
		int actual;
		int offset;
		dwc_otg_pcd_get_iso_packet_params(pcd, ep_handle, req_handle,
						  i, &status, &actual, &offset);
		switch (status) {
		case -DWC_E_NO_DATA:
			status = -ENODATA;
			break;
		default:
			if (status) {
				DWC_DEBUGPL(DBG_CIL,"unknown status in isoc packet\n");
			}

		}
		iso_packet[i].status = status;
		iso_packet[i].offset = offset;
		iso_packet[i].actual_length = actual;
	}

	iso_req->status = 0;
	iso_req->process_buffer(ep_handle, iso_req);

	return 0;
}
コード例 #24
0
ファイル: dwc_otg_pcd.c プロジェクト: spfy/040005
/**
 * This function allocates an I/O buffer to be used for a transfer
 * to/from the specified endpoint.
 * 
 * @param _ep The endpoint to be used with with the request
 * @param _bytes The desired number of bytes for the buffer
 * @param _dma Pointer to the buffer's DMA address; must be valid
 * @param _gfp_flags the GFP_* flags to use.
 * @return address of a new buffer or null is buffer could not be allocated.
 */
static void *dwc_otg_pcd_alloc_buffer(struct usb_ep *_ep, unsigned _bytes,
									  dma_addr_t *_dma, int _gfp_flags)
{
	void *buf;
	dwc_otg_pcd_ep_t *ep;
	dwc_otg_pcd_t *pcd = 0;

	ep = container_of(_ep, dwc_otg_pcd_ep_t, ep);
	pcd = ep->pcd;

	DWC_DEBUGPL(DBG_PCDV,"%s(%p,%d,%p,%0x)\n", __func__, _ep, _bytes, 
				_dma, _gfp_flags);

	/* Check dword alignment */
	if ((_bytes & 0x3UL) != 0) 
	{
		DWC_WARN("%s() Buffer size is not a multiple of" 
				 "DWORD size (%d)",__func__, _bytes);
	}

	if (GET_CORE_IF(pcd)->dma_enable) 
	{
		buf = dma_alloc_coherent (NULL, _bytes, _dma, _gfp_flags);
	}
	else 
	{
		buf = kmalloc( _bytes, _gfp_flags);
	}

	/* Check dword alignment */
	if (((int)buf & 0x3UL) != 0) 
	{
		DWC_WARN("%s() Buffer is not DWORD aligned (%p)",
					__func__, buf);
	}
		
	return buf;
}
コード例 #25
0
/**
 * Cleanup the PCD.
 */
void pcd_remove(
struct platform_device *_dev
	)
{
	dwc_otg_device_t *otg_dev = platform_get_drvdata(_dev);
	dwc_otg_pcd_t *pcd = otg_dev->pcd;
	int plug_irq;

	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, _dev);

	/*
	 * Free the IRQ
	 */
	//free_irq(_dev->irq, pcd);
	plug_irq = usb_get_vbus_irq();
	usb_free_vbus_irq(plug_irq);
	dwc_otg_pcd_remove(pcd);
	destroy_workqueue(gadget_wrapper->detect_wq);
	wake_lock_destroy(&usb_wake_lock);
	switch_dev_unregister(&gadget_wrapper->sdev);
	free_wrapper(gadget_wrapper);
	pcd = 0;
}
コード例 #26
0
/**
 * This function registers a gadget driver with the PCD.
 *
 * When a driver is successfully registered, it will receive control
 * requests including set_configuration(), which enables non-control
 * requests.  then usb traffic follows until a disconnect is reported.
 * then a host may connect again, or the driver might get unbound.
 *
 * @param driver The driver being registered
 */
int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
	int (*bind)(struct usb_gadget *))
{
	int retval;

	pr_info("%s\n", __func__);
	if (!driver || driver->speed == USB_SPEED_UNKNOWN ||
			!driver->disconnect || !driver->setup) {
		//!driver->unbind || !driver->disconnect || !driver->setup) {
		DWC_DEBUGPL(DBG_PCDV, "EINVAL\n");
		return -EINVAL;
	}

	DWC_DEBUGPL(DBG_PCD, "registering gadget driver '%s'\n",
			driver->driver.name);
	
	if (gadget_wrapper == 0) {
		DWC_DEBUGPL(DBG_PCDV, "ENODEV\n");
		return -ENODEV;
	}
	if (gadget_wrapper->driver != 0) {
		DWC_DEBUGPL(DBG_PCDV, "EBUSY (%p)\n", gadget_wrapper->driver);
		return -EBUSY;
	}

	/* hook up the driver */
	gadget_wrapper->driver = driver;
	gadget_wrapper->gadget.dev.driver = &driver->driver;

	DWC_DEBUGPL(DBG_PCD, "bind to driver %s\n", driver->driver.name);
	retval = bind(&gadget_wrapper->gadget);
	gadget_wrapper->enabled = 1;
	if (retval) {
		DWC_ERROR("bind to driver %s --> error %d\n",
				driver->driver.name, retval);
		gadget_wrapper->driver = 0;
		gadget_wrapper->gadget.dev.driver = 0;
		gadget_wrapper->enabled = 0;
		return retval;
	}
	DWC_DEBUGPL(DBG_ANY, "registered gadget driver '%s'\n",
			driver->driver.name);

	return 0;
}
コード例 #27
0
/** 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;})) ;
コード例 #28
0
/**
 * This function initialized the usb_ep structures to there default
 * state.
 *
 * @param d Pointer on gadget_wrapper.
 */
void gadget_add_eps(struct gadget_wrapper *d)
{
	static const char *names[] = {

		"ep0",
		"ep1in",
		"ep2in",
		"ep3in",
		"ep4in",
		"ep5in",
		"ep6in",
		"ep7in",
		"ep8in",
		"ep9in",
		"ep10in",
		"ep11in",
		"ep12in",
		"ep13in",
		"ep14in",
		"ep15in",
		"ep1out",
		"ep2out",
		"ep3out",
		"ep4out",
		"ep5out",
		"ep6out",
		"ep7out",
		"ep8out",
		"ep9out",
		"ep10out",
		"ep11out",
		"ep12out",
		"ep13out",
		"ep14out",
		"ep15out"
	};

	int i;
	struct usb_ep *ep;

	DWC_DEBUGPL(DBG_PCDV, "%s\n", __func__);

	INIT_LIST_HEAD(&d->gadget.ep_list);
	d->gadget.ep0 = &d->ep0;
	d->gadget.speed = USB_SPEED_UNKNOWN;

	INIT_LIST_HEAD(&d->gadget.ep0->ep_list);

	/**
	 * Initialize the EP0 structure.
	 */
	ep = &d->ep0;

	/* Init the usb_ep structure. */
	ep->name = names[0];
	ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;

	/**
	 * @todo NGS: What should the max packet size be set to
	 * here?  Before EP type is set?
	 */
	ep->maxpacket = MAX_PACKET_SIZE;
	dwc_otg_pcd_ep_enable(d->pcd, NULL, ep);

	list_add_tail(&ep->ep_list, &d->gadget.ep_list);

	/**
	 * Initialize the EP structures.
	 */

	for (i = 0; i < 15; i++) {
		ep = &d->in_ep[i];

		/* Init the usb_ep structure. */
		ep->name = names[i + 1];
		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;

		/**
		 * @todo NGS: What should the max packet size be set to
		 * here?  Before EP type is set?
		 */
		ep->maxpacket = MAX_PACKET_SIZE;
		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
	}

	for (i = 0; i < 15; i++) {
		ep = &d->out_ep[i];

		/* Init the usb_ep structure. */
		ep->name = names[15 + i + 1];
		ep->ops = (struct usb_ep_ops *)&dwc_otg_pcd_ep_ops;

		/**
		 * @todo NGS: What should the max packet size be set to
		 * here?  Before EP type is set?
		 */
		ep->maxpacket = MAX_PACKET_SIZE;

		list_add_tail(&ep->ep_list, &d->gadget.ep_list);
	}

	/* remove ep0 from the list.  There is a ep0 pointer. */
	list_del_init(&d->ep0.ep_list);

	d->ep0.maxpacket = MAX_EP0_SIZE;
}
コード例 #29
0
/**
 * This function releases the Gadget device.
 * required by device_unregister().
 *
 * @todo Should this do something?	Should it free the PCD?
 */
static void dwc_otg_pcd_gadget_release(struct device *dev)
{
	DWC_DEBUGPL(DBG_PCDV, "%s(%p)\n", __func__, dev);
}
コード例 #30
0
ファイル: dwc_otg_hcd_queue.c プロジェクト: 4pao/openwrt
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;
}