/*
 * ----------------------------------------------------------------------------
 *
 * 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,
 *    without modification.
 * 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 the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
 *
 * ----------------------------------------------------------------------------
 *
 * Alternatively, this software may be distributed under the terms of the
 * terms of the GNU General Public License version 2 as published by the
 * Free Software Foundation.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * ----------------------------------------------------------------------------
 *
 * For history of changes, ChangeLog.txt
 *
 * This header file describes the register of the Quantis PCI card. The code has been adapted from
 * a microsoft provided sample file.
 *
 *
 *Module Name:

    QuantisOp.h  - Code to manipulate the Quantis card

Environment:

    Kernel/User mode
 */

#ifndef __QUANTIS_OP
#define __QUANTIS_OP

#include "CommonWindows.h"

QUANTIS_EXTERN_C_START

#include "QuantisReg.h"
#include "Quantis.h"

/**
 * 
 * @param mask an integer with in the bits 0-3 set if the bit "type" should be set
 *             for the corresponding Quantis module.
 * @param type The bit to set for each module
 * @return a A value with the bit "type" correctly set for each Quantis module.
 */
QuantisConfRegValue mask2reg(__in ModuleMask_t mask, __in int type);

/**
 *
 * @param reg is a register describing many Quantis modules. 
 * @param type is a bit which should be checked for any of the module
 * @return a positive value where the bits 0-3 are set if the
 *         bit "type" was set for the corresponding module. The result can be used
 *         as a boolean value to know if any of the bit was set for a module.
 */
ModuleMask_t reg2mask(__in QuantisConfReg reg,__in int type);

/**
 * Flush the FIFO.
 * @param qdev pointer to the Quantis extension of the WDF device.
 */
void quantis_flush_fifo(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 *
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @return a mask indicating if any of the modules is in error.
 */
ModuleMask_t quantis_rng_error(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * Returns the number of bytes of random data available in the FIFO.
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @return the number of bytes of random data available in the FIFO.
 */
int quantis_rng_fifo_bytes(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * Try few times to get  data from FIFO. Stops after
 * too many unsuccesful retries.
 * 
 * @return the number of bytes of random data available in the FIFO or a 
 * negative value on timeout.
 */
int quantis_rng_wait_fifo(__in PQUANTIS_DEVICE_EXTENSION qdev);


/**
 * @param qdev pointer to the Quantis extension of the WDF device.
 * Reset the card (all modules are reset).
 */
void quantis_rng_reset(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * @param qdev pointer to the Quantis extension of the WDF device.
 * Returns the core version
 */
QuantisConfRegValue quantis_rng_version(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * Enable module(s) speficified by mask
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @param mask
 */
void quantis_rng_enable_modules(__in PQUANTIS_DEVICE_EXTENSION qdev, __in ModuleMask_t mask);

/**
 * Disable module(s) speficified by mask
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @param mask
 */
void quantis_rng_disable_modules(__in PQUANTIS_DEVICE_EXTENSION qdev,__in ModuleMask_t mask);

/**
 *
 * @param qdev pointer to the Quantis extension of the WDF device. 
 * @return a mask indicating which Quantis module
 *         is ready.
 */
ModuleMask_t quantis_rng_modules_status(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * Return the modules presents on the device as a mask of 4 bits.
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @return
 */
ModuleMask_t quantis_rng_modules_mask(__in PQUANTIS_DEVICE_EXTENSION qdev);

/**
 * Fills buffer with random bytes.
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @param buffer a pointer to a buffer which size is at most
 *               QUANTIS_DEVICE_BUFFER_SIZE.
 * @param length the requested number of bytes to fill into the buffer.
 * @return the number of random bytes filled into the buffer or a negative
 *         value on error.
 * @warning if (length > QUANTIS_DEVICE_BUFFER_SIZE), only
 *          QUANTIS_DEVICE_BUFFER_SIZE will be filled!
 */
 int quantis_rng_read(__in PQUANTIS_DEVICE_EXTENSION qdev,
                      __out_bcount(length) unsigned char* buffer,
                      __in unsigned int length);

/* The following function are forced to be inlined, mainly to optimize
   the inner loop of the reading of random bytes */
                                     
/**
 * Modify a register of the Quantis board.
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @param Reg a pointer to the Quantis register to set.
 * @param Val The value to set in register.
 */
static __forceinline void quantis_reg_set(__inout PQUANTIS_DEVICE_EXTENSION pDevExt,__out QuantisConfReg *Reg,__in QuantisConfRegValue Val){
    if (pDevExt->PortMapped){
        WRITE_PORT_ULONG((PULONG)Reg,(ULONG)Val);
    }
    else{
        WRITE_REGISTER_ULONG((PULONG)Reg,(ULONG)Val);
    }
}

/**
 * Read a register of the Quantis board.
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @param Reg a pointer to the Quantis register to set.
 * @return the value of the register
 */
static __forceinline QuantisConfRegValue quantis_reg_get(__in PQUANTIS_DEVICE_EXTENSION pDevExt,__in QuantisConfReg *Reg){
    if (pDevExt->PortMapped){
        return (QuantisConfRegValue) READ_PORT_ULONG((PULONG)Reg);
    }
    else{
        return (QuantisConfRegValue) READ_REGISTER_ULONG((PULONG)Reg);
    }
}

/**
 * Returns the FIFO status
 * @param qdev pointer to the Quantis extension of the WDF device.
 * @return the value of the FIFO status register
 */
static __forceinline QuantisConfRegValue quantis_get_fifo_status(__in PQUANTIS_DEVICE_EXTENSION qdev){
  return quantis_reg_get(qdev, &qdev->Regs->FS_RR);
}

QUANTIS_EXTERN_C_END

#endif