/* Declarations for PCI-E ECAT series.

   Author: Golden Wang

   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, 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. */

/* File level history (record changes for this file here.)

   v 0.1.1 24 Aug 2018 by Golden Wang
     support the "reg_off" in struct "ixecat_reg_t".

   v 0.1.0 11 May 2018 by Golden Wang
     support SN2401, EEPROM(Spertan6 Flash) and EMG signal.

   v 0.0.0 20 Dec 2016 by Golden Wang
     create, blah blah... */

/* *INDENT-OFF* */

#ifndef _IXECAT_H
#define _IXECAT_H

#include <linux/types.h>
#include <linux/pci.h>
#include <linux/version.h>
#include <linux/wait.h>

#define ICPDAS_LICENSE "GPL"

/* General Definition */
#ifndef SUCCESS
#define SUCCESS 0
#endif

#ifndef FAILURE
#define FAILURE -1
#endif

#ifndef SA_SHIRQ
#define SA_SHIRQ IRQF_SHARED
#endif

#define IXECAT_DRIVER_VERSION "0.1.7"
#define ORGANIZATION "icpdas"
#define FAMILY "ixecat"			/* name of family */
#define DEVICE_NAME "ixecat"		/* device name used in /dev and /proc */
#define DEVICE_NAME_LEN 6
#define DEVICE_NR_DEVS 4
#define DEVICE_MAJOR 0			/* dynamic allocation of major number */
#define DEVICE_MINOR 0			

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
#define IXECAT_PROC_FILE "/proc/ixecat/ixecat"
#else
#define IXECAT_PROC_FILE "/proc/ixecat"
#endif

#define PCI_BASE_ADDRESSES_NUMBER  6
#define PBAN  PCI_BASE_ADDRESSES_NUMBER

#define CARD_NAME_LENGTH  32
#define CNL  CARD_NAME_LENGTH

#define KMSG(fmt, args...) printk(KERN_INFO FAMILY ": " fmt, ## args)

/* PCI Card's ID (vendor id).(device id) */
/*
          0x 1234 5678 1234 5678
             ---- ---- ---- ----
              |    |     |    |
      vendor id    |     |    sub-device id
	       device id     sub-vendor id
*/

#define PCI_ECAT_R3600		0xe159000141800000	//R3600 CPU Board
#define PCI_ECAT_GENERIC	0x10ee000735778001	//Generic x86 PC

#define IXECAT_VENDOR(a)		((a) >> 48)
#define IXECAT_DEVICE(a)		(((a) >> 32) & 0x0ffff)
#define IXECAT_SUBVENDOR(a)	(((a) >> 16) & 0x0ffff)
#define IXECAT_SUBDEVICE(a)	((a) & 0x0ffff)

/* The chaos of name convention from hardware manual... */
enum {
	IXECAT_8254_COUNTER_0,
	IXECAT_8254_COUNTER_1,
	IXECAT_8254_COUNTER_2,
	IXECAT_8254_CONTROL_REG,
	IXECAT_SELECT_THE_ACTIVE_8254_CHIP,
	IXECAT_GENERAL_CONTROL_REG,
	IXECAT_STATUS_REG,
	IXECAT_AD_SOFTWARE_TRIGGER_REG,
	IXECAT_DIGITAL_INPUT_PORT,
	IXECAT_DIGITAL_OUTPUT_PORT,
	IXECAT_ANALOG_INPUT_CHANNEL_CONTROL_REG,
	IXECAT_ANALOG_INPUT_GAIN_CONTROL_REG,
	IXECAT_ANALOG_INPUT_PORT,
	IXECAT_ANALOG_OUTPUT_CHANNEL_1,
	IXECAT_ANALOG_OUTPUT_CHANNEL_2,
	IXECAT_PCI_INTERRUPT_CONTROL_REG,
	IXECAT_CLEAR_INTERRUPT,
	IXECAT_LAST_REG,
	IXECAT_SRAM_512,
	IXECAT_BATTERY_VOLTAGE_STATUS,
	IXECAT_AD_GAIN_CONTROL_AND_MULTIPLEXER_CONTROL_REGISTER,
	IXECAT_AD_POLLING_REGISTER,
	IXECAT_EEPROM_REGISTER,
	IXECAT_READ_COUNTER0,
	IXECAT_CLEAR_COUNTER0,
	IXECAT_READ_COUNTER1,
	IXECAT_CLEAR_COUNTER1,

	/* defined for ECAT Card */
	IXECAT_SRAM_1,
	IXECAT_INTERRUPT_SERVICE,
	IXECAT_GPI_GPO,
	IXECAT_INTERRUPT_TRIGGER,
	IXECAT_HOST_BAR0
};

#define IXECAT_8254C0       IXECAT_8254_COUNTER_0
#define IXECAT_8254C1       IXECAT_8254_COUNTER_1
#define IXECAT_8254C2       IXECAT_8254_COUNTER_2
#define IXECAT_8254CR       IXECAT_8254_CONTROL_REG
#define IXECAT_8254_CHIP_SELECT IXECAT_SELECT_THE_ACTIVE_8254_CHIP
#define IXECAT_8254CS       IXECAT_8254_CHIP_SELECT
#define IXECAT_GCR          IXECAT_GENERAL_CONTROL_REG
#define IXECAT_CONTROL_REG  IXECAT_GENERAL_CONTROL_REG
#define IXECAT_CR           IXECAT_CONTROL_REG
#define IXECAT_SR           IXECAT_STATUS_REG
#define IXECAT_ADST         IXECAT_AD_SOFTWARE_TRIGGER_REG
#define IXECAT_DI           IXECAT_DIGITAL_INPUT_PORT
#define IXECAT_DO           IXECAT_DIGITAL_OUTPUT_PORT
#define IXECAT_AICR         IXECAT_ANALOG_INPUT_CHANNEL_CONTROL_REG
#define IXECAT_AIGR         IXECAT_ANALOG_INPUT_GAIN_CONTROL_REG
#define IXECAT_AI           IXECAT_ANALOG_INPUT_PORT
#define IXECAT_AD           IXECAT_AI
#define IXECAT_AO1          IXECAT_ANALOG_OUTPUT_CHANNEL_1
#define IXECAT_DA1          IXECAT_AO1
#define IXECAT_AO2          IXECAT_ANALOG_OUTPUT_CHANNEL_2
#define IXECAT_DA2          IXECAT_AO2
#define IXECAT_PICR         IXECAT_PCI_INTERRUPT_CONTROL_REG
#define IXECAT_CI           IXECAT_CLEAR_INTERRUPT
#define IXECAT_SRAM512      IXECAT_SRAM_512
#define IXECAT_BATTERY_STATUS IXECAT_BATTERY_VOLTAGE_STATUS
#define IXECAT_ADGCR	   IXECAT_AD_GAIN_CONTROL_AND_MULTIPLEXER_CONTROL_REGISTER	
#define IXECAT_ADPR	   IXECAT_AD_POLLING_REGISTER	
#define IXECAT_EEP	   IXECAT_EEPROM_REGISTER	
#define IXECAT_READ_C0	   IXECAT_READ_COUNTER0	
#define IXECAT_CLEAR_C0	   IXECAT_CLEAR_COUNTER0	
#define IXECAT_READ_C1	   IXECAT_READ_COUNTER1	
#define IXECAT_CLEAR_C1	   IXECAT_CLEAR_COUNTER1	
/* defined for ECAT Card */
#define IXECAT_SRAM1      IXECAT_SRAM_1
#define IXECAT_ISR        IXECAT_INTERRUPT_SERVICE
#define IXECAT_GPIO       IXECAT_GPI_GPO
#define IXECAT_INT_TRIG   IXECAT_INTERRUPT_TRIGGER
#define IXECAT_HOST_B0	  IXECAT_HOST_BAR0

/* IXECAT structure for signal conditions */
typedef struct ixecat_signal {
	int sid;			/* signal id */
	pid_t pid;			/* process id */
	struct task_struct *task;	/* pointer to task structure */
	int is;				/* mask for irq source 0 disable 1 enable */
	int edge;			/* active edge for each irq source 0 for
					   negative (falling) edge 1 for positive
					   (rising) edge */
	int bedge;			/* both edges, or bipolar. 0 up to the
					   setting in variable edge. 1 does action 
					   for both negative and positive
					   edges, discards setting in variable edge.  */
} ixecat_signal_t;

/* IXECAT structure for register */
typedef struct ixecat_reg {
	unsigned int id;			/* register's id */
	unsigned int value;			/* register's value for read/write */
	unsigned int reg_off;			/* register offset */
	unsigned int sram_off;			/* sram offset for sram card */
	int mode;
} ixecat_reg_t;

/* register operation mode */
enum {
	IXECAT_RM_RAW,				/* read/write directly without data mask */
	IXECAT_RM_NORMAL,			/* read/write directly */
	IXECAT_RM_READY,				/* blocks before ready */
	IXECAT_RM_TRIGGER,			/* do software trigger before ready (blocked) */
	IXECAT_RM_LAST_MODE
};

/* IXECAT cards' definition */
struct ixecat_carddef {
	__u64 id;						/* composed sub-ids */
	unsigned int present;		/* card's present counter */
	char *module;				/* module name, if card is present then
								   load module in this name */
	char *name;					/* card's name */
};

/* IXPCI strcture for read EEPROM */
typedef struct ixecat_eep{
        unsigned long offset;
        unsigned char uBLOCK;          /* 0 Read EEPROM, 1 Recover EEPROM */
        unsigned short wCount;	
        unsigned char uVal[256];       /* EEPROM Data */
} ixecat_eep_t;

extern struct ixecat_carddef ixecat_card[];

/* IXECAT device information for found cards' list */
typedef struct ixecat_devinfo {
	struct ixecat_devinfo *next;	/* next device (ixecat card) */
	struct ixecat_devinfo *prev;	/* previous device */
	struct ixecat_devinfo *next_f;	/* next device in same family */
	struct ixecat_devinfo *prev_f;	/* previous device in same family */
	unsigned int cno;			/* card number */
	unsigned int no;			/* device number (minor number) */
	__u64 id;		/* card's id */
	unsigned int irq;			/* interrupt */
	unsigned long base[PBAN];	/* base I/O addresses */
	unsigned int range[PBAN];	/* ranges for each I/O address */
	void *ioaddr[PBAN];	/* mmio address */
	unsigned int open;			/* open counter */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
        struct cdev *cdev;
#else
        struct file_operations *fops;   /* file operations for this device */
#endif
	char name[CNL];				/* card name information */
	struct ixecat_signal sig;	/* user signaling for interrupt */

} ixecat_devinfo_t;

/* IOCTL command IDs */
enum {
	IXECAT_IOCTL_ID_RESET,
	IXECAT_IOCTL_ID_GET_INFO,
	IXECAT_IOCTL_ID_SET_SIG,
	IXECAT_IOCTL_ID_READ_REG,
	IXECAT_IOCTL_ID_WRITE_REG,
	IXECAT_IOCTL_ID_TIME_SPAN,
	IXECAT_IOCTL_ID_DI,
	IXECAT_IOCTL_ID_DO,
	IXECAT_IOCTL_ID_IRQ_ENABLE,
	IXECAT_IOCTL_ID_IRQ_DISABLE,
	IXECAT_IOCTL_ID_XOR,
	IXECAT_IOCTL_ID_LAST_ITEM,
	IXECAT_IOCTL_ID_WRITE_EEP,
	IXECAT_IOCTL_ID_READ_EEP
};
/* IXECAT IOCTL command */
#define IXECAT_MAGIC_NUM  0x26	/* why? ascii codes 'P' + 'D' + 'A' + 'Q' */
#define IXECAT_GET_INFO   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_GET_INFO, ixecat_devinfo_t *)

#define IXECAT_SET_SIG    _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_SET_SIG, ixecat_signal_t *)

#define IXECAT_READ_REG   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_READ_REG, ixecat_reg_t *)
#define IXECAT_WRITE_REG  _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_WRITE_REG, ixecat_reg_t *)
#define IXECAT_TIME_SPAN  _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_TIME_SPAN, int)
#define IXECAT_WAIT       IXECAT_TIME_SPAN
#define IXECAT_DELAY      IXECAT_TIME_SPAN
#define IXECAT_BLOCK      IXECAT_TIME_SPAN
#define IXECAT_RESET      _IO(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_RESET)

#define IXECAT_IOCTL_DI   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_DI, void *)
#define IXECAT_IOCTL_DO   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_DO, void *)

#define IXECAT_IRQ_ENABLE  _IO(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_IRQ_ENABLE)
#define IXECAT_IRQ_DISABLE  _IO(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_IRQ_DISABLE)
#define IXECAT_IOCTL_XOR   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_XOR, void *)
#define IXECAT_WRITE_EEP  _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_WRITE_EEP, ixecat_eep_t *)
#define IXECAT_READ_EEP   _IOR(IXECAT_MAGIC_NUM, IXECAT_IOCTL_ID_READ_EEP, ixecat_eep_t *)

/* Exported Symbols */
#ifdef __KERNEL__

/* from ixecatecat.o */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
long ixecat_generic_ioctl(struct file *, unsigned int, unsigned long);
#else
int ixecat_generic_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
#endif

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)
int ixecat_generic_release(struct inode *, struct file *);
#else
void ixecat_generic_release(struct inode *, struct file *);
#endif
int ixecat_generic_open(struct inode *, struct file *);

/* from ixecat.o */
void *(_cardname) (__u64, int);
void *(_pci_cardname) (__u64);
void (ixecat_copy_devinfo) (ixecat_devinfo_t *, ixecat_devinfo_t *);
extern ixecat_devinfo_t *ixecat_dev;
extern int ixecat_major;
//extern int ixecat_total_boards;

/* from _proc.o */
int ixecat_proc_init(void);
void ixecat_proc_exit(void);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
#define devfs_register_chrdev(a,b,c) module_register_chrdev(a,b,c)
#define devfs_unregister_chrdev(a,b) module_unregister_chrdev(a,b)
#define ixecat_init(a) init_module(a)
#define ixecat_cleanup(a) cleanup_module(a)
#endif

#endif							/* __KERNEL__ */

#endif							/* _IXECAT_H */
/* *INDENT-ON* */
