linux/drivers/atm/lanai.c

// SPDX-License-Identifier: GPL-2.0-or-later
/* lanai.c -- Copyright 1999-2003 by Mitchell Blank Jr <[email protected]>
 *
 * This driver supports ATM cards based on the Efficient "Lanai"
 * chipset such as the Speedstream 3010 and the ENI-25p.  The
 * Speedstream 3060 is currently not supported since we don't
 * have the code to drive the on-board Alcatel DSL chipset (yet).
 *
 * Thanks to Efficient for supporting this project with hardware,
 * documentation, and by answering my questions.
 *
 * Things not working yet:
 *
 * o  We don't support the Speedstream 3060 yet - this card has
 *    an on-board DSL modem chip by Alcatel and the driver will
 *    need some extra code added to handle it
 *
 * o  Note that due to limitations of the Lanai only one VCC can be
 *    in CBR at once
 *
 * o We don't currently parse the EEPROM at all.  The code is all
 *   there as per the spec, but it doesn't actually work.  I think
 *   there may be some issues with the docs.  Anyway, do NOT
 *   enable it yet - bugs in that code may actually damage your
 *   hardware!  Because of this you should hardware an ESI before
 *   trying to use this in a LANE or MPOA environment.
 *
 * o  AAL0 is stubbed in but the actual rx/tx path isn't written yet:
 *	vcc_tx_aal0() needs to send or queue a SKB
 *	vcc_tx_unqueue_aal0() needs to attempt to send queued SKBs
 *	vcc_rx_aal0() needs to handle AAL0 interrupts
 *    This isn't too much work - I just wanted to get other things
 *    done first.
 *
 * o  lanai_change_qos() isn't written yet
 *
 * o  There aren't any ioctl's yet -- I'd like to eventually support
 *    setting loopback and LED modes that way.
 *
 * o  If the segmentation engine or DMA gets shut down we should restart
 *    card as per section 17.0i.  (see lanai_reset)
 *
 * o setsockopt(SO_CIRANGE) isn't done (although despite what the
 *   API says it isn't exactly commonly implemented)
 */

/* Version history:
 *   v.1.00 -- 26-JUL-2003 -- PCI/DMA updates
 *   v.0.02 -- 11-JAN-2000 -- Endian fixes
 *   v.0.01 -- 30-NOV-1999 -- Initial release
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/atmdev.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <linux/spinlock.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>

/* -------------------- TUNABLE PARAMATERS: */

/*
 * Maximum number of VCIs per card.  Setting it lower could theoretically
 * save some memory, but since we allocate our vcc list with get_free_pages,
 * it's not really likely for most architectures
 */
#define NUM_VCI

/*
 * Enable extra debugging
 */
#define DEBUG
/*
 * Debug _all_ register operations with card, except the memory test.
 * Also disables the timed poll to prevent extra chattiness.  This
 * isn't for normal use
 */
#undef DEBUG_RW

/*
 * The programming guide specifies a full test of the on-board SRAM
 * at initialization time.  Undefine to remove this
 */
#define FULL_MEMORY_TEST

/*
 * This is the number of (4 byte) service entries that we will
 * try to allocate at startup.  Note that we will end up with
 * one PAGE_SIZE's worth regardless of what this is set to
 */
#define SERVICE_ENTRIES
/* TODO: make above a module load-time option */

/*
 * We normally read the onboard EEPROM in order to discover our MAC
 * address.  Undefine to _not_ do this
 */
/* #define READ_EEPROM */ /* ***DONT ENABLE YET*** */
/* TODO: make above a module load-time option (also) */

/*
 * Depth of TX fifo (in 128 byte units; range 2-31)
 * Smaller numbers are better for network latency
 * Larger numbers are better for PCI latency
 * I'm really sure where the best tradeoff is, but the BSD driver uses
 * 7 and it seems to work ok.
 */
#define TX_FIFO_DEPTH
/* TODO: make above a module load-time option */

/*
 * How often (in jiffies) we will try to unstick stuck connections -
 * shouldn't need to happen much
 */
#define LANAI_POLL_PERIOD
/* TODO: make above a module load-time option */

/*
 * When allocating an AAL5 receiving buffer, try to make it at least
 * large enough to hold this many max_sdu sized PDUs
 */
#define AAL5_RX_MULTIPLIER
/* TODO: make above a module load-time option */

/*
 * Same for transmitting buffer
 */
#define AAL5_TX_MULTIPLIER
/* TODO: make above a module load-time option */

/*
 * When allocating an AAL0 transmiting buffer, how many cells should fit.
 * Remember we'll end up with a PAGE_SIZE of them anyway, so this isn't
 * really critical
 */
#define AAL0_TX_MULTIPLIER
/* TODO: make above a module load-time option */

/*
 * How large should we make the AAL0 receiving buffer.  Remember that this
 * is shared between all AAL0 VC's
 */
#define AAL0_RX_BUFFER_SIZE
/* TODO: make above a module load-time option */

/*
 * Should we use Lanai's "powerdown" feature when no vcc's are bound?
 */
/* #define USE_POWERDOWN */
/* TODO: make above a module load-time option (also) */

/* -------------------- DEBUGGING AIDS: */

#define DEV_LABEL

#ifdef DEBUG

#define DPRINTK(format, args...)
#define APRINTK(truth, format, args...)

#else /* !DEBUG */

#define DPRINTK
#define APRINTK

#endif /* DEBUG */

#ifdef DEBUG_RW
#define RWDEBUG
#else /* !DEBUG_RW */
#define RWDEBUG(format, args...)
#endif

/* -------------------- DATA DEFINITIONS: */

#define LANAI_MAPPING_SIZE
#define LANAI_EEPROM_SIZE

vci_t;
bus_addr_t;

/* DMA buffer in host memory for TX, RX, or service list. */
struct lanai_buffer {};

struct lanai_vcc_stats {};

struct lanai_dev;			/* Forward declaration */

/*
 * This is the card-specific per-vcc data.  Note that unlike some other
 * drivers there is NOT a 1-to-1 correspondance between these and
 * atm_vcc's - each one of these represents an actual 2-way vcc, but
 * an atm_vcc can be 1-way and share with a 1-way vcc in the other
 * direction.  To make it weirder, there can even be 0-way vccs
 * bound to us, waiting to do a change_qos
 */
struct lanai_vcc {};

enum lanai_type {};

struct lanai_dev_stats {};

struct lanai_dev {};

/*
 * Each device has two bitmaps for each VCC (baclog_vccs and transmit_ready)
 * This function iterates one of these, calling a given function for each
 * vci with their bit set
 */
static void vci_bitfield_iterate(struct lanai_dev *lanai,
	const unsigned long *lp,
	void (*func)(struct lanai_dev *,vci_t vci))
{}

/* -------------------- BUFFER  UTILITIES: */

/*
 * Lanai needs DMA buffers aligned to 256 bytes of at least 1024 bytes -
 * usually any page allocation will do.  Just to be safe in case
 * PAGE_SIZE is insanely tiny, though...
 */
#define LANAI_PAGE_SIZE

/*
 * Allocate a buffer in host RAM for service list, RX, or TX
 * Returns buf->start==NULL if no memory
 * Note that the size will be rounded up 2^n bytes, and
 * if we can't allocate that we'll settle for something smaller
 * until minbytes
 */
static void lanai_buf_allocate(struct lanai_buffer *buf,
	size_t bytes, size_t minbytes, struct pci_dev *pci)
{}

/* size of buffer in bytes */
static inline size_t lanai_buf_size(const struct lanai_buffer *buf)
{}

static void lanai_buf_deallocate(struct lanai_buffer *buf,
	struct pci_dev *pci)
{}

/* size of buffer as "card order" (0=1k .. 7=128k) */
static int lanai_buf_size_cardorder(const struct lanai_buffer *buf)
{}

/* -------------------- PORT I/O UTILITIES: */

/* Registers (and their bit-fields) */
enum lanai_register {};

static inline bus_addr_t reg_addr(const struct lanai_dev *lanai,
	enum lanai_register reg)
{}

static inline u32 reg_read(const struct lanai_dev *lanai,
	enum lanai_register reg)
{}

static inline void reg_write(const struct lanai_dev *lanai, u32 val,
	enum lanai_register reg)
{}

static inline void conf1_write(const struct lanai_dev *lanai)
{}

static inline void conf2_write(const struct lanai_dev *lanai)
{}

/* Same as conf2_write(), but defers I/O if we're powered down */
static inline void conf2_write_if_powerup(const struct lanai_dev *lanai)
{}

static inline void reset_board(const struct lanai_dev *lanai)
{}

/* -------------------- CARD SRAM UTILITIES: */

/* The SRAM is mapped into normal PCI memory space - the only catch is
 * that it is only 16-bits wide but must be accessed as 32-bit.  The
 * 16 high bits will be zero.  We don't hide this, since they get
 * programmed mostly like discrete registers anyway
 */
#define SRAM_START
#define SRAM_BYTES

static inline bus_addr_t sram_addr(const struct lanai_dev *lanai, int offset)
{}

static inline u32 sram_read(const struct lanai_dev *lanai, int offset)
{}

static inline void sram_write(const struct lanai_dev *lanai,
	u32 val, int offset)
{}

static int sram_test_word(const struct lanai_dev *lanai, int offset,
			  u32 pattern)
{}

static int sram_test_pass(const struct lanai_dev *lanai, u32 pattern)
{}

static int sram_test_and_clear(const struct lanai_dev *lanai)
{}

/* -------------------- CARD-BASED VCC TABLE UTILITIES: */

/* vcc table */
enum lanai_vcc_offset {};

#define CARDVCC_SIZE

static inline bus_addr_t cardvcc_addr(const struct lanai_dev *lanai,
	vci_t vci)
{}

static inline u32 cardvcc_read(const struct lanai_vcc *lvcc,
	enum lanai_vcc_offset offset)
{}

static inline void cardvcc_write(const struct lanai_vcc *lvcc,
	u32 val, enum lanai_vcc_offset offset)
{}

/* -------------------- COMPUTE SIZE OF AN AAL5 PDU: */

/* How many bytes will an AAL5 PDU take to transmit - remember that:
 *   o  we need to add 8 bytes for length, CPI, UU, and CRC
 *   o  we need to round up to 48 bytes for cells
 */
static inline int aal5_size(int size)
{}

/* -------------------- FREE AN ATM SKB: */

static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb)
{}

/* -------------------- TURN VCCS ON AND OFF: */

static void host_vcc_start_rx(const struct lanai_vcc *lvcc)
{}

static void host_vcc_start_tx(const struct lanai_vcc *lvcc)
{}

/* Shutdown receiving on card */
static void lanai_shutdown_rx_vci(const struct lanai_vcc *lvcc)
{}

/* Shutdown transmitting on card.
 * Unfortunately the lanai needs us to wait until all the data
 * drains out of the buffer before we can dealloc it, so this
 * can take awhile -- up to 370ms for a full 128KB buffer
 * assuming everone else is quiet.  In theory the time is
 * boundless if there's a CBR VCC holding things up.
 */
static void lanai_shutdown_tx_vci(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc)
{}

/* -------------------- MANAGING AAL0 RX BUFFER: */

static inline int aal0_buffer_allocate(struct lanai_dev *lanai)
{}

static inline void aal0_buffer_free(struct lanai_dev *lanai)
{}

/* -------------------- EEPROM UTILITIES: */

/* Offsets of data in the EEPROM */
#define EEPROM_COPYRIGHT
#define EEPROM_COPYRIGHT_LEN
#define EEPROM_CHECKSUM
#define EEPROM_CHECKSUM_REV
#define EEPROM_MAC
#define EEPROM_MAC_REV
#define EEPROM_SERIAL
#define EEPROM_SERIAL_REV
#define EEPROM_MAGIC
#define EEPROM_MAGIC_REV

#define EEPROM_MAGIC_VALUE

#ifndef READ_EEPROM

/* Stub functions to use if EEPROM reading is disabled */
static int eeprom_read(struct lanai_dev *lanai)
{}

static int eeprom_validate(struct lanai_dev *lanai)
{}

#else /* READ_EEPROM */

static int eeprom_read(struct lanai_dev *lanai)
{
	int i, address;
	u8 data;
	u32 tmp;
#define set_config1
#define clock_h
#define clock_l
#define data_h
#define data_l
#define pre_read
#define read_pin
#define send_stop
	/* start with both clock and data high */
	data_h(); clock_h(); udelay(5);
	for (address = 0; address < LANAI_EEPROM_SIZE; address++) {
		data = (address << 1) | 1;	/* Command=read + address */
		/* send start bit */
		data_l(); udelay(5);
		clock_l(); udelay(5);
		for (i = 128; i != 0; i >>= 1) {   /* write command out */
			tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) |
			    ((data & i) ? CONFIG1_PROMDATA : 0);
			if (lanai->conf1 != tmp) {
				set_config1(tmp);
				udelay(5);	/* Let new data settle */
			}
			clock_h(); udelay(5); clock_l(); udelay(5);
		}
		/* look for ack */
		data_h(); clock_h(); udelay(5);
		if (read_pin() != 0)
			goto error;	/* No ack seen */
		clock_l(); udelay(5);
		/* read back result */
		for (data = 0, i = 7; i >= 0; i--) {
			data_h(); clock_h(); udelay(5);
			data = (data << 1) | !!read_pin();
			clock_l(); udelay(5);
		}
		/* look again for ack */
		data_h(); clock_h(); udelay(5);
		if (read_pin() == 0)
			goto error;	/* Spurious ack */
		clock_l(); udelay(5);
		send_stop();
		lanai->eeprom[address] = data;
		DPRINTK("EEPROM 0x%04X %02X\n",
		    (unsigned int) address, (unsigned int) data);
	}
	return 0;
    error:
	clock_l(); udelay(5);		/* finish read */
	send_stop();
	printk(KERN_ERR DEV_LABEL "(itf %d): error reading EEPROM byte %d\n",
	    lanai->number, address);
	return -EIO;
#undef set_config1
#undef clock_h
#undef clock_l
#undef data_h
#undef data_l
#undef pre_read
#undef read_pin
#undef send_stop
}

/* read a big-endian 4-byte value out of eeprom */
static inline u32 eeprom_be4(const struct lanai_dev *lanai, int address)
{
	return be32_to_cpup((const u32 *) &lanai->eeprom[address]);
}

/* Checksum/validate EEPROM contents */
static int eeprom_validate(struct lanai_dev *lanai)
{
	int i, s;
	u32 v;
	const u8 *e = lanai->eeprom;
#ifdef DEBUG
	/* First, see if we can get an ASCIIZ string out of the copyright */
	for (i = EEPROM_COPYRIGHT;
	    i < (EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN); i++)
		if (e[i] < 0x20 || e[i] > 0x7E)
			break;
	if ( i != EEPROM_COPYRIGHT &&
	    i != EEPROM_COPYRIGHT + EEPROM_COPYRIGHT_LEN && e[i] == '\0')
		DPRINTK("eeprom: copyright = \"%s\"\n",
		    (char *) &e[EEPROM_COPYRIGHT]);
	else
		DPRINTK("eeprom: copyright not found\n");
#endif
	/* Validate checksum */
	for (i = s = 0; i < EEPROM_CHECKSUM; i++)
		s += e[i];
	s &= 0xFF;
	if (s != e[EEPROM_CHECKSUM]) {
		printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM checksum bad "
		    "(wanted 0x%02X, got 0x%02X)\n", lanai->number,
		    (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM]);
		return -EIO;
	}
	s ^= 0xFF;
	if (s != e[EEPROM_CHECKSUM_REV]) {
		printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM inverse checksum "
		    "bad (wanted 0x%02X, got 0x%02X)\n", lanai->number,
		    (unsigned int) s, (unsigned int) e[EEPROM_CHECKSUM_REV]);
		return -EIO;
	}
	/* Verify MAC address */
	for (i = 0; i < 6; i++)
		if ((e[EEPROM_MAC + i] ^ e[EEPROM_MAC_REV + i]) != 0xFF) {
			printk(KERN_ERR DEV_LABEL
			    "(itf %d) : EEPROM MAC addresses don't match "
			    "(0x%02X, inverse 0x%02X)\n", lanai->number,
			    (unsigned int) e[EEPROM_MAC + i],
			    (unsigned int) e[EEPROM_MAC_REV + i]);
			return -EIO;
		}
	DPRINTK("eeprom: MAC address = %pM\n", &e[EEPROM_MAC]);
	/* Verify serial number */
	lanai->serialno = eeprom_be4(lanai, EEPROM_SERIAL);
	v = eeprom_be4(lanai, EEPROM_SERIAL_REV);
	if ((lanai->serialno ^ v) != 0xFFFFFFFF) {
		printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM serial numbers "
		    "don't match (0x%08X, inverse 0x%08X)\n", lanai->number,
		    (unsigned int) lanai->serialno, (unsigned int) v);
		return -EIO;
	}
	DPRINTK("eeprom: Serial number = %d\n", (unsigned int) lanai->serialno);
	/* Verify magic number */
	lanai->magicno = eeprom_be4(lanai, EEPROM_MAGIC);
	v = eeprom_be4(lanai, EEPROM_MAGIC_REV);
	if ((lanai->magicno ^ v) != 0xFFFFFFFF) {
		printk(KERN_ERR DEV_LABEL "(itf %d): EEPROM magic numbers "
		    "don't match (0x%08X, inverse 0x%08X)\n", lanai->number,
		    lanai->magicno, v);
		return -EIO;
	}
	DPRINTK("eeprom: Magic number = 0x%08X\n", lanai->magicno);
	if (lanai->magicno != EEPROM_MAGIC_VALUE)
		printk(KERN_WARNING DEV_LABEL "(itf %d): warning - EEPROM "
		    "magic not what expected (got 0x%08X, not 0x%08X)\n",
		    lanai->number, (unsigned int) lanai->magicno,
		    (unsigned int) EEPROM_MAGIC_VALUE);
	return 0;
}

#endif /* READ_EEPROM */

static inline const u8 *eeprom_mac(const struct lanai_dev *lanai)
{}

/* -------------------- INTERRUPT HANDLING UTILITIES: */

/* Interrupt types */
#define INT_STATS
#define INT_SOOL
#define INT_LOCD
#define INT_LED
#define INT_GPIN
#define INT_PING
#define INT_WAKE
#define INT_CBR0
#define INT_LOCK
#define INT_MISMATCH
#define INT_AAL0_STR
#define INT_AAL0
#define INT_SERVICE
#define INT_TABORTSENT
#define INT_TABORTBM
#define INT_TIMEOUTBM
#define INT_PCIPARITY

/* Sets of the above */
#define INT_ALL
#define INT_STATUS
#define INT_DMASHUT
#define INT_SEGSHUT

static inline u32 intr_pending(const struct lanai_dev *lanai)
{}

static inline void intr_enable(const struct lanai_dev *lanai, u32 i)
{}

static inline void intr_disable(const struct lanai_dev *lanai, u32 i)
{}

/* -------------------- CARD/PCI STATUS: */

static void status_message(int itf, const char *name, int status)
{}

static void lanai_check_status(struct lanai_dev *lanai)
{}

static void pcistatus_got(int itf, const char *name)
{}

static void pcistatus_check(struct lanai_dev *lanai, int clearonly)
{}

/* -------------------- VCC TX BUFFER UTILITIES: */

/* space left in tx buffer in bytes */
static inline int vcc_tx_space(const struct lanai_vcc *lvcc, int endptr)
{}

/* test if VCC is currently backlogged */
static inline int vcc_is_backlogged(const struct lanai_vcc *lvcc)
{}

/* Bit fields in the segmentation buffer descriptor */
#define DESCRIPTOR_MAGIC
#define DESCRIPTOR_AAL5
#define DESCRIPTOR_AAL5_STREAM
#define DESCRIPTOR_CLP

/* Add 32-bit descriptor with its padding */
static inline void vcc_tx_add_aal5_descriptor(struct lanai_vcc *lvcc,
	u32 flags, int len)
{}

/* Add 32-bit AAL5 trailer and leave room for its CRC */
static inline void vcc_tx_add_aal5_trailer(struct lanai_vcc *lvcc,
	int len, int cpi, int uu)
{}

static inline void vcc_tx_memcpy(struct lanai_vcc *lvcc,
	const unsigned char *src, int n)
{}

static inline void vcc_tx_memzero(struct lanai_vcc *lvcc, int n)
{}

/* Update "butt" register to specify new WritePtr */
static inline void lanai_endtx(struct lanai_dev *lanai,
	const struct lanai_vcc *lvcc)
{}

/*
 * Add one AAL5 PDU to lvcc's transmit buffer.  Caller garauntees there's
 * space available.  "pdusize" is the number of bytes the PDU will take
 */
static void lanai_send_one_aal5(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc, struct sk_buff *skb, int pdusize)
{}

/* Try to fill the buffer - don't call unless there is backlog */
static void vcc_tx_unqueue_aal5(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc, int endptr)
{}

/* Given an skb that we want to transmit either send it now or queue */
static void vcc_tx_aal5(struct lanai_dev *lanai, struct lanai_vcc *lvcc,
	struct sk_buff *skb)
{}

static void vcc_tx_unqueue_aal0(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc, int endptr)
{}

static void vcc_tx_aal0(struct lanai_dev *lanai, struct lanai_vcc *lvcc,
	struct sk_buff *skb)
{}

/* -------------------- VCC RX BUFFER UTILITIES: */

/* unlike the _tx_ cousins, this doesn't update ptr */
static inline void vcc_rx_memcpy(unsigned char *dest,
	const struct lanai_vcc *lvcc, int n)
{}

/* Receive AAL5 data on a VCC with a particular endptr */
static void vcc_rx_aal5(struct lanai_vcc *lvcc, int endptr)
{}

static void vcc_rx_aal0(struct lanai_dev *lanai)
{}

/* -------------------- MANAGING HOST-BASED VCC TABLE: */

/* Decide whether to use vmalloc or get_zeroed_page for VCC table */
#if (NUM_VCI * BITS_PER_LONG) <= PAGE_SIZE
#define VCCTABLE_GETFREEPAGE
#else
#include <linux/vmalloc.h>
#endif

static int vcc_table_allocate(struct lanai_dev *lanai)
{}

static inline void vcc_table_deallocate(const struct lanai_dev *lanai)
{}

/* Allocate a fresh lanai_vcc, with the appropriate things cleared */
static inline struct lanai_vcc *new_lanai_vcc(void)
{}

static int lanai_get_sized_buffer(struct lanai_dev *lanai,
	struct lanai_buffer *buf, int max_sdu, int multiplier,
	const char *name)
{}

/* Setup a RX buffer for a currently unbound AAL5 vci */
static inline int lanai_setup_rx_vci_aal5(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc, const struct atm_qos *qos)
{}

/* Setup a TX buffer for a currently unbound AAL5 vci */
static int lanai_setup_tx_vci(struct lanai_dev *lanai, struct lanai_vcc *lvcc,
	const struct atm_qos *qos)
{}

static inline void host_vcc_bind(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc, vci_t vci)
{}

static inline void host_vcc_unbind(struct lanai_dev *lanai,
	struct lanai_vcc *lvcc)
{}

/* -------------------- RESET CARD: */

static void lanai_reset(struct lanai_dev *lanai)
{}

/* -------------------- SERVICE LIST UTILITIES: */

/*
 * Allocate service buffer and tell card about it
 */
static int service_buffer_allocate(struct lanai_dev *lanai)
{}

static inline void service_buffer_deallocate(struct lanai_dev *lanai)
{}

/* Bitfields in service list */
#define SERVICE_TX
#define SERVICE_TRASH
#define SERVICE_CRCERR
#define SERVICE_CI
#define SERVICE_CLP
#define SERVICE_STREAM
#define SERVICE_GET_VCI(x)
#define SERVICE_GET_END(x)

/* Handle one thing from the service list - returns true if it marked a
 * VCC ready for xmit
 */
static int handle_service(struct lanai_dev *lanai, u32 s)
{}

/* Try transmitting on all VCIs that we marked ready to serve */
static void iter_transmit(struct lanai_dev *lanai, vci_t vci)
{}

/* Run service queue -- called from interrupt context or with
 * interrupts otherwise disabled and with the lanai->servicelock
 * lock held
 */
static void run_service(struct lanai_dev *lanai)
{}

/* -------------------- GATHER STATISTICS: */

static void get_statistics(struct lanai_dev *lanai)
{}

/* -------------------- POLLING TIMER: */

#ifndef DEBUG_RW
/* Try to undequeue 1 backlogged vcc */
static void iter_dequeue(struct lanai_dev *lanai, vci_t vci)
{}
#endif /* !DEBUG_RW */

static void lanai_timed_poll(struct timer_list *t)
{}

static inline void lanai_timed_poll_start(struct lanai_dev *lanai)
{}

static inline void lanai_timed_poll_stop(struct lanai_dev *lanai)
{}

/* -------------------- INTERRUPT SERVICE: */

static inline void lanai_int_1(struct lanai_dev *lanai, u32 reason)
{}

static irqreturn_t lanai_int(int irq, void *devid)
{}

/* TODO - it would be nice if we could use the "delayed interrupt" system
 *   to some advantage
 */

/* -------------------- CHECK BOARD ID/REV: */

/*
 * The board id and revision are stored both in the reset register and
 * in the PCI configuration space - the documentation says to check
 * each of them.  If revp!=NULL we store the revision there
 */
static int check_board_id_and_rev(const char *name, u32 val, int *revp)
{}

/* -------------------- PCI INITIALIZATION/SHUTDOWN: */

static int lanai_pci_start(struct lanai_dev *lanai)
{}

/* -------------------- VPI/VCI ALLOCATION: */

/*
 * We _can_ use VCI==0 for normal traffic, but only for UBR (or we'll
 * get a CBRZERO interrupt), and we can use it only if no one is receiving
 * AAL0 traffic (since they will use the same queue) - according to the
 * docs we shouldn't even use it for AAL0 traffic
 */
static inline int vci0_is_ok(struct lanai_dev *lanai,
	const struct atm_qos *qos)
{}

/* return true if vci is currently unused, or if requested qos is
 * compatible
 */
static int vci_is_ok(struct lanai_dev *lanai, vci_t vci,
	const struct atm_vcc *atmvcc)
{}

static int lanai_normalize_ci(struct lanai_dev *lanai,
	const struct atm_vcc *atmvcc, short *vpip, vci_t *vcip)
{}

/* -------------------- MANAGE CBR: */

/*
 * CBR ICG is stored as a fixed-point number with 4 fractional bits.
 * Note that storing a number greater than 2046.0 will result in
 * incorrect shaping
 */
#define CBRICG_FRAC_BITS
#define CBRICG_MAX

/*
 * ICG is related to PCR with the formula PCR = MAXPCR / (ICG + 1)
 * where MAXPCR is (according to the docs) 25600000/(54*8),
 * which is equal to (3125<<9)/27.
 *
 * Solving for ICG, we get:
 *    ICG = MAXPCR/PCR - 1
 *    ICG = (3125<<9)/(27*PCR) - 1
 *    ICG = ((3125<<9) - (27*PCR)) / (27*PCR)
 *
 * The end result is supposed to be a fixed-point number with FRAC_BITS
 * bits of a fractional part, so we keep everything in the numerator
 * shifted by that much as we compute
 *
 */
static int pcr_to_cbricg(const struct atm_qos *qos)
{}

static inline void lanai_cbr_setup(struct lanai_dev *lanai)
{}

static inline void lanai_cbr_shutdown(struct lanai_dev *lanai)
{}

/* -------------------- OPERATIONS: */

/* setup a newly detected device */
static int lanai_dev_open(struct atm_dev *atmdev)
{}

/* called when device is being shutdown, and all vcc's are gone - higher
 * levels will deallocate the atm device for us
 */
static void lanai_dev_close(struct atm_dev *atmdev)
{}

/* close a vcc */
static void lanai_close(struct atm_vcc *atmvcc)
{}

/* open a vcc on the card to vpi/vci */
static int lanai_open(struct atm_vcc *atmvcc)
{}

static int lanai_send(struct atm_vcc *atmvcc, struct sk_buff *skb)
{}

static int lanai_change_qos(struct atm_vcc *atmvcc,
	/*const*/ struct atm_qos *qos, int flags)
{}

#ifndef CONFIG_PROC_FS
#define lanai_proc_read
#else
static int lanai_proc_read(struct atm_dev *atmdev, loff_t *pos, char *page)
{}
#endif /* CONFIG_PROC_FS */

/* -------------------- HOOKS: */

static const struct atmdev_ops ops =;

/* initialize one probed card */
static int lanai_init_one(struct pci_dev *pci,
			  const struct pci_device_id *ident)
{}

static const struct pci_device_id lanai_pci_tbl[] =;
MODULE_DEVICE_TABLE(pci, lanai_pci_tbl);

static struct pci_driver lanai_driver =;

module_pci_driver();

MODULE_AUTHOR();
MODULE_DESCRIPTION();
MODULE_LICENSE();