linux/drivers/net/fddi/skfp/skfddi.c

// SPDX-License-Identifier: GPL-2.0-or-later
/*
 * File Name:
 *   skfddi.c
 *
 * Copyright Information:
 *   Copyright SysKonnect 1998,1999.
 *
 * The information in this file is provided "AS IS" without warranty.
 *
 * Abstract:
 *   A Linux device driver supporting the SysKonnect FDDI PCI controller
 *   familie.
 *
 * Maintainers:
 *   CG    Christoph Goos ([email protected])
 *
 * Contributors:
 *   DM    David S. Miller
 *
 * Address all question to:
 *   [email protected]
 *
 * The technical manual for the adapters is available from SysKonnect's
 * web pages: www.syskonnect.com
 * Goto "Support" and search Knowledge Base for "manual".
 *
 * Driver Architecture:
 *   The driver architecture is based on the DEC FDDI driver by
 *   Lawrence V. Stefani and several ethernet drivers.
 *   I also used an existing Windows NT miniport driver.
 *   All hardware dependent functions are handled by the SysKonnect
 *   Hardware Module.
 *   The only headerfiles that are directly related to this source
 *   are skfddi.c, h/types.h, h/osdef1st.h, h/targetos.h.
 *   The others belong to the SysKonnect FDDI Hardware Module and
 *   should better not be changed.
 *
 * Modification History:
 *              Date            Name    Description
 *              02-Mar-98       CG	Created.
 *
 *		10-Mar-99	CG	Support for 2.2.x added.
 *		25-Mar-99	CG	Corrected IRQ routing for SMP (APIC)
 *		26-Oct-99	CG	Fixed compilation error on 2.2.13
 *		12-Nov-99	CG	Source code release
 *		22-Nov-99	CG	Included in kernel source.
 *		07-May-00	DM	64 bit fixes, new dma interface
 *		31-Jul-03	DB	Audit copy_*_user in skfp_ioctl
 *					  Daniele Bellucci <[email protected]>
 *		03-Dec-03	SH	Convert to PCI device model
 *
 * Compilation options (-Dxxx):
 *              DRIVERDEBUG     print lots of messages to log file
 *              DUMPPACKETS     print received/transmitted packets to logfile
 * 
 * Tested cpu architectures:
 *	- i386
 *	- sparc64
 */

/* Version information string - should be updated prior to */
/* each new release!!! */
#define VERSION

static const char * const boot_msg =;

/* Include files */

#include <linux/capability.h>
#include <linux/compat.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/fddidevice.h>
#include <linux/skbuff.h>
#include <linux/bitops.h>
#include <linux/gfp.h>

#include <asm/byteorder.h>
#include <asm/io.h>
#include <linux/uaccess.h>

#include	"h/types.h"
#undef ADDR			// undo Linux definition
#include	"h/skfbi.h"
#include	"h/fddi.h"
#include	"h/smc.h"
#include	"h/smtstate.h"


// Define module-wide (static) routines
static int skfp_driver_init(struct net_device *dev);
static int skfp_open(struct net_device *dev);
static int skfp_close(struct net_device *dev);
static irqreturn_t skfp_interrupt(int irq, void *dev_id);
static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev);
static void skfp_ctl_set_multicast_list(struct net_device *dev);
static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev);
static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr);
static int skfp_siocdevprivate(struct net_device *dev, struct ifreq *rq,
			       void __user *data, int cmd);
static netdev_tx_t skfp_send_pkt(struct sk_buff *skb,
				       struct net_device *dev);
static void send_queued_packets(struct s_smc *smc);
static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr);
static void ResetAdapter(struct s_smc *smc);


// Functions needed by the hardware module
void *mac_drv_get_space(struct s_smc *smc, u_int size);
void *mac_drv_get_desc_mem(struct s_smc *smc, u_int size);
unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt);
unsigned long dma_master(struct s_smc *smc, void *virt, int len, int flag);
void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr,
		  int flag);
void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd);
void llc_restart_tx(struct s_smc *smc);
void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
			 int frag_count, int len);
void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
			 int frag_count);
void mac_drv_fill_rxd(struct s_smc *smc);
void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
		       int frag_count);
int mac_drv_rx_init(struct s_smc *smc, int len, int fc, char *look_ahead,
		    int la_len);
void dump_data(unsigned char *Data, int length);

// External functions from the hardware module
extern u_int mac_drv_check_space(void);
extern int mac_drv_init(struct s_smc *smc);
extern void hwm_tx_frag(struct s_smc *smc, char far * virt, u_long phys,
			int len, int frame_status);
extern int hwm_tx_init(struct s_smc *smc, u_char fc, int frag_count,
		       int frame_len, int frame_status);
extern void fddi_isr(struct s_smc *smc);
extern void hwm_rx_frag(struct s_smc *smc, char far * virt, u_long phys,
			int len, int frame_status);
extern void mac_drv_rx_mode(struct s_smc *smc, int mode);
extern void mac_drv_clear_rx_queue(struct s_smc *smc);
extern void enable_tx_irq(struct s_smc *smc, u_short queue);

static const struct pci_device_id skfddi_pci_tbl[] =;
MODULE_DEVICE_TABLE(pci, skfddi_pci_tbl);
MODULE_DESCRIPTION();
MODULE_LICENSE();
MODULE_AUTHOR();

// Define module-wide (static) variables

static int num_boards;	/* total number of adapters configured */

static const struct net_device_ops skfp_netdev_ops =;

/*
 * =================
 * = skfp_init_one =
 * =================
 *   
 * Overview:
 *   Probes for supported FDDI PCI controllers
 *  
 * Returns:
 *   Condition code
 *       
 * Arguments:
 *   pdev - pointer to PCI device information
 *
 * Functional Description:
 *   This is now called by PCI driver registration process
 *   for each board found.
 *   
 * Return Codes:
 *   0           - This device (fddi0, fddi1, etc) configured successfully
 *   -ENODEV - No devices present, or no SysKonnect FDDI PCI device
 *                         present for this device name
 *
 *
 * Side Effects:
 *   Device structures for FDDI adapters (fddi0, fddi1, etc) are
 *   initialized and the board resources are read and stored in
 *   the device structure.
 */
static int skfp_init_one(struct pci_dev *pdev,
				const struct pci_device_id *ent)
{}

/*
 * Called for each adapter board from pci_unregister_driver
 */
static void skfp_remove_one(struct pci_dev *pdev)
{}

/*
 * ====================
 * = skfp_driver_init =
 * ====================
 *   
 * Overview:
 *   Initializes remaining adapter board structure information
 *   and makes sure adapter is in a safe state prior to skfp_open().
 *  
 * Returns:
 *   Condition code
 *       
 * Arguments:
 *   dev - pointer to device information
 *
 * Functional Description:
 *   This function allocates additional resources such as the host memory
 *   blocks needed by the adapter.
 *   The adapter is also reset. The OS must call skfp_open() to open 
 *   the adapter and bring it on-line.
 *
 * Return Codes:
 *    0 - initialization succeeded
 *   -1 - initialization failed
 */
static  int skfp_driver_init(struct net_device *dev)
{}				// skfp_driver_init


/*
 * =============
 * = skfp_open =
 * =============
 *   
 * Overview:
 *   Opens the adapter
 *  
 * Returns:
 *   Condition code
 *       
 * Arguments:
 *   dev - pointer to device information
 *
 * Functional Description:
 *   This function brings the adapter to an operational state.
 *
 * Return Codes:
 *   0           - Adapter was successfully opened
 *   -EAGAIN - Could not register IRQ
 */
static int skfp_open(struct net_device *dev)
{}				// skfp_open


/*
 * ==============
 * = skfp_close =
 * ==============
 *   
 * Overview:
 *   Closes the device/module.
 *  
 * Returns:
 *   Condition code
 *       
 * Arguments:
 *   dev - pointer to device information
 *
 * Functional Description:
 *   This routine closes the adapter and brings it to a safe state.
 *   The interrupt service routine is deregistered with the OS.
 *   The adapter can be opened again with another call to skfp_open().
 *
 * Return Codes:
 *   Always return 0.
 *
 * Assumptions:
 *   No further requests for this adapter are made after this routine is
 *   called.  skfp_open() can be called to reset and reinitialize the
 *   adapter.
 */
static int skfp_close(struct net_device *dev)
{}				// skfp_close


/*
 * ==================
 * = skfp_interrupt =
 * ==================
 *   
 * Overview:
 *   Interrupt processing routine
 *  
 * Returns:
 *   None
 *       
 * Arguments:
 *   irq        - interrupt vector
 *   dev_id     - pointer to device information
 *
 * Functional Description:
 *   This routine calls the interrupt processing routine for this adapter.  It
 *   disables and reenables adapter interrupts, as appropriate.  We can support
 *   shared interrupts since the incoming dev_id pointer provides our device
 *   structure context. All the real work is done in the hardware module.
 *
 * Return Codes:
 *   None
 *
 * Assumptions:
 *   The interrupt acknowledgement at the hardware level (eg. ACKing the PIC
 *   on Intel-based systems) is done by the operating system outside this
 *   routine.
 *
 *       System interrupts are enabled through this call.
 *
 * Side Effects:
 *   Interrupts are disabled, then reenabled at the adapter.
 */

static irqreturn_t skfp_interrupt(int irq, void *dev_id)
{}				// skfp_interrupt


/*
 * ======================
 * = skfp_ctl_get_stats =
 * ======================
 *   
 * Overview:
 *   Get statistics for FDDI adapter
 *  
 * Returns:
 *   Pointer to FDDI statistics structure
 *       
 * Arguments:
 *   dev - pointer to device information
 *
 * Functional Description:
 *   Gets current MIB objects from adapter, then
 *   returns FDDI statistics structure as defined
 *   in if_fddi.h.
 *
 *   Note: Since the FDDI statistics structure is
 *   still new and the device structure doesn't
 *   have an FDDI-specific get statistics handler,
 *   we'll return the FDDI statistics structure as
 *   a pointer to an Ethernet statistics structure.
 *   That way, at least the first part of the statistics
 *   structure can be decoded properly.
 *   We'll have to pay attention to this routine as the
 *   device structure becomes more mature and LAN media
 *   independent.
 *
 */
static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev)
{}				// ctl_get_stat


/*
 * ==============================
 * = skfp_ctl_set_multicast_list =
 * ==============================
 *   
 * Overview:
 *   Enable/Disable LLC frame promiscuous mode reception
 *   on the adapter and/or update multicast address table.
 *  
 * Returns:
 *   None
 *       
 * Arguments:
 *   dev - pointer to device information
 *
 * Functional Description:
 *   This function acquires the driver lock and only calls
 *   skfp_ctl_set_multicast_list_wo_lock then.
 *   This routine follows a fairly simple algorithm for setting the
 *   adapter filters and CAM:
 *
 *      if IFF_PROMISC flag is set
 *              enable promiscuous mode
 *      else
 *              disable promiscuous mode
 *              if number of multicast addresses <= max. multicast number
 *                      add mc addresses to adapter table
 *              else
 *                      enable promiscuous mode
 *              update adapter filters
 *
 * Assumptions:
 *   Multicast addresses are presented in canonical (LSB) format.
 *
 * Side Effects:
 *   On-board adapter filters are updated.
 */
static void skfp_ctl_set_multicast_list(struct net_device *dev)
{}				// skfp_ctl_set_multicast_list



static void skfp_ctl_set_multicast_list_wo_lock(struct net_device *dev)
{}				// skfp_ctl_set_multicast_list_wo_lock


/*
 * ===========================
 * = skfp_ctl_set_mac_address =
 * ===========================
 *   
 * Overview:
 *   set new mac address on adapter and update dev_addr field in device table.
 *  
 * Returns:
 *   None
 *       
 * Arguments:
 *   dev  - pointer to device information
 *   addr - pointer to sockaddr structure containing unicast address to set
 *
 * Assumptions:
 *   The address pointed to by addr->sa_data is a valid unicast
 *   address and is presented in canonical (LSB) format.
 */
static int skfp_ctl_set_mac_address(struct net_device *dev, void *addr)
{}				// skfp_ctl_set_mac_address


/*
 * =======================
 * = skfp_siocdevprivate =
 * =======================
 *   
 * Overview:
 *
 * Perform IOCTL call functions here. Some are privileged operations and the
 * effective uid is checked in those cases.
 *  
 * Returns:
 *   status value
 *   0 - success
 *   other - failure
 *       
 * Arguments:
 *   dev  - pointer to device information
 *   rq - pointer to ioctl request structure
 *   cmd - ?
 *
 */


static int skfp_siocdevprivate(struct net_device *dev, struct ifreq *rq, void __user *data, int cmd)
{}				// skfp_ioctl


/*
 * =====================
 * = skfp_send_pkt     =
 * =====================
 *   
 * Overview:
 *   Queues a packet for transmission and try to transmit it.
 *  
 * Returns:
 *   Condition code
 *       
 * Arguments:
 *   skb - pointer to sk_buff to queue for transmission
 *   dev - pointer to device information
 *
 * Functional Description:
 *   Here we assume that an incoming skb transmit request
 *   is contained in a single physically contiguous buffer
 *   in which the virtual address of the start of packet
 *   (skb->data) can be converted to a physical address
 *   by using dma_map_single().
 *
 *   We have an internal queue for packets we can not send 
 *   immediately. Packets in this queue can be given to the 
 *   adapter if transmit buffers are freed.
 *
 *   We can't free the skb until after it's been DMA'd
 *   out by the adapter, so we'll keep it in the driver and
 *   return it in mac_drv_tx_complete.
 *
 * Return Codes:
 *   0 - driver has queued and/or sent packet
 *       1 - caller should requeue the sk_buff for later transmission
 *
 * Assumptions:
 *   The entire packet is stored in one physically
 *   contiguous buffer which is not cached and whose
 *   32-bit physical address can be determined.
 *
 *   It's vital that this routine is NOT reentered for the
 *   same board and that the OS is not in another section of
 *   code (eg. skfp_interrupt) for the same board on a
 *   different thread.
 *
 * Side Effects:
 *   None
 */
static netdev_tx_t skfp_send_pkt(struct sk_buff *skb,
				       struct net_device *dev)
{}				// skfp_send_pkt


/*
 * =======================
 * = send_queued_packets =
 * =======================
 *   
 * Overview:
 *   Send packets from the driver queue as long as there are some and
 *   transmit resources are available.
 *  
 * Returns:
 *   None
 *       
 * Arguments:
 *   smc - pointer to smc (adapter) structure
 *
 * Functional Description:
 *   Take a packet from queue if there is any. If not, then we are done.
 *   Check if there are resources to send the packet. If not, requeue it
 *   and exit. 
 *   Set packet descriptor flags and give packet to adapter.
 *   Check if any send resources can be freed (we do not use the
 *   transmit complete interrupt).
 */
static void send_queued_packets(struct s_smc *smc)
{}				// send_queued_packets


/************************
 * 
 * CheckSourceAddress
 *
 * Verify if the source address is set. Insert it if necessary.
 *
 ************************/
static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr)
{}				// CheckSourceAddress


/************************
 *
 *	ResetAdapter
 *
 *	Reset the adapter and bring it back to operational mode.
 * Args
 *	smc - A pointer to the SMT context struct.
 * Out
 *	Nothing.
 *
 ************************/
static void ResetAdapter(struct s_smc *smc)
{}				// ResetAdapter


//--------------- functions called by hardware module ----------------

/************************
 *
 *	llc_restart_tx
 *
 *	The hardware driver calls this routine when the transmit complete
 *	interrupt bits (end of frame) for the synchronous or asynchronous
 *	queue is set.
 *
 * NOTE The hardware driver calls this function also if no packets are queued.
 *	The routine must be able to handle this case.
 * Args
 *	smc - A pointer to the SMT context struct.
 * Out
 *	Nothing.
 *
 ************************/
void llc_restart_tx(struct s_smc *smc)
{}				// llc_restart_tx


/************************
 *
 *	mac_drv_get_space
 *
 *	The hardware module calls this function to allocate the memory
 *	for the SMT MBufs if the define MB_OUTSIDE_SMC is specified.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	size - Size of memory in bytes to allocate.
 * Out
 *	!= 0	A pointer to the virtual address of the allocated memory.
 *	== 0	Allocation error.
 *
 ************************/
void *mac_drv_get_space(struct s_smc *smc, unsigned int size)
{}				// mac_drv_get_space


/************************
 *
 *	mac_drv_get_desc_mem
 *
 *	This function is called by the hardware dependent module.
 *	It allocates the memory for the RxD and TxD descriptors.
 *
 *	This memory must be non-cached, non-movable and non-swappable.
 *	This memory should start at a physical page boundary.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	size - Size of memory in bytes to allocate.
 * Out
 *	!= 0	A pointer to the virtual address of the allocated memory.
 *	== 0	Allocation error.
 *
 ************************/
void *mac_drv_get_desc_mem(struct s_smc *smc, unsigned int size)
{}				// mac_drv_get_desc_mem


/************************
 *
 *	mac_drv_virt2phys
 *
 *	Get the physical address of a given virtual address.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	virt - A (virtual) pointer into our 'shared' memory area.
 * Out
 *	Physical address of the given virtual address.
 *
 ************************/
unsigned long mac_drv_virt2phys(struct s_smc *smc, void *virt)
{}				// mac_drv_virt2phys


/************************
 *
 *	dma_master
 *
 *	The HWM calls this function, when the driver leads through a DMA
 *	transfer. If the OS-specific module must prepare the system hardware
 *	for the DMA transfer, it should do it in this function.
 *
 *	The hardware module calls this dma_master if it wants to send an SMT
 *	frame.  This means that the virt address passed in here is part of
 *      the 'shared' memory area.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	virt - The virtual address of the data.
 *
 *	len - The length in bytes of the data.
 *
 *	flag - Indicates the transmit direction and the buffer type:
 *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
 *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
 *		SMT_BUF (0x80)	SMT buffer
 *
 *	>> NOTE: SMT_BUF and DMA_RD are always set for PCI. <<
 * Out
 *	Returns the pyhsical address for the DMA transfer.
 *
 ************************/
u_long dma_master(struct s_smc * smc, void *virt, int len, int flag)
{}				// dma_master


/************************
 *
 *	dma_complete
 *
 *	The hardware module calls this routine when it has completed a DMA
 *	transfer. If the operating system dependent module has set up the DMA
 *	channel via dma_master() (e.g. Windows NT or AIX) it should clean up
 *	the DMA channel.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	descr - A pointer to a TxD or RxD, respectively.
 *
 *	flag - Indicates the DMA transfer direction / SMT buffer:
 *		DMA_RD	(0x01)	system RAM ==> adapter buffer memory
 *		DMA_WR	(0x02)	adapter buffer memory ==> system RAM
 *		SMT_BUF (0x80)	SMT buffer (managed by HWM)
 * Out
 *	Nothing.
 *
 ************************/
void dma_complete(struct s_smc *smc, volatile union s_fp_descr *descr, int flag)
{}				// dma_complete


/************************
 *
 *	mac_drv_tx_complete
 *
 *	Transmit of a packet is complete. Release the tx staging buffer.
 *
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	txd - A pointer to the last TxD which is used by the frame.
 * Out
 *	Returns nothing.
 *
 ************************/
void mac_drv_tx_complete(struct s_smc *smc, volatile struct s_smt_fp_txd *txd)
{}				// mac_drv_tx_complete


/************************
 *
 * dump packets to logfile
 *
 ************************/
#ifdef DUMPPACKETS
void dump_data(unsigned char *Data, int length)
{
	printk(KERN_INFO "---Packet start---\n");
	print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1, Data, min_t(size_t, length, 64), false);
	printk(KERN_INFO "------------------\n");
}				// dump_data
#else
#define dump_data(data,len)
#endif				// DUMPPACKETS

/************************
 *
 *	mac_drv_rx_complete
 *
 *	The hardware module calls this function if an LLC frame is received
 *	in a receive buffer. Also the SMT, NSA, and directed beacon frames
 *	from the network will be passed to the LLC layer by this function
 *	if passing is enabled.
 *
 *	mac_drv_rx_complete forwards the frame to the LLC layer if it should
 *	be received. It also fills the RxD ring with new receive buffers if
 *	some can be queued.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	rxd - A pointer to the first RxD which is used by the receive frame.
 *
 *	frag_count - Count of RxDs used by the received frame.
 *
 *	len - Frame length.
 * Out
 *	Nothing.
 *
 ************************/
void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
			 int frag_count, int len)
{}				// mac_drv_rx_complete


/************************
 *
 *	mac_drv_requeue_rxd
 *
 *	The hardware module calls this function to request the OS-specific
 *	module to queue the receive buffer(s) represented by the pointer
 *	to the RxD and the frag_count into the receive queue again. This
 *	buffer was filled with an invalid frame or an SMT frame.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	rxd - A pointer to the first RxD which is used by the receive frame.
 *
 *	frag_count - Count of RxDs used by the received frame.
 * Out
 *	Nothing.
 *
 ************************/
void mac_drv_requeue_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
			 int frag_count)
{}				// mac_drv_requeue_rxd


/************************
 *
 *	mac_drv_fill_rxd
 *
 *	The hardware module calls this function at initialization time
 *	to fill the RxD ring with receive buffers. It is also called by
 *	mac_drv_rx_complete if rx_free is large enough to queue some new
 *	receive buffers into the RxD ring. mac_drv_fill_rxd queues new
 *	receive buffers as long as enough RxDs and receive buffers are
 *	available.
 * Args
 *	smc - A pointer to the SMT context struct.
 * Out
 *	Nothing.
 *
 ************************/
void mac_drv_fill_rxd(struct s_smc *smc)
{}				// mac_drv_fill_rxd


/************************
 *
 *	mac_drv_clear_rxd
 *
 *	The hardware module calls this function to release unused
 *	receive buffers.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	rxd - A pointer to the first RxD which is used by the receive buffer.
 *
 *	frag_count - Count of RxDs used by the receive buffer.
 * Out
 *	Nothing.
 *
 ************************/
void mac_drv_clear_rxd(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd,
		       int frag_count)
{}				// mac_drv_clear_rxd


/************************
 *
 *	mac_drv_rx_init
 *
 *	The hardware module calls this routine when an SMT or NSA frame of the
 *	local SMT should be delivered to the LLC layer.
 *
 *	It is necessary to have this function, because there is no other way to
 *	copy the contents of SMT MBufs into receive buffers.
 *
 *	mac_drv_rx_init allocates the required target memory for this frame,
 *	and receives the frame fragment by fragment by calling mac_drv_rx_frag.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	len - The length (in bytes) of the received frame (FC, DA, SA, Data).
 *
 *	fc - The Frame Control field of the received frame.
 *
 *	look_ahead - A pointer to the lookahead data buffer (may be NULL).
 *
 *	la_len - The length of the lookahead data stored in the lookahead
 *	buffer (may be zero).
 * Out
 *	Always returns zero (0).
 *
 ************************/
int mac_drv_rx_init(struct s_smc *smc, int len, int fc,
		    char *look_ahead, int la_len)
{}				// mac_drv_rx_init


/************************
 *
 *	smt_timer_poll
 *
 *	This routine is called periodically by the SMT module to clean up the
 *	driver.
 *
 *	Return any queued frames back to the upper protocol layers if the ring
 *	is down.
 * Args
 *	smc - A pointer to the SMT context struct.
 * Out
 *	Nothing.
 *
 ************************/
void smt_timer_poll(struct s_smc *smc)
{}				// smt_timer_poll


/************************
 *
 *	ring_status_indication
 *
 *	This function indicates a change of the ring state.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	status - The current ring status.
 * Out
 *	Nothing.
 *
 ************************/
void ring_status_indication(struct s_smc *smc, u_long status)
{}				// ring_status_indication


/************************
 *
 *	smt_get_time
 *
 *	Gets the current time from the system.
 * Args
 *	None.
 * Out
 *	The current time in TICKS_PER_SECOND.
 *
 *	TICKS_PER_SECOND has the unit 'count of timer ticks per second'. It is
 *	defined in "targetos.h". The definition of TICKS_PER_SECOND must comply
 *	to the time returned by smt_get_time().
 *
 ************************/
unsigned long smt_get_time(void)
{}				// smt_get_time


/************************
 *
 *	smt_stat_counter
 *
 *	Status counter update (ring_op, fifo full).
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	stat -	= 0: A ring operational change occurred.
 *		= 1: The FORMAC FIFO buffer is full / FIFO overflow.
 * Out
 *	Nothing.
 *
 ************************/
void smt_stat_counter(struct s_smc *smc, int stat)
{}				// smt_stat_counter


/************************
 *
 *	cfm_state_change
 *
 *	Sets CFM state in custom statistics.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	c_state - Possible values are:
 *
 *		EC0_OUT, EC1_IN, EC2_TRACE, EC3_LEAVE, EC4_PATH_TEST,
 *		EC5_INSERT, EC6_CHECK, EC7_DEINSERT
 * Out
 *	Nothing.
 *
 ************************/
void cfm_state_change(struct s_smc *smc, int c_state)
{}				// cfm_state_change


/************************
 *
 *	ecm_state_change
 *
 *	Sets ECM state in custom statistics.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	e_state - Possible values are:
 *
 *		SC0_ISOLATED, SC1_WRAP_A (5), SC2_WRAP_B (6), SC4_THRU_A (12),
 *		SC5_THRU_B (7), SC7_WRAP_S (8)
 * Out
 *	Nothing.
 *
 ************************/
void ecm_state_change(struct s_smc *smc, int e_state)
{}				// ecm_state_change


/************************
 *
 *	rmt_state_change
 *
 *	Sets RMT state in custom statistics.
 * Args
 *	smc - A pointer to the SMT context struct.
 *
 *	r_state - Possible values are:
 *
 *		RM0_ISOLATED, RM1_NON_OP, RM2_RING_OP, RM3_DETECT,
 *		RM4_NON_OP_DUP, RM5_RING_OP_DUP, RM6_DIRECTED, RM7_TRACE
 * Out
 *	Nothing.
 *
 ************************/
void rmt_state_change(struct s_smc *smc, int r_state)
{}				// rmt_state_change


/************************
 *
 *	drv_reset_indication
 *
 *	This function is called by the SMT when it has detected a severe
 *	hardware problem. The driver should perform a reset on the adapter
 *	as soon as possible, but not from within this function.
 * Args
 *	smc - A pointer to the SMT context struct.
 * Out
 *	Nothing.
 *
 ************************/
void drv_reset_indication(struct s_smc *smc)
{}				// drv_reset_indication

static struct pci_driver skfddi_pci_driver =;

module_pci_driver();