/** @file ksample06.c
 *
 * @author A. Lecomte
 *
 * Simple kernel sample with EEPROM header access.
 */

/** @par LICENCE
 * @verbatim
 Copyright (C) 2020 ADDI-DATA GmbH for the source code and the documentation.

 ADDI-DATA GmbH
 Dieselstrasse 3
 D-77833 Ottersweier
Tel: +19(0)7223/9493-0
Fax: +49(0)7223/9493-92
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 shoud find the complete GPL in the COPYING file accompanying
this source code.
 * @endverbatim
 */

#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
 #include <linux/config.h>
#else
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33)
  #include <linux/autoconf.h>
 #else
 #include <generated/autoconf.h>
 #endif
#endif
#include <linux/spinlock.h>
#include <linux/ioctl.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/pci.h> // struct pci_dev
#include <asm/io.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0)
#include <asm/system.h>
#endif
#include <asm/uaccess.h>
#include <asm/bitops.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/proc_fs.h>

#include <xpci3xxx.h>
#include <xpci3xxx-kapi.h>

#include "../xpci3xxx-options.h"

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ADDI-DATA");
MODULE_DESCRIPTION("XPCI-3XXX Read EEPROM Header sample");

#if LINUX_VERSION_CODE < KERNEL_VERSION(5,12,0)
MODULE_SUPPORTED_DEVICE("XPCI-3XXX");
#endif

EXPORT_NO_SYMBOLS;

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

#define MODULE_NAME "ksample06"

#define NUMBER_OF_BOARDS 1

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

static struct pci_dev * _pdev[NUMBER_OF_BOARDS];

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

static int ksample06_init(struct pci_dev *pdev)
{
#ifndef USE_ADDIEEPROM // In this case the symbol are exported to be used on ksamples
	int ret = 0;
	uint32_t dw_SerialNumber = 0;
	uint32_t dw_FirmwareVersion = 0;

	if ((ret = i_xpci3xxx_ReadEepromHeader_SerialNumber(pdev, &dw_SerialNumber)) == 0)
		printk("Serial number of board in slot %d: 0x%x | %d \n", PCI_SLOT(pdev->devfn), dw_SerialNumber, dw_SerialNumber);	
	else
		printk("i_xpci3xxx_ReadeEepromHeader_SerialNumber returned Error %d\n", ret);

	if ((ret = i_xpci3xxx_GetFirmwareVersion(pdev, &dw_FirmwareVersion)) == 0)
		printk("Firmware version of board in slot %d: 0x%x | %d | %c%c%c%c\n",
			PCI_SLOT(pdev->devfn), dw_FirmwareVersion, dw_FirmwareVersion,
			((char) (dw_FirmwareVersion >> 24)), ((char) (dw_FirmwareVersion >> 16)),
			((char) (dw_FirmwareVersion >> 8)), ((char) (dw_FirmwareVersion)));
	else
		printk("i_xpci3xxx_GetFirmwareVersion returned Error %d\n", ret);

	return ret;
#else
	return -2;
#endif
}
//--------------------------------------------------------------------------------

static int ksample06_release(struct pci_dev *pdev)
{
	printk("Release sample \n");

	return 0;
}
//--------------------------------------------------------------------------------

/** Called when the driver is loaded.*/
static int __init _init_module(void)
{
	int index = 0; /* Index of the board to use (here the fisrt board) */

	/* Get a pointer on the board to use */
	for (index=0; index < NUMBER_OF_BOARDS; index++)
	{
		if ((_pdev[index] = xpci3xxx_lookup_board_by_index(index)) == NULL)
		{
			printk ( KERN_DEBUG "Board index %i not found\n", index);
			return -ENODEV;
		}
		printk ( KERN_DEBUG "Board index %i found (slot: %s)\n", index,pci_name(_pdev[index]));
	}

	/* Test the first board found */
	for (index=0; index<NUMBER_OF_BOARDS; index++)
	{
		ksample06_init (_pdev[index]);
	}

	printk("Sample concluded, you can now rmmod it!\n");

	return 0;
}
//--------------------------------------------------------------------------------

/** Called when the driver is unloaded.*/
static void __exit _cleanup_module(void)
{
	int index = 0;

	printk("Cleanup module\n");
	for (index=0; index < NUMBER_OF_BOARDS; index++)
		ksample06_release (_pdev[index]);
}

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

module_init(_init_module);
module_exit(_cleanup_module);

