/**
 * \file
 *
 * \brief Common API for USB Device Drivers (UDD)
 *
 * Copyright (C) 2009 Atmel Corporation. All rights reserved.
 *
 * \page License
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * 3. The name of Atmel may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 *
 * 4. This software may only be redistributed and used in connection with an
 * Atmel AVR product.
 *
 * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
 * DAMAGE.
 */

#ifndef _UDD_H_
#define _UDD_H_

#include "usb_protocol.h"
#include "udc_desc.h"

#ifdef __cplusplus
extern "C" {
#endif

/**
 * \ingroup usb_device_group
 * \defgroup udd_group USB Device Driver (UDD)
 *
 * The UDD driver provides a low-level abstraction of the device
 * controller hardware. Most events coming from the hardware such as
 * interrupts, which may cause the UDD to call into the UDC and UDI.
 *
 * @{
 */

//! \brief Endpoint identifier
typedef uint8_t udd_ep_id_t;

//! \brief Endpoint transfer status
//! Returned in parameters of callback register via udd_ep_run routine.
typedef enum {
	UDD_EP_TRANSFER_OK = 0,
	UDD_EP_TRANSFER_ABORT = 1,
} udd_ep_status_t;

/**
 * \brief A USB Device SETUP request
 *
 * SETUP packet contains following information.
 */
COMPILER_PACK_SET(1);
typedef struct {
	uint8_t bmRequestType;
	uint8_t bRequest;
	uint16_t wValue;
	uint16_t wIndex;
	uint16_t wLength;
} udd_setup_req_t;
COMPILER_PACK_RESET();

/**
 * \brief Global variable to give and record information of the setup request management
 * 
 * This global variable allows to decode and response a setup request.
 * It can be updated by udc_process_setup() from UDC or *setup() from UDIs.
 */
typedef struct {
	udd_setup_req_t req;	//!< Data received in USB SETUP packet
	uint8_t *payload;	//!< Point to buffer to send or fill with data following SETUP packet
	uint16_t payload_size;	//!< Size of buffer to send or fill, and content the number of byte transfered 
									//! when the calbbacks "callback/over_under_run" are called.
	void (*callback) (void);	//!< Callback called after reception of ZLP from setup request
	 bool(*over_under_run) (void);	//!< Callback called when the buffer given (.payload) is full or empty.
	//!  This one return false to abort data transfer, or true with a new buffer in .payload.
} udd_ctrl_request_t;
extern udd_ctrl_request_t udd_g_ctrlreq;

//! Return true if the setup request \a udd_g_ctrlreq indicates IN data transfer
#define  Udd_setup_is_in()       \
      (USB_REQ_DIR_IN == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK))
//! Return true if the setup request \a udd_g_ctrlreq indicates OUT data transfer
#define  Udd_setup_is_out()      \
      (USB_REQ_DIR_OUT == (udd_g_ctrlreq.req.bmRequestType & USB_REQ_DIR_MASK))
//! Return the type of the SETUP request \a udd_g_ctrlreq. \see usb_reqtype.
#define  Udd_setup_type()        \
      (udd_g_ctrlreq.req.bmRequestType & USB_REQ_TYPE_MASK)
//! Return the recipient of the SETUP request \a udd_g_ctrlreq. \see usb_recipient
#define  Udd_setup_recipient()   \
      (udd_g_ctrlreq.req.bmRequestType & USB_REQ_RECIP_MASK)

/**
 * \brief End of halt callback function type.
 * Registered by routine udd_ep_wait_stall_clear()
 * Callback called when endpoint stall is cleared.
 */
typedef void (*udd_callback_halt_cleared_t) (void);

/**
 * \brief End of transfer callback function type.
 * Registered by routine udd_ep_run()
 * Callback called by USB interrupt after data transfer or abort (reset,...).
 *
 * \param status     UDD_EP_TRANSFER_OK, if transfer is complete
 * \param status     UDD_EP_TRANSFER_ABORT, if transfer is aborted
 * \param n          number of data transfered
 */
typedef void (*udd_callback_trans_t) (udd_ep_status_t status,
		iram_size_t nb_transfered);

/**
 * \brief Authorizes the VBUS event
 *
 * \return true, if the VBUS monitoring is possible.
 */
bool udd_include_vbus_monitoring(void);

/**
 * \brief Enables the USB Device mode
 */
void udd_enable(void);

/**
 * \brief Disables the USB Device mode
 */
void udd_disable(void);

/**
 * \brief Attach device to the bus when possible
 *
 * \warning If a VBus control is included in driver,
 * then it will attach device when an acceptable Vbus
 * level from the host is detected.
 */
void udd_attach(void);

/**
 * \brief Detaches the device from the bus
 *
 * The driver must remove pull-up on USB line D- or D+.
 */
void udd_detach(void);

/**
 * \brief Test whether the USB Device Controller is running at high
 * speed or not.
 *
 * \return \c true if the Device is running at high speed mode, otherwise \c false.
 */
bool udd_is_high_speed(void);

/**
 * \brief Changes the USB address of device
 *
 * \param address    New USB address
 */
void udd_set_address(uint8_t address);

/**
 * \brief Returns the USB address of device
 *
 * \return USB address
 */
uint8_t udd_getaddress(void);

/**
 * \brief Returns the current start of frame number
 *
 * \return current start of frame number.
 */
uint16_t udd_get_frame_number(void);

/*! \brief The USB driver sends a resume signal called Upstream Resume
 */
void udd_send_wake_up(void);

/**
 * \brief Load setup payload
 *
 * \param payload       Pointer on payload
 * \param payload_size  Size of payload
 */
void udd_set_setup_payload( uint8_t *payload,	uint16_t payload_size );


/**
 * \name Endpoint Management
 *
 * The following functions allow drivers to create and remove
 * endpoints, as well as set, clear and query their "halted" and
 * "wedged" states.
 */
//@{

#if (0!=USB_DEVICE_MAX_EP)

/**
 * \brief Configures and enables an endpoint 
 *
 * \param ep               Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT).
 * \param bmAttributes     Attributes of endpoint declared in the descriptor.
 * \param MaxEndpointSize  Endpoint maximum size 
 *
 * \return \c 1 if the endpoint is enabled, otherwise \c 0.
 */
bool udd_ep_alloc(udd_ep_id_t ep, uint8_t bmAttributes,
		uint16_t MaxEndpointSize);

/**
 * \brief Disables an endpoint 
 *
 * \param ep               Endpoint number including direction (USB_EP_DIR_IN/USB_EP_DIR_OUT).
 */
void udd_ep_free(udd_ep_id_t ep);

/**
 * \brief Check if the endpoint \a ep is halted.
 *
 * \param ep The ID of the endpoint to check.
 *
 * \return \c 1 if \a ep is halted, otherwise \c 0.
 */
bool udd_ep_is_halted(udd_ep_id_t ep);

/**
 * \brief Set the halted state of the endpoint \a ep
 *
 * After calling this function, any transaction on \a ep will result
 * in a STALL handshake being sent. Any pending transactions will be
 * performed first, however.
 *
 * \param ep The ID of the endpoint to be halted
 *
 * \return \c 1 if \a ep is halted, otherwise \c 0.
 */
bool udd_ep_set_halt(udd_ep_id_t ep);

/**
 * \brief Clear the halted state of the endpoint \a ep
 *
 * After calling this function, any transaction on \a ep will
 * be handled normally, i.e. a STALL handshake will not be sent, and
 * the data toggle sequence will start at DATA0.
 *
 * \param ep The ID of the endpoint to be un-halted
 *
 * \return \c 1 if function was successfully done, otherwise \c 0.
 */
bool udd_ep_clear_halt(udd_ep_id_t ep);

/**
 * \brief Registers a callback to call when endpoint halt is cleared
 *
 * \param ep            The ID of the endpoint to use
 * \param callback      NULL or function to call when endpoint halt is cleared
 *
 * \warning if the endpoint is not halted then the \a callback is called immediately.
 * 
 * \return \c 1 if the register is accepted, otherwise \c 0.
 */
bool udd_ep_wait_stall_clear(udd_ep_id_t ep,
		udd_callback_halt_cleared_t callback);

/**
 * \brief Allows to receive or send data on an endpoint
 *
 * The driver uses a specific DMA USB to transfer data
 * from internal RAM to endpoint, if this one is available.
 * When the transfer is finished or aborted (stall, reset, ...), the \a callback is called.
 * The \a callback returns the transfer status and eventually the number of byte transfered.
 *
 * \param ep            The ID of the endpoint to use
 * \param b_shortpacket Enabled automatic short packet
 * \param buf           Buffer on Internal RAM to send or fill.
 *                      It must be align, then use COMPILER_WORD_ALIGNED.
 * \param buf_size      Buffer size to send or fill
 * \param callback      NULL or function to call at the end of transfer
 *
 * \warning About \a b_shortpacket, for IN endpoint it means that a short packet
 * (or a Zero Length Packet) will be sent to the USB line to properly close the usb 
 * transfer at the end of the data transfer. 
 * For Bulk and Interrupt OUT endpoint, it will automatically stop the transfer 
 * at the end of the data transfer (received short packet).
 * 
 * \return \c 1 if function was successfully done, otherwise \c 0.
 */
bool udd_ep_run(udd_ep_id_t ep, bool b_shortpacket,
		uint8_t * buf, iram_size_t buf_size,
		udd_callback_trans_t callback);
/**
 * \brief Aborts transfer on going on endpoint
 *
 * If a transfer is on going, then it is stopped and the callback registered is called to signal the end of transfer.
 *
 * \param ep            The ID of the endpoint to use
 * \param b_shortpacket Enabled automatic short packet
 * \param buf           Buffer on Internal RAM to send or fill
 * \param buf_size      Buffer size to send or fill
 * \param callback      NULL or function to call at the end of transfer
 */
void udd_ep_abort(udd_ep_id_t ep);

#endif

//@}


/**
 * \name High speed test mode management
 *
 * The following functions allow the device to jump to a specific test mode required in high speed mode.
 */
//@{
void udd_test_mode_j(void);
void udd_test_mode_k(void);
void udd_test_mode_se0_nak(void);
void udd_test_mode_packet(void);
//@}


/**
 * \name UDC callbacks to provide for UDD
 *
 * The following callbacks are used by UDD.
 */
//@{

/**
 * \brief Decodes and manages a setup request
 *
 * The driver call it when a SETUP packet is received.
 * The \c udd_g_ctrlreq contains the data of SETUP packet.
 * If this callback accepts the setup request then it must 
 * return \c 1 and eventually update \c udd_g_ctrlreq to send or receive data.
 *
 * \return \c 1 if the request is accepted, otherwise \c 0.
 */
extern bool udc_process_setup(void);

/**
 * \brief Reset the UDC
 *
 * The UDC must reset all configuration.
 */
extern void udc_reset(void);

//@}

//@}

#ifdef __cplusplus
}
#endif
#endif // _UDD_H_
