static int dma_channel_abort(struct dma_channel *channel)
{
	struct musbfsh_dma_channel *musbfsh_channel = channel->private_data;
	void __iomem *mbase = musbfsh_channel->controller->base;

	u8 bchannel = musbfsh_channel->idx;
	int offset;
	u16 csr;
	
	INFO("idx=%d\n", musbfsh_channel->idx);
	if (channel->status == MUSBFSH_DMA_STATUS_BUSY) {
		if (musbfsh_channel->transmit) {
			offset = MUSBFSH_EP_OFFSET(musbfsh_channel->epnum,
						MUSBFSH_TXCSR);

			/*
			 * The programming guide says that we must clear
			 * the DMAENA bit before the DMAMODE bit...
			 */
			csr = musbfsh_readw(mbase, offset);
			csr &= ~(MUSBFSH_TXCSR_AUTOSET | MUSBFSH_TXCSR_DMAENAB);
			musbfsh_writew(mbase, offset, csr);
			csr &= ~MUSBFSH_TXCSR_DMAMODE;
			musbfsh_writew(mbase, offset, csr);
		} else {
			offset = MUSBFSH_EP_OFFSET(musbfsh_channel->epnum,
						MUSBFSH_RXCSR);

			csr = musbfsh_readw(mbase, offset);
			csr &= ~(MUSBFSH_RXCSR_AUTOCLEAR |
				 MUSBFSH_RXCSR_DMAENAB |
				 MUSBFSH_RXCSR_DMAMODE);
			musbfsh_writew(mbase, offset, csr);
		}

		musbfsh_writew(mbase,
			MUSBFSH_HSDMA_CHANNEL_OFFSET(bchannel, MUSBFSH_HSDMA_CONTROL),
			0);
		musbfsh_write_hsdma_addr(mbase, bchannel, 0);
		musbfsh_write_hsdma_count(mbase, bchannel, 0);
		channel->status = MUSBFSH_DMA_STATUS_FREE;
	}

	return 0;
}
static void configure_channel(struct dma_channel *channel,
				u16 packet_sz, u8 mode,
				dma_addr_t dma_addr, u32 len)
{
	struct musbfsh_dma_channel *musbfsh_channel = channel->private_data;
	struct musbfsh_dma_controller *controller = musbfsh_channel->controller;
	//struct musbfs *musb = controller->private_data;
	void __iomem *mbase = controller->base;
	u8 bchannel = musbfsh_channel->idx;
	u16 csr = 0;
	
	INFO("idx=%d\n", musbfsh_channel->idx);
	INFO("%p, pkt_sz %d, addr 0x%x, len %d, mode %d\n",
			channel, packet_sz, dma_addr, len, mode);

	if (mode) { //mode 1,multi-packet
		csr |= 1 << MUSBFSH_HSDMA_MODE1_SHIFT;
		BUG_ON(len < packet_sz);
	}
	csr |= MUSBFSH_HSDMA_BURSTMODE_INCR16
				<< MUSBFSH_HSDMA_BURSTMODE_SHIFT;

	csr |= (musbfsh_channel->epnum << MUSBFSH_HSDMA_ENDPOINT_SHIFT)
		| (1 << MUSBFSH_HSDMA_ENABLE_SHIFT)
		| (1 << MUSBFSH_HSDMA_IRQENABLE_SHIFT)
		| (musbfsh_channel->transmit
				? (1 << MUSBFSH_HSDMA_TRANSMIT_SHIFT)
				: 0);

	/* address/count */
	musbfsh_write_hsdma_addr(mbase, bchannel, dma_addr);
	musbfsh_write_hsdma_count(mbase, bchannel, len);

	/* control (this should start things) */
	musbfsh_writew(mbase,
		MUSBFSH_HSDMA_CHANNEL_OFFSET(bchannel, MUSBFSH_HSDMA_CONTROL),
		csr);
}
/*
 * Load an endpoint's FIFO
 */
void musbfsh_write_fifo(struct musbfsh_hw_ep *hw_ep, u16 len, const u8 *src)
{
	void __iomem *fifo = hw_ep->fifo;
	prefetch((u8 *)src);

	INFO("%cX ep%d fifo %p count %d buf %p\n",
			'T', hw_ep->epnum, fifo, len, src);

	/* we can't assume unaligned reads work */
	if (likely((0x01 & (unsigned long) src) == 0)) {
		u16	index = 0;

		/* best case is 32bit-aligned source address */
		if ((0x02 & (unsigned long) src) == 0) {
			if (len >= 4) {
				writesl(fifo, src + index, len >> 2);
				index += len & ~0x03;
			}
			if (len & 0x02) {
				musbfsh_writew(fifo, 0, *(u16 *)&src[index]);
				index += 2;
			}
		} else {
irqreturn_t musbfsh_dma_controller_irq(int irq, void *private_data)
{
	struct musbfsh_dma_controller *controller = private_data;
	struct musbfsh *musbfsh = controller->private_data;
	struct musbfsh_dma_channel *musbfsh_channel;
	struct dma_channel *channel;

	void __iomem *mbase = controller->base;

	irqreturn_t retval = IRQ_NONE;

	// unsigned long flags;

	u8 bchannel;
	u8 int_hsdma;

	u32 addr, count;
	u16 csr;
	
	INFO("++\n");
	// spin_lock_irqsave(&musbfsh->lock, flags); // removed due to now this function is called inside generic_interrupt

	int_hsdma = musbfsh->int_dma;

	if (!int_hsdma) {//should not to run here!
		WARNING("spurious DMA irq\n");

		for (bchannel = 0; bchannel < MUSBFSH_HSDMA_CHANNELS; bchannel++) {
			musbfsh_channel = (struct musbfsh_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musbfsh_channel->channel;
			if (channel->status == MUSBFSH_DMA_STATUS_BUSY) {
				count = musbfsh_read_hsdma_count(mbase, bchannel);

				if (count == 0)//all of the data have been transferred, should notify the CPU to process. 
					int_hsdma |= (1 << bchannel);
			}
		}

		INFO("int_hsdma = 0x%x\n", int_hsdma);

		if (!int_hsdma)
			goto done;
	}

	for (bchannel = 0; bchannel < MUSBFSH_HSDMA_CHANNELS; bchannel++) {
		if (int_hsdma & (1 << bchannel)) {
			musbfsh_channel = (struct musbfsh_dma_channel *)
					&(controller->channel[bchannel]);
			channel = &musbfsh_channel->channel;

			csr = musbfsh_readw(mbase,
					MUSBFSH_HSDMA_CHANNEL_OFFSET(bchannel,
							MUSBFSH_HSDMA_CONTROL));

			if (csr & (1 << MUSBFSH_HSDMA_BUSERROR_SHIFT)) {
				musbfsh_channel->channel.status =
					MUSBFSH_DMA_STATUS_BUS_ABORT;
			} else {
				u8 devctl;

				addr = musbfsh_read_hsdma_addr(mbase,
						bchannel);//the register of address will increase with the data transfer.
				channel->actual_len = addr
					- musbfsh_channel->start_addr;

				INFO("ch %p, 0x%x -> 0x%x (%zu / %d) %s\n",
					channel, musbfsh_channel->start_addr,
					addr, channel->actual_len,
					musbfsh_channel->len,
					(channel->actual_len
						< musbfsh_channel->len) ?
					"=> reconfig 0" : "=> complete");

				devctl = musbfsh_readb(mbase, MUSBFSH_DEVCTL);

				channel->status = MUSBFSH_DMA_STATUS_FREE;

				/* completed */
				if ((devctl & MUSBFSH_DEVCTL_HM)
					&& (musbfsh_channel->transmit)//Tx
					&& ((channel->desired_mode == 0)
					    || (channel->actual_len &//indicate it is a short packet
					    (musbfsh_channel->max_packet_sz - 1)))
				    ) {
					u8  epnum  = musbfsh_channel->epnum;
					int offset = MUSBFSH_EP_OFFSET(epnum,
								    MUSBFSH_TXCSR);
					u16 txcsr;

					/*
					 * The programming guide says that we
					 * must clear DMAENAB before DMAMODE.
					 */
					musbfsh_ep_select(mbase, epnum);
					txcsr = musbfsh_readw(mbase, offset);
					txcsr &= ~(MUSBFSH_TXCSR_DMAENAB
							| MUSBFSH_TXCSR_AUTOSET);
					musbfsh_writew(mbase, offset, txcsr);
					/* Send out the packet */
					txcsr &= ~MUSBFSH_TXCSR_DMAMODE;
					txcsr |=  MUSBFSH_TXCSR_TXPKTRDY;//the packet has been in the fifo,only need to set TxPktRdy
					musbfsh_writew(mbase, offset, txcsr);
				}
					musbfsh_dma_completion(musbfsh, musbfsh_channel->epnum,
						    musbfsh_channel->transmit);
				}
			}
		}

	retval = IRQ_HANDLED;
done:
	// spin_unlock_irqrestore(&musbfsh->lock, flags);
	return retval;
}