Re: [RFC][PATCH 8/13] Equinox SST driver: driver init and shutdown

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Straub, Michael napsal(a):
> Adds Equinox multi-port serial (SST) driver.
> 
> Part 8: new source file: drivers/char/eqnx/sst.c.  Driver "main".  Does
> the
> initialization and cleanup for the driver.  Verifies and initializes any
> discovered SST boards.
> 
> Major number and TTY devices names have been lanana assigned.
> 
> Signed-off-by: Mike Straub <[email protected]>
> 
> ---
>  sst.c | 1626
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 files changed, 1626 insertions(+)
> 
> diff -Naurp -X dontdiff linux-2.6.17/drivers/char/eqnx/sst.c
> linux-2.6.17.eqnx/drivers/char/eqnx/sst.c
> --- linux-2.6.17/drivers/char/eqnx/sst.c	1969-12-31
> 19:00:00.000000000 -0500
> +++ linux-2.6.17.eqnx/drivers/char/eqnx/sst.c	2006-06-20
> 09:50:08.000000000 -0400
> @@ -0,0 +1,1626 @@
> +/*
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + *
> + */
> +
> +/*
> + * This driver supports the PCI models of the Equinox / Avocent SST
> boards
> + * using SSP-4 and SSP-64 ASIC technology
> + * Boards supported:
> + * SSP-4P
> + * SSP-8P
> + * SSP-16P
> + * SSP-64P
> + * SSP-128P
> + *
> + * Currently maintained by mike straub <[email protected]>
> + */
> +
> +/*
> + * driver "main" - discovers and initializes all SST boards
> + */
> +
> +char eqnx_version[] = "Equinox / Avocent SuperSerial Technology Device
> Driver";

static?

> +
> +#include <linux/config.h>
> +#include <linux/version.h>
> +
> +#ifdef CONFIG_MODVERSIONS
> +#define MODVERSIONS	1
> +#endif
> +
> +#include <linux/module.h>
> +#include <linux/errno.h>
> +
> +#ifdef  MODULE_LICENSE
> +MODULE_LICENSE("GPL");
> +#endif

why ifdefs?

> +
> +#include <linux/vermagic.h>
> +#include <linux/compiler.h>
> +MODULE_INFO(vermagic, VERMAGIC_STRING);
> +static const struct modversion_info ____versions[]
> +    __attribute__ ((section("__versions"))) = {
> +};

?

> +
> +#include <linux/sched.h>
> +#include <linux/timer.h>
> +#include <linux/wait.h>
> +#include <linux/tty.h>
> +#include <linux/serial.h>
> +#include <linux/major.h>
> +#include <linux/mm.h>
> +#include <linux/ioport.h>
> +#include <linux/slab.h>
> +#include <linux/vmalloc.h>
> +#include <linux/list.h>
> +#include <linux/isapnp.h>
> +#include <asm/io.h>
> +#include <linux/spinlock.h>
> +#include <linux/pci.h>
> +#include <linux/delay.h>
> +#include <linux/kdev_t.h>
> +#include <linux/devfs_fs_kernel.h>
> +#include <linux/device.h>
> +#include <linux/pci_ids.h>
> +
> +#include "eqnx_def.h"
> +#include "eqnx.h"
> +#include "icp.h"
> +
> +/**********************************************************************
> ***
> + *
> + * global variables and structures
> + *
> +
> ************************************************************************
> */
> +
> +/* maximum number of boards, MAXSSP may be redefined */
> +static int maxbrd = MAXSSP;
> +
> +/* number of boards and ICPs found */
> +int eqnx_nssps = 0;
> +int eqnx_nicps = 0;

static?

> +
> +/* adapter structures - one for each board */
> +struct mpdev eqnx_dev[MAXSSP];

...

> +
> +/* channel structures - one for each channel */
> +struct mpchan *eqnx_chan;

...

> +
> +/* tty driver and termios structs */
> +static struct tty_driver *eqnx_driver;
> +
> +/* default termios */
> +static struct termios eqnx_deftermios = {
> +	.c_iflag = 0,
> +	.c_oflag = 0,
> +	.c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL),
> +	.c_lflag = 0,
> +	.c_cc = INIT_C_CC
> +};
> +
> +/* major numbers */
> +static int din_num;
> +
> +/*
> + * per-channel hardware queue information
> + * index 0 for SSP64 boards, index 1 for SSP4 boards
> + */
> +static struct hwq_struct sst_hwq[] = {
> +	{HWQ4SIZE, HWQ4HIWAT, HWQ4LOWAT, HWQ4RXWRAP, HWQ4TXWRAP,
> HWQ4CMDSIZE},
> +	{HWQ1SIZE, HWQ1HIWAT, HWQ1LOWAT, HWQ1RXWRAP, HWQ1TXWRAP,
> HWQ1CMDSIZE},
> +};
> +
> +/* semaphores and timers */
> +struct timer_list eqnx_timer;
> +
> +/* local buffer for copying output characters. Used in eqnx_put_char */
> +char *eqnx_txcookbuf = (char *)NULL;

what is the cast for?

> +
> +/* initial - unknown board defintion */
> +static struct brdtab_t unknown_board = {
> +	NOID, NOID, 0, 1, 0, 0, "Unknown"
> +};
> +
> +/* board definition tables */
> +static struct brdtab_t board_table[] = {
> +	{0x8, 0x8, SSP64, 1, 64, POLL40, "SST-64P"},
> +	{0x10, 0x10, SSP64, 2, 128, POLL40, "SST-128P"},
> +	{0x14, 0x88, SSP4, 2, 8, RJ, "SST-8P/RJ"},
> +	{0x14, 0x90, SSP4, 2, 8, RJ, "SST-8P/RJ"},
> +	{0x68, 0x8, SSP64, 1, 64, POLL40, "SST-64P (HP)"},
> +	{0x70, 0x10, SSP64, 2, 128, POLL40, "SST-128P (HP)"},
> +	{0x88, 0x88, SSP4, 1, 4, 0, "SST-4P"},
> +	{0x8C, 0x88, SSP4, 1, 4, RJ, "SST-4P/RJ"},
> +	{0x90, 0x90, SSP4, 2, 8, 0, "SST-8P"},
> +	{0x94, 0x90, SSP4, 2, 8, RJ, "SST-8P/RJ"},
> +	{0x98, 0x98, SSP4, 2, 8, MM, "SST-MM8P"},
> +	{0x9C, 0x98, SSP4, 1, 4, MM, "SST-MM4P"},
> +	{0xA0, 0x88, SSP4, 1, 8, 0, "SST-4C 8"},
> +	{0xA4, 0x88, SSP4, 1, 4, 0, "SST-4C 4"},
> +	{0xAC, 0x88, SSP4, 1, 4, 0, "SST-4C 0"},
> +	{0xB0, 0x90, SSP4, 2, 8, 0, "SST-8C 8"},
> +	{0xB4, 0x90, SSP4, 2, 4, 0, "SST-8C 4"},
> +	{0xB8, 0x88, SSP4, 1, 4, LP, "SST-4P/LP"},
> +	{0xBC, 0x90, SSP4, 2, 8, 0, "SST-8C 0"},
> +	{0xC0, 0x80, SSP4, 4, 16, DB25_PAN, "SST-16P CP16-DB"},
> +	{0xC4, 0x80, SSP4, 4, 16, RJ_PAN, "SST-16P CP16-RJ"},
> +	{0xC8, 0x80, SSP4, 4, 16, NOPANEL, "SST-16P No panel"},
> +	{0xD0, 0x80, SSP4, 4, 16, DB9_PAN, "SST-16P CP16-DB9"},
> +	{0xD4, 0x80, SSP4, 2, 8, 0, "SST-8P-DB"},
> +	{0xEC, 0x88, SSP4, 1, 4, 0, "SST-4P,PWR"},
> +	{0xF0, 0x90, SSP4, 2, 8, 0, "SST-8P (HP)"},
> +	{0xF4, 0x90, SSP4, 2, 8, 0, "SST-8P,PWR"},
> +	{0xFC, 0x88, SSP4, 1, 4, LP, "SST-4P/ULP"},
> +};
> +
> +#ifdef	MODULE

nope

> +static struct pci_device_id eqnx_pcibrds[] = {
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST64P, PCI_ANY_ID,
> PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST128P, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PRJ, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PRJ2, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST64PHP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST128PHP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4P, PCI_ANY_ID,
> PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PRJ, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8P, PCI_ANY_ID,
> PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PRJ3, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SSTMM8P, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SSTMM4P, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PC8, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PC4, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PC0, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PC8, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PC4, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PLP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PC0, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST16PDB, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST16PRJ, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST16PNP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST16PDB9, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PDB, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PPWR, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PHP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST8PPWR, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{PCI_VENDOR_ID_EQNX, PCI_DEVICE_ID_EQNX_SST4PULP, PCI_ANY_ID,
> +	 PCI_ANY_ID},
> +	{0}
> +};

use PCI_DEVICE()

> +
> +MODULE_DEVICE_TABLE(pci, eqnx_pcibrds);
> +#endif
> +
> +/* total number of entries */
> +static int brdtab_entries = sizeof board_table / sizeof(struct
> brdtab_t);
> +
> +static char *eqnPCIcfg;
> +
> +/**********************************************************************
> ***
> + *
> + * miscellaneous definitions
> + *
> +
> ************************************************************************
> */
> +
> +/* 16K register space for each ICP */
> +#define	HWREGSLEN	0x4000
> +
> +/* serial subtype definitions */
> +#define SERIAL_TYPE_NORMAL	1
> +#define SERIAL_TYPE_CALLOUT	2
> +
> +/**********************************************************************
> ***
> + *
> + * module declarations
> + *
> +
> ************************************************************************
> */
> +
> +#ifdef MODULE

nope

> +MODULE_AUTHOR("Mike Straub - Avocent Corporation");
> +MODULE_DESCRIPTION("Equinox/Avocent SST Driver");
> +MODULE_LICENSE("GPL");
> +#endif
> +
> +/**********************************************************************
> ***
> + *
> + * function declarations
> + *
> +
> ************************************************************************
> */
> +
> +static __init void brd_mem_cfg(struct mpdev *mpd);
> +static int eqnx_pcifindbrds(struct pci_cfg *);
> +
> +static __init int mem_zero(struct mpdev *mpd, unsigned short *ramw,
> +			   int testlen);
> +static __init int mem_test(struct mpdev *mpd, int icp);
> +static __init int mem_test_dram(struct mpdev *mpd, u16 * ramw, int
> testlen);
> +static __init int mem_test_pram(struct mpdev *mpd, u16 * ramw, int
> testlen);
> +static __init int mem_test_tag(struct mpdev *mpd, u8 * ramb, int
> testlen);
> +
> +static __init int register_eqnx(void);
> +
> +extern void eqnx_chnl_sync(struct mpchan *mpc);
> +extern void sstpoll(unsigned long arg);
> +extern int eqnx_open(struct tty_struct *, struct file *);
> +extern void eqnx_close(struct tty_struct *, struct file *);
> +extern int eqnx_write(struct tty_struct *, const unsigned char *, int);
> +extern void eqnx_put_char(struct tty_struct *, unsigned char);
> +extern void eqnx_flush_chars(struct tty_struct *);
> +extern int eqnx_write_room(struct tty_struct *);
> +extern int eqnx_chars_in_buffer(struct tty_struct *);
> +extern int eqnx_chars_in_buffer(struct tty_struct *);
> +extern void eqnx_throttle(struct tty_struct *);
> +extern void eqnx_unthrottle(struct tty_struct *);
> +extern void eqnx_flush_buffer(struct tty_struct *);
> +extern void eqnx_stop(struct tty_struct *);
> +extern void eqnx_start(struct tty_struct *);
> +extern void eqnx_hangup(struct tty_struct *);
> +extern void eqnx_set_termios(struct tty_struct *, struct termios *);
> +extern int eqnx_tiocmget(struct tty_struct *, struct file *);
> +extern int eqnx_tiocmset(struct tty_struct *, struct file *, unsigned
> int,
> +			 unsigned int);
> +extern int eqnx_ioctl(struct tty_struct *, struct file *, unsigned int,
> +		      unsigned long);
> +
> +extern void eqnx_create_sysfs(struct device *);
> +extern void eqnx_remove_sysfs(struct device *);
> +extern void eqnx_create_tty_sysfs(struct class_device *);
> +extern void eqnx_remove_tty_sysfs(struct class_device *);
> +
> +/**********************************************************************
> ***
> + *
> + * tty interface struct
> + *
> +
> ************************************************************************
> */
> +static struct tty_operations eqnx_ops = {
> +	.open = eqnx_open,
> +	.close = eqnx_close,
> +	.write = eqnx_write,
> +	.put_char = eqnx_put_char,
> +	.flush_chars = eqnx_flush_chars,
> +	.write_room = eqnx_write_room,
> +	.chars_in_buffer = eqnx_chars_in_buffer,
> +	.throttle = eqnx_throttle,
> +	.unthrottle = eqnx_unthrottle,
> +	.flush_buffer = eqnx_flush_buffer,
> +	.stop = eqnx_stop,
> +	.start = eqnx_start,
> +	.hangup = eqnx_hangup,
> +	.set_termios = eqnx_set_termios,
> +	.ioctl = eqnx_ioctl,
> +	.tiocmget = eqnx_tiocmget,
> +	.tiocmset = eqnx_tiocmset,
> +};
> +
> +/*
> + * SSTMINOR(maj, min)
> + * return channel index using major and minor numbers
> + *
> + * maj	= major number
> + * min	= minor number
> + */
> +int SSTMINOR(unsigned int maj, unsigned int min)
> +{
> +	if (maj != din_num)
> +		return (-1);
> +
> +	return (min);
> +}
> +
> +/*
> + * find_board_def(id)
> + *
> + *	return pointer to board definition entry for the board
> + *	with the specified full (16-bit) id.
> + *
> + *	returns NULL if not found.
> + */
> +static struct brdtab_t *find_board_def(unsigned short id)
> +{
> +	int i;
> +	struct brdtab_t *brdtab_ptr = NULL;
> +	unsigned char primary_id = NOID, secondary_id = NOID;
> +
> +	primary_id = id & 0xFC;
> +	secondary_id = (id & 0xFF00) >> 8;
> +
> +	/*
> +	 * mask off rev-id bits, special case
> +	 * chrysler board
> +	 */
> +	if ((primary_id != 0x14) && (secondary_id != 0x88) &&
> +	    (primary_id < 0x80))
> +		primary_id &= 0xF8;
> +
> +	/*
> +	 * Now search the board table for a matching entry
> +	 */
> +	for (i = 0; i < brdtab_entries; i++) {
> +		brdtab_ptr = &board_table[i];
> +
> +		if (brdtab_ptr->primary_id == primary_id) {
> +			if ((brdtab_ptr->secondary_id == secondary_id)
> ||
> +			    (brdtab_ptr->secondary_id == NOID) ||
> +			    (secondary_id == NOID)) {
> +				break;
> +			}
> +		}
if (a) {
    if (b) {
    }
}
->
if (a && b) {
}
> +	}
> +
> +	if (i >= brdtab_entries)
> +		brdtab_ptr = NULL;
> +
> +	return brdtab_ptr;
> +}
> +
> +/*
> + * eqnx_init(kmem_start)
> + *
> + * initialization routine
> + */
> +static int __init eqnx_init(void)
> +{
> +	struct mpdev *mpd;
> +	struct mpchan *mpc;
> +	volatile struct icp_in_struct *icpi;
> +	volatile struct icp_out_struct *icpo;
> +	volatile union global_regs_u *icpg = NULL;
> +	volatile struct cout_que_struct *icpq;
> +	struct icp_struct *icp;
> +	volatile struct hwq_struct *hwq;
> +	mpaddr_t mp;
> +	int i, j, k, lmx, ii, jj, addr, duplicate, di, addr1, nextmin;
> +	u8 cchnl;
> +	volatile unsigned char *chnl_ptr;
> +	u16 no_cache, no_icp, nxt_dma, attn_ena, status, cntrl_sig;
> +	struct pci_cfg *cfgp;
> +	unsigned short numboards = 0;
> +	void *base_addr;
> +	unsigned char config, rev_id, c_code;
> +	unsigned long flags;
> +	int ssp_channels = 0, lmx_factor, pcicfg_size;
> +	volatile u8 *bus_ctrl_p;
> +
> +	printk(KERN_INFO "Loading %s Version %s\n", eqnx_version,
> VERSNUM);
> +
> +	/* initialize board structs */
> +	for (ii = 0; ii < maxbrd; ii++) {
> +		eqnx_dev[ii].mpd_alive = 0;
> +		spin_lock_init(&eqnx_dev[ii].mpd_lock);
> +	}
> +
> +	eqnx_nssps = 0;
> +	eqnx_nicps = 0;
> +	nextmin = 0;
> +
> +	pcicfg_size = sizeof(struct pci_cfg) * maxbrd;
> +	eqnPCIcfg = (char *)kmalloc(pcicfg_size, GFP_KERNEL);

not cast

> +	if (eqnPCIcfg == (char *)NULL) {

cast

> +		printk(KERN_ERR "eqnx_init: Failed eqnPCIcfg allocate of
> "
> +		       "size %d\n", pcicfg_size);
> +		return (-ENOMEM);

no (), use goto and return at the end of function

> +	}
> +
> +	memset(eqnPCIcfg, 0, pcicfg_size);

kzalloc

> +	cfgp = (struct pci_cfg *)&eqnPCIcfg[0];
> +	numboards = eqnx_pcifindbrds(cfgp);
> +
> +	if (numboards) {
> +		for (i = 0; i < numboards; i++, cfgp++) {
> +			mpd = &eqnx_dev[eqnx_nssps];
> +
> +			mpd->mpd_pdev = cfgp->pdev;
> +			mpd->mpd_board_def =
> find_board_def(mpd->mpd_pdev->
> +							    device);
> +
> +			if (mpd->mpd_board_def == NULL)
> +				mpd->mpd_board_def = &unknown_board;
> +
> +			mpd->dev = &mpd->mpd_pdev->dev;
> +			eqnx_create_sysfs(mpd->dev);
> +			dev_info(mpd->dev, "eqnx SST brd: id %4.4x
> (%s)\n",
> +				 mpd->mpd_pdev->device,
> +				 mpd->mpd_board_def->name);
> +
> +			config = cfgp->command;
> +			rev_id = cfgp->rev_id;
> +			base_addr =
> +			    (void *)((unsigned long)cfgp->base_addr_reg0
> &
> +				     PCI_BASE_ADDR_MASK);
> +			/*
> +			 * This code checks for duplicate boards.
> +			 * This happens because some brain-dead
> +			 * PCI controllers "see" multiple busses
> +			 * when there aren't multiple busses.
> +			 * So, they see the same bus multiple times,
> +			 * reporting our board on all the busses.
> +			 */
> +			duplicate = 0;
> +			for (di = 0; di < i; di++) {
> +				struct mpdev *mpd = &eqnx_dev[di];
> +
> +				if (base_addr == mpd->mpd_pmem) {
> +
> +					duplicate = 1;
> +					break;
> +				}
> +			}
> +			if (duplicate)
> +				continue;
> +			/* Make sure base address was really configured
> */
> +			if (!base_addr) {
> +				dev_err(mpd->dev, "PCI Base Addr not "
> +					"configured.\n");
> +				continue;
> +			}
> +
> +			/* 
> +			 * Look at the Memory Space Control bit to
> +			 * see if this has been configured.
> +			 */
> +			if (!(config & PCI_MSC))
> +				continue;
> +
> +			/* Make sure we don't find more boards than the
> max. */
> +			if (eqnx_nssps >= maxbrd) {
> +				mpd->mpd_cnfg_state = CNFG_STATE_FAIL;
> +				mpd->mpd_cnfg_fail = CNFG_FAIL_MAXBRD;
> +				continue;
> +			} else
> +				mpd->mpd_cnfg_state = CNFG_STATE_OK;
> +
> +			/* Mark board as being alive */
> +			mpd->mpd_alive = true;
> +
> +			/* revision */
> +			mpd->mpd_rev = rev_id;
> +
> +			mpd->mpd_nicps =
> mpd->mpd_board_def->number_of_asics;
> +			eqnx_nicps += mpd->mpd_nicps;
> +			mpd->mpd_lmx_index = 0;
> +
> +			/* Save the physical address */
> +			mpd->mpd_pmem = base_addr;
> +
> +			/* Get the memory size */
> +			if (mpd->mpd_board_def->number_of_ports >= 64)
> +				mpd->mpd_addrsz = FLAT128_MEM_LEN;
> +			else
> +				mpd->mpd_addrsz = FLAT64K_MEM_LEN;
> +
> +			if (mpd->mpd_board_def->number_of_asics == 4)
> +				/* SSP4 SST-16P */
> +				mpd->mpd_memsz = mpd->mpd_addrsz;
> +			else	/* DRAM memory size is one-half memory
> size */
> +				mpd->mpd_memsz = mpd->mpd_addrsz / 2;
> +
> +			/* PCI memory width is always 32 */
> +			mpd->mpd_mem_width = 32;
> +
> +			mpd->mpd_nchan =
> mpd->mpd_board_def->number_of_ports;
> +			mpd->mpd_minor = nextmin;
> +			nextmin += MAXCHNL_BRD;
> +
> +			eqnx_nssps++;
> +		}
> +	}
> +
> +	if (!eqnx_nssps) {
> +		printk(KERN_INFO "eqnx_init: No SST boards found.\n");
> +		return 0;
> +	}
> +
> +	eqnx_chan = (struct mpchan *)vmalloc(sizeof(struct mpchan) *
> +					     eqnx_nssps * MAXCHNL_BRD);
> +	if (eqnx_chan == (struct mpchan *)NULL) {

cast

> +		printk(KERN_ERR "eqnx_init: Failed eqnx_chan allocate of
> "
> +		       "size %d\n",
> +		       (sizeof(struct mpchan) * eqnx_nssps *
> MAXCHNL_BRD));
> +		return (-ENOMEM);
> +	}
> +	memset(eqnx_chan, 0, (sizeof(struct mpchan) * eqnx_nssps *
> +			      MAXCHNL_BRD));
> +	mpc = eqnx_chan;
> +	for (k = 0; k < eqnx_nssps; k++) {
> +		/* map Adapter memory */
> +		mpd = &eqnx_dev[k];
> +		/* skip board if dead */
> +		if (mpd->mpd_alive == 0)
> +			continue;
> +		mpd->mpd_mpc = (struct mpchan *)&eqnx_chan[k *
> MAXCHNL_BRD];
> +
> +		mpd->mpd_mem = ioremap((unsigned long)mpd->mpd_pmem,
> +				       mpd->mpd_addrsz);
> +		if (!mpd->mpd_mem) {
> +			dev_err(mpd->dev, "eqnx_init: Memory map failed
> "
> +				"for board %d\n", k + 1);
> +			/* Driver init failed */
> +			mpd->mpd_cnfg_state = CNFG_STATE_FAIL;
> +			mpd->mpd_cnfg_fail = CNFG_FAIL_MEMORY;
> +			mpd->mpd_alive = false;
> +			continue;
> +		}
> +		brd_mem_cfg(mpd);
> +		hwq = mpd->mpd_hwq;
> +
> +		if (mpd->mpd_board_def->asic == SSP64)
> +			/* SSP-64 */
> +			mpd->mpd_sspchan = MAXCHNL_ICP;
> +		else
> +			/* SSP-4 */
> +			mpd->mpd_sspchan = 4;
> +
> +		/* loop through each ICP */
> +		for (j = 0; j < (int)mpd->mpd_nicps; j++) {
> +			int mux;
> +
> +			/* reset ICP to known state */
> +			icp = &mpd->icp[j];
> +			icp->icp_minor_start = mpd->mpd_minor +
> +			    (j * mpd->mpd_sspchan);
> +			if (mpd->mpd_board_def->asic == SSP64) {
> +				/* SSP-64 */
> +				icpg = (volatile union global_regs_u *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x2000);
> +				icpg->ssp.gicp_attn = 0;
> +				icpg->ssp.gicp_initiate = 0;
> +				bus_ctrl_p =
> &(icpg->ssp.gicp_bus_cntrl);
> +
> +				/*
> +				 * set up Global Bus Control register
> with
> +				 * the CPU bus width (32 bit bus) and
> the
> +				 * 40 bit DRAM bit
> +				 */
> +				if (!j)
> +					*bus_ctrl_p =
> +					    (STERNG | DRAM_40 |
> CPU_BUS_32);
> +				else
> +					*bus_ctrl_p = (DRAM_40 |
> CPU_BUS_32);
> +			} else {
> +				/* SSP-4 */
> +				volatile union global_regs_u *icp_glo =
> +				    (volatile union global_regs_u *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x400);
> +				volatile struct icp_out_struct *icp_cout
> =
> +				    (volatile struct icp_out_struct *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x200);
> +				volatile struct icp_in_struct *icp_cin =
> +				    (volatile struct icp_in_struct *)
> +				    (icp->icp_regs_start);
> +
> +				icp_glo->ssp4.on_line = 0;
> +				/* lock input and output */
> +				icp_cin->cin_locks = 0xFF;
> +				icp_cout->cout_lck_cntrl = 0x77;
> +				/* Set Bus Control = 16 bits */
> +				bus_ctrl_p = &(icp_glo->ssp4.bus_cntrl);
> +				*bus_ctrl_p = (BUS_CNTRL_16 |
> BUS_CNTRL_WR);
> +
> +				ssp_channels = 4;
> +
> +				for (ii = 0; ii < ssp_channels; ii++) {
> +					((volatile struct icp_in_struct
> *)
> +					 ((char *)icp_cin +
> ii))->cin_locks =
> +					    0xFF;
> +					((volatile struct icp_out_struct
> *)
> +					 ((char *)icp_cout +
> +					  ii))->cout_lck_cntrl = 0x77;
> +					SSTWR16(((volatile struct
> +						  icp_out_struct *)
> +						 ((char *)icp_cout +
> +						  ii))->cout_cntrl_sig,
> 0x0F);
> +				}
> +				icp_glo->ssp4.bus_cntrl = BUS_CNTRL_16;
> +				icp_glo->ssp4.on_line = 0;
> +			}
> +
> +			if ((ii = mem_test(mpd, j))) {
> +				dev_err(mpd->dev, "eqnx_init: Memory
> test "
> +					"failed for SST board %d ICP
> %d\n",
> +					k + 1, j + 1);
> +				mpd->mpd_cnfg_state = CNFG_STATE_FAIL;
> +				mpd->mpd_cnfg_fail = CNFG_FAIL_MEM_FAIL;
> +				mpd->mpd_alive = false;
> +				continue;
> +			}
> +
> +			/* verify that pram is not cached */
> +			if (mpd->mpd_board_def->asic == SSP64) {
> +				/* SSP-64 board */
> +				icpg = (volatile union global_regs_u *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x2000);
> +				/* verify that pram is not cached */
> +				cchnl = icpg->ssp.gicp_chan;
> +				chnl_ptr = &(icpg->ssp.gicp_chan);
> +			} else {
> +				/* SSP-4 board */
> +				struct icp_struct *icp;
> +				volatile union global_regs_u *icp_glo;
> +				icp = &mpd->icp[j];
> +				icp_glo = (volatile union global_regs_u
> *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x400);
> +				cchnl = icp_glo->ssp4.chan_ctr;
> +				chnl_ptr = &(icp_glo->ssp4.chan_ctr);
> +			}
> +			no_cache = false;
> +			for (ii = 0; ii < 0x100000; ii++) {
> +				if (*chnl_ptr != cchnl) {
> +					no_cache = true;
> +					break;
> +				}
> +			}
> +			if (!no_cache) {
> +				dev_err(mpd->dev, "eqnx_init: PRAM
> memory "
> +					"appears to be cached %lx.\n",
> +					(unsigned long)mpd->mpd_mem);
> +				/* Driver init failed */
> +				mpd->mpd_cnfg_state = CNFG_STATE_FAIL;
> +				mpd->mpd_cnfg_fail =
> CNFG_FAIL_PRAM_FAIL;
> +				mpd->mpd_alive = false;
> +				continue;
> +			}
> +
> +			lmx = 0;
> +			mp = (mpaddr_t) mpd->icp[j].icp_regs_start;
> +
> +			if (mpd->mpd_board_def->asic == SSP64) {
> +				if (mpd->mpd_board_def->number_of_asics
>> 0)
> +					/* Number per ICP */
> +					ssp_channels = 64;
> +				else
> +					ssp_channels = 0;
> +			}
> +
> +			if (mpd->mpd_board_def->asic != SSP64) {
> +				/* SSP-4 */
> +				struct icp_struct *icp;
> +				volatile union global_regs_u *icp_glo;
> +				icp = &mpd->icp[j];
> +				icp_glo = (volatile union global_regs_u
> *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x400);
> +				cchnl = icp_glo->ssp4.chan_ctr;
> +				chnl_ptr = &(icp_glo->ssp4.chan_ctr);
> +				for (ii = 0; ii < 0x10000; ii++)
> +					if (*chnl_ptr != cchnl)
> +						break;
> +				icp_glo->ssp4.bus_cntrl = 0xCD;
> +				cchnl = icp_glo->ssp4.chan_ctr;
> +				for (ii = 0; ii < 0x10000; ii++)
> +					if (*chnl_ptr != cchnl)
> +						break;
> +			}
> +
> +			/* mux control sigs on SST-16P */
> +			mux = 0;
> +			if ((mpd->mpd_board_def->asic != SSP64) &&
> +			    (mpd->mpd_board_def->number_of_ports == 16))
> +				mux = 1;
> +
> +			/* loop through each channel */
> +			for (i = 0; i < ssp_channels; i++) {
> +				/*
> +				 * setup mpc virtual addresses for cpu
> access 
> +				 * of icp
> +				 */
> +				jj = mpd->mpd_minor + i +
> +				    (j * mpd->mpd_sspchan);
> +				mpc = &eqnx_chan[jj];
> +				mpc->mpc_brdno = k;
> +				mpc->mpc_chan = i;
> +				mpc->mpc_icpi =
> +				    (volatile struct icp_in_struct *)
> +				    &mp->mp_icpi[i];
> +				if (mpd->mpd_board_def->asic == SSP64)
> +					mpc->mpc_icpo =
> +					    (volatile struct
> icp_out_struct *)
> +					    &mp->mp_icpo[i];
> +				else
> +					mpc->mpc_icpo =
> +					    (volatile struct
> icp_out_struct *)
> +					    ((unsigned char
> *)(mpc->mpc_icpi) +
> +					     0x200);
> +				mpc->mpc_mpd = mpd;
> +				mpc->mpc_icp = (struct icp_struct *)
> +				    &mpd->icp[j];
> +				mpc->mpc_icpno = j;
> +
> +				if ((mpc->normaltermios = (struct
> termios *)
> +				     vmalloc(sizeof(struct termios))) ==
> +				    (struct termios *)NULL) {
> +					dev_err(mpd->dev, "eqnx_int:
> Failed "
> +						"normaltermios alloc of
> "
> +						"size %d\n",
> +						sizeof(struct termios));
> +					return (-ENOMEM);
> +				}
> +				memset(mpc->normaltermios, 0,
> +				       sizeof(struct termios));
> +				*mpc->normaltermios = eqnx_deftermios;
> +				mpc->closing_wait = CLSTIMEO;
> +				mpc->close_delay = EQNX_CLOSEDELAY;
> +
> +				/* initialize each of the wait queues */
> +				mpc->open_wait_wait = 0;
> +				init_waitqueue_head(&mpc->open_wait);
> +				init_waitqueue_head(&mpc->close_wait);
> +				init_waitqueue_head(&mpc->raw_wait);
> +
> +				mpc->mpc_input = 0;
> +				mpc->mpc_output = 0;
> +				mpc->mpc_cin_events = 0;
> +				mpc->mpc_cout_events = 0;
> +				mpc->mpc_cin_ena = 0;
> +				mpc->mpc_cout_ena = 0;
> +
> +				mpc->mpc_parity_err_cnt = 0;
> +				mpc->mpc_framing_err_cnt = 0;
> +				mpc->mpc_break_cnt = 0;
> +
> +				icpi = mpc->mpc_icpi;
> +				icpo = mpc->mpc_icpo;
> +				if (mpd->mpd_board_def->asic == SSP64) {
> +					/* SSP-64 */
> +					icpg = (volatile union
> global_regs_u *)
> +					    icpo;
> +					lmx_factor = 16;
> +				} else {
> +					icpg = (volatile union
> global_regs_u *)
> +					    ((unsigned long)icpi +
> 0x400);
> +					lmx_factor = 4;
> +				}
> +				icpq = &icpo->cout_q0;
> +				if (i == (0 * lmx_factor)) {
> +					lmx = 0;
> +					mpc->mpc_icp->lmx[lmx].lmx_mpc =
> mpc;
> +					mpc->mpc_icp->lmx[lmx].lmx_wait
> = -1;
> +				}
> +
> +				if (i == (1 * lmx_factor)) {
> +					lmx = 1;
> +					mpc->mpc_icp->lmx[lmx].lmx_mpc =
> mpc;
> +					mpc->mpc_icp->lmx[lmx].lmx_wait
> = -1;
> +				}
> +
> +				if (i == (2 * lmx_factor)) {
> +					lmx = 2;
> +					mpc->mpc_icp->lmx[lmx].lmx_mpc =
> mpc;
> +					mpc->mpc_icp->lmx[lmx].lmx_wait
> = -1;
> +				}
> +
> +				if (i == (3 * lmx_factor)) {
> +					lmx = 3;
> +					mpc->mpc_icp->lmx[lmx].lmx_mpc =
> mpc;
> +					mpc->mpc_icp->lmx[lmx].lmx_wait
> = -1;
> +				}
> +				mpc->mpc_lmxno = lmx;
> +
> +				/* icp input - assign queues, etc. */
> +				/* setup input hardware registers */
> +				icpi->cin_locks = 0xff;
> +				icpo->cout_lck_cntrl = 0xff;
> +				spin_lock_irqsave(&mpd->mpd_lock,
> flags);
> +				eqnx_chnl_sync(mpc);
> +				spin_unlock_irqrestore(&mpd->mpd_lock,
> flags);
> +				if (mpd->mpd_board_def->asic == SSP64) {
> +					/* SSP64 */
> +					addr = (i + j * MAXCHNL_ICP) * 2
> *
> +					    hwq->hwq_size;
> +					icpi->cin_dma_hi = (addr >> 16);
> +					nxt_dma = addr & 0xffff;
> +				} else {
> +					/* SSP4 */
> +					addr = i * 0x400;
> +					nxt_dma = addr & 0xffff;
> +				}
> +				SSTWR16(icpi->cin_bank_a.bank_nxt_dma,
> nxt_dma);
> +				SSTWR16(icpi->cin_bank_b.bank_nxt_dma,
> nxt_dma);
> +				SSTWR16(icpi->cin_tail_ptr_a, nxt_dma);
> +				SSTWR16(icpi->cin_tail_ptr_b, nxt_dma);
> +
> +				/* setup mpc values for input registers
> */
> +				mpc->mpc_rxq.q_begin = addr & 0xffff;
> +				mpc->mpc_rxq.q_ptr = addr & 0xffff;
> +				mpc->mpc_rxbase = 0;
> +				mpc->mpc_rxpg = 0;
> +				mpc->mpc_tgpg = 0;
> +				mpc->mpc_rxq.q_end = (addr & 0xffff) +
> +				    (hwq->hwq_size - 1);
> +				mpc->mpc_rxq.q_size = hwq->hwq_size;
> +				if (mpd->mpd_board_def->asic == SSP64) {
> +					/* SSP64 */
> +					mpc->mpc_tags = addr >> 4;
> +					mpc->mpc_rxq.q_addr = (char *)
> +					    (icp->icp_dram_start +
> +					     ((i * 2 * hwq->hwq_size) &
> +					      0xffff0000));
> +				} else {
> +					/* SSP4 */
> +					mpc->mpc_tags = 0;
> +					mpc->mpc_rxq.q_addr = (char *)
> +					    (icp->icp_dram_start +
> +					     ((i * hwq->hwq_size) &
> +					      0xffff0000));
> +				}
> +
> +				/* setup additional icp input registers
> */
> +				SSTWR16(icpi->cin_overload_lvl,
> hwq->hwq_hiwat);
> +				icpi->cin_susp_output_lmx =
> (LMX_NOT_CONN |
> +
> LMX_OFF_LINE);
> +				icpi->cin_susp_output_sig = 0x00;
> +				icpi->cin_q_cntrl = hwq->hwq_rxwrap |
> +				    EN_IXOFF_SVC;
> +				SSTWR16(icpi->cin_min_char_lvl, 1);
> +				icpi->cin_iband_flow_cntrl = 0;
> +				/* unlock input */
> +				/* Start with Bank B locked */
> +				icpi->cin_locks = 0x10 | LOCK_B;
> +
> +				/* icp output - assign data & cmd queues
> */
> +				/* setup queue 0 only for each channel
> */
> +				/* use circular output data queue */
> +				/* - no session registers */
> +
> +				status = SSTRD16(icpo->cout_status);
> +				if (mpd->mpd_board_def->asic == SSP64) {
> +					/* SSP-64 */
> +					addr = ((i + j * MAXCHNL_ICP) *
> 2 + 1) *
> +					    hwq->hwq_size;
> +					icpq->q_data_ptr_u = (addr >>
> 16);
> +					SSTWR16(icpq->q_data_ptr_l,
> +						(addr & 0xffff));
> +					icpq->q_data_q_type =
> +					    EN_CIRC_Q | EN_TX_LOW |
> +					    EN_TX_EMPTY |
> hwq->hwq_txwrap;
> +					/* permanent send data state */
> +					icpq->q_block_count =
> +					    hwq->hwq_lowat / 64;
> +					/* lowat mark in 64-byte blocks
> */
> +					status |= (i << 10);
> +				} else {
> +					/* SSP-4 */
> +					addr = i * 0x400;
> +
> SSTWR16(icpo->cout_q0.q_data_ptr_l,
> +						(addr & 0xFFFF));
> +					icpo->cout_q0.q_data_q_type =
> +					    EN_CIRC_Q | EN_TX_LOW |
> +					    EN_TX_EMPTY |
> hwq->hwq_txwrap;
> +					icpo->cout_q0.q_block_count =
> +					    hwq->hwq_lowat / 64;
> +					status |= ((i * 4) << 8);
> +				}
> +				SSTWR16(icpo->cout_status, status);
> +
> +				if (mpd->mpd_board_def->asic == SSP64) {
> +					/* SSP-64 */
> +					/* circular, size, cause empty &
> */
> +					/* lowat events */
> +					icpq->q_out_state =
> CMDQ_CONT_SND |
> +					    hwq->hwq_cmdsize;
> +					icpo->cout_ses_cntrl_a = SCR_EN;
> +					addr1 = addr;
> +				} else {
> +					/* SSP-4 */
> +					icpo->cout_q0.q_out_state =
> CMDQ_SND;
> +					icpo->cout_ses_cntrl_a = SCR_EN;
> +					addr1 = addr + 0x1000;
> +				}
> +
> +				mpc->mpc_txq.q_begin = addr1 & 0xffff;
> +				mpc->mpc_txq.q_ptr = addr1 & 0xffff;
> +				mpc->mpc_txbase = 0;
> +				mpc->mpc_txpg = 0;
> +				mpc->mpc_txq.q_end =
> +				    (addr1 & 0xffff) + (hwq->hwq_size -
> 1);
> +				mpc->mpc_txq.q_size = hwq->hwq_size;
> +				if (mpd->mpd_board_def->asic == SSP64)
> +					/* SSP-64 */
> +					mpc->mpc_txq.q_addr =
> +					    (char *)(icp->icp_dram_start
> +
> +						     (((i * 2 + 1) *
> +						       hwq->hwq_size) &
> +						      0xffff0000));
> +				else
> +					/* SSP-4 */
> +					mpc->mpc_txq.q_addr =
> +					    (char *)(icp->icp_dram_start
> +
> +						     ((i *
> hwq->hwq_size) &
> +						      0xFFFF0000));
> +
> +				/* cmd queue */
> +				if (mpd->mpd_board_def->asic == SSP64)
> +					addr = (MAXCHNL_ICP + i +
> +						(j * MAXCHNL_ICP)) *
> +					    hwq->hwq_size / 4;
> +				else
> +					addr = i * 0x400;
> +				icpq->q_cmnd_ptr_u = (addr >> 16);
> +				SSTWR16(icpq->q_cmnd_ptr_l, (addr &
> 0xffff));
> +
> +				/* output timer - setup for 10 ms
> prescale */
> +				icpo->cout_tim_scale = 2;
> +				/* place ms count here */
> +				icpo->cout_tim_reg = 0;
> +
> +				/* misc. output registers */
> +				cntrl_sig =
> SSTRD16(icpo->cout_cntrl_sig);
> +				cntrl_sig &= ~0xff;
> +				if (mux)
> +					/* mux control signals */
> +					cntrl_sig |= 0x44;
> +				SSTWR16(icpo->cout_cntrl_sig,
> cntrl_sig);
> +
> +				/* unlock output */
> +				icpo->cout_lck_cntrl = 0x02;
> +				icpo->cout_cpu_req ^= 0x04;
> +				/* force send data state */
> +			}
> +
> +			/* check sanity of ICP */
> +			/* "ring clock failure" should be on since ring
> */
> +			/* clock is off */
> +			if (mpd->mpd_board_def->asic == SSP64) {
> +				/* SSP64 */
> +				no_icp = !(icpg->ssp.gicp_attn &
> RNG_FAIL);
> +				if (!no_icp) {
> +					mpc =
> &eqnx_chan[icp->icp_minor_start];
> +					/* setup mpc structs for each
> chan */
> +					for (ii = 0; ii < ssp_channels;
> ii++,
> +					     mpc++) {
> +						/* don't enable
> lmx_cond_chng */
> +						/* until ring found */
> +						icpi = mpc->mpc_icpi;
> +						icpo = mpc->mpc_icpo;
> +						/* allow software attn
> */
> +						attn_ena =
> EN_REG_UPDT_EV;
> +						if (!(ii % 16))
> +							attn_ena |=
> ENA_LMX_CNG;
> +
> SSTWR16(icpi->cin_attn_ena,
> +							attn_ena);
> +						/* start with Bank B
> locked */
> +						icpi->cin_locks =
> LOCK_B;
> +						/* allow software attn
> */
> +
> SSTWR16(icpo->cout_attn_enbl,
> +							EN_REG_UPDT_EV);
> +						icpo->cout_lck_cntrl ^=
> +						    (LCK_EVT_A |
> LCK_EVT_B);
> +					}
> +
> +					/* setup global interval timer
> for 1 */
> +					/* second pulse */
> +					/* 0.1 seconds before decrement
> */
> +					icpg->ssp.gicp_tmr_size = 192;
> +					/* 10 decrements before pulse */
> +					icpg->ssp.gicp_tmr_count = 10;
> +					icpg->ssp.gicp_bus_cntrl |=
> GTIMER_EN;
> +
> +					/* disable watchdog */
> +					icpg->ssp.gicp_watchdog = 0;
> +
> +					/* enable global pram writes,
> dma */
> +					/* and ring clock */
> +					icpg->ssp.gicp_initiate =
> +					    (RNG_CLK_ON | ICP_PRAM_WR |
> +					     DMA_EN | DISABLE_ATTN_CLR);
> +					mpd->icp[j].icp_rng_state =
> RNG_BAD;
> +					/* set ring bad */
> +					mpd->icp[j].icp_rng_last = 0x4;
> +				} else {
> +					dev_err(mpd->dev, "eqnx_init:
> ICP %d "
> +						"not detected for board
> with "
> +						"I/O address %d\n",
> +						j + 1, k + 1);
> +					mpd->mpd_cnfg_state =
> CNFG_STATE_FAIL;
> +					mpd->mpd_cnfg_fail =
> CNFG_FAIL_ICP_FAIL;
> +					mpd->mpd_alive = false;
> +					continue;
> +				}
> +			} else {
> +				/* SSP-4 */
> +				volatile union global_regs_u *icp_glo;
> +				icp_glo = (volatile union global_regs_u
> *)
> +				    ((unsigned long)icp->icp_regs_start
> +
> +				     0x400);
> +				mpc = &eqnx_chan[icp->icp_minor_start];
> +				for (jj = 0; jj < ssp_channels; jj++,
> mpc++) {
> +					icpi = mpc->mpc_icpi;
> +					icpo = mpc->mpc_icpo;
> +					icpi->cin_q_cntrl |= 0x80;
> +					/* allow software attention */
> +					SSTWR16(icpi->cin_attn_ena,
> +						EN_REG_UPDT_EV);
> +					icpi->cin_locks = LOCK_B;
> +					/* 0.1 seconds before decrement
> */
> +					icpi->cin_tmr_preset_sz = 0x00;
> +					/* 10 decrements before pulse */
> +					icpi->cin_tmr_preset_count =
> 0x00;
> +					/* allow software attention */
> +					SSTWR16(icpo->cout_attn_enbl,
> 0x8000);
> +					icpo->cout_lck_cntrl = LOCK_B;
> +				}
> +				/* setup global interval timer for 
> +				   a 1 second pulse */
> +				/* enable it */
> +				icp_glo->ssp4.bus_cntrl |= (BUS_CNTRL_16
> |
> +							    BUS_CNTRL_WR
> |
> +
> BUS_CNTRL_DMA);
> +
> +				mpc = &eqnx_chan[icp->icp_minor_start];
> +				/* fake ldv record */
> +				icp->lmx[0].lmx_active = DEV_GOOD;
> +				icp->lmx[0].lmx_mpc = mpc;
> +				icp->lmx[0].lmx_id = 0;
> +				icp->lmx[1].lmx_active = DEV_BAD;
> +				icp->lmx[2].lmx_active = DEV_BAD;
> +				icp->lmx[3].lmx_active = DEV_BAD;
> +				icp->lmx[0].lmx_chan = 4;
> +				icp->lmx[0].lmx_speed = 3;
> +
> +				icp->lmx[0].lmx_bridge = false;
> +				icp->lmx[0].lmx_rmt_active = 0;
> +				icp->lmx[0].lmx_good_count = 0;
> +				icp->lmx[0].lmx_wait = -1;
> +				/* fake ring state flags */
> +				icp->icp_rng_state = RNG_GOOD;
> +				/* set "ring bad" last pass */
> +				icp->icp_rng_last = 0x04;
> +				icp_glo->ssp4.on_line = 0x01;
> +			}
> +		}
> +
> +		/* Store Multimodem country code and print to log */
> +		if (mpd->mpd_board_def->flags & MM) {
> +			c_code = readb(mpd->mpd_mem +
> MM_COUNTRY_CODE_REG)
> +				& 0x7F;
> +			mpd->mpd_ccode = c_code;
> +			dev_info(mpd->dev, "eqnx_init: Multimodem board
> "
> +				 "country code ID is %X\n", c_code);
> +		}
> +	}
> +
> +	mpd = eqnx_dev;
> +
> +	printk(KERN_INFO "eqnx_init: Driver Enabled for %d board%s.\n",
> +	       eqnx_nssps, (eqnx_nssps > 1) ? "s" : "");
> +
> +	/*
> +	 * Allocate temporary write buffer.
> +	 */
> +	eqnx_txcookbuf = (char *)kmalloc(XMIT_BUF_SIZE, GFP_KERNEL);
> +	if (eqnx_txcookbuf == (char *)NULL)
> +		printk(KERN_ERR "eqnx_init: failed write buffer allocate
> "
> +		       "(size=%d)\n", XMIT_BUF_SIZE);
> +
> +	/* Initialize the tty_driver structure */
> +	if (register_eqnx() != 0)
> +		return (-ENODEV);
> +
> +	init_timer(&eqnx_timer);
> +	eqnx_timer.expires = jiffies + MPTIMEO;
> +	eqnx_timer.data = 0;
> +	eqnx_timer.function = &sstpoll;
> +	add_timer(&eqnx_timer);
> +
> +#ifdef DEBUG
> +	printk(KERN_DEBUG "eqnx_init: registered EQNX driver\n");
> +#endif
> +	return 0;
> +}
> +
> +/*
> + * eqnx_cleanup()
> + * cleanup on module unload
> + */
> +void eqnx_cleanup(void)

static? _exit?

> +{
> +	struct mpdev *mpd;
> +	volatile union global_regs_u *icpg;
> +	struct icp_struct *icp;
> +	unsigned long flags;
> +	int i, n = 0, k, numchans, base;
> +
> +#ifdef DEBUG
> +	printk(KERN_DEBUG "eqnx_cleanup: trying to unregister
> eqnx_driver\n");
> +#endif
> +
> +	if (timer_pending(&eqnx_timer))
> +		del_timer(&eqnx_timer);
> +
> +	/* for each board */
> +	for (k = 0; k < eqnx_nssps; k++) {
> +		mpd = &eqnx_dev[k];
> +
> +		eqnx_remove_sysfs(mpd->dev);
> +		if (mpd->mpd_alive == 0)
> +			continue;
> +		else
> +			mpd->mpd_alive = 0;
> +
> +		numchans = mpd->mpd_nicps * mpd->mpd_sspchan;
> +		base = k * MAXCHNL_BRD;
> +
> +		for (i = 0; i < numchans; i++) {
> +			eqnx_remove_tty_sysfs(eqnx_chan[base + i].cdev);
> +			tty_unregister_device(eqnx_driver, base + i);
> +		}
> +
> +		spin_lock_irqsave(&mpd->mpd_lock, flags);
> +		if (mpd->mpd_board_def->asic == SSP64) {
> +			/* SSP64 */
> +			/* for each ICP */
> +			for (i = 0; i < (int)mpd->mpd_nicps; i++) {
> +				icp = &mpd->icp[i];
> +				icpg = (volatile union global_regs_u *)
> +				    ((unsigned long)icp->icp_regs_start
> +				     + 0x2000);
> +#ifdef	DEBUG
> +				printk(KERN_DEBUG "eqnx_cleanup: turn
> off ring "
> +				       "clock, PRAM and DMA\n");
> +#endif
> +				icpg->ssp.gicp_initiate &=
> +				    ~(RNG_CLK_ON | ICP_PRAM_WR | DMA_EN
> |
> +				      DISABLE_ATTN_CLR);
> +				icpg->ssp.gicp_attn = 0;
> +				icpg->ssp.gicp_initiate = 0;
> +				icpg->ssp.gicp_watchdog = 0;
> +			}
> +		}
> +		spin_unlock_irqrestore(&mpd->mpd_lock, flags);
> +		iounmap(mpd->mpd_mem);
> +	}
> +
> +	if (eqnx_chan != (struct mpchan *)NULL)
> +		vfree((void *)eqnx_chan);
> +	if (eqnPCIcfg != (char *)NULL)
> +		kfree((void *)eqnPCIcfg);
> +	if (eqnx_txcookbuf != (char *)NULL)
> +		kfree(eqnx_txcookbuf);

5x cast?

> +
> +	n = tty_unregister_driver(eqnx_driver);
> +
> +	if (n) {
> +		printk(KERN_WARNING "eqnx cleanup: Failed to unregister
> "
> +		       "tty driver, return = %d\n", n);
> +		return;
> +	}
> +
> +	put_tty_driver(eqnx_driver);
> +
> +}
> +
> +/*
> + * brd_mem_cfg(mpd)
> + * setup pointers to buffer, tag and cmd memory in icp structs.
> + *
> + * mpd	= board structure
> + */
> +static __init void brd_mem_cfg(struct mpdev *mpd)
> +{
> +	int i;
> +
> +	/* for each ICP */
> +	for (i = 0; i < (int)mpd->mpd_nicps; i++) {
> +		if (mpd->mpd_board_def->asic == SSP64) {
> +			/* SSP64 */
> +			mpd->icp[i].icp_regs_start = (mpaddr_t)
> +			    ((unsigned long)mpd->mpd_mem + (i *
> 0x4000));
> +			/* Special case PCI 64 port boards */
> +			if ((mpd->mpd_pdev->device & 0xF8) == 0x08)
> +				mpd->icp[i].icp_dram_start = (void *)
> +				    ((unsigned long)mpd->mpd_mem +
> +				     mpd->mpd_memsz / 2);
> +			else
> +				mpd->icp[i].icp_dram_start = (void *)
> +				    ((unsigned long)mpd->mpd_mem +
> +				     mpd->mpd_memsz + (i *
> mpd->mpd_memsz / 2));
> +			mpd->icp[i].icp_tags_start = (void *)
> +			    ((unsigned long)mpd->mpd_mem + 0x40000 +
> +			     (i * 0x20000));
> +			mpd->icp[i].icp_cmds_start = (void *)
> +			    ((unsigned long)mpd->mpd_mem + 0x40000 +
> +			     (i * 0x20000));
> +			mpd->mpd_hwq = &sst_hwq[0];
> +		} else {
> +			/* SSP4 */
> +			mpd->icp[i].icp_regs_start = (mpaddr_t)
> +			    ((unsigned long)mpd->mpd_mem +
> +			     (i * sizeof(struct ssp4_addr_space_s)));
> +			mpd->icp[i].icp_dram_start = (void *)
> +			    ((unsigned long)mpd->mpd_mem +
> +			     (i * sizeof(struct ssp4_addr_space_s)) +
> 0x1000);
> +			mpd->icp[i].icp_tags_start = (void *)
> +			    ((unsigned long)mpd->mpd_mem + 0x3000 +
> +			     (i * sizeof(struct ssp4_addr_space_s)));
> +			/* cmds doesn't exist, so point to tags */
> +			mpd->icp[i].icp_cmds_start =
> mpd->icp[i].icp_tags_start;
> +			mpd->mpd_hwq = &sst_hwq[1];
> +		}
> +	}
> +}
> +
> +/*
> + * mem_test_pram(mpd, ramw, testlen)
> + * verify processor ram memory (ICP registers) is valid.
> + *
> + * mpd	= board structure
> + * ramw	= beginning of ram buffer
> + * testlen = length of ram buffer
> + */
> +static __init int mem_test_pram(struct mpdev *mpd, u16 * ramw, int
> testlen)
> +{
> +	int ram_ok = 0, ii, jj;
> +
> +	/* test input and output registers */
> +	for (ii = 0; ii < testlen; ii += 2, ramw++) {
> +		if (mpd->mpd_board_def->asic == SSP64) {
> +			/* SSP64 */
> +			jj = ii & 0x7f;
> +			/* protect sensitive registers */
> +			if ((ii >= HWREGSLEN / 2) &&
> +			    ((jj >= 0x18 && jj < 0x20) ||
> +			     (jj >= 0x38 && jj < 0x40) ||
> +			     (jj >= 0x58 && jj < 0x60) ||
> +			     (jj >= 0x78 && jj < 0x80)))
> +				continue;
> +		}
> +
> +		*ramw = 0x55aa;
> +		ram_ok = true;
> +		if (*ramw != 0x55aa) {
> +			ram_ok = false;
> +			break;
> +		}
> +		*ramw = 0xaa55;
> +		if (*ramw != 0xaa55) {
> +			ram_ok = false;
> +			break;
> +		}
> +	}
> +
> +	if (ram_ok)
> +		return (0);
> +	return (ii);
> +}
> +
> +/*
> + * mem_test_dram(mpd, ramw, testlen)
> + * verify on-board memory is valid.
> + *
> + * mpd	= board structure
> + * ramw	= beginning of ram buffer
> + * testlen = length of ram buffer
> + */
> +static __init int mem_test_dram(struct mpdev *mpd, u16 * ramw, int
> testlen)
> +{
> +	int ram_ok, ii;
> +	u8 ram_pg;
> +
> +	ram_ok = true;
> +	ram_pg = 0;
> +	for (ii = 0; ii < testlen; ii += 2, ramw++) {
> +		*ramw = 0x55aa;
> +		if (*ramw != 0x55aa) {
> +			ram_ok = false;
> +			break;
> +		}
> +		*ramw = 0xaa55;
> +		if (*ramw != 0xaa55) {
> +			ram_ok = false;
> +			break;
> +		}
> +	}
> +
> +	if (ram_ok)
> +		return (0);
> +	return (ii);
> +}
> +
> +/*
> + * mem_test_tag(mpd, ramb, testlen)
> + * verify on-board tag memory is valid.
> + *
> + * mpd	= board structure
> + * ramb	= beginning of ram buffer
> + * testlen = length of ram buffer
> + */
> +static __init int mem_test_tag(struct mpdev *mpd, u8 * ramb, int
> testlen)
> +{
> +	int ram_ok, ii;
> +	u8 ram_pg;
> +	volatile u8 *ramb2;
> +
> +	ramb2 = ramb + 1;
> +	ram_ok = true;
> +	ram_pg = 0;
> +	for (ii = 0; ii < testlen; ii += 2, ramb += 2, ramb2 += 2) {
> +		*ramb = 0x55;
> +		*ramb2 = 0xaa;
> +		if (*ramb != 0x55 || *ramb2 != 0xaa) {
> +			ram_ok = false;
> +			break;
> +		}
> +	}
> +
> +	if (ram_ok)
> +		return (0);
> +	return (ii);
> +}
> +
> +/*
> + * mem_zero(mpd, ramw, testlen)
> + * zero processor ram memory.
> + *
> + * mpd	= board structure
> + * ramw	= beginning of ram buffer
> + * testlen = length of ram buffer
> + */
> +static __init int mem_zero(struct mpdev *mpd, unsigned short *ramw, int
> testlen)
> +{
> +	int ii, jj;
> +
> +	for (ii = 0; ii < testlen; ii += 2, ramw++) {
> +		if (mpd->mpd_board_def->asic == SSP64) {
> +			/* SSP-64 */
> +			jj = ii & 0x7f;
> +			/* protect sensitive registers */
> +			if ((ii >= HWREGSLEN / 2) &&
> +			    ((jj >= 0x18 && jj < 0x20) ||
> +			     (jj >= 0x38 && jj < 0x40) ||
> +			     (jj >= 0x58 && jj < 0x60) ||
> +			     (jj >= 0x78 && jj < 0x80)))
> +				continue;
> +		} else {
> +			/* SSP-4 */
> +			jj = ii & 0x7f;
> +			/* protect sensitive registers */
> +			if ((jj == 0x02) || (jj == 0x64) || (jj ==
> 0x72))
> +				continue;
> +		}
> +		*ramw = 0;
> +	}
> +
> +	return (0);
> +}
> +
> +/*
> + * mem_test(mpd, icp)
> + * full memory test
> + *
> + * mpd	= board structure
> + * icp	= ICP index
> + */
> +static __init int mem_test(struct mpdev *mpd, int icp)
> +{
> +	int ram_index, err = 0, testlen;
> +	u8 *ramb;
> +	u16 *ramw;
> +
> +	/* test pram  - 16-bit test */
> +	ramw = (u16 *) (mpd->icp[icp].icp_regs_start);
> +	if (mpd->mpd_board_def->asic == SSP64) {
> +		/* SSP-64 */
> +		testlen = HWREGSLEN;
> +		ram_index = mem_test_pram(mpd, ramw, testlen);
> +	} else {
> +		/* SSP-4 */
> +		testlen = 0x200;
> +		ram_index = mem_test_pram(mpd, ramw, testlen);
> +		if (!ram_index) {
> +			ramw = (u16 *) ((unsigned char *)
> +					(mpd->icp[icp].icp_regs_start) +
> 0x200);
> +			ram_index = mem_test_pram(mpd, ramw, testlen);
> +		}
> +	}
> +
> +	if (ram_index) {
> +		dev_err(mpd->dev, "eqnx_init: PRAM memory test failure,
> "
> +			"index=%d\n", ram_index);
> +		err = 1;
> +	}
> +
> +	/* test dram - word test */
> +	if (mpd->mpd_board_def->asic == SSP64) {
> +		/* SSP-64 */
> +		ramw = (u16 *) (mpd->icp[0].icp_dram_start);
> +		testlen = mpd->mpd_memsz;
> +		ram_index = mem_test_dram(mpd, ramw, testlen);
> +	} else {
> +		/* SSP-4 */
> +		testlen = 0x1000;
> +
> +		/* test input buff */
> +		ramw = (u16 *) (mpd->icp[icp].icp_dram_start);
> +		ram_index = mem_test_dram(mpd, ramw, testlen);
> +
> +		if (!ram_index) {
> +			/* test output buff */
> +			ramw = (u16 *) ((unsigned long)
> +					mpd->icp[icp].icp_dram_start +
> 0x1000);
> +			ram_index = mem_test_dram(mpd, ramw, testlen);
> +		}
> +	}
> +
> +	if (ram_index) {
> +		dev_err(mpd->dev, "eqnx_init: DRAM memory test failure,
> "
> +			"index=%d\n", ram_index);
> +		err |= 2;
> +	}
> +
> +	/* test tag dram - requires BYTE accesses! */
> +	ramb = (u8 *) (mpd->icp[0].icp_tags_start);
> +	if (mpd->mpd_board_def->asic == SSP64)
> +		/* SSP-64 */
> +		testlen = mpd->mpd_memsz / 4;
> +	else
> +		testlen = 0x400;
> +	ram_index = mem_test_tag(mpd, ramb, testlen);
> +	if (ram_index) {
> +		dev_err(mpd->dev, "eqnx_init: DRAM tags memory test
> failure, "
> +			"index=%d\n", ram_index);
> +		err |= 4;
> +	}
> +
> +	/* zero pram */
> +	ramw = (u16 *) (mpd->icp[icp].icp_regs_start);
> +	if (mpd->mpd_board_def->asic == SSP64)
> +		/* SSP-64 */
> +		testlen = HWREGSLEN;
> +	else
> +		/* SSP-4 */
> +		testlen = 0x400;
> +	mem_zero(mpd, ramw, testlen);
> +
> +	return (err);
> +}
> +
> +/*
> + * register_eqnx_devs(driver)
> + * Register eqnx devices.
> + */
> +static __init void register_eqnx_devs(struct tty_driver *driver)
> +{
> +	int i, numchans, base, brd;
> +	struct class_device *classp;
> +
> +	for (brd = 0; brd < eqnx_nssps; brd++) {
> +		numchans = eqnx_dev[brd].mpd_nicps *
> eqnx_dev[brd].mpd_sspchan;
> +		base = brd * MAXCHNL_BRD;
> +		for (i = 0; i < numchans; i++) {
> +			classp = tty_register_device(driver, base + i,
> NULL);
> +			eqnx_chan[base + i].cdev = classp;
> +			eqnx_create_tty_sysfs(classp);
> +		}
> +	}
> +}
> +
> +/*
> + * register_eqnx
> + * Register eqnx driver with tty driver.
> + */
> +static __init int register_eqnx(void)
> +{
> +	int i;
> +
> +#ifdef DEBUG
> +	printk(KERN_DEBUG "eqnx: registering the driver\n");
> +#endif
> +	eqnx_driver = alloc_tty_driver(eqnx_nssps * MAXCHNL_BRD);
> +	if (!eqnx_driver) {
> +		printk(KERN_ERR "eqnx_init: Failed alloc_tty_driver\n");
> +		return (-1);
> +	}
> +
> +	eqnx_driver->owner = THIS_MODULE;
> +	eqnx_driver->driver_name = "Equinox_SST";
> +	eqnx_driver->name = "ttyEQ";
> +	eqnx_driver->devfs_name = "tts/EQ";
> +	eqnx_driver->major = EQNX_MAJOR;
> +	eqnx_driver->minor_start = 0;
> +	eqnx_driver->minor_num = eqnx_nssps * MAXCHNL_BRD;
> +	eqnx_driver->type = TTY_DRIVER_TYPE_SERIAL;
> +	eqnx_driver->subtype = SERIAL_TYPE_NORMAL;
> +	eqnx_driver->init_termios = eqnx_deftermios;
> +	eqnx_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
> +	tty_set_operations(eqnx_driver, &eqnx_ops);
> +
> +	if (tty_register_driver(eqnx_driver)) {
> +		printk(KERN_ERR "eqnx_init: failed to register
> device\n");
> +		put_tty_driver(eqnx_driver);
> +		return (-1);
> +	}
> +
> +	din_num = eqnx_driver->major;
> +	if (din_num <= 0) {
> +		printk(KERN_ERR "eqnx_init: failed to register
> device\n");
> +		put_tty_driver(eqnx_driver);
> +		return (-1);
> +	}
> +
> +	for (i = 0; i < eqnx_nssps; i++) {
> +		eqnx_dev[i].mpd_major = din_num;
> +		eqnx_dev[i].mpd_minor_start = i * MAXCHNL_BRD;
> +	}
> +
> +	register_eqnx_devs(eqnx_driver);
> +
> +	return (0);

We are not *bsd. omit (), everywhere.

> +}
> +
> +/*
> + * eqnx_pcifindbrds(cfg)
> + *
> + * locate all PCI SST boards
> + *
> + * return: cfg with board information
> + * return: number of boards found
> + */
> +static __init int eqnx_pcifindbrds(struct pci_cfg *cfg)
> +{
> +	struct pci_dev *dev = NULL;
> +	int i, brd_index = 0;
> +	u16 devid;
> +
> +	for (i = 0; i < brdtab_entries && brd_index < maxbrd; i++) {
> +		devid = (board_table[i].secondary_id << 8) & 0xff00;
> +		devid |= board_table[i].primary_id;
> +
> +		while ((dev = pci_find_device(PCI_VENDOR_ID_EQNX, devid,
> dev))) {

Probably needs pci probing.

> +			if (pci_enable_device(dev))
> +				continue;
> +			pci_read_config_byte(dev, PCI_REVISION_ID,
> +					     &cfg->rev_id);
> +			pci_read_config_word(dev, PCI_COMMAND,
> &cfg->command);
> +			cfg->base_addr_reg0 =
> +			    (void *)pci_resource_start(dev, 0);
> +			cfg->pdev = dev;
> +			brd_index++;
> +			cfg++;
> +		}
> +	}
> +
> +	return (brd_index);
> +}
> +
> +module_init(eqnx_init);
> +module_exit(eqnx_cleanup);

regards,
-- 
Jiri Slaby         www.fi.muni.cz/~xslaby
\_.-^-._   [email protected]   _.-^-._/
B67499670407CE62ACC8 22A032CC55C339D47A7E
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux