/** @file sample_apci1710_common.c

   This file provides common functions shared between all samples.

   @par CREATION
   @author Addi-Data development team
   @date   30.09.2021
   
   @par VERSION
   @verbatim
   $LastChangedRevision:$
   $LastChangedDate:$
   @endverbatim

   @par LICENCE
   @verbatim
    Copyright (C) 2009-2021 ADDI-DATA GmbH for the source code of this module.

    ADDI-DATA GmbH
    Airpark Business Center
    Airport Boulevard B210
    77836 Rheinmünster
    Germany
    Tel: +49(0)7229/1847-0
    Fax: +49(0)7229/1847-200
    http://www.addi-data-com
    info@addi-data.com

   This program is free software; you can redistribute it and/or modify it under
   the terms of the GNU General Public License as published by the Free Software
   Foundation; either version 2 of the License, or (at your option) any later version.

   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

   You shoud also find the complete GPL in the COPYING file
   accompanying this source code.
   @endverbatim
 */

#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/sysmacros.h> // major() minor()

//------------------------------------------------------------------------------

/**
 * @brief Filter function for scandir to ignore "." and ".." entries 
 * in the struct dirent ** area set up by the scandir() function (utility function)
 * @param ent Pointer to the dirent structure
 * @return 0 if the entry is "." or "..", 1 otherwise
 */
int get_real_dir_entry (const struct dirent * ent)
{
  if (! strcmp(ent->d_name,"."))
    return 0;

  if (! strcmp(ent->d_name,".."))
    return 0;

  return 1;
}

//--------------------------------------------------------------------------------

/** 
* @brief this function look up for cards in the /proc/sys/apci1710/ directory 
* @param cards A pointer to the card area to fill
* @return The number of cards detected (may be zero if nor cards found).
*/
int apci1710_find_cards(int **cards)
{
  struct dirent **eps;
  int cnt = 0; // number of card found
  char APCI_SPECIAL_FILE_DIR[255]={0}; 
	char proc_path_template[255]={0};

	/* Test which node is availabe */
	{
		struct stat file_stat;
		const char PROC_PATH[]="/proc/sys/apci1710";
		const char DEV_PATH[]="/dev/apci1710/";

		if (stat(PROC_PATH,&file_stat) == 0)
		{
				/* Kernel 2.4 */
				strncpy(APCI_SPECIAL_FILE_DIR, PROC_PATH, strlen(PROC_PATH));
				strcpy(proc_path_template, "%s%s/ctrl");
		}
		else if (stat(DEV_PATH,&file_stat) == 0)
		{
				/* Kernel 2.6 */
				strncpy(APCI_SPECIAL_FILE_DIR, DEV_PATH, strlen(DEV_PATH));
				strcpy(proc_path_template, "%s%s");
		}
		else
		{
				perror("fstat");
				exit(1);
		}
	}

  /* scan directory for card entry */
  if ( (cnt = scandir (APCI_SPECIAL_FILE_DIR, &eps, get_real_dir_entry , alphasort)) == -1 )
  {
    perror ("scandir");
    return 0;
  }

  if (cnt == 0)
    return 0;

  /* allocate cards area */
  if ( ! ( (*cards) = malloc( cnt * sizeof(int) ) ) )
  {
    perror ("malloc");
    free(eps);
    return 0;
  }

  /* for each card entry, open it and store file descriptor in cards[] */
  {
    int i;

    for (i=0; i< cnt; i++)
    {
      int fd;
      char name[100];

      snprintf(name,sizeof(name),proc_path_template,APCI_SPECIAL_FILE_DIR,eps[i]->d_name);

      if ( ( fd = open(name, O_RDWR)) == -1 )
      {
        perror ("open");
        exit(1);
      }

      {
        struct stat file_stat;
        if ( fstat(fd,&file_stat) )
        {
          perror ("fstat");
          exit(1);
        }
        if (!S_ISCHR(file_stat.st_mode))
        {
          /* should never happen !*/
          printf("file %d is not a character device\n",i);
          exit(1);
        }
        printf("%s, major:%d minor:%d \n",name, major(file_stat.st_rdev),minor(file_stat.st_rdev));

        (*cards)[minor(file_stat.st_rdev)] = fd;
      }
      /* index device file descriptor by the minor number */
    }
  }

  return cnt;
}

