#undef __NO_VERSION__

/******************************************************************************
*h*
*   Name:               ga.c
*
*   Description:        This is the source code for the Linux Network OS
*		                Specific Module
*
*h*
******************************************************************************/

#include "nsmtypes.h"
#include "ga622t.h"
#include "nsm.h"
#include "hsm.h"


static char version[] __initdata =
"ga622t ethernet driver, version 1.02, May 15 2001, linux 2.4.x kernel\n";

/* Default initialisation of load time parameters */
UINT MaxTxDesc=200;
UINT MaxRxDesc=200;
UINT SetAutoNeg=1;
UINT RxBufSize=2048;
UINT MediaSpeed=1000;
UINT CacheLineSz=512;
UINT NCBit=1;
UINT Duplex=1;

#ifdef PRIORITY_QUEUES

UINT MaxPrio=8;

#else

UINT MaxPrio=1;

#endif

#if defined(MODULE)

MODULE_DESCRIPTION("NETGEAR GA622T Gigabit UTP Adapter driver");

/* Load time parameters */
MODULE_PARM(MaxTxDesc, "i");
MODULE_PARM(MaxRxDesc, "i");
MODULE_PARM(RxBufSize, "i");
MODULE_PARM(MediaSpeed, "i");
MODULE_PARM(SetAutoNeg, "i");
MODULE_PARM(NCBit, "i");
MODULE_PARM(Duplex, "i");

#endif

#ifdef LINK_AGGR
void LacpRegister(AdapterContext *);
INT  AggrSendPackets(AdapterContext *, PktStruct *, UCHAR, INT *);
INT  AggrSendPacket(AdapterContext *, PktStruct *, UCHAR, INT *);
UCHAR AdapterOpen (struct net_device *dev);
void AdapterClose (struct net_device *dev);
#define GEC_FLAG        0x01
extern	char *format(int);
extern	void stringcpy(char *dest, char *src); 
#endif

/* List of the various instances of the GA622T */
struct net_device *DevList = NULL;

/******************************************************************************
*f*
*   Name:           dp_module_init
*
*   Description     This routine is called when an "insmod" is done for this 
*                   module 
*
*   Parameters:     None
*
*   Return Value:   OK or -ENODEV 
*
*f*
******************************************************************************/

int __init dp_module_init(void)
{
	return DrvProbe(NULL);
}

/******************************************************************************
*f*
*   Name:           dp_module_cleanup
*
*   Description     This routine is called when an "rmmod" is done for this 
*                   module 
*
*   Parameters:     None
*
*   Return Value:   None 
*
*f*
******************************************************************************/

void __exit
dp_module_cleanup(void)
{
	struct net_device *cur_dev;
	struct net_device *pDev;
	AdapterContext *pNsc;

	/* Traverse through the list of net_device structures */
	cur_dev= DevList;
	while (cur_dev) 
	{
		/* Get the next net_device structure in the list */
		pDev = (struct net_device *) (((NsmContext *)cur_dev->priv)->next);

		AdapterClose(cur_dev);
		pNsc = &((NsmContext *)(cur_dev->priv))->AdpCtxt;

		#ifdef LINK_AGGR	
			if(pNsc->nFlags)
				LacpUnInitialize(pNsc);
		#endif

		/* Unregister the instance of the network device, corresponding to this 
			device structure  */
		unregister_netdev (cur_dev);

#ifdef IOMAPPED_IO
		
		/* Release the IO region held by this instance of the net_device */
		release_region(cur_dev->base_addr, PCI_IO_SIZE);
#endif

		kfree(((NsmContext *)cur_dev->priv)->pAdapterStats);
	
		kfree(cur_dev); 
	
		/* Update the cur_dev to point to the next net_device in the list */
		cur_dev = pDev;
	}
}

module_init(dp_module_init);
module_exit(dp_module_cleanup);

/******************************************************************************
*f*
*   Name:           DrvProbe
*
*   Description     This routine enumerates Drv ethernet devices on the PCI 
*   				bus, and registers each device found.
*
*   Parameters:     dev: Pointer to the net_device structure 
*
*   Return Value:   OK or -ENODEV 
*
*f*
******************************************************************************/

int
DrvProbe (struct net_device *dev)
{
	int 			DevCount=0;
	struct pci_dev 	*pdev=NULL;
	UINT  			iobase;
	UINT  			membase;
	AdapterContext 	*pNsc;
	NsmContext 		*pNsm;
	int				version_disp;
	UINT 			cfg_val;
	UINT 			cfg_lat;
	UINT			srr_val;

	/* Check for PCI BIOS being present, return ENODEV if not present */
	if (! pci_present())
	{
#ifdef FAILURE_MESSAGES
		printk("\nPCI bios not present"); 
#endif
	
		/* No such device */
   		return -ENODEV; 
	}

	version_disp = 0;

	/* Find the instances of the device present, and for each instance of the 
	device do the following */

	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) 
	{
		if (!((pdev->vendor == PCI_VENDOR_ID_NS) && 
			(pdev->device == PCI_DEVICE_ID_83820)))
			continue;

		iobase = pci_resource_start(pdev, 0);
		membase = pci_resource_start(pdev, 1);

#ifdef IOMAPPED_IO
		
		/* Check if a range of ports is already locked by other drivers */
		if (check_region(iobase,PCI_IO_SIZE))
		{  
#ifdef FAILURE_MESSAGES
			printk ("check_region failed : IO region already in use\n");
#endif
			continue;
		}
#endif		
		/* Allocate space for the device structure, name the device, and also 
		for the private data structure, in this case, the NsmContext. Add the 
		device to the ethernet device list and register the network 
		device. */

		dev = init_etherdev(dev, sizeof(NsmContext));

		if (dev == NULL) 
		{	
#ifdef FAILURE_MESSAGES
			printk (KERN_ERR "%s: Failed to create device struct\n",DRV_NAME);
#endif

			break;
		}

		/* Display version info if Adapter is found */
		if(!version_disp)
		{
			/* Display string only once */
			version_disp = 1;
			printk(version);
		}

#ifdef LINK_AGGR
		stringcpy(dev->name, format(DevCount));
		printk(KERN_INFO "\nNETGEAR GA622T Gigabit UTP Adapter : %s\n",dev->name);
#else
		printk(KERN_INFO "\nNETGEAR GA622T Gigabit UTP Adapter : %s\n",dev->name);
#endif

		/* Get the pointer to the NsmContext */
		pNsm = (NsmContext *)dev->priv;
		
		pNsm->dev = dev;

		/* Get the pointer to the adapter context */
		pNsc = &pNsm->AdpCtxt ;
		
		/* Allocate the structure to hold the net_device_stats*/
		/* This is reqd here because an ifconfig done can request the statistcs 
			even before an open is done */
		pNsm->pAdapterStats = (struct net_device_stats *) 
			kmalloc(sizeof(struct net_device_stats), GFP_KERNEL);	

		/* Check if the allocation was successful */
		if(pNsm->pAdapterStats == NULL)
		{
#ifdef FAILURE_MESSAGES
			printk(KERN_INFO "Allocation of Statistics struct failed\n");
#endif
			unregister_netdev(dev);
			kfree(dev);
			break;
		}

		pNsc->pNsmContext = (void *)pNsm;

		/* initialize the device data like iobase, irq, and the entry points 
		for the driver in the device structure */

		pNsc->TxMaxDMASize= CacheLineSz;
		pNsc->RxMaxDMASize= CacheLineSz;

		pNsc->MaxPktSize = RxBufSize;

#ifdef MEMMAPPED_IO

		dev->base_addr = (ULONG) membase; /* Memory mapped IO */
		pNsc->RegAddr = (UCHAR *)ioremap(membase, PCI_MEM_SIZE);

#elif IOMAPPED_IO

		dev->base_addr = (ULONG) iobase;
		pNsc->RegAddr =  (UCHAR *)dev->base_addr;
#endif

		dev->irq       = pdev->irq;
		dev->open      = DrvOpen;
    	dev->stop      = DrvClose;
    	dev->get_stats = DrvGetStatistics;
		dev->do_ioctl  = DrvIoctl;
		dev->hard_start_xmit = DrvSend;
		dev->set_multicast_list = DrvSetMulticastList;
		dev->set_mac_address = DrvSetMacAddress;
		dev->tx_timeout = DrvTxTimeout;
		//ether_setup(dev);

		/* Change the mtu function in the device structure as ether_setup sets 
		it to a function which can accepts MTUs of size less than 1500, so 
		change it to a function which can change the MTU to any value 
		less than 65280 and greater than 68. */
		
		dev->change_mtu = ChangeMtu; 

#ifdef IOMAPPED_IO
		
		/* reserve IO region, this locks the ports for later use */
		request_region (iobase, PCI_IO_SIZE, dev->name);

#endif

		/* Chain the device */
		pNsm->next = (void *)DevList;
   		DevList = dev;

		/* Work Around to fix 8byte replicating issue */
		NsmRegRead32(pNsm, (pNsc->RegAddr + CFG), &cfg_val);
		NsmRegRead32(pNsm, (pNsc->RegAddr + SRR), &srr_val);

		if(!(cfg_val & PCI64_DET) && (srr_val <= 0x103)) {
			pci_read_config_dword(pdev, CFGLAT, &cfg_lat);
			cfg_lat |= 0x0000FE00;
			pci_write_config_dword(pdev, CFGLAT, cfg_lat);	
		}

		HsmGetMacAddress(pNsc);
		
		/* Install interrupt vector and register the interrupt service 
		routine */
		if((AdapterOpen(dev)) != OK)
		{
		#ifdef FAILURE_MESSAGES
			printk (KERN_ERR "%s: AdapterOpen Failed \n", DRV_NAME);
		#endif
			kfree(pNsm->pAdapterStats);
			unregister_netdev(dev);
			kfree(dev);
			break;
		}

		/* Update Counters for the number of devices found */
		DevCount++;
		
	#ifdef	LINK_AGGR	
	
		pNsc->FuncStruct.HsmSendPkt = HsmSendPacket;
		pNsc->FuncStruct.HsmSendPkts = HsmSendPkts;
		pNsc->FuncStruct.HsmMulticastAdd = HsmMulticastAdd;
		pNsc->FuncStruct.DrvSend = NULL;
		pNsc->FuncStruct.HsmMulticastDelete = HsmMultiCastDelete;
		pNsc->FuncStruct.HsmSetMacAddress = HsmSetMacAddress;
		pNsc->FuncStruct.HsmRxFilter = HsmRxFilter;
		pNsc->FuncStruct.HsmSetPhyCapabilities = HsmSetPhyCapabilities;
		pNsc->FuncStruct.NsmSetPktStatus = NULL;
		pNsc->FuncStruct.NsmIndicateLinkStatus = NsmIndicateLinkStatus;

		LacpRegister(pNsc);

	#endif
		dev=NULL;

  	}

	if(DevCount == 0)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "No device of NETGEAR present\n");
#endif
		return -ENODEV;
	}
	
	return 0;
}

/******************************************************************************
*f*
*   Name:           DrvOpen
*
*   Description:    DrvOpen opens and initializes a device. This is 
*    				typically called when an ifconfig is done for this 
*					interface.
*
*   Parameters:     dev: Pointer to the net_device structure 
*
*   Return Value:   OK or -EAGAIN 
*
*f*
******************************************************************************/

STATIC int
DrvOpen (struct net_device *dev)
{
#if 0
	UINT 			stat;
	NsmContext 		*pNsm;
	AdapterContext 	*pNsc;
	UINT			i;
	
	/* Get the pointer to the allocated private data structure, NsmContext, 
	from the device structure */
	pNsm = (NsmContext *)dev->priv;

	/* Get the pointer to the AdapterContext structure from the NsmContext */
	pNsc = &pNsm->AdpCtxt;

	for(i=0; i< MAX_PRI_QUEUE; i++)
	{
		pNsc->RxQueueSz[i] = MaxRxDesc;
		pNsc->TxQueueSz[i] = MaxTxDesc;
	}
	pNsc->TxDrth = TxDrth;		
	pNsc->RxDrth = RxDrth;
	pNsc->TxFlth = TxFlth;
	pNsc->PauseCounterVal = PauseCounterVal;
	pNsc->RxFFLO = 2;
	pNsc->RxFFHI = 8;
	pNsc->RxSTLO = 2;
	pNsc->RxSTHI = 8;

	/* Initialize fields which would indicate the capabilities of the hardware,
	 such as the, checksum offload */
	HsmInitContext(pNsc);

	/* Find out the capabilities of the OS and indicate whether the above 
	capabilties are supported by the OS. */

	pNsc->OsPrio = MaxPrio;
	pNsc->PhysCapabilities &= ~(VLAN_TAG_INSERTION_GEN_ON | 
		BIG_ENDIAN | TX_CHKSUM_OFFLOAD_ON_GEN ); 

	if(SetAutoNeg == 0)
	{
		pNsc->PhysCapabilities &= ~AUTO_NEG_ON;  
		pNsc->InfMediaSpeed = MediaSpeed;
		pNsc->InfDuplexMode = DuplexMode;
	}	

	/* Allocate the Tx and Rx lists, based on the number of priority levels 
	supported. Call the HsmInitialise routine of the HSM, this will also setup 
	transmit & receive control. This will set up descriptor lists for each 
	level of priorities on both send and receive side. */

	if ( (stat = HsmInitialize(pNsc) ) == FAILURE )
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: HsmInitialize Failed \n", DRV_NAME);
#endif
		return -EAGAIN;
	}

	/* Now set the Mac address in the device structure */
	NsmCopy((char *)pNsc->PermMacAddr, (char *)dev->dev_addr, 
		MAC_ADDR_LEN); 

	/* Install interrupt vector and register the interrupt service routine */
	if(request_irq (dev->irq, DrvIsr, SA_SHIRQ,
    	dev->name, dev) != OK)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: request_irq Failed \n", DRV_NAME);
#endif
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	}

	/* Reset the adapter  */
	if( ( stat =HsmReset(pNsc, 0) ) == FAILURE)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: Resetting the adapter, failed \n", 
			DRV_NAME);
#endif
		free_irq (dev->irq, dev);
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	} 

	/* Call HsmOpen call to open the adapter */
	if( ( stat =HsmOpen(pNsc) ) == FAILURE)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: Opening the adapter, failed \n", 
			DRV_NAME);
#endif
		free_irq (dev->irq, dev);
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	}
	
	HsmRxFilter(pNsc, (ACCEPT_PERFECT_MATCH_ON | ACCEPT_ALL_BROADCAST_ON));

	/* Set the transmit queue length in the device structure */
	dev->tx_queue_len = (MaxTxDesc*MaxPrio);
#endif
	
	((NsmContext *)dev->priv)->status |= NSM_OPEN;
	/* Increment module reference count, MOD_INC_USE_COUNT */
	MOD_INC_USE_COUNT;

    return OK;
}

/******************************************************************************
*f*
*   Name:           DrvClose
*
*   Description:    This closes the device and reclaims the resources
*
*   Parameters:     dev: Pointer to the net_device structure 
*
*   Return Value:   OK or ERROR  
*
*f*
******************************************************************************/

STATIC int
DrvClose (struct net_device *dev)
{

#if 0
	NsmContext 		*pNsm;
	AdapterContext 	*pNsc;

	/* Get the pointer to the NsmContext and thereby to the AdapterContext, 
	from the device structure */
	pNsm = (NsmContext *)dev->priv;
	pNsc   = &(pNsm->AdpCtxt);

	/* Stop Tx & Rx by calling HsmClose */
	HsmClose(pNsc); 

	/* Uninstall the interrupt vector, and deregister the interrupt service 
	routine */
	free_irq (dev->irq, dev);

	/* Free the Tx and Rx lists by calling HsmUnInitialize */
	HsmUnInitialize(pNsc);  
#endif
	
	((NsmContext *)dev->priv)->status &= ~NSM_OPEN;
	/* Decrement module reference count using MOD_DEC_USE_COUNT */
	MOD_DEC_USE_COUNT;

  	return OK;
}

/******************************************************************************
*f*
*   Name:           DrvSend
*
*   Description:    This sends a packet down to the HSM, to be sent on wire
*
*   Parameters:     dev: Pointer to the net_device structure
*                   
*                   skb: Pointer to the sk_buff which contains the data to be 
*                   sent down
*
*   Return Value:   OK or ERROR
*
*f*
******************************************************************************/


STATIC int
DrvSend (struct sk_buff *skb, struct net_device *dev)
{
	NsmContext 		*pNsm;
	AdapterContext 	*pNsc;
	UINT			retval=OK, Priority;
	#ifdef LINK_AGGR
		INT				CableStatus = 0;
	#endif

#ifdef SINGLE_PACKET

	PktInfo			Pkt;
	UCHAR			status;

#elif MULTIPLE_PACKETS

	static PktStruct		Pkts;
	UCHAR 			stat;

#endif
	
	/* Get the pointer to the NsmContext and thereby to the AdapterContext, 
	from the device structure */
	pNsm = (NsmContext *)dev->priv;
	pNsc = &(pNsm->AdpCtxt);

	/* Set the transmit start time in the device structure */
	dev->trans_start = jiffies;

	/* Encapsulate the data which needs to be sent on the wire in a Packet 
	struct */

#ifdef SINGLE_PACKET

	CreatePacketInfo( skb, &Pkt);

#elif MULTIPLE_PACKETS

	CreatePacketStruct( skb, &Pkts);

#endif

	/* Get the priority of the packet, which is going to be sent down from the 
	priority field in the skbuff. */

	/* Call the HSM routine to send the packet on the wire with the priority 
	obtained from the priority field of the skbuff. */ 

#ifdef SINGLE_PACKET

#ifdef LINK_AGGR
	Pkt.pDLHeader = (VOID *)(skb->data); 
#endif

#ifdef PRIORITY_QUEUES	
	Priority = skb->priority;
#else
	Priority = 0;
#endif
#ifdef LINK_AGGR
        if((pNsc->nFlags) & GEC_FLAG) 
		{
	        status = AggrSendPacket(pNsc,&Pkt,Priority, &CableStatus); 

			/* Check if no link - Ravi */
			if (CableStatus == -1) {
				//NsmDbgMsg("\nCable not connected");
				retval = ERROR;
				//break;
			}
		}
        else
		{
		//printk(KERN_INFO "dp.c :Before calling Hsm Send\n");
            status = HsmSendPacket(pNsc, &Pkt,Priority);
		}
#else
		status = HsmSendPacket(pNsc,&Pkt,Priority);
#endif
	
	if(status == FAILURE)
	{
		retval = ERROR;
	}
#elif MULTIPLE_PACKETS

#ifdef LINK_AGGR
	Pkts.PktArray[0].pDLHeader = 
		(VOID *)(skb->data); 
#endif

	#ifdef PRIORITY_QUEUES	
		Priority = skb->priority;
	#else
		Priority = 0;
	#endif

	#ifdef LINK_AGGR
      if((pNsc->nFlags) & GEC_FLAG) 
		{
	       	stat = AggrSendPackets(pNsc,&Pkts,Priority, &CableStatus); 
			
			/* Check if no link - Ravi */
				if (CableStatus == -1) 
				{
					//NsmDbgMsg("\nCable not connected");
					retval = ERROR;
					//break;
				}
		}
		else
		{
            stat = HsmSendPkts(pNsc, &Pkts,Priority,0);
		}
	#else
			stat = HsmSendPkts(pNsc,&Pkts,Priority);
	#endif
		if(stat == 0)
		{
			/* MKC change it */
			retval = ERROR;
		}
#endif
	
 	return retval;
}

/******************************************************************************
*f*
*   Name:           DrvSetMulticastList 
*
*   Description:    DrvSetMulticastList sets multicast filters & promiscuous 
*                   mode 
*
*   Parameters:     dev: Pointer to the net_device structure
*
*   Return Value:   None 
*
*f*
******************************************************************************/


STATIC void
DrvSetMulticastList (struct net_device *dev)
{
	struct dev_mc_list 	*mc_list;
	MultiList 			*pMultiList;
	MultiList			*pMulti;
	MultiList 			*pMultiNext;
	NsmContext			*pNsm = ((NsmContext *)dev->priv);
	UINT				FilterFlags;

	/* Get the pointer to the NsmContext and thereby to the AdapterContext, 
	from the device structure */
	AdapterContext 		*pNsc = &(pNsm->AdpCtxt);

	FilterFlags = (pNsm->FilterFlags | ACCEPT_PERFECT_MATCH_ON | 
		ACCEPT_ALL_BROADCAST_ON);
    
	/* Setup promiscuous mode */ 
	if (dev->flags & IFF_PROMISC)
	{

		if(pNsm->FilterFlags & PROMISCUOUS_ON)
		{
			FilterFlags |= PROMISCUOUS_OFF;
			FilterFlags &= ~PROMISCUOUS_ON;
		}
		else if (pNsm->FilterFlags & PROMISCUOUS_OFF)
		{
			FilterFlags |= PROMISCUOUS_ON;
			FilterFlags &= ~PROMISCUOUS_OFF;
		}
		else /* The first time */
		{
			FilterFlags |= PROMISCUOUS_ON;
		}
			
	}
 
	/* Receiving all multicast packets  */
	if (dev->flags & IFF_ALLMULTI) 
	{

		if(pNsm->FilterFlags & ACCEPT_ALL_MULTICAST_OFF)
		{
			FilterFlags |= ACCEPT_ALL_MULTICAST_ON;
			FilterFlags &= ~ACCEPT_ALL_MULTICAST_OFF;
		}
		else if (pNsm->FilterFlags & ACCEPT_ALL_MULTICAST_ON)
		{
			FilterFlags |= ACCEPT_ALL_MULTICAST_OFF;
			FilterFlags &= ~ACCEPT_ALL_MULTICAST_ON;
		}
		else /* First time */
		{
			FilterFlags |= ACCEPT_ALL_MULTICAST_ON;
		}
	}		

	/* Call the HSM function to set the receive filters */
	if(FilterFlags)
	{
		HsmRxFilter(pNsc, FilterFlags);
		pNsm->FilterFlags = FilterFlags;
	}

	/* Set the list of multicast addresses in the mc_list */
	mc_list = dev->mc_list;
	pMultiList = NULL;

	/* Get the multicast address list from the mc_list and allocate a 
	MultiList structure and put the multicast addresses into the MultiList 
	structure  */

	while(mc_list)
	{
		pMulti = (MultiList *)kmalloc(sizeof(MultiList), GFP_KERNEL);
		if(pMulti == NULL)
		{
			if(pMultiList)
			{
				pMulti = pMultiList;
				while(pMulti)
				{
					pMultiNext = pMulti->Next;
					kfree(pMulti);
					pMulti = pMultiNext;
				}
			}
			return;
		}
		NsmCopy(mc_list->dmi_addr, 
			pMulti->MulticastAddr,MAX_ADDR_LEN); 
		pMulti->Next = pMultiList;
		pMultiList = pMulti;
		mc_list = mc_list->next;		        	
	}

	/* Call the HSM function to add the list of multicast addresses to the 
	filter */
	HsmMulticastAdd(pNsc, pMultiList, TRUE);	

	/* Free up the list of MultiList structures */
	pMulti = pMultiList;
	while(pMulti)
	{
		pMultiNext = pMulti->Next;
		kfree(pMulti);
		pMulti = pMultiNext;
	}

}

/******************************************************************************
*f*
*   Name:           DrvSetMacAddress
*
*   Description:    This sets a new MAC address
*
*   Parameters:     dev: Pointer to the net_device structure
*
*                   addr: The new MAC address that needs to be set 
*
*   Return Value:   OK or ERROR 
*
*f*
******************************************************************************/

int DrvSetMacAddress(struct net_device *dev, void *addr)
{
	AdapterContext *pNsc = &((NsmContext *)dev->priv)->AdpCtxt;

	void *MacAddr = (void *) (((struct sockaddr *)addr)->sa_data);

	NsmCopy(MacAddr, (void *)dev->dev_addr, MAC_ADDR_LEN);

	NsmCopy(MacAddr, (void *)pNsc->CurrMacAddr, MAC_ADDR_LEN);

	HsmSetMacAddress(pNsc, pNsc->CurrMacAddr); 

	return OK;
}
	

/******************************************************************************
*f*
*   Name:           DrvIsr 
*
*   Description:    This is the interrupt handler of the driver
*
*   Parameters:    	irq: This represents the IRQ value for which this handler 
*                   was registered
*
*                  	dev_id:  This is a pointer to the net_device structure
*
*                  	regs:    This is a pointer to a snapshot of the processor's 
*                   context, before the processor entered the interrupt code
* 
*   Return Value:   None
*
*f*
***************************************************************************/

STATIC void
DrvIsr (int irq, void *dev_id, struct pt_regs *regs)
{
	/* Get the pointer to the device structure from the dev_id */
	struct net_device 	*dev = ( struct net_device *) dev_id;

	/* Get the pointer to the AdapterContext */
	AdapterContext 	*pNsc = &(((struct NsmInfo *)dev->priv)->AdpCtxt);

	/* Call the HSMs interrupt service routine */
	HsmIsr (pNsc);
}


/******************************************************************************
*f*
*   Name:           DrvIoctl 
*
*   Description:    This is the ioctl handler of the driver 
*
*   Parameters:     dev: This is a pointer to the net_device structure
*
*                   rq:  pointer to a copy of the structure passed by the user 
*                   for this command
*
*                   cmd: This indicates the ioctl command
*
*   Return Value:   OK or -EOPNOTSUPP 
*
*f*
***************************************************************************/

int 
DrvIoctl( struct net_device *dev, struct ifreq *rq, int cmd )
{

	/* Get the data for the ioctl from the ifreq structure */ 
	void 			*data = &(rq->ifr_data);

	/* Get the pointer to the AdapterContext */
	AdapterContext 	*pNsc = &((NsmContext *)(dev->priv))->AdpCtxt;

	/* Depending on the cmd perform the following */
	switch( cmd )
	{
		/* For setting interface address(dev->dev_addr) */
		case SIOCSIFADDR:

			/* Set the MAC address in the device structure and also the 
			AdapterContext, with the one obtained from the data */

			NsmCopy((const void *)data, (void *)dev->dev_addr, MAC_ADDR_LEN);
			NsmCopy((const void *)data, (void *)pNsc->CurrMacAddr, 
				MAC_ADDR_LEN);
			HsmSetMacAddress(pNsc, pNsc->CurrMacAddr); 
			break;	

		/* The ioctl implementation for sockets, defines 16 ioctls cmds as 
		private to the interface, SIOCSDEVPRIVATE, SIOCSDEVPRIVATE+ 1,.. 
		& so on  */

		case SIOCDEVPRIVATE: 
			break;
		default:
			return -EOPNOTSUPP;
	}
	return OK;
}

/******************************************************************************
*f*
*   Name:           DrvGetStatistics 
*
*   Description:    This is the routine used to get the statistical information
*                   regarding the transmission and reception of packets.
*
*   Parameters:     dev: This is a pointer to the net_device structure
*
*   Return Value:   Pointer to the statistics structure 
*
*f*
***************************************************************************/

struct net_device_stats *
DrvGetStatistics(struct net_device *dev)
{
	/* Get the pointer to the NsmContext and thereby to the AdapterContext, 
		from the device structure */
	NsmContext 				*pNsm = (NsmContext *)dev->priv;
	AdapterContext 			*pNsc = &(pNsm->AdpCtxt);

	struct net_device_stats 	*pAdpStats = pNsm->pAdapterStats; 

	/* Update the fields in the StatInfo structure (MacStats) in the 
		AdapterContext, by reading the current values from the MIB 
		registers of the adapter */
	if(HsmGetStatistics(pNsc) == FAILURE) 
	{
		return NULL;
	}
	
	/* Get the statistics from the adapter context structure & set the values 
		of the statistics in the net_device_stats structure */

	pAdpStats->rx_packets = pNsc->MacStats.rxOkCount;
	pAdpStats->rx_errors = pNsc->MacStats.rxErrorCount;
	pAdpStats->rx_dropped = pNsc->MacStats.rxDroppedCount;
	pAdpStats->rx_crc_errors = pNsc->MacStats.rxCrcErrorCount;
	pAdpStats->rx_frame_errors = pNsc->MacStats.rxFaeCount;
	pAdpStats->rx_missed_errors = pNsc->MacStats.rxNoBufferCount;
	
	pAdpStats->tx_errors = pNsc->MacStats.txErrorCount;
	pAdpStats->tx_packets = pNsc->MacStats.txOkCount;
	pAdpStats->tx_dropped = pNsc->MacStats.txDroppedCount;
	
	pAdpStats->tx_carrier_errors = pNsc->MacStats.txCrsLostCount;
	pAdpStats->tx_aborted_errors = pNsc->MacStats.txAbortCount;
	pAdpStats->tx_fifo_errors = pNsc->MacStats.txUnderrunCount;
	pAdpStats->collisions = pNsc->MacStats.txTotCollisionCount;

	pAdpStats->rx_length_errors = 0;
	pAdpStats->rx_over_errors = 0;
	pAdpStats->rx_fifo_errors = 0;
	
	pAdpStats->tx_heartbeat_errors = 0;
	pAdpStats->tx_window_errors = 0;

 	return pAdpStats;
}

/******************************************************************************
*f*
*   Name:           DrvTxTimeout 
*
*   Description:    This is the routine to be called when the transmit engine
*                   appears to be halted
*
*   Parameters:     dev: This is a pointer to the net_device structure
*
*   Return Value:   None
*
*f*
***************************************************************************/

void DrvTxTimeout(struct net_device *dev)
{
	UCHAR stat;
	AdapterContext *pNsc = &((NsmContext *)(dev->priv))->AdpCtxt;
	printk("\nResetting the card");
	stat = HsmReset(pNsc, 0);
	if(stat == SUCCESS)
		printk("\nReset completed"); 
	else
		printk("\nReset could not be completed properly"); 
}
	
/******************************************************************************
*f*
*   Name:           NsmTxCompleted 
*
*   Description:    This is called by HSM to indicate that transmission is 
*                   complete for a sublist of HsmTCBs in the HsmTCB list, 
*                   which is indicated by sending the first and the TCB, next 
*                   to the last TCB in list.
*
*   Parameters:     pNsc:	Pointer to the AdapterContext structure
*
*                   TcbFirst:    Pointer to the first HsmTCB in the list for 
*                   which transmit completion has happened
*
*                   TcbLast:     Pointer to the HsmTCB which is the next from 
*                   the last TCB in the list for which transmit completion has 
*                   happened
* 
*
*   Return Value:   None 
*
*f*
***************************************************************************/

void NsmTxCompleted(AdapterContext *pNsc, HsmTCB *TcbFirst, HsmTCB *TcbLast)
{

	HsmTCB *tcb;

	tcb = TcbFirst;

	/* Free up the data buffer associated with the indicated HsmTCBs */  
	do
	{
		if((struct sk_buff *)tcb->pOsCtrlBlk) 
		{
			dev_kfree_skb_irq((struct sk_buff *)tcb->pOsCtrlBlk);
			tcb->pOsCtrlBlk = NULL;
		}
		tcb = tcb->pNext;
	}while(tcb != TcbLast);
}

/******************************************************************************
*f*
*   Name:           NsmRxPackets 
*
*   Description:    This is called by the HSM, to send the received packets in 
*                   a particular priority, over to the upper layers
*
*   Parameters:     pNsc:	Pointer to the AdapterContext structure
*
*                   RcbStart:	Pointer to the first HsmRCB in the list for 
*                   which receive completion has happened
*     
*                   RcbEnd:	Pointer to the HsmRCB which is the next from 
*                   the last RCB in the list for which receive completion has 
*                   happened
*
*                   Priority:    Priority queue on which the packet was obtained
*
*   Return Value:   None
*
*f*
***************************************************************************/

STATIC VOID 
NsmRxPackets (AdapterContext *pNsc, HsmRCB *RcbStart, HsmRCB *RcbEnd, 
	UCHAR Priority) 
{
	HsmRCB 			*rcb;
	HsmRCB 			*CurrRCB;
	HsmRCB 			*StartRCB;
	HsmRCB 			*TempRcb;
	struct sk_buff 	*NewSkb;
	struct sk_buff	*skb_new;
	struct sk_buff	*skb;
	UINT 			RemainingRCBs = 0;
	struct net_device 	*dev;
	UINT 			status=OK;
	UINT 			BufSizeReqd;

	/* Get the pointer to the NsmContext */
	NsmContext 		*pNsm = (NsmContext *)pNsc->pNsmContext; 

	/* Get the start of the list of HsmRCBs for which Rx complete has happened  
		*/
	rcb = RcbStart;

	/* Get the device structure from the skb */
	dev = ( (struct sk_buff *) rcb->pOsCtrlBlk)->dev;

	/* Traverse through the HsmRCB list and for each RCB from RcbStart to 
		RcbEnd */
	while ( rcb != RcbEnd )
	{

		/* check for jumbo frames by checking the More flag in HsmRCB, if it's a
			jumbo packet */
		if(rcb->More)
		{
			/* Get the start of the HsmRCB list */
			StartRCB = rcb;

			/* Initialise the variable to update the size of the jumbo packet 
				received */
			BufSizeReqd = 0;

			/* For all the HsmRCBs into which this packet has spanned, do the 
				following */
			while( rcb->More) 
			{
				/* Calculate the size of the entire packet by adding the PktSize
					in the individual HsmRCBs, constituting the packet */
				BufSizeReqd += rcb->PktSize;

				/* Get the next HsmRCB in the RCB list */
				rcb = rcb->pNext;
			}

			CurrRCB = StartRCB;

			/* Update with the size of the last fragment of the packet */
			BufSizeReqd += rcb->PktSize;
			
			rcb = rcb->pNext;

			/* Allocate a new sk_buff to hold the complete jumbo packet, thereby
				one having a data buffer of enough size */
			NewSkb = alloc_skb(BufSizeReqd + HEAD_SPACE, GFP_ATOMIC);

			if( NewSkb == NULL)
			{

#ifdef FAILURE_MESSAGES
				printk("The allocation of the sk_buff of size %d for the jumbo packet FAILED\n", BufSizeReqd);
#endif
				/* Update statisitics */
				pNsc->MacStats.rxErrorCount++;
				pNsc->MacStats.rxDroppedCount++;

				continue;	
			}

#ifdef PRIORITY_QUEUES			
			/* Set the priority field of the new sk_buff */
			NewSkb->priority = Priority;
#else
			NewSkb->priority = 0;
#endif

			/* Reserve some space at the beginning of the buffer */
			skb_reserve(NewSkb, HEAD_SPACE);

			#ifdef LINK_AGGR
				if(pNsc->nFlags & GEC_FLAG)
					dev = pNsm->dev_aggr;
				else
					dev = ( (struct sk_buff *) rcb->pOsCtrlBlk)->dev;
			#else
				dev = ( (struct sk_buff *) rcb->pOsCtrlBlk)->dev;
			#endif

			/* Traverse through the HsmRCB list to copy the entire jumbo 
			/* Traverse through the HsmRCB list to copy the entire jumbo 
				packet into the newly allocated sk_buff */
			while(CurrRCB != rcb)
 			{
				memcpy( NewSkb->tail, 
					((struct sk_buff *)CurrRCB->pOsCtrlBlk)->data, 
						CurrRCB->PktSize);		
						
				skb_put(NewSkb, CurrRCB->PktSize); 

				CurrRCB->Status = RCB_FREE;
				
				CurrRCB = CurrRCB->pNext;
			}

			/* If checksum offloading is supported ie if it is already done in 
				hardware then indicate it in the skbuff */

#ifdef CHECKSUM
			NewSkb->ip_summed = CHECKSUM_UNNECESSARY; 
#else
			NewSkb->ip_summed = CHECKSUM_NONE; 
#endif
			NewSkb->dev = dev;

			NewSkb->protocol = eth_type_trans(NewSkb,dev);

			/* Send the new sk_buff up */
			netif_rx(NewSkb);
		}
		else
		{
			/* Through the HsmRCB, get the pointer to the OsCtrlBlk 
				( sk_buff ) */

			skb = (struct sk_buff *)rcb->pOsCtrlBlk;

			/* Clone this sk_buff */
			skb_new = skb_clone(skb, GFP_ATOMIC); 

			if( skb_new == NULL)
			{
				printk(KERN_ERR "NsmRxPackets : The cloning failed\n");
				TempRcb = rcb;

				/* Find out the number of packets remaining, which are now 
				going to be dropped*/
				while((TempRcb != RcbEnd) && TempRcb)
				{
					while(TempRcb->More) 
						TempRcb = TempRcb->pNext;
					RemainingRCBs++;
					TempRcb = TempRcb->pNext;
				}	

				/* Update statistics */
				pNsc->MacStats.rxErrorCount += RemainingRCBs; 
				pNsc->MacStats.rxDroppedCount += RemainingRCBs; 

				status = ERROR;

				break;
			}
			
			rcb->Status = DUPED;

			skb_put(skb_new,rcb->PktSize);

			#ifdef LINK_AGGR
				if(pNsc->nFlags & GEC_FLAG)
					dev = skb_new->dev = pNsm->dev_aggr;
				else
					dev = skb_new->dev = skb->dev;
			#else
				dev = skb_new->dev = skb->dev;
			#endif
			
			skb_new->protocol = eth_type_trans(skb_new,dev);

#ifdef CHECKSUM
			skb_new->ip_summed = CHECKSUM_UNNECESSARY;			
#else
			skb_new->ip_summed = CHECKSUM_NONE;			
#endif

			/* If checksum offloading is supported ie if it is already done in 
				hardware then indicate it in the skbuff */

#ifdef PRIORITY_QUEUES			
			/* Set the priority field of the new sk_buff */
			skb_new->priority = Priority;
#else
			skb_new->priority = 0;
#endif

			netif_rx(skb_new);  

			/* Get the next HsmRCB in the RCB list */
			rcb = rcb->pNext;
		}
	}

}

/******************************************************************************
*f*
*   Name:           NsmMallocContiguous 
*
*   Description:    This is called by HSM to allocate a contiguous chunk of 
*                   memory, the virtual & physical addresses of the start of 
*                   the chunk of memory, is set in the Addrstruct structure. 
*                   The byte alignment required is given by the Alignment 
*                   parameter.
*
*   Parameters:     pNsm: Pointer to the NsmContext
*					
*                   pAddrstruct: Pointer to the Addrstruct structure, where the 
*                   virtual and physical addresses need to be put
*
*                   BitAlignment:   The alignment factor, to which the memory 
*                   allocated needs to be aligned
*
*                   Cached: Cached/Non-Cached memory
*
*   Return Value:   SUCCESS or FAILURE 
*
*f*
***************************************************************************/

UCHAR  NsmMallocContiguous(VOID *pNsm,AddrStruct *pAddrStruct, 
	USHORT BitAlignment, UINT Cached)
{

	VOID 	*pMem;

	UINT 	AlignedMem;

	USHORT 	Alignment = BitAlignment/8;
		
	pMem = kmalloc (pAddrStruct->BufSize + Alignment -1, 
		GFP_KERNEL | GFP_DMA | GFP_ATOMIC);
	
	if(pMem == NULL)
	{
#ifdef FAILURE_MESSAGES
		printk("\nAllocation of contiguous memory failed");
#endif
		return FAILURE;
	}
	
	NsmZeroMemory(pMem, pAddrStruct->BufSize + Alignment - 1);	

	AlignedMem = ((UINT) pMem) + (Alignment -1);

	pAddrStruct->pCookie = pMem;

	AlignedMem &= ~(Alignment -1);

	pAddrStruct->VirtAddr = (UCHAR  *)AlignedMem;

#ifdef ASSERTION
	if(AlignedMem & (Alignment-1))
		NsmDbgMsg1("ASSERTION FAILED: In NsmMallocContiguous, the allocated memory is not %d byte aligned\n",Alignment);
#endif

	pAddrStruct->PhysAddr = (UCHAR *)virt_to_bus ((VOID *)AlignedMem);
	return SUCCESS;
	 
}

/******************************************************************************
*f*
*   Name:           NsmFreeContiguous
*
*   Description:    This is called by HSM to free a contiguous chunk of memory 
*
*   Parameters:     pNsm: Pointer to the NsmContext 
*	 				
*                   pAddrstruct: Pointer to the Addrstruct structure, where the 
*                   virtual and physical addresses are put
*					
*                   Cached: Cached/Non-Cached Memory
*   
*	Return Value:   None
*
*f*
******************************************************************************/
			
void NsmFreeContiguous(VOID *pNsm, AddrStruct *pAddrStruct, UINT Cached)
{
	kfree(pAddrStruct->pCookie);
	pAddrStruct->VirtAddr = 0;
	pAddrStruct->PhysAddr = 0;
	pAddrStruct->pCookie = 0;
}

/******************************************************************************
*f*
*   Name:           NsmAllocatePacket
*
*   Description:    This is called by HSM to allocate an sk_buff with a data 
*                   buffer associated with it.
*
*   Parameters:     pNsm:    Pointer to the NsmContext structure
*
*                   pRcb:    Pointer to the HsmRCB, to which the allocated 
*                   packet is to be linked to
*
*                   pAddr: Pointer to the Addrstruct structure, where the 
*                   virtual and physical addresses are put
*
*   Return Value:   SUCCESS or FAILURE
*
*f*
******************************************************************************/

UCHAR  NsmAllocatePacket(VOID *pNsm, struct _HsmRCB *pRcb, AddrStruct *pAddr)
{
	struct sk_buff 	*skb;
	skb = alloc_skb(pAddr->BufSize, 
		GFP_KERNEL | GFP_DMA | GFP_ATOMIC);
	
	if(skb == NULL)
	{
#ifdef FAILURE_MESSAGES
		printk("Allocation of the sk_buff failed\n");
#endif
		return FAILURE;
	}
	skb->dev = ((NsmContext *)pNsm)->dev;
	NsmZeroMemory(skb->data, pAddr->BufSize);	

	pAddr->pCookie = (VOID *)skb;
	pAddr->PhysAddr = (UCHAR *)virt_to_bus(skb->data);
	pRcb->pDataBuf = pAddr->VirtAddr = skb->data;

#ifdef ASSERTION
	if(((UINT)skb->data) & 7)
		NsmDbgMsg("ASSERTION FAILED : In NsmAllocatePacket, the allocated memory is not 8 byte aligned\n");
#endif

	pRcb->pOsCtrlBlk = (VOID *)skb;
	return SUCCESS;
}

/******************************************************************************
*f*
*   Name:           NsmDeAllocatePacket
*
*   Description:    This is called by HSM to deallocate the sk_buff structure 
*                   and consequently the data buffer associated with it, within
*                   an HsmRCB
*
*   Parameters:     pNsm: Pointer to the NsmContext
*
*					Addr: Pointer to the AddrStruct
*
*					pRcb:    Pointer to the HsmRCB, to which the allocated 
*                   packet is to be linked to
*
*   Return Value:   None
*
*f*
******************************************************************************/

void NsmDeAllocatePacket(VOID *pNsm, AddrStruct *Addr, HsmRCB *pRcb)
{
	kfree_skb(pRcb->pOsCtrlBlk);
	pRcb->pOsCtrlBlk = NULL;
	pRcb->pDataBuf = NULL;
}

/* Utility routines */

/******************************************************************************
*f*
*   Name:         CreatePacketstruct
*
*   Description:  This creates a packet struct and encapsulates the data in 
*                 the sk_buff in to the Pktstruct
*
*   Parameters:   skb: Pointer to the sk_buff, from which the data to be sent 
*                 down is taken to be encapsulated in to the Pktstruct data 
*                 structure. 
*    
*                 pPkt:  Pointer to the Pktstruct structure, into which the 
*                 data to be sent down is put
*
*   Return Value: None
*
*f*
******************************************************************************/

void 
CreatePacketStruct(struct sk_buff *skb, PktStruct *pPkt)
{
	/* Set the pointer to the physical memory for this fragment in the packet 
		structure */
	pPkt->PktArray[0].FragArray[0].pFrag = 
		(UCHAR *)virt_to_bus(skb->data);

	/* Update the length field of the fragment */
	pPkt->PktArray[0].FragArray[0].FragLen = skb->len; 

	/* Put the number of fragments within the packet in the NumOfFrags field 
		within the packet struct */
	pPkt->PktArray[0].NumFrags = 1;	

	/* Make the pOsCtrlBlk point to the skb */
	pPkt->PktArray[0].pOSCtrlBlk = skb;	
	
	pPkt->PktArray[0].ChkSum = 0;	

	pPkt->PktCount = 1;

}

/******************************************************************************
*f*
*   Name:         CreatePacketInfo
*
*   Description:  This creates a packet info structure and encapsulates 
*                 the data in the sk_buff in to the PktInfo structure
*
*   Parameters:   skb: Pointer to the sk_buff, from which the data to be sent 
*                 down is taken to be encapsulated in to the PktInfo data 
*                 structure. 
*    
*                 pPkt:  Pointer to the PktInfo structure, into which the 
*                 data to be sent down is put
*
*   Return Value: None
*
*f*
******************************************************************************/

VOID 
CreatePacketInfo(struct sk_buff *skb, PktInfo *pPkt)
{
	/* Set the pointer to the physical memory for this fragment in the packet 
		structure */
	pPkt->FragArray[0].pFrag = 
		(UCHAR *)virt_to_phys(skb->data);

	/* Update the length field of the fragment */
	pPkt->FragArray[0].FragLen = skb->len; 

	/* Put the number of fragments within the packet in the NumOfFrags field 
		within the packet struct */
	pPkt->NumFrags = 1;	

	/* Make the pOsCtrlBlk point to the skb */
	pPkt->pOSCtrlBlk = skb;	
	pPkt->ChkSum = 0;	

}

/******************************************************************************
*f*
*   Name:         IsBrdCastOrMultiCast
*
*   Description:  This is used to check whether a particular address is a 
*                 broadcast or multicast address address
*
*   Parameters:   dev: Pointer to the net_device structure
*
*                 DestMac: Pointer to the destination MAC address
*
*   Return Value: SUCCESS or FAILURE
*
*f*
******************************************************************************/


UCHAR IsBrdCastOrMultiCast(struct net_device *dev, UCHAR *DestMac)
{
	struct dev_mc_list *mc_list;

	/* Check for broadcast address */
	if ((DestMac[0]==0xff) && (DestMac[1]==0xff) 
		&& (DestMac[2]==0xff) && (DestMac[3]==0xff) 
			&& (DestMac[4]==0xff) && (DestMac[5]==0xff))
		return SUCCESS;

	/* Check for multicast address */
	if(DestMac[0]==0x01)
	{
		mc_list = dev->mc_list;

		while(mc_list)
		{
			if(CMP_ETH_ADDR(mc_list->dmi_addr, (UCHAR *)DestMac, MAC_ADDR_LEN))
				return SUCCESS;
			
			mc_list = mc_list->next;
			
		}
		return FAILURE;
	}

	else
		return FAILURE;		    
}

/******************************************************************************
*f*
*   Name:         ChangeMtu
*
*   Description:  This changes the MTU size in the device structure to the new 
*                 value specified by NewMtu
*
*   Parameters:   dev:     Pointer to the net_device structure
*
*                 NewMtu:  The new MTU size which needs to be set in the device 
*                 structure
*
*   Return Value: EINVAL or OK
*
*f*
******************************************************************************/

STATIC int ChangeMtu(struct net_device *dev, int NewMtu)
{
	/* Check for the accepatable range of MTU sizes */
	if( (NewMtu < 68) || (NewMtu > 65280) )
		return -EINVAL;

	/* Set the mtu field in the device structure to the NewMtu if it is 
		falling within the acceptable range */
	dev->mtu = NewMtu;
	return (0);
}
		
/******************************************************************************
*f*
*   Name:         CMP_ETH_ADDR
*
*   Description:  This is used to compare two ethernet ( MAC ) addresses
*                 
*   Parameters:   SrcMac: Address of source 
*
*                 DstMac: Address of destination 
*                 
*                 Len: Number of bytes to be compared
*   
*	Return Value: 0 or 1 
*
*f*
******************************************************************************/

inline UCHAR CMP_ETH_ADDR(UCHAR *SrcMac,UCHAR *DestMac, UINT Len)
{
	UINT i = 0;
	while(i<Len)
	{
       	if(DestMac[i]!=SrcMac[i])
			break;	
		i++;
	}
	if(i == Len)
		return 0;
    else
        return 1;
}                                                                              

/******************************************************************************
*f*
*   Name:         NsmCreateLock
*
*   Description:  Allocates the data structure for a lock and intialises it
*
*   Parameters:   None
*
*   Return Value: Pointer to the LockId
*
*f*
******************************************************************************/

inline VOID *NsmCreateLock()
{
	VOID *LockId = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
	
	if(LockId == NULL)
		return NULL;
	
	spin_lock_init((spinlock_t *)LockId);	
	return LockId;
}

/******************************************************************************
*f*
*   Name:         NsmAcquireLock
*
*   Description:  Acquires a lock which has been initialized early on
*
*   Parameters:   pAdapter: Pointer to the AdapterContext 
*
*                 LockId: Pointer to the data structure allocated for the lock 
*
*   Return Value: None
*
*f*
******************************************************************************/

inline VOID NsmAcquireLock(AdapterContext *pAdapter,VOID *LockId)
{
	spin_lock((spinlock_t *)LockId);
}

/******************************************************************************
*f*
*   Name:         NsmReleaseLock
*
*   Description:  Release a lock which has been acquired early on
*
*   Parameters:   pAdapter: Pointer to the AdapterContext 
*
*                 LockId: Pointer to the data structure allocated for the lock 
*
*   Return Value: None
*
*f*
******************************************************************************/

inline VOID NsmReleaseLock(AdapterContext *pAdapter, VOID *LockId)
{
	spin_unlock((spinlock_t *)LockId);
}

/******************************************************************************
*f*
*   Name:         NsmMalloc
*
*   Description:  Allocates kernel memory of the specified size
*
*   Parameters:   size: Size of the memory that needs to be allocated
*
*   Return Value: Pointer to the memory that is allocated
*
*f*
******************************************************************************/

inline VOID *NsmMalloc(UINT size)
{
	VOID *ptr = kmalloc(size, GFP_KERNEL);
	
	if(ptr == NULL)
		return NULL;
	
	NsmZeroMemory(ptr,size);
	return ptr;
}

/******************************************************************************
*f*
*   Name:         PrintContents
*
*   Description:  Prints the contents of kernel memory locations in the range
*                 specified 
*
*   Parameters:   start: Start address 
*
*                 len: Length of the range 
*
*   Return Value: None
*
*f*
******************************************************************************/

inline VOID PrintContents(UCHAR *start, UINT len)
{
	UCHAR	*ptr = start;
	UINT 	i;
	printk("The contents of the location :\n");
	for(i=0;i<len;i++)
	{
		printk(": %x :"	,*ptr);			
		ptr++;
	}
}


UCHAR AdapterOpen (struct net_device *dev)
{
	UINT 			stat;
	NsmContext 		*pNsm;
	AdapterContext 	*pNsc;
	UINT 			dp_val;
	UINT			i;
	
#ifdef FT_DBG
	static UINT 	CallCount=0;
	printk("The DrvOpen call No : %d",CallCount++);
#endif

	/* Get the pointer to the allocated private data structure, NsmContext, 
	from the device structure */
	pNsm = (NsmContext *)dev->priv;

	/* Get the pointer to the AdapterContext structure from the NsmContext */
	pNsc = &pNsm->AdpCtxt;

	for(i=0; i< MAX_PRI_QUEUE; i++)
	{
		pNsc->RxQueueSz[i] = MaxRxDesc;
		pNsc->TxQueueSz[i] = MaxTxDesc;
	}
	pNsc->TxDrth = 200;		
	pNsc->RxDrth = 0;
	pNsc->TxFlth = 2;
	pNsc->PauseCounterVal = 40000;
	pNsc->RxFFLO = 2;
	pNsc->RxFFHI = 8;
	pNsc->RxSTLO = 2;
	pNsc->RxSTHI = 8;

	/* Initialize fields which would indicate the capabilities of the hardware,
	 such as the, checksum offload */
	HsmInitContext(pNsc);

#ifdef NSCDEBUG
	printk(KERN_INFO "HsmInitContext called\n");
#endif

	/* Find out the capabilities of the OS and indicate whether the above 
	capabilties are supported by the OS. */

	if(MaxPrio > 8)
		MaxPrio = 8;
	
	pNsc->OsPrio = MaxPrio;
	pNsc->PhysCapabilities &= ~(VLAN_TAG_INSERTION_GEN_ON | 
		BIG_ENDIAN | TX_CHKSUM_OFFLOAD_ON_GEN ); 
			//SET_RX_CHKSUM_OFFLOAD_ON );

	if(SetAutoNeg == 0)
	{
		pNsc->PhysCapabilities &= ~AUTO_NEG_ON;  
	}
	pNsc->UserMediaSpeed = MediaSpeed;
	pNsc->UserDuplexMode = Duplex;
	pNsc->NcBit = NCBit;

#if 0
	pNsc->PhysCapabilities |=
		(RX_UDP_CHKSUM_DISCARD_ON |
			RX_TCP_CHKSUM_DISCARD_ON |
				RX_IP_CHKSUM_DISCARD_ON); 
#endif
	
	/* Allocate the Tx and Rx lists, based on the number of priority levels 
	supported. Call the HsmInitialise routine of the HSM, this will also setup 
	transmit & receive control. This will set up descriptor lists for each 
	level of priorities on both send and receive side. */

	if ( (stat = HsmInitialize(pNsc) ) == FAILURE )
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: HsmInitialize Failed \n", DRV_NAME);
#endif
		return -EAGAIN;
	}

#ifdef NSCDEBUG
	
	printk("The value of the tail %p 's CMDSTS : %x\n" , pNsc->PriQue[0].pRcbListTail->pRxDp, pNsc->PriQue[0].pRcbListTail->pRxDp->CmdSts);

#endif


#ifdef NSCDEBUG
	printk("The number of RX priorities : %d\n",pNsc->RxNumPrio);
#endif

	/* Now set the Mac address in the device structure */
	NsmCopy((char *)pNsc->PermMacAddr, (char *)dev->dev_addr, 
		MAC_ADDR_LEN); 

	/* Install interrupt vector and register the interrupt service routine */
	if(request_irq (dev->irq, DrvIsr, SA_SHIRQ,
    	dev->name, dev) != OK)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: request_irq Failed \n", DRV_NAME);
#endif
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	}

	/* Reset the adapter  */
	if( ( stat =HsmReset(pNsc, 0) ) == FAILURE)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: Resetting the adapter, failed \n", 
			DRV_NAME);
#endif
		free_irq (dev->irq, dev);
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	} 

	/* Call HsmOpen call to open the adapter */
	if( ( stat =HsmOpen(pNsc) ) == FAILURE)
	{
#ifdef FAILURE_MESSAGES
		printk (KERN_ERR "%s: Opening the adapter, failed \n", 
			DRV_NAME);
#endif
		free_irq (dev->irq, dev);
		HsmUnInitialize(pNsc);
		return -EAGAIN;
	}
	
	HsmRxFilter(pNsc, (ACCEPT_PERFECT_MATCH_ON | ACCEPT_ALL_BROADCAST_ON));

#if 0
	/* Mark the start flag in the device structure */
	dev->start = DEV_STARTED;

	dev->tbusy = 0;
	dev->interrupt = 0;

#endif 

	/* Set the transmit queue length in the device structure */
	dev->tx_queue_len = (MaxTxDesc*MaxPrio);

	//NsmRegRead32(pNsm, (pNsc->RegAddr + RXDP), &dp_val);

#ifdef NSCDEBUG			
	NsmDbgMsg1("RXDP's initial Val : %x\n", dp_val);
#endif

    return OK;
}


void AdapterClose (struct net_device *dev)
{
	NsmContext 		*pNsm;
	AdapterContext 	*pNsc;

#ifdef FT_DBG
	static UINT 	CallCount=0;
	printk("The DrvClose call No : %d",CallCount++);
#endif

#if 0
	dev->start = 0;
	dev->tbusy = 1;
#endif

	/* Get the pointer to the NsmContext and thereby to the AdapterContext, 
	from the device structure */
	pNsm = (NsmContext *)dev->priv;
	pNsc   = &(pNsm->AdpCtxt);

#ifdef NSCDEBUG
	printk(KERN_INFO "DrvClose called\n");
#endif

	/* Stop Tx & Rx by calling HsmClose */
	HsmClose(pNsc); 

	/* Uninstall the interrupt vector, and deregister the interrupt service 
	routine */
	free_irq (dev->irq, dev);

	/* Free the Tx and Rx lists by calling HsmUnInitialize */
	HsmUnInitialize(pNsc);  
}

void 
NsmIndicateLinkStatus(AdapterContext *pAdapter) 
{
	return;
}
