// Copyright(c) 2017, Intel Corporation
//
// Redistribution  and  use  in source  and  binary  forms,  with  or  without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of  source code  must retain the  above copyright notice,
//   this list of conditions and the following disclaimer.
// * 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.
// * Neither the name  of Intel Corporation  nor the names of its contributors
//   may be used to  endorse or promote  products derived  from this  software
//   without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,  BUT NOT LIMITED TO,  THE
// IMPLIED WARRANTIES OF  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED.  IN NO EVENT  SHALL THE COPYRIGHT OWNER  OR CONTRIBUTORS 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.

/**
 * @file event.h
 * @brief Functions for registering events and managing the lifecycle for
 * `fpga_event_handle`s.
 *
 * OPAE provides an interface to asynchronous events that can be generated by
 * different FPGA resources. The event API provides functions to register for
 * these events; associated with every event a process has registered for is an
 * fpga_event_handle, which encapsulates the OS-specific data structure for
 * event objects. On Linux, an fpga_event_handle can be used as a file
 * descriptor and passed to select(), poll(), epoll() and similar functions to
 * wait for asynchronous events.
 */

#ifndef __FPGA_EVENT_H__
#define __FPGA_EVENT_H__

#include <opae/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * Initialize an event_handle
 *
 * Platform independent way to initialize an event_handle used for
 * notifications from the driver to application. For Linux, this function
 * creates an eventfd and returns the eventfd file descriptor in
 * `*event_handle`.
 *
 * @param[out] event_handle  Pointer to event handle variable.
 *
 * @returns FPGA_OK on success. FPGA_INVALID_PARAM if `event_handle` is NULL.
 * FPGA_NOT_SUPPORTED if platform does not support events.
 */
fpga_result fpgaCreateEventHandle(fpga_event_handle *event_handle);

/**
 * Destroy an event_handle
 *
 * Destroy handle and free resources. On Linux this corresponds
 * to closing the file descriptor pointed to by handle
 *
 * @note fpgaDestroyEventHandle() requires the address of an
 * event_handle as created by fpgaCreateEventHandle(). Passing
 * any other value results in undefined behavior.
 *
 * @param[in] event_handle Pointer to handle to be destroyed
 *
 * @returns FPGA_OK on success. FPGA_INVALID_PARAM if `event_handle` is NULL.
 */
fpga_result fpgaDestroyEventHandle(fpga_event_handle *event_handle);


/**
 * Get OS object from event handle
 *
 * Check validity of event handle, and get the OS object used to
 * subscribe and unsubscribe to events. On Linux, the object corresponds
 * to a file descriptor.
 *
 * @param[in] eh Event handle to get the descriptor value from
 * @param[out] fd integer to store the descriptor value
 *
 * @returns FPGA_OK on success. FPGA_INVALID_PARAM if `event_handle` is invalid.
 */
fpga_result fpgaGetOSObjectFromEventHandle(const fpga_event_handle eh, int *fd);

/**
 * Register an FPGA event
 *
 * This function tells the driver that the caller is interested in notification
 * for the event specified by the type and flags pair.
 *
 * The event_handle points to an OS specific mechanism for event notification.
 * An event_handle is associated with only a single event.
 *
 * In case of user interrupts, the flags parameter will be used to specify
 * the vector ID. The value of the flags parameter indicates the vector ID,
 * no bit encoding is used.
 *
 * @todo define if calling fpgaRegisterEvent multiple times with the
 * same event_handle is an error condition or if it is silently ignored.
 *
 * @param[in]  handle       Handle to previously opened FPGA resource.
 * @param[in]  event_type   Type of event
 * @param[in]  event_handle Handle to previously opened resource for event
 *                          notification.
 * @param[in]  flags        Optional argument for specifying additional
 *                          information about event.  For example irq number
 *			    for interrupt events.
 * @returns FPGA_OK on success. FPGA_INVALID_PARAM if handle does not refer to
 * a resource supporting the requested event, or if event_handle is not valid.
 * FPGA_EXCEPTION if an internal exception occurred while accessing the handle
 * or the event_handle. On Linux: FPGA_NO_DAEMON if the driver does not support
 * the requested event and there is no FPGA Daemon (fpgad) running to proxy it.
 */
fpga_result fpgaRegisterEvent(fpga_handle handle,
			      fpga_event_type event_type,
			      fpga_event_handle event_handle,
			      uint32_t flags);

/**
 * Unregister an FPGA event
 *
 * This function tells the driver that the caller is no longer interested in
 * notification for the event associated with the event_handle
 *
 * The event_handle points to an OS specific mechanism for event notification.
 * An event_handle is associated with only a single event.
 *
 * @todo define if calling fpgaUnregisterEvent multiple times with the
 * same event_handle is an error condition or if it is silently ignored.
 *
 * @param[in]  handle       Handle to previously opened FPGA resource.
 * @param[in]  event_type   Type of event to unregister.
 * @param[in]  event_handle Handle to previously registered resource for event
 *                          notification.
 * @returns             FPGA_OK on success. FPGA_INVALID_PARAM if handle does
 *                      not refer to a resource supporting the requested event,
 *                      or if event_handle is not valid. FPGA_EXCEPTION if an
 *                      internal error occurred accessing the handle or the
 *                      event_handle.
 */
fpga_result fpgaUnregisterEvent(fpga_handle handle,
					     fpga_event_type event_type,
					     fpga_event_handle event_handle);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

#endif // __FPGA_EVENT_H__
