/* -*- linux-c -*- */
/*
* Copyright (C) 2001 By Joachim Martillo, Telford Tools, Inc.
*
* 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.
*
**/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/sockios.h>
#include <asm/io.h>
#include <asm/byteorder.h>
#include <asm/pgtable.h>
#include <linux/skbuff.h>
#include <linux/if_arp.h>
#include <linux/fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>
#include <linux/version.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include "Reg9050.h"
#include "8253xctl.h"
#include "ring.h"
#include "8253x.h"
#include "crc32dcl.h"
#include "8253xmcs.h"
#include "sp502.h"
/* card names */
char *aura_functionality[] =
{
"NR",
"AO",
"NA",
"UN"
};
char *board_type[] =
{
"unknown",
"1020P",
"1520P",
"2020P",
"2520P",
"4020P",
"4520P",
"8020P",
"8520P",
"SUNSE",
"WANMS",
"1020C",
"1520C",
"2020C",
"2520C",
"4020C",
"4520C",
"8020C",
"8520C",
};
unsigned int sab8253x_rebootflag = 0;
AURAXX20PARAMS AuraXX20DriverParams; /* loaded at startup */
/* from variables below */
SAB_BOARD *AuraBoardRoot = NULL; /* The order of this list is not important */
SAB_CHIP *AuraChipRoot = NULL; /* chips grouped by board chip0 before chip1 */
SAB_PORT *AuraPortRoot = NULL; /* ports grouped by board and by chip, chip0, chip1, etc */
AURA_CIM *AuraCimRoot = NULL; /* only used for deallocating the cim structures, etc */
/* CIM stands for Communications Interface Module -- the G.Link logic provided by the Altera parts. */
/* Arrays of lists of boards of each type on a given interrupt */
SAB_BOARD *AuraBoardESCC2IrqRoot[NUMINTS];
SAB_BOARD *AuraBoardESCC8IrqRoot[NUMINTS];
SAB_BOARD *AuraBoardMCSIrqRoot[NUMINTS];
unsigned int NumSab8253xPorts = 0;
unsigned BD1020Pcounter = 0; /* keep count of each board */
unsigned BD1520Pcounter = 0; /* may change to just keeping count */
unsigned BD2020Pcounter = 0; /* of the total number of boards */
unsigned BD2520Pcounter = 0;
unsigned BD4020Pcounter = 0;
unsigned BD4520Pcounter = 0;
unsigned BD8020Pcounter = 0;
unsigned BD8520Pcounter = 0;
unsigned BD1020CPcounter = 0; /* keep count of each board */
unsigned BD1520CPcounter = 0; /* may change to just keeping count */
unsigned BD2020CPcounter = 0; /* of the total number of boards */
unsigned BD2520CPcounter = 0;
unsigned BD4020CPcounter = 0;
unsigned BD4520CPcounter = 0;
unsigned BD8020CPcounter = 0;
unsigned BD8520CPcounter = 0;
unsigned BDMCScounter = 0;
static int auraXX20n_debug = 0; /* turns on lots of */
/* debugging messages*/
static char* auraXX20n_name = 0;/* set net dev name on command line */
static char *sab8253xc_name = "sab8253xc";
static int sab8253xc_major = 0;
int sab8253xn_listsize = 32; /* recommend descriptor list size */
int sab8253xn_rbufsize = RXSIZE; /* recommend rbuf list size */
int sab8253xt_listsize = 256; /* recommend descriptor list size */
int sab8253xt_rbufsize = 32; /* recommend rbuf list size for tty */
int sab8253xs_listsize = 64; /* recommend descriptor list size */
int sab8253xs_rbufsize = RXSIZE; /* recommend rbuf list size */
int sab8253xc_listsize = 64; /* recommend descriptor list size */
int sab8253xc_rbufsize = RXSIZE; /* recommend rbuf list size for tty */
int xx20_minorstart = 128;
int sab8253x_vendor_id = PCI_VENDOR_ID_AURORATECH;
int sab8253x_cpci_device_id = PCI_DEVICE_ID_AURORATECH_CPCI;
int sab8253x_wmcs_device_id = PCI_DEVICE_ID_AURORATECH_WANMS;
int sab8253x_mpac_device_id = PCI_DEVICE_ID_AURORATECH_MULTI;
int sab8253x_default_sp502_mode = SP502_RS232_MODE;
MODULE_PARM(sab8253x_vendor_id, "i");
MODULE_PARM(sab8253x_cpci_device_id, "i");
MODULE_PARM(sab8253x_wmcs_device_id, "i");
MODULE_PARM(sab8253x_mpac_device_id, "i");
MODULE_PARM(sab8253x_default_sp502_mode, "i");
MODULE_PARM(xx20_minorstart, "i");
MODULE_PARM(sab8253xc_major, "i");
MODULE_PARM(auraXX20n_debug, "i");
MODULE_PARM(auraXX20n_name, "s"); /* this and the following for sync */
MODULE_PARM(sab8253xn_listsize, "i"); /* network driver */
MODULE_PARM(sab8253xn_rbufsize, "i"); /* network driver */
MODULE_PARM(sab8253xt_listsize, "i"); /* tty driver */
MODULE_PARM(sab8253xt_rbufsize, "i"); /* tty driver */
MODULE_PARM(sab8253xc_listsize, "i"); /* network driver */
MODULE_PARM(sab8253xc_rbufsize, "i"); /* network driver */
MODULE_PARM(sab8253xs_listsize, "i"); /* tty driver */
MODULE_PARM(sab8253xs_rbufsize, "i"); /* tty driver */
MODULE_PARM(sab8253xc_name, "s");
struct pci_dev *XX20lastpdev = NULL; /* just used for finding all PCI devices */
static SAB_BOARD *find_ati_multiport_card(void); /* actually implemented */
static SAB_BOARD *find_ati_cpci_card(void); /* to be done */
static SAB_BOARD *find_ati_wanms_card(void); /* to be done */
#if (!defined(MODULE)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
/* unpleasantness for 2.2 kernels
* and probe illogic */
/* The LRP project is still working on
2.2.* kernels but I suspect
that initially we will see more
purchases for complete Linux
machines using 2.4.*, LRP
machines tend to be underpowered
and have a paucity of PCI slots
*/
unsigned int do_probe = 1;
#endif
/* One could argue that these could be in */
/* the 8253xnet.c file but they are fairly */
/* intimately involved with initialization.*/
struct net_device *Sab8253xRoot = NULL;
struct net_device auraXX20n_prototype = /* used for the network device */
{
"8253x0",
0, 0, 0, 0,
0x000,
-1, /* bad irq */
0, 0, 0,
NULL,
sab8253xn_init /* network driver initialization */
};
struct file_operations sab8253xc_fops =
{
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 0))
NULL,
#endif
NULL, /* llseek */
sab8253xc_read, /* read */
sab8253xc_write, /* write */
NULL, /* readdir */
sab8253xc_poll, /* poll */
sab8253xc_ioctl, /* ioctl */
NULL, /* mmap */
sab8253xc_open, /* open */
NULL, /* flush */
sab8253xc_release, /* release */
NULL, /* fsync */
sab8253xc_fasync, /* fasync */
NULL, /* check_media_change */
NULL, /* revalidate */
NULL /* lock */
};
/* A few function defined in this file */
/* These functions are basically functionality */
/* independent -- they are used with asynchronous ttys */
/* synchronous ttys, the network device and the */
/* raw character device */
/* used for reading and writing ports
readw and writew require some reprogramming
of the PLX9050
*/
static unsigned char aura_readb(struct sab_port *port, unsigned char *reg);
static unsigned char wmsaura_readb(struct sab_port *port, unsigned char *reg);
static unsigned short aura_readw(struct sab_port *port, unsigned short *reg);
static unsigned short wmsaura_readw(struct sab_port *port, unsigned short *reg);
static void aura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val);
static void wmsaura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val);
static void aura_writew(struct sab_port *port, unsigned short *reg,unsigned short val);
static void wmsaura_writew(struct sab_port *port, unsigned short *reg,unsigned short val);
static void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes);
static void aura_writefifo(struct sab_port *port);
static void wmsaura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes);
static void wmsaura_writefifo(struct sab_port *port);
/* function definitions */
/* [124]X20 type cards */
static void DisableESCC2Interrupts(SAB_CHIP *chipptr) /* in processing ports may have to disable ints */
{
struct sab82532_async_wr_regs *regs;
regs = chipptr->c_regs;
writeb(0xff,®s->pim); /* All interrupts off */
/* Note that regs/->c_regs
is set to base reg
address, thus taking
address or regs->pim
gets the address of
the PIM register/int mask */
}
static SAB_CHIP* CreateESCC2(SAB_BOARD *bptr, unsigned int offset)
{
SAB_CHIP *cptr;
struct sab82532_async_wr_regs *regs;
printk(KERN_ALERT
"auraXX20n: creating ESCC2 structure on board %p at offset %x.\n",
bptr, offset);
cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL);
if(cptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC2 structure on board %p at offset %x.\n",
bptr, offset);
return NULL;
}
memset(cptr, 0, sizeof(SAB_CHIP));
cptr->chip_type = ESCC2;
cptr->c_board = bptr;
cptr->c_cim = NULL;
cptr->c_chipno = (offset ? 1 : 0); /* first or second chip on board */
cptr->c_revision =
(readb(((char *)bptr->virtbaseaddress2) + offset + SAB85232_REG_VSTR) &
SAB82532_VSTR_VN_MASK);
cptr->c_nports = 2;
cptr->c_portbase = NULL;
cptr->next = AuraChipRoot; /* chips are added to chiplist in reverse order */
AuraChipRoot = cptr;
cptr->next_by_board = bptr->board_chipbase; /* likewise for the local board chiplist */
bptr->board_chipbase = cptr;
printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n",
cptr->c_chipno, bptr, cptr->c_revision);
/* lets set up the generic parallel
* port register which is used to
* control signaling and other stuff*/
/*
* SAB82532 (Aurora) 1 8-bit parallel port
* To summarize the use of the parallel port:
* RS-232
* A B I/O descr
* P0 P4 output TxClk ctrl
* P1 P5 output DTR
* P2 P6 input DSR
* P3 P7 output 485 control
*
*/
/*
* Configuring the parallel port
*/
regs = (struct sab82532_async_wr_regs *)(((char *)bptr->virtbaseaddress2) + offset);
DEBUGPRINT((KERN_ALERT "Writing 0x44 to 0x%p + 0x%x for chip %d\n",
regs, SAB82532_REG_PCR, cptr->c_chipno));
writeb(0x44,®s->pcr); /* 2 input bits */
writeb(0xff,®s->pim);/* All interrupts off */
writeb(0x33,®s->pvr); /* Txclk and DTR low */
cptr->c_regs = (void*) regs;
cptr->int_disable = DisableESCC2Interrupts;
return cptr;
}
static void CreateESCC2Port(SAB_CHIP *cptr, unsigned int portno, unsigned int function)
{
SAB_BOARD *bptr;
SAB_PORT *pptr;
extern void sab8253x_setup_ttyport(struct sab_port *p_port) ;
++NumSab8253xPorts;
bptr = cptr->c_board;
pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL);
if(pptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n",
cptr, bptr);
return;
}
memset(pptr, 0, sizeof(SAB_PORT));
DEBUGPRINT
((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n",
portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number));
pptr->portno = portno;
pptr->chip=cptr;
pptr->board=bptr;
pptr->open_type=OPEN_NOT;
pptr->is_console=0;
pptr->regs=
(union sab82532_regs *)
(((unsigned int)cptr->c_regs) +
(portno * SAB82532_REG_SIZE));
pptr->type = cptr->c_revision;
pptr->function = function;
/* Simpify reading */
#define PVR pptr->regs->async_write.pvr
#define PCR pptr->regs->async_write.pcr
#define PIM pptr->regs->async_write.pim
#define ISR0 pptr->regs->async_read.isr0
#define IMR0 pptr->regs->async_write.imr0
#define IMR1 pptr->regs->async_write.imr1
#define PIS pptr->regs->async_read.pis
#define VSTR pptr->regs->async_read.vstr
#define STAR pptr->regs->async_read.star
#define MODE pptr->regs->async_read.mode
pptr->irq = bptr->b_irq;
if(portno == 0)
{ /* Port A .... */
pptr->dsr.reg=(unsigned char *)&(PVR);
pptr->dsr.mask=0x04;
pptr->dsr.irq=PIS_IDX;
pptr->dsr.irqmask=0x04;
pptr->dtr.reg=(unsigned char *)&(PVR);
pptr->dtr.mask=0x02;
pptr->txclkdir.reg=(unsigned char *)&(PVR);
pptr->txclkdir.mask=0x01;
}
else
{ /* Port B */
pptr->dsr.reg=(unsigned char *)&(PVR);
pptr->dsr.mask=0x40;
pptr->dsr.irq=PIS_IDX;
pptr->dsr.irqmask=0x40;
pptr->dtr.reg=(unsigned char *)&(PVR);
pptr->dtr.mask=0x20;
pptr->txclkdir.reg=(unsigned char *)&(PVR);
pptr->txclkdir.mask=0x10;
}
pptr->dsr.inverted=1;
pptr->dsr.cnst = 0;
pptr->dtr.inverted=1;
pptr->dtr.cnst = 0;
pptr->txclkdir.inverted=1;
pptr ->dcd.reg =(unsigned char *) &(VSTR);
DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr ->dcd.reg));
pptr->dcd.mask = SAB82532_VSTR_CD;
pptr->dcd.inverted = 1;
pptr->dcd.irq=ISR0_IDX;
pptr->dcd.irqmask=SAB82532_ISR0_CDSC;
pptr->dcd.cnst = 0;
pptr->cts.reg = (unsigned char *)&(STAR);
pptr->cts.mask = SAB82532_STAR_CTS;
pptr->cts.inverted = 0;
pptr->cts.irq=ISR1_IDX;
pptr->cts.irqmask=SAB82532_ISR1_CSC;
pptr->cts.cnst = 0;
pptr->rts.reg = (unsigned char *)&(MODE);
pptr->rts.mask = SAB82532_MODE_FRTS;
pptr->rts.inverted = 1;
pptr->rts.cnst = SAB82532_MODE_RTS;
/* Set the read and write function */
pptr->readbyte=aura_readb;
pptr->readword=aura_readw;
pptr->writebyte=aura_writeb;
pptr->writeword=aura_writew;
pptr->readfifo=aura_readfifo;
pptr->writefifo=aura_writefifo;
sab8253x_setup_ttyport(pptr); /* asynchronous */
/* ttys are default, basic */
/* initialization, everything */
/* else works as a modification */
/* thereof */
pptr->next = AuraPortRoot;
AuraPortRoot = pptr;
pptr->next_by_chip = cptr->c_portbase;
cptr->c_portbase = pptr;
pptr->next_by_board = bptr->board_portbase;
bptr->board_portbase = pptr;
}
/* 8x20 type functions */
static void DisableESCC8Interrupts(SAB_CHIP *chipptr)
{
unsigned int regbase; /* a lot more to do for ESCC8 */
regbase = (unsigned int) chipptr->c_regs;
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_A); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_B); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_C); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_D); /* All interrupts off */
}
static SAB_CHIP* CreateESCC8(SAB_BOARD *bptr, unsigned int offset)
{
SAB_CHIP *cptr;
unsigned int regbase;
printk(KERN_ALERT
"auraXX20n: creating ESCC8 structure on board %p at offset %x.\n",
bptr, offset);
cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL);
if(cptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC8 structure on board %p at offset %x.\n",
bptr, offset);
return NULL;
}
memset(cptr, 0, sizeof(SAB_CHIP));
cptr->chip_type = ESCC8;
cptr->c_board = bptr;
cptr->c_cim = NULL;
cptr->c_chipno = (offset ? 1 : 0); /* no card actually has 2 ESCC8s on it */
cptr->c_revision =
(readb(((char *)bptr->virtbaseaddress2) + offset + SAB85232_REG_VSTR) &
SAB82532_VSTR_VN_MASK);
cptr->c_nports = 8;
cptr->c_portbase = NULL; /* used for the list of ports associated
with this chip
*/
cptr->next = AuraChipRoot;
AuraChipRoot = cptr;
cptr->next_by_board = bptr->board_chipbase;
bptr->board_chipbase = cptr;
printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n",
cptr->c_chipno, bptr, cptr->c_revision);
/* lets set up the generic parallel
* port register which is used to
* control signaling and other stuff*/
/* SAB82538 4 8-bits parallel ports
* To summarize the use of the parallel port:
* RS-232
* Parallel port A -- TxClkdir control (output) ports 0 - 7
* Parallel port B -- DTR (output) ports 0 - 7
* Parallel port C -- DSR (input) ports 0 - 7
* Parallel port D -- driver power down (output) drivers 0 - 3
*
* Note port D is not used on recent boards
*/
regbase = (unsigned int)(((char *)bptr->virtbaseaddress2) + offset);
DEBUGPRINT((KERN_ALERT "Setting up parallel port A (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_A, SAB82538_REG_PIM_A, SAB82538_REG_PVR_A));
/* Configuring Parallel Port A (Clkdir)*/
writeb(0x0,((unsigned char *)regbase) + SAB82538_REG_PCR_A); /* All output bits */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_A); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PVR_A); /* All low */
DEBUGPRINT((KERN_ALERT "Setting up parallel port B (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_B,SAB82538_REG_PIM_B,SAB82538_REG_PVR_B));
writeb(0x0,((unsigned char *)regbase) + SAB82538_REG_PCR_B); /* All output bits */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_B); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PVR_B); /* All low */
DEBUGPRINT((KERN_ALERT "Setting up parallel port C (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_C, SAB82538_REG_PIM_C, SAB82538_REG_PVR_C));
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PCR_C); /* All intput bits */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_C); /* All interrupts off */
/* don't set port value register on input register */
/* Configuring Parallel Port D */
DEBUGPRINT((KERN_ALERT "Setting up parallel port D (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_D, SAB82538_REG_PIM_D, SAB82538_REG_PVR_D));
writeb(0x0f,((unsigned char *)regbase) + SAB82538_REG_PCR_D); /* 4 input bits */
writeb(0xff,((unsigned char *)regbase) + SAB82538_REG_PIM_D); /* All interrupts off */
/* don't set port value register on input register */
/* The priority rotation thing */
DEBUGPRINT((KERN_ALERT "Setting IVA (0x%x + 0x%x = 0x%x\n", regbase,
SAB82532_REG_IVA, regbase + SAB82532_REG_IVA));
writeb(SAB82538_IVA_ROT, ((unsigned char *)regbase) + SAB82532_REG_IVA);
cptr->c_regs = (void*) regbase;
cptr->int_disable = DisableESCC8Interrupts;
return cptr;
}
static void DisableESCC8InterruptsFromCIM(SAB_CHIP *chipptr)
{
unsigned int regbase; /* a lot more to do for ESCC8 */
regbase = (unsigned int) chipptr->c_regs;
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_A)); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_B)); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_C)); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_D)); /* All interrupts off */
}
static void CreateESCC8Port(SAB_CHIP *cptr, unsigned int portno, unsigned int function)
{
SAB_BOARD *bptr;
SAB_PORT *pptr;
extern void sab8253x_setup_ttyport(struct sab_port *p_port) ;
++NumSab8253xPorts;
bptr = cptr->c_board;
pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL);
if(pptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n",
cptr, bptr);
return;
}
memset(pptr, 0, sizeof(SAB_PORT));
DEBUGPRINT
((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n",
portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number));
pptr->portno = portno;
pptr->chip=cptr;
pptr->board=bptr;
pptr->open_type=OPEN_NOT;
pptr->is_console=0;
pptr->regs=
(union sab82532_regs *)
(((unsigned int)cptr->c_regs) +
(portno * SAB82538_REG_SIZE));
pptr->type = cptr->c_revision;
pptr->function = function;
pptr->irq = bptr->b_irq;
pptr->dsr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_C;
pptr->dsr.mask = 0x1 << portno;
pptr->dsr.inverted = 1;
pptr->dsr.irq=PIS_IDX; /* need to check this constant */
pptr->dsr.irqmask=0x1 << portno;
pptr->dsr.cnst = 0;
pptr->txclkdir.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_A;
pptr->txclkdir.mask = 0x1 << portno;
/* NOTE: Early 8 ports boards had different tx clkdir sense */
pptr->txclkdir.inverted = 1;
pptr->dtr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_B;
pptr->dtr.mask = 0x1 << portno;
pptr->dtr.inverted = 1;
pptr->dtr.cnst = 0;
pptr ->dcd.reg = (unsigned char *)&(VSTR);
DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr ->dcd.reg));
pptr->dcd.mask = SAB82532_VSTR_CD;
pptr->dcd.inverted = 1;
pptr->dcd.irq=ISR0_IDX;
pptr->dcd.irqmask=SAB82532_ISR0_CDSC;
pptr->dcd.cnst = 0;
pptr->cts.reg = (unsigned char *)&(STAR);
pptr->cts.mask = SAB82532_STAR_CTS;
pptr->cts.inverted = 0;
pptr->cts.irq=ISR1_IDX;
pptr->cts.irqmask=SAB82532_ISR1_CSC;
pptr->cts.cnst = 0;
pptr->rts.reg = (unsigned char *)&(MODE);
pptr->rts.mask = SAB82532_MODE_FRTS;
pptr->rts.inverted = 1;
pptr->rts.cnst = SAB82532_MODE_RTS;
/* Set the read and write function */
pptr->readbyte=aura_readb;
pptr->readword=aura_readw;
pptr->writebyte=aura_writeb;
pptr->writeword=aura_writew;
pptr->readfifo=aura_readfifo;
pptr->writefifo=aura_writefifo;
sab8253x_setup_ttyport(pptr); /* asynchronous */
/* ttys are default, basic */
/* initialization, everything */
/* else works as a modification */
/* thereof */
pptr->next = AuraPortRoot;
AuraPortRoot = pptr;
pptr->next_by_chip = cptr->c_portbase;
cptr->c_portbase = pptr;
pptr->next_by_board = bptr->board_portbase;
bptr->board_portbase = pptr;
}
/* Multichannel server functions */
static SAB_CHIP* CreateESCC8fromCIM(SAB_BOARD *bptr, AURA_CIM *cim, unsigned int chipno)
{
SAB_CHIP *cptr;
unsigned int regbase;
printk(KERN_ALERT
"auraXX20n: creating ESCC8 %d structure on board %p from cim %p.\n",
chipno, bptr, cim);
cptr = (SAB_CHIP*) kmalloc(sizeof(SAB_CHIP), GFP_KERNEL);
if(cptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC8 structure %d on board %p at from cim %p.\n",
chipno, bptr, cim);
return NULL;
}
memset(cptr, 0, sizeof(SAB_CHIP));
cptr->chip_type = ESCC8;
cptr->c_board = bptr;
cptr->c_cim = cim;
cptr->c_chipno = chipno;
cptr->c_revision =
(readb((unsigned char *) (bptr->CIMCMD_REG +
(CIMCMD_RDREGB | (((chipno*8) << 6) | SAB85232_REG_VSTR))))
& SAB82532_VSTR_VN_MASK);
cptr->c_nports = 8;
cptr->c_portbase = NULL; /* used for the list of ports associated
with this chip
*/
cptr->next = AuraChipRoot;
AuraChipRoot = cptr;
cptr->next_by_board = bptr->board_chipbase;
bptr->board_chipbase = cptr;
cptr->next_by_cim = cim->ci_chipbase;
cim->ci_chipbase = cptr;
printk(KERN_ALERT "auraXX20n: chip %d on board %p is revision %d.\n",
cptr->c_chipno, bptr, cptr->c_revision);
/* lets set up the generic parallel
* port register which is used to
* control signaling and other stuff*/
/* SAB82538 4 8-bits parallel ports
* To summarize the use of the parallel port:
* RS-232
* Parallel port A -- TxClkdir control (output) ports 0 - 7
* Parallel port B -- DTR (output) ports 0 - 7
* Parallel port C -- DSR (input) ports 0 - 7
* Parallel port D -- driver power down (output) drivers 0 - 3
*
* Note port D is not used on recent boards
*/
regbase = (unsigned int)
(bptr->CIMCMD_REG + (0 | (((chipno*8) << 6) | 0))); /* need to add in RDB/WRB cmd bits
* and reg offset (> 32) */
DEBUGPRINT((KERN_ALERT "Setting up parallel port A (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_A, SAB82538_REG_PIM_A, SAB82538_REG_PVR_A));
/* Configuring Parallel Port A (Clkdir)*/
writeb(0x00,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_A)); /* All output bits */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_A)); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PVR_A)); /* All low */
DEBUGPRINT((KERN_ALERT "Setting up parallel port B (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_B,SAB82538_REG_PIM_B,SAB82538_REG_PVR_B));
writeb(0x00,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_B)); /* All output bits */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_B)); /* All interrupts off */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PVR_B)); /* All low */
DEBUGPRINT((KERN_ALERT "Setting up parallel port C (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_C, SAB82538_REG_PIM_C, SAB82538_REG_PVR_C));
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_C)); /* All intput bits */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_C)); /* All interrupts off */
/* don't set port value register on input register */
/* Configuring Parallel Port D */
DEBUGPRINT((KERN_ALERT "Setting up parallel port D (0x%x), 0x%x, 0x%x, 0x%x\n", regbase,
SAB82538_REG_PCR_D, SAB82538_REG_PIM_D, SAB82538_REG_PVR_D));
writeb(0x0f,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PCR_D)); /* 4 input bits */
writeb(0xff,((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82538_REG_PIM_D)); /* All interrupts off */
/* don't set port value register on input register */
/* The priority rotation thing */
DEBUGPRINT((KERN_ALERT "Setting IVA (0x%x + 0x%x = 0x%x\n", regbase,
SAB82532_REG_IVA, regbase + SAB82532_REG_IVA));
writeb(SAB82538_IVA_ROT, ((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82532_REG_IVA));
writeb(0, ((unsigned char *)regbase) + (CIMCMD_WRREGB | SAB82532_REG_IPC));
cptr->c_regs = (void*) regbase;
cptr->int_disable = DisableESCC8InterruptsFromCIM;
return cptr;
}
static void CreateESCC8PortWithCIM(SAB_CHIP *cptr, unsigned int portno,
AURA_CIM *cim, unsigned flag)
{
SAB_BOARD *bptr;
SAB_PORT *pptr;
extern void sab8253x_setup_ttyport(struct sab_port *p_port) ;
++NumSab8253xPorts;
bptr = cptr->c_board;
pptr = (SAB_PORT*) kmalloc(sizeof(SAB_PORT), GFP_KERNEL);
if(pptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: Failed to create ESCC2 port structure on chip %p on board %p.\n",
cptr, bptr);
return;
}
memset(pptr, 0, sizeof(SAB_PORT));
DEBUGPRINT
((KERN_ALERT "Setting up port %d, chipno %d for %s type board number %d.\n",
portno, cptr->c_chipno, board_type[bptr->b_type],bptr->board_number));
pptr->portno = portno;
pptr->chip=cptr;
pptr->board=bptr;
pptr->open_type=OPEN_NOT;
pptr->is_console=0;
pptr->regs=
(union sab82532_regs *)
(((unsigned int)cptr->c_regs) +
(portno << 6)); /* addressing is different when there is a cim */
pptr->type = cptr->c_revision;
pptr->function = (((cim->ci_flags & CIM_SYNC) || flag) ? FUNCTION_NR :
FUNCTION_AO);
pptr->irq = bptr->b_irq;
pptr->dsr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_C;
pptr->dsr.mask = 0x1 << portno;
pptr->dsr.inverted = 1;
pptr->dsr.irq=PIS_IDX; /* need to check this constant */
pptr->dsr.irqmask=0x1 << portno;
pptr->dsr.cnst = 0;
pptr->txclkdir.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_A;
pptr->txclkdir.mask = 0x1 << portno;
/* NOTE: Early 8 ports boards had different tx clkdir sense */
pptr->txclkdir.inverted = 1;
pptr->dtr.reg = ((unsigned char *)cptr->c_regs) + SAB82538_REG_PVR_B;
pptr->dtr.mask = 0x1 << portno;
pptr->dtr.inverted = 1;
pptr->dtr.cnst = 0;
pptr->dcd.reg = ((unsigned char *)pptr->regs) + SAB85232_REG_VSTR;
DEBUGPRINT((KERN_ALERT "cd register set to 0x%p\n", pptr->dcd.reg));
pptr->dcd.mask = SAB82532_VSTR_CD;
pptr->dcd.inverted = 1;
pptr->dcd.irq=ISR0_IDX;
pptr->dcd.irqmask=SAB82532_ISR0_CDSC;
pptr->dcd.cnst = 0;
pptr->cts.reg = (unsigned char *)&(STAR);
pptr->cts.mask = SAB82532_STAR_CTS;
pptr->cts.inverted = 0;
pptr->cts.irq=ISR1_IDX;
pptr->cts.irqmask=SAB82532_ISR1_CSC;
pptr->cts.cnst = 0;
pptr->rts.reg = (unsigned char *)&(MODE);
pptr->rts.mask = SAB82532_MODE_FRTS;
pptr->rts.inverted = 1;
pptr->rts.cnst = SAB82532_MODE_RTS;
/* Set the read and write function */
pptr->readbyte=wmsaura_readb;
pptr->readword=wmsaura_readw;
pptr->writebyte=wmsaura_writeb;
pptr->writeword=wmsaura_writew;
pptr->readfifo=wmsaura_readfifo;
pptr->writefifo=wmsaura_writefifo;
sab8253x_setup_ttyport(pptr); /* asynchronous */
/* ttys are default, basic */
/* initialization, everything */
/* else works as a modification */
/* thereof */
pptr->next = AuraPortRoot;
AuraPortRoot = pptr;
pptr->next_by_chip = cptr->c_portbase;
cptr->c_portbase = pptr;
pptr->next_by_board = bptr->board_portbase;
bptr->board_portbase = pptr;
pptr->next_by_cim = cim->ci_portbase;
cim->ci_portbase = pptr;
}
static void CreateCIMs(SAB_BOARD *bptr)
{
unsigned int cimnum;
unsigned char *wrcsr;
unsigned char *rdcsr;
unsigned char tmp;
AURA_CIM *cim;
unsigned short intrmask;
for(intrmask = 0, cimnum = 0; cimnum < MAX_NCIMS; ++cimnum)
{
intrmask >>= 2;
/*
* The hardware is mapped. Try writing to CIM CSR.
*/
wrcsr = bptr->CIMCMD_REG +
(CIMCMD_WRCIMCSR | (cimnum << CIMCMD_CIMSHIFT));
rdcsr = bptr->CIMCMD_REG +
(CIMCMD_RDCIMCSR | (cimnum << CIMCMD_CIMSHIFT));
/* Try to write an 0xff */
writeb((unsigned char) 0xff, (unsigned char *) wrcsr);
/* and read it back */
tmp = (unsigned char) readb((unsigned char *) rdcsr);
DEBUGPRINT((KERN_ALERT
"aura wan mcs: wrcsr %p rdcsr %p cim %d 0xff readback: 0x%x.\n",
(void*) wrcsr, (void*) rdcsr, cimnum, tmp));
/* make sure it's really all ones. */
if ((tmp & CIMCMD_CIMCSR_TESTMASK) != CIMCMD_CIMCSR_TESTMASK)
{
printk(KERN_ALERT
"aura wan mcs: not found -- wrcsr %p rdcsr %p cim %d 0xff readback: 0x%x.\n",
(void*) wrcsr, (void*) rdcsr, cimnum, tmp);
continue;
}
/* Try to write a zero */
writeb((unsigned char) 0, (unsigned char*) wrcsr);
/* and read it back */
tmp = (unsigned char) readb((unsigned char *) rdcsr);
DEBUGPRINT((KERN_ALERT
"aura wan mcs: wrcsr %p rdcsr %p cim %d 0x0 readback: 0x%x.\n",
(void*) wrcsr, (void*) rdcsr, cimnum, tmp));
/* make sure it's really zero. */
if ((tmp & CIMCMD_CIMCSR_TESTMASK) != 0)
{
printk(KERN_ALERT
"aura wan mcs: not found -- wrcsr %p rdcsr %p cim %d 0x0 readback: 0x%x.\n",
(void*) wrcsr, (void*) rdcsr, cimnum, tmp);
continue;
}
cim = (AURA_CIM*) kmalloc(sizeof(AURA_CIM), GFP_KERNEL);
if(cim == NULL)
{
printk(KERN_ALERT
"aura wan mcs: unable to allocate memory, board %p, cim %d.\n",
bptr, cimnum);
continue;
}
cim->ci_num = cimnum;
cim->ci_board = bptr;
cim->ci_chipbase = NULL;
cim->ci_portbase = NULL;
cim->ci_nports = CIM_NPORTS;
cim->ci_port0lbl = cimnum * CIM_NPORTS;
if (mcs_ciminit(bptr, cim) == FALSE)
{
kfree(cim);
continue;
}
intrmask |= 0xc0; /* turn on the high two bits
* a little obscure, borrowed
* from solaris driver 0th cim
* gets lowest two bits*/
cim->next = AuraCimRoot;
AuraCimRoot = cim;
cim->next_by_mcs = bptr->b_cimbase;
bptr->b_cimbase = cim;
printk(KERN_ALERT
"aura wan mcs: Created cim %d type %d on board %p.\n",
cim->ci_num, cim->ci_type, bptr);
}
bptr->b_intrmask = intrmask;
}
/* put the chips on the boards */
static void SetupAllChips(SAB_BOARD *bptr)
{ /* note that port ordering */
/* is important in chip setup */
/* the open routine walks the */
/* port list for sync and async */
/* ttys */
SAB_CHIP *chip;
AURA_CIM *cim;
unsigned int chipno;
switch(bptr->b_type)
{
case BD_1020P:
case BD_1020CP:
/* setup 1 ESCC2 */
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_NA);
CreateESCC2Port(chip, 0, FUNCTION_AO);
}
break;
case BD_1520P:
case BD_1520CP:
/* setup 1 ESCC2 */
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_NA);
CreateESCC2Port(chip, 0, FUNCTION_NR);
}
break;
case BD_2020P:
case BD_2020CP:
/* setup 1 ESCC2 */
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_AO);
CreateESCC2Port(chip, 0, FUNCTION_AO);
}
break;
case BD_2520P:
case BD_2520CP:
/* setup 1 ESCC2 */
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_NR);
CreateESCC2Port(chip, 0, FUNCTION_NR);
}
break;
case BD_4020P:
case BD_4020CP: /* do chips in reverCse
order so that they
are on lists in forward
order
*/
/* setup 2 ESCC2 */
chip = CreateESCC2(bptr, AURORA_4X20_CHIP_OFFSET);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_AO);
CreateESCC2Port(chip, 0, FUNCTION_AO);
}
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_AO);
CreateESCC2Port(chip, 0, FUNCTION_AO);
}
break;
case BD_4520P:
case BD_4520CP:
/* setup 2 ESCC2 */
chip = CreateESCC2(bptr, AURORA_4X20_CHIP_OFFSET);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_NR);
CreateESCC2Port(chip, 0, FUNCTION_NR);
}
chip = CreateESCC2(bptr, 0);
if(chip != NULL)
{
CreateESCC2Port(chip, 1, FUNCTION_NR);
CreateESCC2Port(chip, 0, FUNCTION_NR);
}
break;
case BD_8020P:
case BD_8020CP:
/* setup 1 ESCC8 */
chip = CreateESCC8(bptr, 0);
if(chip != NULL)
{
CreateESCC8Port(chip, 7, FUNCTION_AO);
CreateESCC8Port(chip, 6, FUNCTION_AO);
CreateESCC8Port(chip, 5, FUNCTION_AO);
CreateESCC8Port(chip, 4, FUNCTION_AO);
CreateESCC8Port(chip, 3, FUNCTION_AO);
CreateESCC8Port(chip, 2, FUNCTION_AO);
CreateESCC8Port(chip, 1, FUNCTION_AO);
CreateESCC8Port(chip, 0, FUNCTION_AO);
}
break;
case BD_8520P:
case BD_8520CP:
/* setup 1 ESCC8 */
chip = CreateESCC8(bptr, 0);
if(chip != NULL)
{
CreateESCC8Port(chip, 7, FUNCTION_NR);
CreateESCC8Port(chip, 6, FUNCTION_NR);
CreateESCC8Port(chip, 5, FUNCTION_NR);
CreateESCC8Port(chip, 4, FUNCTION_NR);
CreateESCC8Port(chip, 3, FUNCTION_NR);
CreateESCC8Port(chip, 2, FUNCTION_NR);
CreateESCC8Port(chip, 1, FUNCTION_NR);
CreateESCC8Port(chip, 0, FUNCTION_NR);
}
break;
case BD_WANMCS:
CreateCIMs(bptr);
for(chipno = 7, cim = bptr->b_cimbase;
cim != NULL; cim = cim->next_by_mcs)
{
chip = CreateESCC8fromCIM(bptr, cim, chipno--);
if(chip != NULL)
{
CreateESCC8PortWithCIM(chip, 7, cim, 0);
CreateESCC8PortWithCIM(chip, 6, cim, 0);
CreateESCC8PortWithCIM(chip, 5, cim, 0);
CreateESCC8PortWithCIM(chip, 4, cim, 0);
CreateESCC8PortWithCIM(chip, 3, cim, 0);
CreateESCC8PortWithCIM(chip, 2, cim, 0);
CreateESCC8PortWithCIM(chip, 1, cim, 0);
CreateESCC8PortWithCIM(chip, 0, cim, 0);
}
chip = CreateESCC8fromCIM(bptr, cim, chipno--);
if(chip != NULL)
{
CreateESCC8PortWithCIM(chip, 7, cim, 0);
CreateESCC8PortWithCIM(chip, 6, cim, 0);
CreateESCC8PortWithCIM(chip, 5, cim, 0);
CreateESCC8PortWithCIM(chip, 4, cim, 0);
CreateESCC8PortWithCIM(chip, 3, cim, 0);
CreateESCC8PortWithCIM(chip, 2, cim, 0);
CreateESCC8PortWithCIM(chip, 1, cim, 0);
CreateESCC8PortWithCIM(chip, 0, cim, 1);
}
}
break;
default:
printk(KERN_ALERT "auraXX20n: unable to set up chip for board %p.\n", bptr);
break;
}
}
/* finding the cards by PCI device type */
static SAB_BOARD* find_ati_cpci_card(void)
{
struct pci_dev *pdev;
unsigned char bus;
unsigned char devfn;
unsigned char pci_latency;
unsigned short pci_command;
SAB_BOARD *bptr;
unsigned control;
unsigned does_sync;
unsigned use_1port;
printk(KERN_ALERT "auraXX20n: finding ati cpci cards.\n");
bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL);
if(bptr == NULL)
{
printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n");
return 0;
}
memset(bptr, 0, sizeof(SAB_BOARD));
if(!pcibios_present())
{
printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n"));
CPCIRESTART:
if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_cpci_device_id, XX20lastpdev),
pdev == NULL)
{
printk(KERN_ALERT "auraXX20n: could not find cpci card.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: found multiport CPCI serial card.\n"));
XX20lastpdev = pdev;
DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI PLX 9050, %p.\n", pdev));
bptr->b_dev = *pdev;
/* the Solaris and model linux drivers
* comment that there are problems with
* getting the length via PCI operations
* seems to work for 2.4
*/
bptr->length0 = (unsigned int) pci_resource_len(pdev, 0);
bptr->length1 = (unsigned int) pci_resource_len(pdev, 1);
bptr->length2 = (unsigned int) pci_resource_len(pdev, 2);
bptr->b_irq = pdev->irq;
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 0 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 0), bptr->length0));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 1 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 1), bptr->length1));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 2 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 2),
bptr->length2));
DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq));
bus = pdev->bus->number;
devfn = pdev->devfn;
DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn)));
pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command);
#if 0
/* The Aurora card does not act as a PCI master
* ugh!!
*/
new_command = pci_command | PCI_COMMAND_MASTER;
if(pci_command != new_command)
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: the PCI BIOS has not enabled this device!"
" Updating PCI command %4.4x->%4.4x.\n",
pci_command,
new_command));
pcibios_write_config_word(bus, devfn, PCI_COMMAND,
new_command);
}
else
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: the PCI BIOS has enabled this device as master!\n"));
}
#endif
if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n"));
}
pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER,
&pci_latency);
if (pci_latency < 32)
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency));
/* may need to change the latency */
#if 0
pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32);
#endif
}
else
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is %#x.\n",
pci_latency));
}
bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0),
bptr->length0);
if(bptr->virtbaseaddress0 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 0));
goto CPCIRESTART;
}
bptr->b_bridge = (PLX9050*) bptr->virtbaseaddress0; /* MAKE SURE INTS ARE OFF */
writel(PLX_INT_OFF, &(bptr->b_bridge->intr));
printk
(KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0);
dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0);
if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */
{
printk(KERN_ALERT
"auraXX20n: unable to access PLX 9050 registers at %p.\n",
(void*)bptr->virtbaseaddress0);
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto CPCIRESTART;
}
bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2),
bptr->length2);
if(bptr->virtbaseaddress2 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 2));
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto CPCIRESTART;
}
DEBUGPRINT
((KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2));
/* we get clockrate from serial eeprom */
if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
(unsigned short*) bptr->b_eprom,
(unsigned char) 0, EPROM9050_SIZE))
{
printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto CPCIRESTART;
}
printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n");
dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * EPROM9050_SIZE);
if(*(unsigned int*)bptr->b_eprom != PCIMEMVALIDCPCI) /* bridge problem? */
{
printk(KERN_ALERT "auraXX20n: unable to access valid serial eprom data.\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto CPCIRESTART;
}
if(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & PREFETCHBIT)
{
++sab8253x_rebootflag;
printk(KERN_ALERT "8253x: eeprom programmed for prefetchable memory resources; must reprogram!!\n");
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WENCMD, NM93_WENADDR, 0);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
9,
(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & (~PREFETCHBIT)));
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WDSCMD, NM93_WDSADDR, 0);
}
/* get SYNC and ONEPORT values */
control = readl(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl);
/* note we use the actual address
* of the control register in
* memory
*/
if(control & AURORA_MULTI_SYNCBIT)
{
does_sync = 0;
}
else
{
does_sync = 1;
}
if(control & AURORA_MULTI_1PORTBIT)
{
use_1port = 1;
}
else
{
use_1port = 0;
}
/* Figure out the board */
switch(bptr->length2)
{
case AURORA_4X20_SIZE:
if(does_sync)
{
bptr->b_type = BD_4520CP;
bptr->b_nchips = 2;
bptr->b_nports = 4;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD4520CPcounter; /* keep track of boardnumber for naming devices */
++BD4520CPcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 4520CP.\n");
}
else
{
bptr->b_type = BD_4020CP;
bptr->b_nchips = 2;
bptr->b_nports = 4;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD4020CPcounter;
++BD4020CPcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 4020CP.\n");
}
break;
case AURORA_8X20_SIZE:
if(does_sync)
{
bptr->b_type = BD_8520CP;
bptr->b_nchips = 1;
bptr->b_nports = 8;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD8520CPcounter;
++BD8520CPcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 8520CP.\n");
}
else
{
bptr->b_type = BD_8020CP;
bptr->b_nchips = 1;
bptr->b_nports = 8;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD8020CPcounter;
++BD8020CPcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 8020CP.\n");
}
break;
case AURORA_2X20_SIZE:
if(does_sync)
{
if(use_1port)
{
bptr->b_type = BD_1520CP;
printk(KERN_ALERT "auraXX20n: Found Saturn 1520CP.\n");
bptr->b_nchips = 1;
bptr->b_nports = 1;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD1520CPcounter;
++BD1520CPcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 1520CP.\n");
}
else
{
bptr->b_type = BD_2520CP;
bptr->b_nchips = 1;
bptr->b_nports = 2;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD2520CPcounter;
++BD2520CPcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 2520CP.\n");
}
}
else
{
if(use_1port)
{
bptr->b_type = BD_1020CP;
bptr->b_nchips = 1;
bptr->b_nports = 1;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD1020CPcounter;
++BD1020CPcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 1020CP.\n");
}
else
{
bptr->b_type = BD_2020CP;
bptr->b_nchips = 1;
bptr->b_nports = 2;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD2020CPcounter;
++BD2020CPcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 2020CP.\n");
}
}
break;
default:
printk(KERN_ALERT "Error: Board could not be identified\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto CPCIRESTART;
}
/* Let's get the clockrate right -- ugh!*/
bptr->b_clkspeed = bptr->b_eprom[AURORA_MULTI_EPROM_CLKLSW/2];
if(bptr->b_clkspeed == -1) /* misprogrammed -- ugh. */
{
switch(bptr->b_type)
{
case BD_8520CP:
case BD_8020CP:
bptr->b_clkspeed = AURORA_MULTI_CLKSPEED/4;
break;
default:
bptr->b_clkspeed = AURORA_MULTI_CLKSPEED;
break;
}
printk(KERN_ALERT "auraXX20n: UNKNOWN CLOCKSPEED -- ASSUMING %ld.\n", bptr->b_clkspeed);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WENCMD, NM93_WENADDR, 0);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
54, (unsigned short) bptr->b_clkspeed);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
55, (unsigned short) (bptr->b_clkspeed >> 16));
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WDSCMD, NM93_WDSADDR, 0);
}
return bptr;
}
static SAB_BOARD* find_ati_wanms_card(void) /* wan multichanner server == mcs [ multichannel server] */
{
struct pci_dev *pdev;
unsigned char bus;
unsigned char devfn;
unsigned char pci_latency;
unsigned short pci_command;
SAB_BOARD *bptr;
int resetresult;
printk(KERN_ALERT "auraXX20n: finding ati mcs cards.\n");
bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL);
if(bptr == NULL)
{
printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n");
return 0;
}
memset(bptr, 0, sizeof(SAB_BOARD));
if(!pcibios_present())
{
printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n"));
MCSRESTART:
if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_wmcs_device_id, XX20lastpdev),
pdev == NULL)
{
printk(KERN_ALERT "auraXX20n: could not find mcs card.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: found mcs card.\n"));
XX20lastpdev = pdev;
DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI S5920, %p.\n", pdev));
bptr->b_dev = *pdev;
/* the Solaris and model linux drivers
* comment that there are problems with
* getting the length via PCI operations
* seems to work for 2.4
*/
bptr->length0 = (unsigned int) pci_resource_len(pdev, 0); /* AMCC 5920 operation registers
includes access to serial eprom */
bptr->length1 = (unsigned int) pci_resource_len(pdev, 1); /* commands to remote cards */
bptr->length2 = (unsigned int) pci_resource_len(pdev, 2); /* command to host card */
bptr->length3 = (unsigned int) pci_resource_len(pdev, 3); /* RFIFO cache */
bptr->b_irq = pdev->irq;
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 0 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 0), bptr->length0));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 1 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 1), bptr->length1));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 2 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 2),
bptr->length2));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 3 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 3),
bptr->length3));
DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq));
bus = pdev->bus->number;
devfn = pdev->devfn;
DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn)));
pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command);
#if 0
/* The Aurora card does not act as a PCI master
* ugh!!
*/
new_command = pci_command | PCI_COMMAND_MASTER;
if(pci_command != new_command)
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: the PCI BIOS has not enabled this device!"
" Updating PCI command %4.4x->%4.4x.\n",
pci_command,
new_command));
pcibios_write_config_word(bus, devfn, PCI_COMMAND,
new_command);
}
else
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: the PCI BIOS has enabled this device as master!\n"));
}
#endif
if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n"));
}
pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER,
&pci_latency);
if (pci_latency < 32)
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency));
/* may need to change the latency */
#if 0
pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32);
#endif
}
else
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is %#x.\n",
pci_latency));
}
bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0),
bptr->length0);
if(bptr->virtbaseaddress0 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 0));
goto MCSRESTART;
}
bptr->b_bridge = (void*) bptr->virtbaseaddress0; /* b_bridge is not supposed
to be used by the AMCC based
products -- it is set just
in case */
printk(KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0);
/* unfortunate name -- works for any bridge */
dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0);
if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */
{
printk(KERN_ALERT
"auraXX20n: unable to access AMCC registers at %p.\n",
(void*)bptr->virtbaseaddress0);
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto MCSRESTART; /* try the next one if any */
}
writel(AMCC_INT_OFF, (unsigned int*)(bptr->AMCC_REG + AMCC_INTCSR));
bptr->virtbaseaddress1 = ioremap_nocache(pci_base_address(pdev, 1),
bptr->length1);
if(bptr->virtbaseaddress1 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 1));
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto MCSRESTART;
}
DEBUGPRINT
((KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 1), (void*) bptr->virtbaseaddress1));
/* next address space */
bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2),
bptr->length2);
if(bptr->virtbaseaddress2 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 2));
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress1);
iounmap((void*)bptr->virtbaseaddress1);
bptr->virtbaseaddress1 = 0;
goto MCSRESTART;
}
DEBUGPRINT
((KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2));
bptr->virtbaseaddress3 = ioremap_nocache(pci_base_address(pdev, 3),
bptr->length3);
if(bptr->virtbaseaddress3 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 3));
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress1);
iounmap((void*)bptr->virtbaseaddress1);
bptr->virtbaseaddress1 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress2);
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto MCSRESTART;
}
DEBUGPRINT
((KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 3), (void*) bptr->virtbaseaddress3));
bptr->b_type = BD_WANMCS;
resetresult = wanmcs_reset(bptr);
writel(AMCC_INT_OFF, (unsigned int*)(bptr->AMCC_REG + AMCC_INTCSR));
if(resetresult == FALSE)
{
printk(KERN_ALERT "auraXX20n: unable to reset wan mcs %p.\n", bptr);
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress1);
iounmap((void*)bptr->virtbaseaddress1);
bptr->virtbaseaddress1 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress2);
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress3);
iounmap((void*)bptr->virtbaseaddress3);
bptr->virtbaseaddress3 = 0;
goto MCSRESTART;
}
/* we get clockrate from serial eeprom */
if (amcc_read_nvram((unsigned char*) bptr->b_eprom,
AMCC_NVRAM_SIZE, bptr->AMCC_REG) == FALSE)
{
printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress1);
bptr->virtbaseaddress1 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
iounmap((void*)bptr->virtbaseaddress3);
bptr->virtbaseaddress3 = 0;
goto MCSRESTART;
}
printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n");
dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * AMCC_NVRAM_SIZE);
if(bptr->b_eprom[AMCC_NVR_VENDEVID] != PCIMEMVALIDWMCS)
{
printk(KERN_ALERT "auraXX20: bad serial eprom, board %p.\n", bptr);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress1);
bptr->virtbaseaddress1 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
iounmap((void*)bptr->virtbaseaddress3);
bptr->virtbaseaddress3 = 0;
goto MCSRESTART;
}
return bptr;
}
/* initialize the auraXX20 */
static SAB_BOARD* find_ati_multiport_card(void)
{
struct pci_dev *pdev;
unsigned char bus;
unsigned char devfn;
unsigned char pci_latency;
unsigned short pci_command;
SAB_BOARD *bptr;
unsigned control;
unsigned does_sync;
unsigned use_1port;
printk(KERN_ALERT "auraXX20n: finding ati cards.\n");
bptr = (SAB_BOARD*)kmalloc(sizeof(SAB_BOARD), GFP_KERNEL);
if(bptr == NULL)
{
printk(KERN_ALERT "auraXX20n: could not allocate board memory!\n");
return 0;
}
memset(bptr, 0, sizeof(SAB_BOARD));
if(!pcibios_present())
{
printk(KERN_ALERT "auraXX20n: system does not support PCI bus.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: System supports PCI bus.\n"));
MULTIPORTRESTART:
if(pdev = pci_find_device(sab8253x_vendor_id, sab8253x_mpac_device_id, XX20lastpdev),
pdev == NULL)
{
printk(KERN_ALERT "auraXX20n: could not find multiport card.\n");
kfree(bptr);
return 0;
}
DEBUGPRINT((KERN_ALERT "auraXX20n: found multiport PCI serial card.\n"));
XX20lastpdev = pdev;
DEBUGPRINT((KERN_ALERT "auraXX20n: found ATI PLX 9050, %p.\n", pdev));
bptr->b_dev = *pdev;
/* the Solaris and model linux drivers
* comment that there are problems with
* getting the length via PCI operations
* seems to work for 2.4
*/
bptr->length0 = (unsigned int) pci_resource_len(pdev, 0);
bptr->length1 = (unsigned int) pci_resource_len(pdev, 1);
bptr->length2 = (unsigned int) pci_resource_len(pdev, 2);
bptr->b_irq = pdev->irq;
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 0 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 0), bptr->length0));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 1 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 1), bptr->length1));
DEBUGPRINT((KERN_ALERT
"auraXX20n: base address 2 is %p, len is %x.\n",
(void*) pci_base_address(pdev, 2),
bptr->length2));
DEBUGPRINT((KERN_ALERT "auraXX20n: interrupt is %i.\n", pdev->irq));
bus = pdev->bus->number;
devfn = pdev->devfn;
DEBUGPRINT((KERN_ALERT "auraXX20n: bus is %x, slot is %x.\n", bus, PCI_SLOT(devfn)));
pcibios_read_config_word(bus, devfn, PCI_COMMAND, &pci_command);
#if 0
/* The Aurora card does not act as a PCI master
* ugh!!
*/
new_command = pci_command | PCI_COMMAND_MASTER;
if(pci_command != new_command)
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: the PCI BIOS has not enabled this device!"
" Updating PCI command %4.4x->%4.4x.\n",
pci_command,
new_command));
pcibios_write_config_word(bus, devfn, PCI_COMMAND,
new_command);
}
else
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: the PCI BIOS has enabled this device as master!\n"));
}
#endif
if((pci_command & PCI_COMMAND_MASTER) != PCI_COMMAND_MASTER)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: Aurora card is not a bus master.\n"));
}
pcibios_read_config_byte(bus, devfn, PCI_LATENCY_TIMER,
&pci_latency);
if (pci_latency < 32)
{
DEBUGPRINT
((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is low at %i.\n", pci_latency));
/* may need to change the latency */
#if 0
pcibios_write_config_byte(bus, devfn, PCI_LATENCY_TIMER, 32);
#endif
}
else
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: PCI latency timer (CFLT) is %#x.\n",
pci_latency));
}
bptr->virtbaseaddress0 = ioremap_nocache(pci_base_address(pdev, 0),
bptr->length0);
if(bptr->virtbaseaddress0 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 0));
goto MULTIPORTRESTART;
}
bptr->b_bridge = (PLX9050*) bptr->virtbaseaddress0; /* MAKE SURE INTS ARE OFF */
writel(PLX_INT_OFF, &(bptr->b_bridge->intr));
printk(KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 0), (void*) bptr->virtbaseaddress0);
dump_ati_adapter_registers((unsigned int*) bptr->virtbaseaddress0, bptr->length0);
if(*(unsigned int*)bptr->virtbaseaddress0 == -1) /* XP7 problem? */
{
printk(KERN_ALERT
"auraXX20n: unable to access PLX 9050 registers at %p.\n",
(void*)bptr->virtbaseaddress0);
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto MULTIPORTRESTART;
}
bptr->virtbaseaddress2 = ioremap_nocache(pci_base_address(pdev, 2),
bptr->length2);
if(bptr->virtbaseaddress2 == NULL)
{
printk(KERN_ALERT
"auraXX20n: unable to remap physical address %p.\n",
(void*) pci_base_address(pdev, 2));
printk(KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)bptr->virtbaseaddress0);
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
goto MULTIPORTRESTART;
}
DEBUGPRINT((KERN_ALERT
"auraXX20n: remapped physical address %p to virtual address %p.\n",
(void*) pci_base_address(pdev, 2), (void*) bptr->virtbaseaddress2));
if (!plx9050_eprom_read(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
(unsigned short*) bptr->b_eprom,
(unsigned char) 0, EPROM9050_SIZE))
{
printk(KERN_ALERT "auraXX20n: Could not read serial eprom.\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto MULTIPORTRESTART;
}
printk(KERN_ALERT "auraXX20n: dumping serial eprom.\n");
dump_ati_adapter_registers((unsigned int*) bptr->b_eprom, 2 * EPROM9050_SIZE);
if(*(unsigned int*)bptr->b_eprom != PCIMEMVALIDMULTI) /* bridge problem? */
{
printk(KERN_ALERT "auraXX20n: unable to access valid serial eprom data.\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto MULTIPORTRESTART;
}
if(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & PREFETCHBIT)
{
++sab8253x_rebootflag;
printk(KERN_ALERT "8253x: eeprom programmed for prefetchable memory resources; must reprogram!!\n");
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WENCMD, NM93_WENADDR, 0);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
9,
(((unsigned short*) bptr->b_eprom)[EPROMPREFETCHOFFSET] & (~PREFETCHBIT)));
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WDSCMD, NM93_WDSADDR, 0);
}
/* get SYNC and ONEPORT values */
control = readl(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl);
/* note we use the actual address
* of the control register in
* memory
*/
if(control & AURORA_MULTI_SYNCBIT)
{
does_sync = 0;
}
else
{
does_sync = 1;
}
if(control & AURORA_MULTI_1PORTBIT)
{
use_1port = 1;
}
else
{
use_1port = 0;
}
/* Figure out the board */
switch(bptr->length2)
{
case AURORA_4X20_SIZE:
if(does_sync)
{
bptr->b_type = BD_4520P;
bptr->b_nchips = 2;
bptr->b_nports = 4;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD4520Pcounter; /* keep track of boardnumber for naming devices */
++BD4520Pcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 4520P.\n");
}
else
{
bptr->b_type = BD_4020P;
bptr->b_nchips = 2;
bptr->b_nports = 4;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD4020Pcounter;
++BD4020Pcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 4020P.\n");
}
break;
case AURORA_8X20_SIZE:
if(does_sync)
{
bptr->b_type = BD_8520P;
bptr->b_nchips = 1;
bptr->b_nports = 8;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD8520Pcounter;
++BD8520Pcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 8520P.\n");
}
else
{
bptr->b_type = BD_8020P;
bptr->b_nchips = 1;
bptr->b_nports = 8;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD8020Pcounter;
++BD8020Pcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 8020P.\n");
}
break;
case AURORA_2X20_SIZE:
if(does_sync)
{
if(use_1port)
{
bptr->b_type = BD_1520P;
printk(KERN_ALERT "auraXX20n: Found Saturn 1520P.\n");
bptr->b_nchips = 1;
bptr->b_nports = 1;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD1520Pcounter;
++BD1520Pcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 1520P.\n");
}
else
{
bptr->b_type = BD_2520P;
bptr->b_nchips = 1;
bptr->b_nports = 2;
bptr->b_flags = BD_SYNC;
bptr->b_cimbase = NULL;
bptr->board_number = BD2520Pcounter;
++BD2520Pcounter;
printk(KERN_ALERT "auraXX20n: Found Saturn 2520P.\n");
}
}
else
{
if(use_1port)
{
bptr->b_type = BD_1020P;
bptr->b_nchips = 1;
bptr->b_nports = 1;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD1020Pcounter;
++BD1020Pcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 1020P.\n");
}
else
{
bptr->b_type = BD_2020P;
bptr->b_nchips = 1;
bptr->b_nports = 2;
bptr->b_flags = 0x0;
bptr->b_cimbase = NULL;
bptr->board_number = BD2020Pcounter;
++BD2020Pcounter;
printk(KERN_ALERT "auraXX20n: Found Apollo 2020P.\n");
}
}
break;
default:
printk(KERN_ALERT "Error: Board could not be identified\n");
iounmap((void*)bptr->virtbaseaddress0);
bptr->virtbaseaddress0 = 0;
iounmap((void*)bptr->virtbaseaddress2);
bptr->virtbaseaddress2 = 0;
goto MULTIPORTRESTART;
}
/* Let's get the clockrate right -- ugh!*/
bptr->b_clkspeed = bptr->b_eprom[AURORA_MULTI_EPROM_CLKLSW/2];
if(bptr->b_clkspeed == -1) /* misprogrammed -- ugh. */
{
switch(bptr->b_type)
{
case BD_8520P:
case BD_8020P:
bptr->b_clkspeed = AURORA_MULTI_CLKSPEED/4;
break;
default:
bptr->b_clkspeed = AURORA_MULTI_CLKSPEED;
break;
}
printk(KERN_ALERT "auraXX20n: UNKNOWN CLOCKSPEED -- ASSUMING %ld.\n", bptr->b_clkspeed);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WENCMD, NM93_WENADDR, 0);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
54, (unsigned short) bptr->b_clkspeed);
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WRITECMD,
55, (bptr->b_clkspeed >> 16));
plx9050_eprom_cmd(&((PLX9050*)(bptr->virtbaseaddress0))->ctrl,
NM93_WDSCMD, NM93_WDSADDR, 0);
}
return bptr;
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
#ifdef MODULE
int init_module(void) /* all OS */
#else
int auraXX20_probe(struct net_device *devp) /* passed default device structure */
#endif
#else
static int __init auraXX20_probe(void) /* legacy device initialization 2.4.* */
#endif
{
SAB_BOARD *boardptr;
SAB_PORT *portptr;
struct net_device *dev;
unsigned int result;
unsigned int namelength;
unsigned int portno;
int intr_val;
int mp_probe_count = 0; /* multiport count */
int cp_probe_count = 0; /* compact pci count */
int wm_probe_count = 0; /* wan multiserver count */
printk(KERN_ALERT "aurora interea miseris mortalibus almam extulerat lucem\n");
printk(KERN_ALERT " referens opera atque labores\n");
memset(AuraBoardESCC8IrqRoot, 0, sizeof(AuraBoardESCC8IrqRoot));
memset(AuraBoardESCC2IrqRoot, 0, sizeof(AuraBoardESCC2IrqRoot));
memset(AuraBoardMCSIrqRoot, 0, sizeof(AuraBoardMCSIrqRoot));
#if !defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
if(do_probe == 0)
return -1; /* only allow to be called one 2.2.* */
do_probe = 0;
#endif
fn_init_crc_table(); /* used in faking ethernet packets for */
/* the network driver -- crcs are currently */
/* not being checked by this software */
/* but is good to have them in case a frame */
/* passes through a WAN LAN bridge */
sab8253x_setup_ttydriver(); /* add synchronous tty and synchronous network
driver initialization */
AuraBoardRoot = NULL; /* basic lists */
AuraChipRoot = NULL;
AuraPortRoot = NULL;
NumSab8253xPorts = 0;
AuraXX20DriverParams.debug = auraXX20n_debug;
AuraXX20DriverParams.listsize = sab8253xn_listsize;
if(auraXX20n_name != 0)
{
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
auraXX20n_prototype.name = auraXX20n_name;
#else
strcpy(auraXX20n_prototype.name, auraXX20n_name);
#endif
}
/* find all multiport cards */
XX20lastpdev = NULL;
while(1)
{
boardptr = find_ati_multiport_card();
if(boardptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: found %d AURAXX20 multiport device%s.\n",
mp_probe_count, ((mp_probe_count == 1) ? "" : "s"));
break;
}
boardptr->nextboard = AuraBoardRoot;
AuraBoardRoot = boardptr;
printk(KERN_ALERT "auraXX20n: found AURAXX20 multiport device #%d.\n",
mp_probe_count);
++mp_probe_count;
}
/* find all cpci cards */
XX20lastpdev = NULL;
while(1)
{
boardptr = find_ati_cpci_card();
if(boardptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: found %d AURAXX20 CPCI device%s.\n",
cp_probe_count, ((cp_probe_count == 1) ? "" : "s"));
break;
}
boardptr->nextboard = AuraBoardRoot;
AuraBoardRoot = boardptr;
printk(KERN_ALERT "auraXX20n: found AURAXX20 CPCI device #%d.\n",
cp_probe_count);
++cp_probe_count;
}
/* find all WAN MS cards */
XX20lastpdev = NULL;
while(1)
{
boardptr = find_ati_wanms_card();
if(boardptr == NULL)
{
printk(KERN_ALERT
"auraXX20n: found %d AURAXX20 WANMS device%s.\n",
wm_probe_count, ((wm_probe_count == 1) ? "" : "s"));
break;
}
boardptr->nextboard = AuraBoardRoot;
AuraBoardRoot = boardptr;
printk(KERN_ALERT "auraXX20n: found AURAXX20 WANMS device #%d.\n",
wm_probe_count);
++wm_probe_count;
}
/* Now do the chips! */
for(boardptr = AuraBoardRoot; boardptr != NULL; boardptr = boardptr->nextboard)
{
SetupAllChips(boardptr); /* sets up the ports on the chips */
}
/* set up global driver structures
* for async tty, call out device
* for sync tty and for network device
*/
/* NOW TURN ON THE PLX INTS */
/* note all port ints (only receive right now)
* are off */
/* interrupts cannot be turned on by port
this seems to be the only sensible place
to do it*/
/* only at this point is the number of
* ttys to be created known. */
if(finish_sab8253x_setup_ttydriver() == -1) /* only as many termios are allocated */
/* as needed */
{
return 0;
}
for(portno = 0, portptr = AuraPortRoot; portptr != NULL; ++portno, portptr = portptr->next)
{
portptr->line = portno; /* set up the line number == minor dev associated with port */
portptr->sigmode = sab8253x_default_sp502_mode;
/* if we have SP502s let getty work with RS232 by default */
/* unless overridden in module setup. */
}
/* Now lets set up the network devices */
for(portno = 0, portptr = AuraPortRoot; portptr != NULL; ++portno, portptr = portptr->next)
{
dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
if(!dev)
{
break;
}
memset(dev, 0, sizeof(struct net_device));
*dev = auraXX20n_prototype;
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
dev->name = kmalloc(IFNAMSIZ+1, GFP_KERNEL);
if(!dev->name)
{
kfree(dev);
break;
}
#endif
namelength = MIN(strlen(auraXX20n_prototype.name), IFNAMSIZ);
strcpy(dev->name, auraXX20n_prototype.name);
sprintf(&dev->name[namelength-1], "%3.3d", portno);
#if 1
current_sab_port = portptr;
#else
dev->priv = portptr;
#endif
result = register_netdev(dev);
if(result)
{ /* if we run into some internal kernel limit */
break;
}
printk(KERN_ALERT "sab8253xn: found sab8253x network device #%d.\n",
portno);
}
printk(KERN_ALERT
"sab8253xn: found %d sab8253x network device%s.\n",
portno, ((portno == 1) ? "" : "s"));
/* Now lets set up the character device */
if(sab8253xc_name)
{
result = register_chrdev(sab8253xc_major, sab8253xc_name, &sab8253xc_fops);
if(result < 0)
{
sab8253xc_major = result;
printk(KERN_ALERT "Could not install sab8253xc device.\n");
}
else if(result > 0)
{
sab8253xc_major = result;
}
}
for(boardptr = AuraBoardRoot; boardptr != NULL; boardptr = boardptr->nextboard)
{ /* let's set up port interrupt lists */
intr_val = boardptr->b_irq;
if((intr_val < 0) || (intr_val >= NUMINTS))
{
printk(KERN_ALERT "sab8253xn: bad interrupt %i board %p.\n", intr_val, boardptr);
continue;
}
switch(boardptr->b_type)
{
case BD_WANMCS:
boardptr->next_on_interrupt = AuraBoardMCSIrqRoot[intr_val];
AuraBoardMCSIrqRoot[intr_val] = boardptr;
break;
case BD_8520P:
case BD_8520CP:
boardptr->next_on_interrupt = AuraBoardESCC8IrqRoot[intr_val];
AuraBoardESCC8IrqRoot[intr_val] = boardptr;
break;
default:
boardptr->next_on_interrupt = AuraBoardESCC2IrqRoot[intr_val];
AuraBoardESCC2IrqRoot[intr_val] = boardptr;
break;
}
}
for(intr_val = 0; intr_val < NUMINTS; ++intr_val) /* trying to install as few int handlers as possible */
{ /* one for each group of boards on a given irq */
if((AuraBoardESCC2IrqRoot[intr_val] != NULL) || (AuraBoardESCC8IrqRoot[intr_val] != NULL) ||
(AuraBoardMCSIrqRoot[intr_val] != NULL))
{
if (request_irq(intr_val, sab8253x_interrupt, SA_SHIRQ,
"sab8253x", &AuraBoardESCC2IrqRoot[intr_val]) == 0)
/* interrupts on perboard basis
* cycle through chips and then
* ports */
/* NOTE PLX INTS ARE OFF -- so turn them on */
{
for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
writel(PLX_INT_ON, &(boardptr->b_bridge->intr));
}
for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
writel(PLX_INT_ON, &(boardptr->b_bridge->intr));
}
for(boardptr = AuraBoardMCSIrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
/* write to the MIC csr to reset the PCI interrupt */
writeb(0, (unsigned char*)(boardptr->MICCMD_REG + MICCMD_MICCSR));
/* now, write to the CIM interrupt ena to re-enable interrupt generation */
writeb(0, (unsigned char*)(boardptr->CIMCMD_REG + CIMCMD_WRINTENA));
/* now, activate PCI interrupts */
writel(AMCC_AOINTPINENA, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR));
}
}
else
{
printk(KERN_ALERT "Unable to get interrupt, board set up not complete %i.\n", intr_val);
}
}
}
/* all done! a lot of work */
#if !defined(MODULE) && (LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0))
return -1; /* otherwise 2.2 probe uses up
* a default device structure*/
#else
return 0;
#endif
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
#ifdef MODULE
/* cleanup module/free up virtual memory */
/* space*/
void cleanup_module(void)
#endif
#else
void auraXX20_cleanup(void)
#endif
{
SAB_BOARD *boardptr;
SAB_CHIP *chipptr;
SAB_PORT *portptr;
AURA_CIM *cimptr;
int intr_val;
extern void sab8253x_cleanup_ttydriver(void);
printk(KERN_ALERT "auraXX20n: unloading AURAXX20 driver.\n");
sab8253x_cleanup_ttydriver(); /* clean up tty */
/* unallocate and turn off ints */
for(intr_val = 0; intr_val < NUMINTS; ++intr_val)
{
if((AuraBoardESCC2IrqRoot[intr_val] != NULL) || (AuraBoardESCC8IrqRoot[intr_val] != NULL) ||
(AuraBoardMCSIrqRoot[intr_val] != NULL))
{
for(boardptr = AuraBoardESCC2IrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
}
for(boardptr = AuraBoardESCC8IrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
writel(PLX_INT_OFF, &(boardptr->b_bridge->intr));
}
for(boardptr = AuraBoardMCSIrqRoot[intr_val]; boardptr != NULL;
boardptr = boardptr->next_on_interrupt)
{
writel(AMCC_INT_OFF, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR));
(void) wanmcs_reset(boardptr);
writel(AMCC_INT_OFF, (unsigned int*)(boardptr->AMCC_REG + AMCC_INTCSR));
}
free_irq(intr_val, &AuraBoardESCC2IrqRoot[intr_val]); /* free up board int
* note that if two boards
* share an int, two int
* handlers were registered
*
*/
}
}
/* disable chips and free board memory*/
while(AuraBoardRoot)
{
boardptr = AuraBoardRoot;
for(chipptr = boardptr->board_chipbase; chipptr != NULL; chipptr = chipptr->next_by_board)
{
(*chipptr->int_disable)(chipptr); /* make sure no ints can come int */
}
AuraBoardRoot = boardptr->nextboard;
if(boardptr->b_type == BD_WANMCS)
{
if(boardptr->virtbaseaddress0 != 0)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress0));
iounmap((void*)boardptr->virtbaseaddress0);
boardptr->virtbaseaddress0 = 0;
}
if(boardptr->virtbaseaddress1 != 0)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress1));
iounmap((void*)boardptr->virtbaseaddress1);
boardptr->virtbaseaddress1 = 0;
}
if(boardptr->virtbaseaddress2 != 0)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress2));
iounmap((void*)boardptr->virtbaseaddress2);
boardptr->virtbaseaddress2 = 0;
}
if(boardptr->virtbaseaddress3 != 0)
{
DEBUGPRINT((KERN_ALERT "auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress3));
iounmap((void*)boardptr->virtbaseaddress3);
boardptr->virtbaseaddress3 = 0;
}
}
else /* everything but wan multichannel servers */
{
if(boardptr->virtbaseaddress0)
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress0));
iounmap((void*)boardptr->virtbaseaddress0);
boardptr->virtbaseaddress0 = 0;
}
if(boardptr->virtbaseaddress2)
{
DEBUGPRINT((KERN_ALERT
"auraXX20n: unmapping virtual address %p.\n",
(void*)boardptr->virtbaseaddress2));
iounmap((void*)boardptr->virtbaseaddress2);
boardptr->virtbaseaddress2 = 0;
}
}
kfree(boardptr);
}
while(AuraCimRoot)
{
cimptr = AuraCimRoot;
AuraCimRoot = cimptr->next;
kfree(cimptr);
}
while(AuraChipRoot) /* free chip memory */
{
chipptr = AuraChipRoot;
AuraChipRoot = chipptr->next;
kfree(chipptr);
}
if(sab8253xc_name && (sab8253xc_major > 0)) /* unregister the chr device */
{
unregister_chrdev(sab8253xc_major, sab8253xc_name);
}
while(Sab8253xRoot) /* free up network stuff */
{
SAB_PORT *priv;
priv = (SAB_PORT *)Sab8253xRoot->priv;
unregister_netdev(Sab8253xRoot);
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 0)
kfree(Sab8253xRoot.name);
#endif
kfree(Sab8253xRoot);
Sab8253xRoot = priv->next_dev;
}
while(AuraPortRoot) /* free up port memory */
{
portptr = AuraPortRoot;
AuraPortRoot = portptr->next;
if(portptr->dcontrol2.receive)
{
kfree(portptr->dcontrol2.receive);
}
if(portptr->dcontrol2.transmit)
{
kfree(portptr->dcontrol2.transmit);
}
kfree(portptr);
}
}
/*
* Hardware dependent read and write functions.
* We have functions to write/read a byte, write/read
* a word and read and write the FIFO
*/
/***************************************************************************
* aura_readb: Function to read a byte on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the register
*
* Return value : The value of the register.
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static unsigned char aura_readb(struct sab_port *port, unsigned char *reg)
{
return readb(reg);
}
/***************************************************************************
* aura_writeb: Function to write a byte on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the register
* val: The value to put into the register
*
* Return value : None
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static void aura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val)
{
writeb(val,reg);
}
/***************************************************************************
* aura_readw: Function to read a word on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the hw memory to access
*
* Return value : The value of the memory area.
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static unsigned short aura_readw(struct sab_port *port, unsigned short *reg)
{
return readw(reg);
}
/***************************************************************************
* aura_writew: Function to write a word on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the hw memory to access
* val: The value to put into the register
*
* Return value : The value of the memory area.
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static void aura_writew(struct sab_port *port, unsigned short *reg,unsigned short val)
{
writew(val,reg);
}
/***************************************************************************
* aura_readfifo: Function to read the FIFO on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
* buf: The address of a buffer where we should put
* what we read
* nbytes: How many chars to read.
*
* Return value : none
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 13 2000, creation
***************************************************************************/
static void aura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes)
{
int i;
unsigned short *wptr = (unsigned short*) buf;
int nwords = ((nbytes+1)/2);
for(i = 0; i < nwords; i ++)
{
wptr[i] = readw(((unsigned short *)port->regs));
}
}
/***************************************************************************
* aura_writefifo: Function to write the FIFO on a 4X20P, 8X20P or Sun serial
*
*
* Parameters :
* port: The port being accessed
*
* Return value : none
*
* Prerequisite : The port must have been opened
*
* Remark :
*
* Author : fw
*
* Revision : Oct 13 2000, creation
***************************************************************************/
static void aura_writefifo(struct sab_port *port)
{
int i,max,maxw;
unsigned short *wptr;
unsigned char buffer[32];
if(port->xmit_cnt <= 0)
{
return;
}
max= (port->xmit_fifo_size < port->xmit_cnt) ? port->xmit_fifo_size : port->xmit_cnt;
for (i = 0; i < max; i++)
{
buffer[i] = port->xmit_buf[port->xmit_tail++];
port->xmit_tail &= (SAB8253X_XMIT_SIZE - 1);
port->icount.tx++;
port->xmit_cnt--;
}
maxw = max/2;
wptr = (unsigned short*) buffer;
for(i = 0; i < maxw; ++i)
{
writew(wptr[i], (unsigned short *)port->regs);
}
if(max & 1)
{
writeb(buffer[max-1], (unsigned char*)port->regs);
}
}
/***************************************************************************
* wmsaura_readb: Function to read a byte on a LMS, WMS
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the register
*
* Return value : The value of the register.
*
* Prerequisite : The port must have been opened
*
* Remark : TO BE IMPLEMENTED
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static unsigned char wmsaura_readb(struct sab_port *port, unsigned char *reg)
{
return readb((unsigned char*) (((unsigned int) reg) + CIMCMD_RDREGB));
}
/***************************************************************************
* wmsaura_writeb: Function to write a byte on a LMS, WMS
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the register
* val: The value to put into the register
*
* Return value : None
*
* Prerequisite : The port must have been opened
*
* Remark : TO BE IMPLEMENTED
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static void wmsaura_writeb(struct sab_port *port, unsigned char *reg,unsigned char val)
{
writeb(val, (unsigned char*) (((unsigned int) reg) + CIMCMD_WRREGB));
}
/***************************************************************************
* wmsaura_readw: Function to read a word on a LMS, WMS
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the hw memory to access
*
* Return value : The value of the memory area.
*
* Prerequisite : The port must have been opened
*
* Remark : TO BE IMPLEMENTED
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static unsigned short wmsaura_readw(struct sab_port *port, unsigned short *reg)
{
unsigned short readval;
unsigned int address;
address = (unsigned int) reg;
readval = readb((unsigned char*) (address + CIMCMD_RDREGB));
++address;
return (readval | (readb((unsigned char*) (address + CIMCMD_RDREGB)) << 8));
}
/***************************************************************************
* wmsaura_writew: Function to write a word on a LMS, WMS
*
*
* Parameters :
* port: The port being accessed
* reg: The address of the hw memory to access
* val: The value to put into the register
*
* Return value : The value of the memory area.
*
* Prerequisite : The port must have been opened
*
* Remark : TO BE IMPLEMENTED
*
* Author : fw
*
* Revision : Oct 10 2000, creation
***************************************************************************/
static void wmsaura_writew(struct sab_port *port, unsigned short *reg, unsigned short val)
{
unsigned char vallow;
unsigned char valhigh;
unsigned int address;
address = (unsigned int) reg;
vallow = (unsigned char) val;
valhigh = (unsigned char) (val >> 8);
writeb(vallow, (unsigned char*) (address + CIMCMD_WRREGB));
++address;
writeb(valhigh, (unsigned char*) (address + CIMCMD_WRREGB));
}
static void wmsaura_readfifo(struct sab_port *port, unsigned char *buf, unsigned int nbytes)
{
#ifdef FIFO_DIRECT
unsigned short fifo[32/2]; /* this array is word aligned
* buf may not be word aligned*/
unsigned int nwords;
int i;
int wcount;
unsigned int address;
if (nbytes == 0)
{
return;
}
wcount = ((nbytes + 1) >> 1);
/* Read the thing into the local FIFO and copy it out. */
address = (unsigned int) port->regs;
for(i = 0; i < wcount; ++i)
{
fifo[i] = readw((unsigned short*)(address + CIMCMD_RDFIFOW));
}
memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned int) nbytes);
#else /* FIFO_DIRECT */
unsigned short fifo[32/2];
int i;
int wcount;
SAB_BOARD *bptr;
unsigned int channel;
if (nbytes == 0)
{
return;
}
bptr = port->board;
wcount = ((nbytes + 1) >> 1);
channel = (((unsigned char*) port->regs) - bptr->CIMCMD_REG); /* should be properly shifted */
/*
* Trigger a cache read by writing the nwords - 1 to the
* magic place.
*/
writeb((unsigned char) wcount, bptr->MICCMD_REG + (MICCMD_CACHETRIG + channel));
/*
* Now, read out the contents.
*/
channel >>= 1;
for(i = 0; i < wcount; ++i)
{
fifo[i] = readw((unsigned short*)(bptr->FIFOCACHE_REG + (channel + (i << 1))));
}
memcpy((unsigned char*) buf, (unsigned char*) &(fifo[0]), (unsigned int) nbytes);
#endif /* !FIFO_DIRECT */
}
static void wmsaura_writefifo(struct sab_port *port)
{
unsigned short fifo[32/2];
unsigned char* fifob = (unsigned char*) fifo;
int i,max;
int wcount;
unsigned int address;
if(port->xmit_cnt <= 0)
{
return;
}
max = (port->xmit_fifo_size < port->xmit_cnt) ? port->xmit_fifo_size:port->xmit_cnt;
for (i = 0; i < max; i++)
{
fifob[i] = port->xmit_buf[port->xmit_tail++];
port->xmit_tail &= (SAB8253X_XMIT_SIZE - 1);
port->icount.tx++;
port->xmit_cnt--;
}
wcount = (max >> 1);
/* Copy from the linear local FIFO into the hardware fifo. */
address = (unsigned int) port->regs;
for(i = 0; i < wcount; ++i)
{
writew(fifo[i], (unsigned short*)(address + CIMCMD_WRFIFOW));
}
if(max & 1) /* odd byte */
{
--max;
writeb(fifob[max], (unsigned short*)(address + CIMCMD_WRFIFOB));
}
}
module_init(auraXX20_probe);
module_exit(auraXX20_cleanup);
MODULE_DESCRIPTION("Aurora Multiport Multiprotocol Serial Driver");
MODULE_AUTHOR("Joachim Martillo <martillo@telfordtools.com>");