Exemplo n.º 1
0
/*
* This function queues a write request in the DMA queue
* for a given endpoint.  The direction of the
* entry will be inferred from the endpoint direction.
*/
cy_as_return_status_t
cy_as_dma_queue_request(cy_as_device *dev_p,
	cy_as_end_point_number_t ep, void *mem_p,
	uint32_t size, cy_bool pkt, cy_bool readreq, cy_as_dma_callback cb)
{
	uint32_t mask ;
	cy_as_dma_queue_entry *entry_p ;
	cy_as_dma_end_point *ep_p ;

	/*
	* make sure the endpoint is valid
	*/
	if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
		return CY_AS_ERROR_INVALID_ENDPOINT ;

	/* Get the endpoint pointer based on the endpoint number */
	ep_p = CY_AS_NUM_EP(dev_p, ep) ;

	if (!cy_as_dma_end_point_is_enabled(ep_p))
	{
		printk(KERN_ERR"%d ep disabled state=%d maxhwdata=%d maxhaldata=%d\n",ep,ep_p->state,ep_p->maxhwdata,ep_p->maxhaldata);

		if(ep == CY_AS_P2S_WRITE_ENDPOINT)
			cy_as_dma_enable_end_point(dev_p,CY_AS_P2S_WRITE_ENDPOINT,cy_true,cy_as_direction_in);
		else if(ep == CY_AS_P2S_READ_ENDPOINT)
			cy_as_dma_enable_end_point(dev_p,CY_AS_P2S_READ_ENDPOINT,cy_true,cy_as_direction_out);
		else
			return CY_AS_ERROR_ENDPOINT_DISABLED ;
	}
	entry_p = cy_as_dma_get_dma_queue_entry(dev_p) ;

	entry_p->buf_p = mem_p ;
	entry_p->cb = cb ;
	entry_p->size = size ;
	entry_p->offset = 0 ;
	entry_p->packet = pkt ;
	entry_p->readreq = readreq ;

	mask = cy_as_hal_disable_interrupts() ;
	entry_p->next_p = 0 ;
	if (ep_p->last_p)
		ep_p->last_p->next_p = entry_p ;
	ep_p->last_p = entry_p ;
	if (ep_p->queue_p == 0)
		ep_p->queue_p = entry_p ;
	cy_as_hal_enable_interrupts(mask) ;

	return CY_AS_ERROR_SUCCESS ;
}
Exemplo n.º 2
0
cy_as_return_status_t
cy_as_usb_setup_dma(cy_as_device *dev_p)
{
	cy_as_return_status_t ret = CY_AS_ERROR_SUCCESS;
	uint32_t i;

	for (i = 0; i < 10; i++) {
		cy_as_usb_end_point_config *config_p =
			&dev_p->usb_config[end_point_map[i]];
		if (config_p->enabled) {
			/* Map the endpoint direction to the DMA direction */
			cy_as_dma_direction dir = cy_as_direction_out;
			if (config_p->dir == cy_as_usb_in)
				dir = cy_as_direction_in;

			ret = cy_as_dma_enable_end_point(dev_p,
				end_point_map[i], cy_true, dir);
			if (ret != CY_AS_ERROR_SUCCESS)
				break;
		}
	}

	return ret;
}
Exemplo n.º 3
0
/*
 * This function cancels any DMA operations pending with the HAL layer as well
 * as any DMA operation queued on the endpoint.
 */
cy_as_return_status_t
cy_as_dma_cancel(
	cy_as_device *dev_p,
	cy_as_end_point_number_t ep,
	cy_as_return_status_t err)
{
	uint32_t mask ;
	cy_as_dma_end_point *ep_p ;
	cy_as_dma_queue_entry *entry_p ;
	cy_bool epstate ;

	/*
	 * make sure the endpoint is valid
	 */
	if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
		return CY_AS_ERROR_INVALID_ENDPOINT ;

	/* Get the endpoint pointer based on the endpoint number */
	ep_p = CY_AS_NUM_EP(dev_p, ep) ;

	if (ep_p) {
		/* Remember the state of the endpoint */
		epstate = cy_as_dma_end_point_is_enabled(ep_p) ;

		/*
		 * disable the endpoint so no more DMA packets can be
		 * queued.
		 */
		cy_as_dma_enable_end_point(dev_p, ep,
			cy_false, cy_as_direction_dont_change) ;

		/*
		 * don't allow any interrupts from this endpoint
		 * while we get the most current request off of
		 * the queue.
		 */
		cy_as_dma_set_drq(dev_p, ep, cy_false) ;

		/*
		 * cancel any pending request queued in the HAL layer
		 */
		if (cy_as_dma_end_point_in_transit(ep_p))
			cy_as_hal_dma_cancel_request(dev_p->tag, ep_p->ep) ;

		/*
		 * shutdown the DMA for this endpoint so no
		 * more data is transferred
		 */
		cy_as_dma_end_point_set_stopped(ep_p) ;

		/*
		 * mark the endpoint as not in transit, because we are
		 * going to consume any queued requests
		 */
		cy_as_dma_end_point_clear_in_transit(ep_p) ;

		/*
		 * now, remove each entry in the queue and call the
		 * associated callback stating that the request was
		 * canceled.
		 */
		ep_p->last_p = 0 ;
		while (ep_p->queue_p != 0) {
			/* Disable interrupts to manipulate the queue */
			mask = cy_as_hal_disable_interrupts() ;

			/* Remove an entry from the queue */
			entry_p = ep_p->queue_p ;
			ep_p->queue_p = entry_p->next_p ;

			/* Ok, the queue has been updated, we can
			 * turn interrupts back on */
			cy_as_hal_enable_interrupts(mask) ;

			/* Call the callback indicating we have
			 * canceled the DMA */
			if (entry_p->cb)
				entry_p->cb(dev_p, ep,
					entry_p->buf_p, entry_p->size, err) ;

			cy_as_dma_add_request_to_free_queue(dev_p, entry_p) ;
		}

		if (ep == 0 || ep == 1) {
			/*
			 * if this endpoint is zero or one, we need to
			 * clear the queue of any pending CY_RQT_USB_EP_DATA
			 * requests as these are pending requests to send
			 * data to the west bridge device.
			 */
			cy_as_ll_remove_ep_data_requests(dev_p, ep) ;
		}

		if (epstate) {
			/*
			 * the endpoint started out enabled, so we
			 * re-enable the endpoint here.
			 */
			cy_as_dma_enable_end_point(dev_p, ep,
				cy_true, cy_as_direction_dont_change) ;
		}
	}

	return CY_AS_ERROR_SUCCESS ;
}
Exemplo n.º 4
0
/*
* Wait for all entries in the DMA queue associated
* the given endpoint to be drained.  This function
* will not return until all the DMA data has been
* transferred.
*/
cy_as_return_status_t
cy_as_dma_drain_queue(cy_as_device *dev_p,
	cy_as_end_point_number_t ep, cy_bool kickstart)
{
	cy_as_dma_end_point *ep_p ;
	int loopcount = 200 ;
	uint32_t mask ;

	/*
	* make sure the endpoint is valid
	*/
	if (ep >= sizeof(dev_p->endp)/sizeof(dev_p->endp[0]))
		return CY_AS_ERROR_INVALID_ENDPOINT ;

	/* Get the endpoint pointer based on the endpoint number */
	ep_p = CY_AS_NUM_EP(dev_p, ep) ;

	/*
	* if the endpoint is empty of traffic, we return
	* with success immediately
	*/
	mask = cy_as_hal_disable_interrupts() ;
	if (ep_p->queue_p == 0) {
		cy_as_hal_enable_interrupts(mask) ;
		return CY_AS_ERROR_SUCCESS ;
	} else {
		/*
		 * add 10 seconds to the time out value for each 64 KB segment
		 * of data to be transferred.
		 */
		if (ep_p->queue_p->size > 0x10000)
			loopcount += ((ep_p->queue_p->size / 0x10000) * 100) ;
	}
	cy_as_hal_enable_interrupts(mask) ;

	/* If we are already sleeping on this endpoint, it is an error */
	if (cy_as_dma_end_point_is_sleeping(ep_p))
		return CY_AS_ERROR_NESTED_SLEEP ;

	/*
	* we disable the endpoint while the queue drains to
	* prevent any additional requests from being queued while we are waiting
	*/
	cy_as_dma_enable_end_point(dev_p, ep,
		cy_false, cy_as_direction_dont_change) ;

	if (kickstart) {
		/*
		* now, kick start the DMA if necessary
		*/
		cy_as_dma_kick_start(dev_p, ep) ;
	}

	/*
	* check one last time before we begin sleeping to see if the
	* queue is drained.
	*/
	if (ep_p->queue_p == 0) {
		cy_as_dma_enable_end_point(dev_p, ep, cy_true,
			cy_as_direction_dont_change) ;
		return CY_AS_ERROR_SUCCESS ;
	}

	while (loopcount-- > 0) {
		/*
		 * sleep for 10 ms maximum (per loop) while
		 * waiting for the transfer to complete.
		 */
		cy_as_dma_end_point_set_sleep_state(ep_p) ;
		cy_as_hal_sleep_on(&ep_p->channel, 10) ;

		/* If we timed out, the sleep bit will still be set */
		cy_as_dma_end_point_set_wake_state(ep_p) ;

		/* Check the queue to see if is drained */
		if (ep_p->queue_p == 0) {
			/*
			 * clear the endpoint running and in transit flags
			 * for the endpoint, now that its DMA queue is empty.
			 */
			cy_as_dma_end_point_clear_in_transit(ep_p) ;
			cy_as_dma_end_point_set_stopped(ep_p) ;

			cy_as_dma_enable_end_point(dev_p, ep,
				cy_true, cy_as_direction_dont_change) ;
			return CY_AS_ERROR_SUCCESS ;
		}
	}

	printk(KERN_ERR"cyasdevice:timeout 0xA0 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA0));
	printk(KERN_ERR"cyasdevice:timeout 0xA1 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA1));
	printk(KERN_ERR"cyasdevice:timeout 0xA2 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0xA2));
	printk(KERN_ERR"cyasdevice:timeout 0x90 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0x90));
	printk(KERN_ERR"cyasdevice:timeout 0x91 = 0x%x\n",cy_as_hal_read_register(dev_p->tag,0x91));
	/*
	 * the DMA operation that has timed out can be cancelled, so that later
	 * operations on this queue can proceed.
	 */
	cy_as_dma_cancel(dev_p, ep, CY_AS_ERROR_TIMEOUT) ;
	cy_as_dma_enable_end_point(dev_p, ep,
		cy_true, cy_as_direction_dont_change) ;
	return CY_AS_ERROR_TIMEOUT ;
}