/*--------------------------------------------------------------------------*
 * drivers/usb/mcd/usb_mcd_ep0.c
 * 
 * USB controller driver
 * 
 * Copyright 2005,2006 Sony Corporation
 * 
 * This code is based on g_ep0.c,
 * Copyright 2005 Mentor Graphics Corporation
 *
 * This file is part of the Inventra Controller Driver for Linux.
 *
 * The Inventra Controller Driver for Linux is free software; you
 * can redistribute it and/or modify it under the terms of the GNU
 * General Public License version 2 as published by the Free Software
 * Foundation.
 *
 * The Inventra Controller Driver for Linux is distributed in
 * the hope that it will be useful, but WITHOUT ANY WARRANTY;
 * without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
 * License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with The Inventra Controller Driver for Linux ; if not,
 * write to the Free Software Foundation, Inc., 59 Temple Place,
 * Suite 330, Boston, MA  02111-1307  USA
 *
 * ANY DOWNLOAD, USE, REPRODUCTION, MODIFICATION OR DISTRIBUTION
 * OF THIS DRIVER INDICATES YOUR COMPLETE AND UNCONDITIONAL ACCEPTANCE
 * OF THOSE TERMS.THIS DRIVER IS PROVIDED "AS IS" AND MENTOR GRAPHICS
 * MAKES NO WARRANTIES, EXPRESS OR IMPLIED, RELATED TO THIS DRIVER.
 * MENTOR GRAPHICS SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY; FITNESS FOR A PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT.  MENTOR GRAPHICS DOES NOT PROVIDE SUPPORT
 * SERVICES OR UPDATES FOR THIS DRIVER, EVEN IF YOU ARE A MENTOR
 * GRAPHICS SUPPORT CUSTOMER.
 *---------------------------------------------------------------------------*/

#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb_gadget.h>
#include <linux/usb/mcd/usb_otg_control.h>
#include "../core/hub.h"
#include "../core/hcd.h"

#include "usb_mcd_cnf.h"
#include "usb_mcd_debug.h"
#include "usb_mcd_dma.h"
#include "usb_mcd_otg.h"
#include "usb_mcd_gadget.h"
#include "usb_mcd_host.h"
#include "usb_mcd_device.h"
#include "usb_mcd_access.h"
#include "usb_mcd_musbhdrc.h"

#ifdef MCD_MONITOR_DATA
static int monitor_loglevel;
#endif

const uint8_t mcd_test_packet[] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
	0xaa, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee, 0xee,
	0xee, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
	0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xbf, 0xdf,
	0xef, 0xf7, 0xfb, 0xfd, 0xfc, 0x7e, 0xbf, 0xdf,
	0xef, 0xf7, 0xfb, 0xfd, 0x7e
};

/* debug and utility functions */
/*
  Check ControlIn request as:
    USB_REQ_GET_CONFIGURATION:
    USB_REQ_GET_INTERFACE:
    USB_REQ_GET_DESCRIPTOR:
    USB_REQ_GET_STATUS:
    USB_REQ_SYNC_FRAME: 
*/
uint8_t is_tx_request(const struct usb_ctrlrequest *pControlRequest)
{
	return (pControlRequest->bRequestType & USB_DIR_IN);
}

/*
  Check ControlOut request as:
    USB_REQ_SET_DESCRIPTOR:
*/
uint8_t is_rx_request(const struct usb_ctrlrequest * pControlRequest)
{
	return !(pControlRequest->bRequestType & USB_DIR_IN);
}

/*
  Check No-data Control request as:
    USB_REQ_SET_INTERFACE: 
    USB_REQ_SET_CONFIGURATION:
    USB_REQ_SET_ADDRESS:
    USB_REQ_CLEAR_FEATURE:
    USB_REQ_SET_FEATURE:
*/
uint8_t is_zerodata_request(const struct usb_ctrlrequest * pControlRequest)
{
	return (!pControlRequest->wLength) && !is_tx_request(pControlRequest);
}

#if MCD_DEBUG>0

inline char *decode_request(struct usb_ctrlrequest *req)
{
	static char buf[8];
	snprintf(buf, sizeof(buf), "%s%s",
		 (USB_TYPE_STANDARD == (req->bRequestType & USB_TYPE_MASK) ?
		  "S" : "N"),
		 is_tx_request(req) ? "TX" :
		 is_rx_request(req) ? "RX" :
		 is_zerodata_request(req) ? "Z" : "-");
	return buf;
}

#endif

/* FROM: usb_gadget.h
 *
 * Accordingly, the driver's setup() callback must always implement all
 * get_descriptor requests, returning at least a device descriptor and
 * a configuration descriptor.  Drivers must make sure the endpoint
 * descriptors match any hardware constraints. Some hardware also constrains
 * other descriptors. (The pxa250 allows only configurations 1, 2, or 3).
 *
 * The driver's setup() callback must also implement set_configuration,
 * and should also implement set_interface, get_configuration, and
 * get_interface.  Setting a configuration (or interface) is where
 * endpoints should be activated or (config 0) shut down.
 */

/**
 * Read a FULL header packet from the hardware. The buffer starts with 
 * struct usb_ctrlrequest (fields are converted to device specific
 * byte order).
 *
 * @param wCount>0
 * @return 0 when the packet is complete, a negative number when an error 
 * occurred, a positive number when still there are bytes to read.
 */
static int read_control_request(struct mcd_gadget *mgadget, uint16_t wCount)
{
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	struct mcd_end0_buffer *pEnd0Buffer
	    = (struct mcd_end0_buffer *)mgadget->pEnd0Buffer;
	struct usb_ctrlrequest *pControlRequest =
	    (struct usb_ctrlrequest *)pEnd0Buffer;

	if (!pEnd0Buffer) {
		return -EINVAL;
	}

	DBG(3, "<==\n");
	DBG(4, "wCount=%u, pEnd0Buffer->wEnd0Count=%u\n", wCount,
	    pEnd0Buffer->wEnd0Count);

	if (!wCount) {
		return -EINVAL;
	}

	/* buffer overrun, it should never happen */
	if (wCount > (MCD_MAX_END0_PACKET - sizeof(struct usb_ctrlrequest))) {
		ERR("buffer overrun! wCount=%d\n", wCount);
		return -EINVAL;
	}

	/* need to have at least enough bytes for the control request
	 * comment this out to enable fifo size < 8 bytes */
	if (wCount < sizeof(struct usb_ctrlrequest)) {
		ERR("wCount=%u<sizeof(struct usb_ctrlrequest)=%u\n",
		    wCount, sizeof(struct usb_ctrlrequest));
		return -EINVAL;
	}
#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->Lock);
#endif

	spin_lock(&mdev->lock);
	mcd_select_end(regs, 0);	/* select ep0 */

	/* wEnd0Count=0 means that I'm reading the USB standard header:
	 * that's the first thing I need to read from the FIFO (8 bytes). */
	if (0 == pEnd0Buffer->wEnd0Count) {
		DBG(4, "reading header\n");
		mcd_device_unload_fifo(regs, 0, sizeof(struct usb_ctrlrequest),
				       (u8 *) pControlRequest);
		wCount -= sizeof(struct usb_ctrlrequest);
		DBG(6, "header read\n");

		/* data from the USB bus must be converted from LSB to 
		 * host-specific byte ordering; the control request header 
		 * tell me the payload length etc. */
		le16_to_cpus(pControlRequest->wLength);
		le16_to_cpus(pControlRequest->wIndex);
		le16_to_cpus(pControlRequest->wValue);

		DBG(4,
		    "bRequest=%02x, kind=%s, wValue=%04x, wIndex=%04x, wLength=%04x\n",
		    pControlRequest->bRequest, decode_request(pControlRequest),
		    pControlRequest->wValue, pControlRequest->wIndex,
		    pControlRequest->wLength);

		/* the header will set me in the right stage:
		   mgadget->bEnd0Stage=MCD_END0_STAGE_TX
		   mgadget->bEnd0Stage=MCD_END0_STAGE_RX
		 */
		if (pControlRequest->bRequestType & USB_DIR_IN) {
			/* write to host: up to wLength bytes */
			pEnd0Buffer->wEnd0Count = 0;
			mgadget->bEnd0Stage = MCD_END0_STAGE_TX;
			DBG(2, "[1] Ep0Stage %d \n", mgadget->bEnd0Stage);

		} else if (pControlRequest->bRequestType & USB_DIR_OUT) {
			/* out to function: wLength to go for the payload */
			pEnd0Buffer->wEnd0Count = pControlRequest->wLength;
			mgadget->bEnd0Stage = MCD_END0_STAGE_RX;
			DBG(2, "[2] Ep0Stage %d \n", mgadget->bEnd0Stage);
		}
	}

	if (wCount > 0) {
		/* now Im reading the rest of it, */
		/* this will never be executed I guess. */
		/* read past the header */
		uint16_t offset = sizeof(struct usb_ctrlrequest) +
		    (pControlRequest->wLength) - (pEnd0Buffer->wEnd0Count);
		mcd_device_unload_fifo(regs, 0, wCount,
				       &pEnd0Buffer->aEnd0Data[offset]);
		pEnd0Buffer->wEnd0Count -= wCount;
	}

	DBG(5, "pEnd0Buffer->wEnd0Count=%d, ep0stage=%s, %s\n",
	    pEnd0Buffer->wEnd0Count, decode_ep0stage(mgadget->bEnd0Stage),
	    (pEnd0Buffer->wEnd0Count) ? "still to go" : "header completed");
	DBG(3, "==>\n");

	spin_unlock(&mdev->lock);

	/* 0 header completed, <0 error, >0 bytes to go */
	return (pEnd0Buffer->wEnd0Count);
}

static int forward_to_driver(const struct usb_ctrlrequest *pControlRequest)
{
	int handled = -EOPNOTSUPP;

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->ep[0]);
#endif

	DBG(-1002, "<==\n");
	if (mcd_first_gadget->pGadgetDriver) {
		handled =
		    mcd_first_gadget->pGadgetDriver->setup(mcd_first_gadget->
							   pGadget,
							   pControlRequest);
	}
	DBG(-1002, "==>\n");

	return handled;
}

static int service_rx_request(struct usb_ctrlrequest *pControlRequest)
{
#ifdef MCD_PARANOID
	struct mcd_gadget *mgadget = mcd_first_gadget;
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->ep[0]);
#endif

	return forward_to_driver(pControlRequest);
}

/**
 * handle a request, the end0 buffer contains the current request
 * that is supposed to be a standard control request. Assumes the 
 * fifo to be at least 2 bytes long.
 *
 
	case USB_REQ_GET_CONFIGURATION:
	case USB_REQ_GET_INTERFACE:
	case USB_REQ_GET_DESCRIPTOR:
	case USB_REQ_GET_STATUS:
	case USB_REQ_SYNC_FRAME:
 
 
 * @return 0 if the request was NOT HANDLED,
 * < 0 when error (ENOSUPP not supproted)
 * > 0 when the request is processed 
 */
static int service_tx_request(const struct usb_ctrlrequest *pControlRequest)
{
	int handled = 0;	/* not handled */

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->lock);
	ASSERT_SPINLOCK_UNLOCKED(&mcd_gadget_local_end[0]);
#endif

	if (USB_TYPE_STANDARD !=
	    (pControlRequest->bRequestType & USB_TYPE_MASK)) {
		return forward_to_driver(pControlRequest);
	}

	switch (pControlRequest->bRequest) {
	case USB_REQ_GET_CONFIGURATION:
		DBG(3, "USB_REQ_GET_CONFIGURATION()\n");
		break;

	case USB_REQ_GET_INTERFACE:
		DBG(3, "USB_REQ_GET_INTERFACE()\n");
		break;

	case USB_REQ_GET_DESCRIPTOR:
		DBG(3, "USB_REQ_GET_DESCRIPTOR()\n");
		break;

	case USB_REQ_GET_STATUS:{
			DBG(3, "USB_REQ_GET_STATUS()\n");
#if 0
			service_tx_status_request(pControlRequest);
#endif
		}
		break;

		/* case USB_REQ_SYNC_FRAME:
		   break; */

	default:
		break;
	}

	if (!handled) {
		handled = forward_to_driver(pControlRequest);
	}

	/* now tx! */
	return handled;
}

/* Executed @ interrupt time...
 */
void mcd_gadget_complete_ep0_request(void)
{
	struct usb_request *pRequest;
	struct mcd_gadget *mgadget = mcd_first_gadget;

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->lock);
	ASSERT_SPINLOCK_LOCKED(&mgadget->ep[0]);

#endif

	spin_lock(&mgadget->ep[0].Lock);
	pRequest = mcd_get_current_request(&mgadget->ep[0]);

	DBG(5, "completing request pRequest=%p\n", pRequest);
	/* completing on ep0 is from interrupt */
	if (pRequest) {
		/* there's only one request here */
		list_del(&pRequest->list);
		spin_unlock(&mgadget->ep[0].Lock);
		if (pRequest->complete) {
			pRequest->complete(&mgadget->ep[0].end_point, pRequest);
		}
	} else {
		spin_unlock(&mgadget->ep[0].Lock);
	}

	if (((uint8_t) NULL == mcd_first_gadget->bSetAddress) &&
	    ((uint8_t) NULL == mcd_first_gadget->bTestMode)) {
		mcd_first_gadget->bEnd0Stage = MCD_END0_STAGE_SETUP;
		DBG(2, "[4] Ep0Stage %d \n", mcd_first_gadget->bEnd0Stage);
	}
}

/* called when the completiotion interrupt occours.. 
  hopefully */
static uint8_t handle_ep0_completition_irq(void)
{
	struct mcd_gadget *mgadget = mcd_first_gadget;
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	uint16_t wCsrVal;
	uint8_t status = MCD_EP0_COMP_END;
#if (MCD_DEBUG>0)
	struct mcd_gep *pEnd = &mgadget->ep[0];
	struct usb_request *pRequest = mcd_get_current_request(pEnd);
#endif

	DBG(3, "<==\n");
	DBG(4, "post event interrupts ep0stage=%s\n",
	    decode_ep0stage(mgadget->bEnd0Stage));

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_UNLOCKED(&mgadget->ep[0]);
#endif

	DBG(2, "bEp0Stage %d \n", mgadget->bEnd0Stage);
	switch (mgadget->bEnd0Stage) {
		/* end of sequence #2 (RX state) or #3 (no data) */
	case MCD_END0_STAGE_STATUSIN:{
			struct usb_request *pRequest;
			DBG(-1001, "MCD_END0_STAGE_STATUSIN request\n");

			if (mgadget->bSetAddress) {
				mgadget->bSetAddress = false;
				MCD_WRITE8(regs, MCD_O_HDRC_FADDR,
					   mgadget->bAddress);
				mgadget->bEnd0Stage = MCD_END0_STAGE_SETUP;
				DBG(2, "[5] Ep0Stage %d \n", mgadget->bEnd0Stage);
				DBG(-1002,
				    "address configured... mgadget->bAddress=0x%x\n",
				    mgadget->bAddress);
#ifdef MCD_MONITOR_DATA
				mcd_debug_set_level(monitor_loglevel);
#endif
			}

			/* enter test mode if needed */
			if (mgadget->bTestMode) {
				DBG(-1001, "entering TESTMODE\n");

				if (MCD_M_TEST_PACKET == mgadget->bTestModeValue) {
					mcd_device_load_fifo(regs, 0,
							     sizeof(mcd_test_packet),
							     (u8 *)mcd_test_packet);
					spin_lock(&mdev->lock);
					wCsrVal =
					    MCD_READ_CSR16(regs,
							   MCD_O_HDRC_CSR0,
							   bEnd);
					wCsrVal |= (MCD_M_CSR0_TXPKTRDY);
					MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0,
							bEnd, wCsrVal);
					spin_unlock(&mdev->lock);
				}
				if ((uint8_t) NULL == mgadget->bTestModeValue) {
					mgadget->bTestMode = (uint8_t) NULL;
				}
				spin_lock(&mdev->lock);
				mcd_select_end(regs, 0);	/* select ep0 */
				MCD_WRITE8(regs, MCD_O_HDRC_TESTMODE,
					   mgadget->bTestModeValue);
				mgadget->bEnd0Stage = MCD_END0_STAGE_SETUP;
				DBG(2, "[6] Ep0Stage %d \n", mgadget->bEnd0Stage);
				DBG(2, "Read  MCD_O_HDRC_TESTMODE = %x \n",
				    MCD_READ8(regs, MCD_O_HDRC_TESTMODE));
				spin_unlock(&mdev->lock);
			}

			DBG(-1001, "completing posted request (if any)\n");
			/* short_not_ok フラグを確認 */
			pRequest = mcd_get_current_request(&mgadget->ep[0]);
			if ((NULL != pRequest) &&
                            (-EINPROGRESS == pRequest->status)) {
				if ((1 == pRequest->short_not_ok) &&
                                    (0 != (pRequest->actual %
					   (mgadget->ep[0].wPacketSize)))) {
					pRequest->status = -EREMOTEIO;
				} else {
					pRequest->status = 0;
				}
			}
                        /* async complete */
			mcd_gadget_complete_ep0_request();
		}
		break;

		/* sequence #1: write to host (TX state)  */
	case MCD_END0_STAGE_STATUSOUT:{
			struct usb_request *pRequest;
			DBG(-1001, "completing posted request (if any)\n");
			/* short_not_ok フラグを確認 */
			pRequest = mcd_get_current_request(&mgadget->ep[0]);
			if ((NULL != pRequest)
			    && (-EINPROGRESS == pRequest->status)) {
				if ((1 == pRequest->short_not_ok)
				    && (0 != (pRequest->actual %
					      (mgadget->ep[0].wPacketSize)))) {
					pRequest->status = -EREMOTEIO;
				} else {
					pRequest->status = 0;
				}
			}
                        /* async complete */
			mcd_gadget_complete_ep0_request();
		}
		break;

	case MCD_END0_STAGE_TX:
		DBG(-1001, "TX changeing ep status\n");
		DBG(2, " STAGE_TX  status:%d\n",
		    mcd_get_current_request(&mgadget->ep[0])->status);
		if (mcd_get_current_request(&mgadget->ep[0])->status !=
		    -EINPROGRESS) {
			struct usb_request *pRequest;
			pRequest = mcd_get_current_request(&mgadget->ep[0]);
			DBG(3, "length=%d actual=%d\n", pRequest->length,
			    pRequest->actual);
			/* completing on ep0 is from interrupt */
			if (pRequest) {
				/* there's only one request here */
				list_del(&pRequest->list);
				if (pRequest->complete) {
					pRequest->complete(&mgadget->ep[0].
							   end_point, pRequest);
				}
			}
			/* change state in case taht tx ended */
			mgadget->bEnd0Stage = MCD_END0_STAGE_STATUSOUT;
			DBG(2, "[7] Ep0Stage %d \n", mgadget->bEnd0Stage);
		} else {
			DBG(2, " MCD_EP0_COMP_NON \n");
			status = MCD_EP0_COMP_NON;
		}
		break;
	case MCD_END0_STAGE_RX:
		DBG(-1001, "RX changeing ep status\n");
		if (mcd_get_current_request(&mgadget->ep[0])->status !=
		    -EINPROGRESS) {
			mgadget->bEnd0Stage = MCD_END0_STAGE_STATUSIN;
			DBG(2, "[8] Ep0Stage %d \n", mgadget->bEnd0Stage);
		}
		break;

	default:		/* IT WAS STALLED */
		DBG(-1002, "recovering from stall? ep0stage=%s\n",
		    decode_ep0stage(mgadget->bEnd0Stage));
		mgadget->bEnd0Stage = MCD_END0_STAGE_SETUP;
		DBG(2, "[8] Ep0Stage %d \n", mgadget->bEnd0Stage);
		break;
	}

	/* weird core! clear CSR0 */
	//spin_lock(&mgadget->Lock);
	//mcd_select_end(regs, 0);
	//MCD_WRITE_CSR8(regs, MCD_O_HDRC_CSR0, 0, 0);
	//spin_unlock(&mgadget->Lock);
	if (status == MCD_EP0_COMP_END) {
		return true;
	} else {
		return false;
	}
	DBG(3, "==>\n");
}

/*
 *	USB_REQ_SET_INTERFACE: 
 *	USB_REQ_SET_CONFIGURATION:
 *	USB_REQ_SET_ADDRESS:
 *	USB_REQ_CLEAR_FEATURE:
 *	USB_REQ_SET_FEATURE:
 */
static int service_zero_data_request(struct mcd_gadget *mgadget,
				     struct usb_ctrlrequest *pControlRequest)
{
	int handled = 1;	/* handled, DO NOT not pass down */

	DBG(-1002, "<==\n");

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_UNLOCKED(&[0]);
#endif

	/* non standard requests are piped to the gadget */
	if (USB_TYPE_STANDARD !=
	    (pControlRequest->bRequestType & USB_TYPE_MASK)) {
		return forward_to_driver(pControlRequest);
	}

	/* zero data phase */
	switch (pControlRequest->bRequest) {

#if 0
	case USB_REQ_SET_INTERFACE:
		DBG(3, "USB_REQ_SET_INTERFACE()\n");
		handled = 0;	/* pass it to the gadget */
		break;

	case USB_REQ_SET_CONFIGURATION:
		/* remember state & handle on the end status stage interrupt */
		DBG(3, "USB_REQ_SET_CONFIGURATION()\n");
		handled = 0;	/* pass it to the gadget */
		break;
#endif

	case USB_REQ_SET_ADDRESS:
		/* remember state & handle on the end status stage interrupt */
		DBG(3, "USB_REQ_SET_ADDRESS(0x%x)\n", (uint8_t)
		    (pControlRequest->wValue & 0x7f));

		if (pControlRequest->wValue < 0x80) {
			mgadget->bSetAddress = true;
			mgadget->bAddress =
			    (uint8_t) (pControlRequest->wValue & 0x7f);
		} else {
			handled = -EINVAL;
		}

		break;

#if 0
	case USB_REQ_CLEAR_FEATURE:
		DBG(3, "USB_REQ_CLEAR_FEATURE()\n");

		switch (bRecip) {
		case USB_RECIP_DEVICE:
			DBG(3, "USB_RECIP_DEVICE()\n");
			break;
		case USB_RECIP_INTERFACE:
			DBG(3, "USB_RECIP_INTERFACE()\n");
			break;
		case USB_RECIP_ENDPOINT:{
				struct usb_request *pRequest;
				const uint8_t bEnd =
				    (uint8_t) pControlRequest->wIndex & 0x7f;
				struct mcd_gep *pEnd = &mgadget->ep[0];

				DBG(4,
				    "CLEAR_FEATURE: USB_RECIP_ENDPOINT() %d\n",
				    bEnd);
				mcd_gadget_set_halt(&pEnd->end_point, 0);
				EP_SPIN_LOCK(pEnd);
				pRequest = mcd_get_current_request(pEnd);
				EP_SPIN_UNLOCK(pEnd);
				mcd_gadget_restart_request(mgadget, bEnd,
							   pRequest);

				/* select ep0 again */
				mcd_select_end(regs, 0);
			} break;
		default:
			break;
		}
		break;		/* END: CLEAR_FEATURE */

	case USB_REQ_SET_FEATURE:
		DBG(3, "USB_REQ_SET_FEATURE()\n");
		switch (bRecip) {
		case USB_RECIP_DEVICE:
			DBG(3, "USB_RECIP_DEVICE()\n");
			switch (pControlRequest->wValue) {
			case 1:
				DBG(3, "REMOTE_WAKEUP()\n");
				while (0) {
				}	/* remote wakeup */
				break;
			case 2:
				if (pControlRequest->wIndex & 0xff) {
					handled = -EINVAL;
				} else {
					uint16_t wTest;

					DBG(3, "ENTERING TESTMODE\n");
					mgadget->bTestMode = true;
					wTest =
					    (uint8_t) pControlRequest->
					    wIndex >> 8;
					switch (wTest) {
					case 1:
						DBG(3, "TEST_J\n");
						/* TEST_J */
						mgadget->bTestModeValue =
						    MCD_M_TEST_J;
						break;
					case 2:
						/* TEST_K */
						DBG(3, "TEST_K\n");
						mgadget->bTestModeValue =
						    MCD_M_TEST_K;
						break;
					case 3:
						/* TEST_SE0_NAK */
						DBG(3, "TEST_SE0_NAK\n");
						mgadget->bTestModeValue =
						    MCD_M_TEST_SE0_NAK;
						break;
					case 4:
						/* TEST_PACKET */
						DBG(3, "TEST_PACKET\n");
						mgadget->bTestModeValue =
						    MCD_M_TEST_PACKET;
						break;
					default:
						/* my gadget might know what to do with it */
						break;
					}
				}
				break;
#if 0
			case 3:
				GADGET_SET_B_HNP_ENABLE(mgadget->pGadget, 1);
				mcd_otg_machine_set_feature(&
							    (mgadget->OtgMachine),
							    pControlRequest->
							    wValue);
				break;
			case 4:
				GADGET_SET_A_HNP_SUPPORT(mgadget->pGadget, 1);
				mcd_otg_machine_set_feature(&
							    (mgadget->OtgMachine),
							    pControlRequest->
							    wValue);
				break;
			case 5:
				GADGET_SET_A_ALT_HNP_SUPPORT(mgadget->pGadget, 1);
				mcd_otg_machine_set_feature(&
							    (mgadget->OtgMachine),
							    pControlRequest->
							    wValue);
				break;
#endif				/* 0 */
			}
			break;

		case USB_RECIP_INTERFACE:
			DBG(3, "USB_RECIP_INTERFACE()\n");
			break;

		case USB_RECIP_ENDPOINT:{
				const uint8_t bEnd =
				    (uint8_t) pControlRequest->wIndex & 0x7f;
				struct mcd_gep *pEnd = mgadget->ep[0];

				DBG(3, "SET_FEATURE: USB_RECIP_ENDPOINT() %d\n",
				    bEnd);
				mcd_gadget_set_halt(&pEnd->end_point, 1);

				/* select ep0 again */
				mcd_select_end(regs, 0);
			} break;

		}
		break;		/* END: SET_FEATURE */
#endif

	default:
		handled = 0;
		break;
	}

	/* standard request not handed by this code go to the gadget */
	if (!handled) {
		handled = forward_to_driver(pControlRequest);
	}

	DBG(-1002, "==>\n");
	return handled;
}

/* mcd_gadget_ep0_rxstart - enable receive data in ControlOUT */
int mcd_gadget_ep0_rxstart(struct mcd_gadget *mgadget)
{
	unsigned long flags;
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	uint16_t wCount;	/* COUNT0 - received bytes */

	spin_lock_irqsave(&mdev->lock, flags);

	mcd_select_end(regs, 0);
	wCount = MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);

	if (wCount != 0) {
		spin_unlock_irqrestore(&mdev->lock, flags);
		return -ECONNRESET;
	}
	/* ack the request first */
	DBG(3, "delayed acking request %s\n",
	    decode_csr0(MCD_M_CSR0_P_SVDRXPKTRDY));
	MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0, MCD_M_CSR0_P_SVDRXPKTRDY);

	spin_unlock_irqrestore(&mdev->lock, flags);

	return 0;
}

/*
 * mcd_gadget_ep0_rxstate is receive data from FIFO to buffer.
 * it should be called on interrupt context.
 */
int mcd_gadget_ep0_rxstate(struct mcd_gadget *mgadget)
{
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	struct mcd_gep *pEnd = &mgadget->ep[0];
	struct usb_request *pRequest = mcd_get_current_request(pEnd);
	uint16_t wCount;	/* COUNT0 - received bytes */
	uint16_t wCountChk;
	uint32_t dwRemain;	/* Remain size of required data */
	uint8_t *pFifoDist;
	uint8_t wCsrVal = 0;
	uint8_t wCsrValChk;
	uint8_t wFifoCount;

	DBG(-1002, "<==\n");

	/* check EP0 registers */

	spin_lock(&pEnd->Lock);

	spin_lock(&mdev->lock);

	mcd_select_end(regs, 0);	/* select ep0 */
	wCount = MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);

	spin_unlock(&mdev->lock);

	pFifoDist = (uint8_t *) pRequest->buf + pRequest->actual;
	dwRemain = (uint32_t) (pRequest->length - pRequest->actual);
	wFifoCount = (uint16_t) min((int)wCount, (int)dwRemain);

	/* update the ep0 hardware flags and software state */

	if (wCount > MCD_MAX_END0_PACKET) {
		uint8_t bFifoOffset = MCD_FIFO_OFFSET(0);
		/* OUT_CTRL  DATAEND を wCsrValにセット。 
		   以降OUTがきた場合はSTALLを返す。 */
		wCsrVal |= MCD_M_CSR0_P_DATAEND;
		pRequest->actual += wCount;
		pRequest->status = -ECOMM;	/* USB_ST_BUFFEROVERRUN */
		while (wCount / 4) {
			MCD_READ32(regs, bFifoOffset);
			wCount -= 4;
		}
		while (wCount) {
			MCD_READ8(regs, bFifoOffset);
			wCount -= 1;
		}
		goto just_comp;
	} else if (wCount < MCD_MAX_END0_PACKET) {
		wCsrVal |= MCD_M_CSR0_P_DATAEND;
		if (pRequest->short_not_ok) {
			pRequest->status = -EREMOTEIO;	/* USB_ST_SHORT_PACKET */
		} else {
			pRequest->status = 0;
		}
	}
	/* wCount == MCD_MAX_END0_PACKET */
	/* OUT_CTRL  pRequest->zero が立っていれば、
	   1回空でまわしてNULLパケットを受信待ちする。 */
	else if ((dwRemain == wCount)) {
		if (pRequest->zero
		    && pRequest->status == -EINPROGRESS
		    && pRequest->length
		    && ((pRequest->length % mgadget->ep[0].wPacketSize)
			== 0)) {
			pRequest->zero = 0;
		} else {
			wCsrVal |= MCD_M_CSR0_P_DATAEND;
			pRequest->status = 0;
		}
	}

	spin_lock(&mdev->lock);

	/* 直前のControl転送中断のチェック、この後SETUPEND割り込み */
	mcd_select_end(regs, 0);	/* select ep0 */
	wCsrValChk = MCD_READ_CSR16(regs, MCD_O_HDRC_CSR0, 0);
	if (wCsrValChk & MCD_M_CSR0_P_SETUPEND) {
		spin_unlock(&mdev->lock);
		return -ECONNRESET;
	}

	/* Unload data */

	mcd_device_unload_fifo(regs, 0, wFifoCount, pFifoDist);

	if (wCount > wFifoCount) {
		pRequest->actual += wCount;
		pRequest->status = -EOVERFLOW;	/* USB_ST_DATAOVERRUN */
		/* 残余FIFOデータはFlushする */
		wCsrVal |= MCD_M_CSR0_FLUSHFIFO;
		wCsrVal |= MCD_M_CSR0_P_SENDSTALL;
	} else {
		pRequest->actual += wFifoCount;
	}

	wCsrVal |= MCD_M_CSR0_P_SVDRXPKTRDY | MCD_M_CSR0_P_SENTSTALL;
	wCountChk = MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);
	if (!wCountChk || wCountChk == wCount - wFifoCount) {
		DBG(3, "delayed acking request %s\n", decode_csr0(wCsrVal));
		MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0, wCsrVal);
		if (wCsrVal & MCD_M_CSR0_P_DATAEND) {
			DBG(2, "[10] Ep0Stage %d \n", mgadget->bEnd0Stage);
			mgadget->bEnd0Stage = MCD_END0_STAGE_STATUSOUT;
		}
	}

	spin_unlock(&mdev->lock);

      just_comp:
	spin_unlock(&pEnd->Lock);

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_LOCKED(&pEnd->Lock);
#endif

	DBG(-1002, "==>\n");

	return 0;
}

/*
 * im transmitting to the host, this code might be called from IRQ 
 * and from kernel thread.
 *
 * @pre spin_is_locked(&pEnd->Lock)
 */
int mcd_gadget_ep0_txstate(struct mcd_gadget *mgadget)
{
	unsigned long flags;
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	struct mcd_gep *pEnd = &mgadget->ep[0];
	struct usb_request *pRequest = mcd_get_current_request(pEnd);
	uint16_t wCount;	/* COUNT0 - received bytes */
	uint16_t wCsrVal;
	uint8_t *pFifoSource;
	uint8_t wFifoCount;

	DBG(-1002, "<==\n");

#ifdef MCD_PARANOID
	if (!mgadget || !pRequest) {
		ERR("mgadget=%p, pRequest=%p", mgadget, pRequest);
		return -EINVAL;
	}
#endif

#ifdef MCD_PARANOID
	ASSERT_SPINLOCK_UNLOCKED(&mdev->lock);
	ASSERT_SPINLOCK_LOCKED(&pEnd->Lock);
#endif

	spin_lock_irqsave(&mdev->lock, flags);
	mcd_select_end(regs, 0);
	wCount = MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);

	if (wCount != 0) {
		spin_unlock_irqrestore(&mdev->lock, flags);
		return -ECONNRESET;
	}
	if (pRequest->actual == 0) {
		/* ack the request first */
		DBG(3, "delayed acking request %s\n",
		    decode_csr0(MCD_M_CSR0_P_SVDRXPKTRDY));
		MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0,
				MCD_M_CSR0_P_SVDRXPKTRDY |
				MCD_M_CSR0_P_SENTSTALL);
	}

	/* load the data */
	pFifoSource = (uint8_t *) pRequest->buf + pRequest->actual;
	wFifoCount = min((int)MCD_END0_FIFOSIZE,
			 (int)(pRequest->length - pRequest->actual));
	/* 直前のControl転送中断のチェック、この後SETUPEND割り込み */
	wCsrVal = MCD_READ_CSR16(regs, MCD_O_HDRC_CSR0, 0);
	if (wCsrVal & MCD_M_CSR0_P_SETUPEND) {
		spin_unlock_irqrestore(&mdev->lock, flags);
		return -ECONNRESET;
	}
	mcd_device_load_fifo(regs, 0, wFifoCount, pFifoSource);
	pRequest->actual += wFifoCount;	/* done */
	wCsrVal = MCD_M_CSR0_TXPKTRDY;

	/* update the flags */
	if (wFifoCount <= MCD_MAX_END0_PACKET) {
		/* IN_CTRL pRequest->zero が立っていれば、
		   1回空でまわしてNULLパケットを送信する。 */
		if ((pRequest->actual == pRequest->length)) {	/* 転送完了処理 */
			/* use the zero flag to request the transmission setting it to
			 * zero, after the zero packet has been submitted */
			if (pRequest->zero
			    && pRequest->status == -EINPROGRESS
			    && pRequest->length
			    &&
			    ((pRequest->length %
			      mgadget->ep[0].wPacketSize) == 0)) {
				pRequest->zero = 0;
			} else {
				wCsrVal |= MCD_M_CSR0_P_DATAEND;
				pRequest->status = 0;	/* done */
			}
		}
	}

	/* send it out! (this will trigger the ep0 completition IRQ) 
	 * serviced in interrupt_complete()  */
	DBG(-1001, "wrote wFifoCount=%d bytes, wCsrVal=%s\n", wFifoCount,
	    decode_csr0(wCsrVal));
	wCsrVal |= MCD_M_CSR0_P_SENTSTALL;
	MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0, wCsrVal);
	spin_unlock_irqrestore(&mdev->lock, flags);

	DBG(-1002, "==>\n");
	return 0;
}

/**
 * Handle ep0 interrupt of a device, lock & release mgadget.
 * @param mgadget this
 */
uint8_t mcd_gadget_service_ep0(struct mcd_gadget *mgadget)
{
	uint16_t wCsrVal;
	uint16_t wCount;	/* bytes available */
	struct mcd_device* mdev = mgadget_to_mdev(mgadget);
	void *regs = mdev_link_reg(mdev);
	struct usb_request *pRequest =
	    mcd_get_current_request(&mgadget->ep[0]);

	DBG(-1002, "<==\n");

	spin_lock(&mdev->lock);
	mcd_select_end(regs, 0);	/* select ep0 */
	wCsrVal = MCD_READ_CSR16(regs, MCD_O_HDRC_CSR0, 0);
	wCount = MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);

	DEBUG_CODE(4, {
		   uint8_t myaddr = MCD_READ8(regs, MCD_O_HDRC_FADDR);
		   uint8_t devctl = MCD_READ8(regs, MCD_O_HDRC_DEVCTL);
		   printk(KERN_INFO
			  "%s: wCrsVal=0x%x, wCount=%d, myaddr=%0x, mode=%s, ep0stage=%s\n",
			  __FUNCTION__, wCsrVal, wCount, myaddr,
			  decode_devctl(devctl),
			  decode_ep0stage(mgadget->bEnd0Stage));});

	/* I sent a stall.. need to acknowledge it now.. */
	if (wCsrVal & MCD_M_CSR0_P_SENTSTALL) {
		DBG(-1002, "acking stall while in ep0stage=%s\n",
		    decode_ep0stage(mgadget->bEnd0Stage));

		/* STALL送信による中断の場合statusは-EPROTO */
		if (pRequest && ((-EINPROGRESS == pRequest->status)
				 || (0 == pRequest->status))) {
			pRequest->status = -EPROTO;	/* -EPROTO */
		}

		(mgadget->ep[0]).bInactive = 0;

		mcd_gadget_complete_ep0_request();
		MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0,
				wCsrVal & ~(MCD_M_CSR0_P_SENTSTALL |
					    MCD_M_CSR0_TXPKTRDY));
	}

	/* setup ended prematurely, abort it  */
	if (wCsrVal & MCD_M_CSR0_P_SETUPEND) {
		DBG(-1002, "acking setupend while in ep0stage=%s\n",
		    decode_ep0stage(mgadget->bEnd0Stage));

		/* ControlIN FIFO書き込み中にSETUPを受信した場合の処理 */
		/* 受信したSETUPを諦めてSTALLを応答する */
		if (wCsrVal & MCD_M_CSR0_TXPKTRDY) {
			MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0,
					MCD_M_CSR0_P_SVDSETUPEND
					| MCD_M_CSR0_FLUSHFIFO
					| MCD_M_CSR0_P_SENDSTALL);
			spin_unlock(&mdev->lock);
			return true;
		}

		/* IN_CTRL  DataStage,StatusStageによる
		   中断の場合statusは成功 */
		if ((NULL != pRequest)
		    && (mgadget->bEnd0Stage == MCD_END0_STAGE_RX)) {
			if (wCsrVal & MCD_M_CSR0_RXPKTRDY) {
				pRequest->status = -EPROTO;
			}
		}
		if ((NULL != pRequest)
		    && (mgadget->bEnd0Stage == MCD_END0_STAGE_TX)) {
			if (wCsrVal & MCD_M_CSR0_RXPKTRDY) {
				pRequest->status = 0;
			}
		}

		if (!wCount && pRequest) {
			/* short_not_ok フラグを確認 */
			if ((NULL != pRequest)
			    && (-EINPROGRESS == pRequest->status)) {
				if ((1 == pRequest->short_not_ok)
				    && (0 !=
					((pRequest->actual) %
					 (mgadget->ep[0].
					  wPacketSize)))) {
					pRequest->status = -EREMOTEIO;
				} else {
					pRequest->status = 0;
				}
			}
		}
		mcd_gadget_complete_ep0_request();
		/* clearing it */
		MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0,
				MCD_M_CSR0_P_SVDSETUPEND |
				MCD_M_CSR0_P_SENTSTALL);
	}

	spin_unlock(&mdev->lock);

	/* handle completition interrupt */
	if (!wCsrVal && !wCount) {
		DBG(2, "handle_ep0_completition_irq called [!wCount] \n");
		if (handle_ep0_completition_irq() == true) {
			return true;
		}
	}

	switch (mgadget->bEnd0Stage) {
	case MCD_END0_STAGE_TX:
		if ((NULL != pRequest) && (wCsrVal & MCD_M_CSR0_RXPKTRDY)) {
			/* 最終送信データqueue後、データ送信割込みとステータ */
			/* ス割込みを処理できずにSETUPを受信した場合 */
			/* この後EP0ステータスはMCD_END0_STAGE_STATUSOUTとな */
			/* り完了処理をする。 */
			handle_ep0_completition_irq();
			mcd_gadget_complete_ep0_request();
		}
		break;
		/* done transmitting */
	case MCD_END0_STAGE_STATUSOUT:
	case MCD_END0_STAGE_STATUSIN:
		/* short_not_ok フラグを確認 */
		if ((NULL != pRequest) && (-EINPROGRESS == pRequest->status)) {
			if ((1 == pRequest->short_not_ok) &&
			    (0 !=
			     ((pRequest->actual) %
			      (mgadget->ep[0].wPacketSize)))) {
				pRequest->status = -EREMOTEIO;
			} else {
				pRequest->status = 0;
			}
		}
		mcd_gadget_complete_ep0_request();	/* async complete */
		break;
	}

	switch (mgadget->bEnd0Stage) {

		/* im alrewady writing to host, TX state, 
		   sequence #1 initiated during the setup */
	case MCD_END0_STAGE_TX:
		DBG(2, "STAGE_TX to ep0  \n");
		if ((NULL != pRequest)
		    && ((wCsrVal & MCD_M_CSR0_TXPKTRDY) == 0)) {
			DBG(2, "STAGE_TX to mcd_gadget_ep0_txstate \n");
			DBG(-1001, "MCD_END0_STAGE_TX\n");
			mcd_gadget_ep0_txstate(mgadget);
		}
		break;

		/* im alrewady receiving from host, RX state, 
		   sequence #2 initiated during the setup */
	case MCD_END0_STAGE_RX:
		if ((NULL != pRequest) && (wCsrVal & MCD_M_CSR0_RXPKTRDY)) {
			DBG(-1001, "MCD_END0_STAGE_RX\n");
			mcd_gadget_ep0_rxstate(mgadget);
		}
		break;

		/* received from host, RX State, header */
	case MCD_END0_STAGE_SETUP:
		if (wCsrVal & MCD_M_CSR0_RXPKTRDY) {
			int count = 0;
			int handled = 0;

			count = read_control_request(mgadget, wCount);
			if (count < 0) {
				/* ack the request */
				ERR("error reading the control request\n");
			} else if (0 == count) {	/* I got the full packet, GREAT! */
				struct usb_ctrlrequest *pControlRequest =
				    (struct usb_ctrlrequest *)
				    mgadget->pEnd0Buffer;
				uint8_t wCsrValSet = 0;

				DBG(-1002, "%s\n",
				    decode_request(pControlRequest));

				mgadget->ep[0].bInactive = 0;

				/* sequence #3 */
				if (is_zerodata_request(pControlRequest)) {
					wCsrValSet =
					    MCD_M_CSR0_P_SVDRXPKTRDY |
					    MCD_M_CSR0_P_DATAEND;
					mgadget->bEnd0Stage =
					    MCD_END0_STAGE_STATUSIN;
					DBG(2, "[11] Ep0Stage %d \n",
					    mgadget->bEnd0Stage);
					handled =
					    service_zero_data_request(mgadget,
								      pControlRequest);
					if (handled < 0) {
						wCsrValSet |=
						    MCD_M_CSR0_P_SENDSTALL;
					}
				} else {
					/* sequence #1 */
					if (is_tx_request(pControlRequest)) {
						/* write to host, a request is posted on ep0 */
						mgadget->bEnd0Stage =
						    MCD_END0_STAGE_TX;
						DBG(2, "[12] Ep0Stage %d \n",
						    mgadget->bEnd0Stage);
						handled =
						    service_tx_request
						    (pControlRequest);
						/* sequence #2, a request is posted on ep0 */
					} else
					    if (is_rx_request(pControlRequest))
					{
						mgadget->bEnd0Stage =
						    MCD_END0_STAGE_RX;
						DBG(2, "[13] Ep0Stage %d \n",
						    mgadget->bEnd0Stage);
						handled =
						    service_rx_request
						    (pControlRequest);
					}

					/* application stall */
					if (handled < 0) {
						wCsrValSet =
						    MCD_M_CSR0_P_SVDRXPKTRDY |
						    MCD_M_CSR0_P_SENDSTALL;
					}
				}
				/* ack the request */
				DBG(3, "handled=%d, wCsrVal=%s, ep0stage=%s\n",
				    handled, decode_csr0(wCsrValSet),
				    decode_ep0stage(mgadget->bEnd0Stage));
				spin_lock(&mdev->lock);
				mcd_select_end(regs, 0);
				/* SETUP中断時RxPktRdyをクリアしない */
				wCount =
				    MCD_READ_CSR8(regs, MCD_O_HDRC_COUNT0, 0);
				if (!wCount && wCsrValSet) {
					wCsrValSet |= MCD_M_CSR0_P_SENTSTALL;
					MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0,
							0, wCsrValSet);
				}
				spin_unlock(&mdev->lock);
			}

		}
		break;

		/* handle the application stall */
	default:{
			uint16_t wCsrVal = MCD_M_CSR0_P_SENDSTALL;
			switch (mgadget->bEnd0Stage & ~MCD_END0_STAGE_STALL_BIT) {
			case MCD_END0_STAGE_TX:
				wCsrVal |= MCD_M_CSR0_TXPKTRDY;
				break;
			case MCD_END0_STAGE_RX:
				wCsrVal |= MCD_M_CSR0_RXPKTRDY;
				break;
			}

			WARN("Application stall from ep0stage=%s\n",
			     decode_ep0stage(mgadget->bEnd0Stage));
			spin_lock(&mdev->lock);
			mcd_select_end(regs, 0);
			MCD_WRITE_CSR16(regs, MCD_O_HDRC_CSR0, 0, wCsrVal);

			spin_unlock(&mdev->lock);

			mgadget->bEnd0Stage = MCD_END0_STAGE_SETUP;
			DBG(2, "[14] Ep0Stage %d \n", mgadget->bEnd0Stage);
		}
		break;
	}

	return 1;
}
