/***************************************************************************/
/* example_pio_dma.c 
 *
 * Build:  
 *  $COMMONCC -o example_pio_dma example_pio_dma.c $VMELIBS
 *
 * Example for Programmed VME I/O in A32/D32 and
 * VME BLT-D32 DMA (if supported) with one channel. 
 */ 
/***************************************************************************/

#include <stdio.h>
#include <sys/types.h>

#include "Vme.h"

#define VME_PIO_ADDRESS 0x10000000
#define VME_PIO_SIZE    (1024*1024) /* 1 MB */ 
#define VME_PIO_AM      0x09        /* Extended VME address */

#define VME_BLT_AM      0x0b        /* BLT D32 */
#define BUFFER_SIZE     (128*1024)

/***************************************************************************/
main (int argc, char *argv[])
/*---------------------------
*/
/*!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/
{
  u_long vme_address = VME_PIO_ADDRESS;
  int    cid, offset, length, count;
  int    *vme_base;
  int    *buffer;
/*.........................................................................*/

  /* -----------------------------------------------------------------------
   * Use a different VME base address if specified.
   */
  if ((argc==2)&&(sscanf(argv[1],"%x",&vme_address)!=1))
    {
      printf("Usage: %s <vme-base-address>\n",argv[0]);
      exit(1);
    }
  
  /* -----------------------------------------------------------------------
   * Open a VME channel for Programmed I/O and DMA.
   */
  cid = VmeOpenChannel ("pio_dma_2", "pio,dma");

  if (cid < 0 ) 
    exit(1);

  /* -----------------------------------------------------------------------
   * Allocate and prepare some buffer space for DMA. With this buffer DMA 
   * might be significantly faster using contiguous memory and locking the 
   * buffer space in memory in advance.
   * 
   * Note: This special function is not needed but if you call it ONLY 
   *       this buffer is allowed to be for DMA with this channel !
   */
   buffer = (int*)VmeAllocateMemory (cid, NULL, BUFFER_SIZE, 
				     Vme_MEMORY_FASTEST);

   if (buffer == NULL)
     exit(1);

  /* -----------------------------------------------------------------------
   * Map VME address space for PIO and define the base address for the VME 
   * copy function including DMA.
   * 
   * Note: the address modifier and size is valid for PIO only! 
   */
  vme_base = (int*)VmeMapAddress (cid, vme_address, 
				  VME_PIO_SIZE, VME_PIO_AM);
  if (vme_base == NULL)
    exit(1);

  /* -----------------------------------------------------------------------
   * You can do PIO like in example pio_1.c ...
   */
  Vme_D32WRITE(vme_base, &vme_base[7], 0xdeadbeef);

  /* -----------------------------------------------------------------------
   * ... and read/write data from/to VME with the specified offset and
   * length in bytes.
   *
   * Note: the functions return the number of bytes actually read or
   *       written which can be less than requested if the transfer was 
   *       aborted (normally by a VME bus error). 
   */
  offset = 0x100;
  length = 0x10000;

  count = VmeRead (cid, offset, (char *)buffer, length);

  if (count != length)
    exit(1);

  count = VmeWrite (cid, offset, (char *)buffer, length);

  if (count != length)
    exit(1);

  /* -----------------------------------------------------------------------
   * There are a few defaults you can modify with the VmeSetProperty()
   * function:
   *
   * 1. the address modifier to be used for the BLT (default=0x0b). 
   */
  VmeSetProperty(cid, Vme_SET_BLT_AM, 0x08); /* BLT D64 */

  /* 2. the threshold lenght above which DMA will be performed. The setup
   *    of a DMA introduces some overhead which could make the transfer
   *    of small blocks quite slow. PIO is then the faster choice. 
   *
   *    Note: normally there is a good system dependent default but it
   *          might be useful to enable or disable DMA.
   */
  VmeSetProperty(cid, Vme_SET_DMA_THRESHOLD, 0x100);

  /* -----------------------------------------------------------------------
   * Close Vme channel. Do not forget to call this function before
   * you exit otherwise you might get some trouble later.
   */
  (void)VmeCloseChannel(cid);

}