/* This software is covered by the GNU GENERAL PUBLIC LICENSE (GPL). */
/* Any Device - Driver - Linux */
/* $Workfile: main.h $ */
/* $Revision: 4 $ */
/* $Date: 10/27/07 3:41p $ */
/* $Log: /NEW SOURCESAFE DATABASE/SDK/PLX/gsc/common/driver/linux/main.h $
 * 
 * 4     10/27/07 3:41p Dnewbold
 * Remove some dead and commented out code.
 * 
 * 3     10/27/07 10:36a Dnewbold
 * Additional driver porting updates.
 *
 * 2     3/29/07 2:40p Dnewbold
 *
 * 1     5/10/06 1:01p Dnewbold
*/

#ifndef __MAIN_H__
#define __MAIN_H__


#include <asm/types.h>
#include <linux/ioctl.h>
#include <linux/types.h>

#include <asm/io.h>
#include <asm/irq.h>
#include <asm/page.h>
#include <asm/uaccess.h>

#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <linux/version.h>
#include <linux/wait.h>

#include "kernel_2_2.h"
#include "kernel_2_4.h"
#include "kernel_2_6.h"

#include "gsc_driver.h"
#include "dev_version.h"

#ifndef CONFIG_PCI
	#error This driver requires PCI support.
#endif



/* #defines	**************************************************************/

#define	BYTES_TO_PAGE_BYTES(b)			ROUND_UP_BOUNDARY((b), PAGE_SIZE)
#define	MAX_DEVICES						32
#define	ROUND_TO_PAGE_BOUNDARY(p)		ROUND_UP_BOUNDARY((u32)(p), PAGE_SIZE)
#define	ROUND_UP_BOUNDARY(by,bl)		((((by) + (bl) - 1) / (bl)) * (bl))

/* PLX Interrupt Control/Status Register bits. */
#define	INTCSR_PCI_INT_ENABLE			GSC_FIELD_ENCODE(1, 8, 8)

#define	INTCSR_DMA_0_IRQ_ACTIVE			GSC_FIELD_ENCODE(1,21,21)
#define	INTCSR_DMA_0_IRQ_ENABLE			GSC_FIELD_ENCODE(1,18,18)

#define	INTCSR_DMA_1_IRQ_ACTIVE			GSC_FIELD_ENCODE(1,22,22)
#define	INTCSR_DMA_1_IRQ_ENABLE			GSC_FIELD_ENCODE(1,19,19)

#define	INTCSR_LOCAL_IRQ_ACTIVE			GSC_FIELD_ENCODE(1,15,15)
#define	INTCSR_LOCAL_IRQ_ENABLE			GSC_FIELD_ENCODE(1,11,11)
#define	INTCSR_LOCAL_IRQ_OUTPUT_ENABLE	GSC_FIELD_ENCODE(1,16,16)

#define	INTCSR_PCI_DOORBELL_IRQ_ACTIVE	GSC_FIELD_ENCODE(1,13,13)
#define	INTCSR_PCI_DOORBELL_IRQ_ENABLE	GSC_FIELD_ENCODE(1, 9, 9)

#define	INTCSR_PCI_ABORT_IRQ_ACTIVE		GSC_FIELD_ENCODE(1,14,14)
#define	INTCSR_PCI_ABORT_IRQ_ENABLE		GSC_FIELD_ENCODE(1,10,10)

#define	INTCSR_BIST_IRQ_ACTIVE			GSC_FIELD_ENCODE(1,23,23)

/* DMA items */
#define	DMA_CSR_ENABLE					GSC_FIELD_ENCODE(1,0,0)
#define	DMA_CSR_START					GSC_FIELD_ENCODE(1,1,1)
#define	DMA_CSR_ABORT					GSC_FIELD_ENCODE(1,2,2)
#define	DMA_CSR_CLEAR					GSC_FIELD_ENCODE(1,3,3)
#define	DMA_CSR_DONE					GSC_FIELD_ENCODE(1,4,4)

#define	DMA_DPR_DESC_LOC_PCI			GSC_FIELD_ENCODE(1,0,0)
#define	DMA_DPR_END_OF_CHAIN			GSC_FIELD_ENCODE(1,1,1)
#define	DMA_DPR_TERMINAL_COUNT_IRQ		GSC_FIELD_ENCODE(1,2,2)
#define	DMA_DPR_HOST_TO_BOARD			GSC_FIELD_ENCODE(0,3,3)
#define	DMA_DPR_BOARD_TO_HOST			GSC_FIELD_ENCODE(1,3,3)

#define	DMA_MODE_SIZE_8_BITS			GSC_FIELD_ENCODE(0, 1, 0)
#define	DMA_MODE_SIZE_16_BITS			GSC_FIELD_ENCODE(1, 1, 0)
#define	DMA_MODE_SIZE_32_BITS			GSC_FIELD_ENCODE(2, 1, 0)
#define	DMA_MODE_READY_INPUT_ENABLE		GSC_FIELD_ENCODE(1, 6, 6)
#define	DMA_MODE_BTERM_INPUT_ENABLE		GSC_FIELD_ENCODE(1, 7, 7)
#define	DMA_MODE_LOCAL_BURST_ENABLE		GSC_FIELD_ENCODE(1, 8, 8)
#define	DMA_MODE_CHAINING				GSC_FIELD_ENCODE(1, 9, 9)
#define	DMA_MODE_DONE_INTERRUPT_ENABLE	GSC_FIELD_ENCODE(1,10,10)
#define	DMA_MODE_LOCAL_ADDRESS_MODE		GSC_FIELD_ENCODE(1,11,11)
#define	DMA_MODE_DEMAND_MODE			GSC_FIELD_ENCODE(1,12,12)
#define	DMA_MODE_WRITE_INVALIDATE_MODE	GSC_FIELD_ENCODE(1,13,13)
#define	DMA_MODE_EOT_ENABLE				GSC_FIELD_ENCODE(1,14,14)
#define	DMA_MODE_STOP_TRANSFER_MODE		GSC_FIELD_ENCODE(1,15,15)
#define	DMA_MODE_CHANNEL_INT_SELECT		GSC_FIELD_ENCODE(1,17,17)

#define DMA_MARBR_PRIORITY_MASK			GSC_FIELD_ENCODE(3,20,19)
#define DMA_MARBR_PRIORITY_ROTATE		GSC_FIELD_ENCODE(0,20,19)
#define DMA_MARBR_PRIORITY_DMA0			GSC_FIELD_ENCODE(1,20,19)
#define DMA_MARBR_PRIORITY_DMA1			GSC_FIELD_ENCODE(2,20,19)

/* PLX Runtime Registers */
#define GSC_PLX_L2PDBELL	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x64)
#define GSC_PLX_INTCSR	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x68)

/* PLX DMA Registers */
#define GSC_PLX_DMAMODE0	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x80)
#define GSC_PLX_DMAPADR0	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x84)
#define GSC_PLX_DMALADR0	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x88)
#define GSC_PLX_DMASIZ0		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x8C)
#define GSC_PLX_DMADPR0		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x90)
#define GSC_PLX_DMAMODE1	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x94)
#define GSC_PLX_DMAPADR1	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x98)
#define GSC_PLX_DMALADR1	GSC_REG_ENCODE(GSC_REG_PLX, 4, 0x9C)
#define GSC_PLX_DMASIZ1		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0xA0)
#define GSC_PLX_DMADPR1		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0xA4)
#define GSC_PLX_DMACSR0		GSC_REG_ENCODE(GSC_REG_PLX, 1, 0xA8)
#define GSC_PLX_DMACSR1		GSC_REG_ENCODE(GSC_REG_PLX, 1, 0xA9)
#define GSC_PLX_DMAARB		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0xAC)
#define GSC_PLX_DMATHR		GSC_REG_ENCODE(GSC_REG_PLX, 4, 0xB0)



/* typedefs	**************************************************************/

typedef struct
{
	u8		index;			// BARX, X = 1 to 6
	u8		mem_spc;		// Is this in memory space?
	u8		requested;		// Have we requested the region?
	u8		mapped;			// Have we mapped the region?
	u8		flags;			// Taken from "reg".
	u8		pci_offset;		// Offset of BAR in PCI space.
	u32		reg;			// The value read from the register.
	u32		address;		// Decoded from "reg".
	u32		size;			// Size in bytes.
	void*	overlay;		// vaddr of page if page is already mapped.
	void*	vaddr;			// Virtual address of memory region.
	u32		mmap_offset;	// Passed to mmap().
	u32		mmap_size;		// Passed to mmap() and munmap().
	u32		mmap_inset;		// The regs are at mmap() + mmap_inset.
	void*	mmap_vma;		// Mapping structure used by mmap().
} dev_bar_t;

typedef struct
{
	u32			mmap_size;	// Size of regions for mmap() purposes.
	dev_bar_t	bar[6];
} dev_bars_t;

typedef struct
{
	spinlock_t			spinlock;
	struct semaphore	sem;		/* control access */
	char				acquired;	/* Has the IRQ been acquired? */
} dev_irq_t;

typedef struct
{
	u8				index;		// The id/index number (0, 1, ...).
	u8				order;		// For allocating and freeing the pages.
	u32				size;		// The size of the allocation in bytes.
	unsigned long	krn_adrs;	// The address of the allocation.
	u32				phy_adrs;	// The physical address used for DMA and such.
	u32				mmap_offset;// For mmap().
	u32				mmap_size;	// For mmap().
	u8				mmap_users;	// Number of users.
} dev_mem_t;

typedef struct
{
	int					pid;		// Is 0 if not in use.
	dev_mem_t*			mem[GSC_MEM_ALLOC_MAX];

	u32					irq_notify;
	u32					irq_triggered;
	int					irq_cancel;	// Cancel current or next wait request.
	int					queued;		// Is someone on the queue waiting?
	int					timeout;	// Has the wait timed out? Cleared by isr.
	WAIT_QUEUE_HEAD_T	queue;		// Those who wait, do so here.
	int					condition;	// For the queue with the 2.6 kernel.

	struct
	{
		u32				vm_start;	// The address returned by mmap().
		int				mmap_usage;	// Usage count.
	} bar[6];

} dev_pid_t;

typedef struct
{
	u32	padr_32;	// Value to write to the DMAPADR.
	u32	ladr_32;	// Value to write to the DMALADR.
	u32	siz_32;		// Value to write to the DMASIZ register..
	u32	dpr_32;		// Value to write to the DMAPDR for the next structure.
} dev_dpr_t;

typedef struct
{
	int			index;		// 0 or 1
	dev_pid_t*	pid;		// Points to owner. NULL if not owned.
	u32			flags;		// How the owner wants to use the channel.
	u32			map_adrs;	// Address given to dma_un/map_single().
	u32			map_size;	// Size given to dma_un/map_single().

	struct
	{
		// These are for the unaligned structure.
		u32				bytes;	// Size of unaligned buffer.
		void*			alloc;	// Unalligned SGL buffer.

		// These are for the aligned structure.
		u32				size;	// Number of structure entries in aligned list.
		dev_dpr_t*		list;	// SGL descriptor list alligned.
		u32				dpr_32;	// Value to write to the DMADPR.

		// These are for the page access list.
		int				user_mapped;	// Is the user buffer mapped?
		DMA_SGL_SUPPORT_FIELD			// defined in linux_2_x.h
	} sgl;

	struct
	{
		volatile	VADDR_T	mode_32;	/* DMAMODEx */
		volatile	VADDR_T	padr_32;	/* DMAPADRx */
		volatile	VADDR_T	ladr_32;	/* DMALADRx */
		volatile	VADDR_T	siz_32;		/* DMASIZx */
		volatile	VADDR_T	dpr_32;		/* DMADPRx */
		volatile	VADDR_T	csr_8;		/* DMACSRx */
	} vaddr;

} dev_dma_t;

typedef struct
{
	int						usage;
	struct semaphore		sem;		/* control process access */
	struct pci_dev*			pci;		/* For PCI access. */
	dev_bars_t				bars;
	dev_irq_t				irq;
	dev_pid_t*				pid[32];

	struct
	{
		dev_dma_t			channel[2];
	} dma;

	struct
	{
		int			usage;
	} mmap;

	struct
	{
		volatile	VADDR_T		plx_dmaarb_32;	/* DMA Mode Arbitration */
		volatile	VADDR_T		plx_dmacsr0_8;	/* DMA 0 Command/Status */
		volatile	VADDR_T		plx_dmacsr1_8;	/* DMA 1 Command/Status */
		volatile	VADDR_T		plx_dmathr_32;	/* DMA Threshold */
		volatile	VADDR_T		plx_intcsr_32;	/* Interrupt Control/Status */
		volatile	VADDR_T		plx_l2pdbell_32;/* Local-2-PCI Doorbell */
	} vaddr;

} dev_data_t;

typedef struct
{
	char						built[128];
	dev_data_t*					dev_list[MAX_DEVICES];/* minor index */
	int							dev_qty;
	int							driver_loaded;
	struct file_operations		fops;
	int							major_number;
	int							proc_enabled;
	struct vm_operations_struct	vmops;
} dev_global_t;



/* variables	**************************************************************/

extern	dev_global_t	global;



/* prototypes	**************************************************************/

int			bar_info_get_ioctl(dev_data_t* dev, gsc_drv_bar_t* bar);
dev_bar_t*	bar_mmap_locate(dev_data_t* dev, u32 offset, u32 size, int* index);
void		bar_read_all(struct pci_dev* pci, dev_bars_t* bars);
int			bar_regions_check(dev_bars_t* bars);
void		bar_regions_release(dev_bars_t* bars);
int			bar_regions_request(dev_data_t* dev);
dev_bar_t*	bar_vma_locate(dev_data_t* dev, void* vma, int* index);
int			close(struct inode* inode, struct file* filp);
int			close_dev(dev_data_t* dev);
dev_data_t*	dev_locate(struct inode* inode);
int			dev_os_id_device(struct pci_dev* pci);
void		dma_channel_init(dev_data_t* dev, dev_dma_t* dma, int index);
void		dma_channel_reset(dev_dma_t* dma);
int			dma_abort(dev_dma_t* dma);
int			dma_abort_ioctl(dev_data_t* dev, gsc_drv_dma_t* dma);
int			dma_close_ioctl(dev_data_t* dev, gsc_drv_dma_t* dma);
int			dma_open_ioctl(dev_data_t* dev, gsc_drv_dma_t* dma);
void		dma_sgl_user_mem_init(dev_dma_t* dma);
int			dma_sgl_user_mem_map(dev_dma_t* dma, gsc_drv_dma_t* xfer);
void		dma_sgl_user_mem_reset(dev_dma_t* dma);
void		dma_sgl_user_mem_unmap(dev_dma_t* dma);
int			dma_status_ioctl(dev_data_t* dev, gsc_drv_dma_t* dma);
int			dma_transfer_ioctl(dev_data_t* dev, gsc_drv_dma_t* xfer);
int			ioctl_init(void);
void		irq_release(dev_data_t* dev);
int			irq_request(dev_data_t* dev);
int			irq_disable_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			irq_enable_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			irq_notify_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			irq_status_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			irq_isr_common(int irq, void* dev_id);
int			irq_wait_cancel_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			irq_wait_ioctl(dev_data_t* dev, gsc_drv_irq_t* irq);
int			mem_alloc_ioctl(dev_data_t* dev, gsc_drv_mem_t* mem);
dev_mem_t*	mem_dma_locate(dev_pid_t* pid, u32 address);
int			mem_free_ioctl(dev_data_t* dev, gsc_drv_mem_t* mem);
int			mem_info_ioctl(dev_data_t* dev, gsc_drv_mem_t* mem);
dev_mem_t*	mem_mmap_locate(dev_pid_t* pid, u32 offset, u32 size, int exact);
int			mmap(struct file* filp, struct vm_area_struct* vma);
void		mmap_setup(void);
int			open(struct inode* inode, struct file* filp);
int			pid_add(dev_data_t* dev);
dev_pid_t*	pid_locate(dev_data_t* dev);
int			pid_remove(dev_data_t* dev);
int			proc_start(void);
void		proc_stop(void);
int			reg_mod_ioctl(dev_data_t* dev, gsc_drv_reg_t* reg);
int			reg_read_ioctl(dev_data_t* dev, gsc_drv_reg_t* reg);
VADDR_T		reg_vaddr(dev_data_t* dev, unsigned long reg);
int			reg_write_ioctl(dev_data_t* dev, gsc_drv_reg_t* reg);

int		ioctl(						struct inode*			inode,
									struct file*			filp,
									unsigned int			cmd,
									unsigned long			arg);

int		mmap_mem_compute_settings(	dev_data_t*				dev,
									dev_pid_t*				pid,
									dev_mem_t*				mem);

void	mmap_nopage_common(			struct vm_area_struct*	vma,
									unsigned long			address,
									struct page**			page);

int		proc_read(					char*					page,
									char**					start,
									off_t					offset,
									int						count,
									int*					eof,
									void*					data);



#endif
