Initial version

This commit is contained in:
Karsten Keil 1999-07-01 08:07:59 +00:00
parent c10db89681
commit c618e1bea3
10 changed files with 3847 additions and 0 deletions

View File

@ -0,0 +1,385 @@
/* $Id$
* bkm_a4t.c low level stuff for T-Berkom A4T
* derived from the original file sedlbauer.c
* derived from the original file niccy.c
* derived from the original file netjet.c
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
#include "bkm_ax.h"
#include <linux/pci.h>
#ifndef COMPAT_HAS_NEW_PCI
#include <linux/bios32.h>
#endif
extern const char *CardType[];
const char *bkm_a4t_revision = "$Revision$";
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_int ret;
long flags;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
save_flags(flags);
cli();
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_READ);
__WAITI20__(po);
ret = *po;
restore_flags(flags);
return ((unsigned char) ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo read without cli because it's allready done */
int i;
for (i = 0; i < size; i++)
*data++ = readreg(ale, adr, off);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
unsigned int *po = (unsigned int *) adr; /* Postoffice */
save_flags(flags);
cli();
*po = (GCS_2 | PO_WRITE | off);
__WAITI20__(po);
*po = (ale | PO_WRITE | data);
__WAITI20__(po);
restore_flags(flags);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo write without cli because it's allready done */
int i;
for (i = 0; i < size; i++)
writereg(ale, adr, off, *data++);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
readfifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
writefifo(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, 0, data, size);
}
static u_char
ReadJADE(struct IsdnCardState *cs, int jade, u_char offset)
{
return (readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80))));
}
static void
WriteJADE(struct IsdnCardState *cs, int jade, u_char offset, u_char value)
{
writereg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, offset + (jade == -1 ? 0 : (jade ? 0xC0 : 0x80)), value);
}
/*
* fast interrupt JADE stuff goes here
*/
#define READJADE(cs, nr, reg) readreg(cs->hw.ax.jade_ale,\
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)))
#define WRITEJADE(cs, nr, reg, data) writereg(cs->hw.ax.jade_ale,\
cs->hw.ax.jade_adr, reg + (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), data)
#define READJADEFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.jade_ale,\
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#define WRITEJADEFIFO(cs, nr, ptr, cnt) writefifo( cs->hw.ax.jade_ale,\
cs->hw.ax.jade_adr, (nr == -1 ? 0 : (nr ? 0xC0 : 0x80)), ptr, cnt)
#include "jade_irq.c"
static void
bkm_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val = 0;
I20_REGISTER_FILE *pI20_Regs;
if (!cs) {
printk(KERN_WARNING "HiSax: Telekom A4T: Spurious interrupt!\n");
return;
}
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
/* ISDN interrupt pending? */
if (pI20_Regs->i20IntStatus & intISDN) {
/* Reset the ISDN interrupt */
pI20_Regs->i20IntStatus = intISDN;
/* Disable ISDN interrupt */
pI20_Regs->i20IntCtrl &= ~intISDN;
/* Channel A first */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0x80);
if (val) {
jade_int_main(cs, val, 0);
}
/* Channel B */
val = readreg(cs->hw.ax.jade_ale, cs->hw.ax.jade_adr, jade_HDLC_ISR + 0xC0);
if (val) {
jade_int_main(cs, val, 1);
}
/* D-Channel */
val = readreg(cs->hw.ax.isac_ale, cs->hw.ax.isac_adr, ISAC_ISTA);
if (val) {
isac_interrupt(cs, val);
}
/* Reenable ISDN interrupt */
pI20_Regs->i20IntCtrl |= intISDN;
}
}
void
release_io_bkm(struct IsdnCardState *cs)
{
if (cs->hw.ax.base) {
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
}
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if (bEnable)
pI20_Regs->i20IntCtrl |= (intISDN | intPCI);
else
/* CAUTION: This disables the video capture driver too */
pI20_Regs->i20IntCtrl &= ~(intISDN | intPCI);
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
long flags;
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
I20_REGISTER_FILE *pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
save_flags(flags);
sti();
/* Issue the I20 soft reset */
pI20_Regs->i20SysControl = 0xFF; /* all in */
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
pI20_Regs->i20SysControl = sysRESET | 0xFF;
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
/* Set our configuration */
pI20_Regs->i20SysControl = sysRESET | sysCFG;
/* Issue ISDN reset */
pI20_Regs->i20GuestControl = guestWAIT_CFG |
g_A4T_JADE_RES |
g_A4T_ISAR_RES |
g_A4T_ISAC_RES |
g_A4T_JADE_BOOTR |
g_A4T_ISAR_BOOTR;
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
/* Remove RESET state from ISDN */
pI20_Regs->i20GuestControl &= ~(g_A4T_ISAC_RES |
g_A4T_JADE_RES |
g_A4T_ISAR_RES);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
switch (mt) {
case CARD_RESET:
/* Disable ints */
enable_bkm_int(cs, 0);
reset_bkm(cs);
return (0);
case CARD_RELEASE:
/* Sanity */
enable_bkm_int(cs, 0);
reset_bkm(cs);
release_io_bkm(cs);
return (0);
case CARD_SETIRQ:
return (request_irq(cs->irq, &bkm_interrupt, I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs));
case CARD_INIT:
clear_pending_isac_ints(cs);
clear_pending_jade_ints(cs);
initisac(cs);
initjade(cs);
/* Enable ints */
enable_bkm_int(cs, 1);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_a4t __initdata = NULL;
#else
static int pci_index __initdata = 0;
#endif
__initfunc(int
setup_bkm_a4t(struct IsdnCard *card))
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
u_int pci_memaddr = 0, found = 0;
I20_REGISTER_FILE *pI20_Regs;
#if CONFIG_PCI
#ifndef COMPAT_HAS_NEW_PCI
u_char pci_bus, pci_device_fn, pci_irq = 0;
#endif
#endif
strcpy(tmp, bkm_a4t_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_BKM_A4T) {
cs->subtyp = BKM_A4T;
} else
return (0);
#if CONFIG_PCI
#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
return (0);
}
if ((dev_a4t = pci_find_device(I20_VENDOR_ID, I20_DEVICE_ID, dev_a4t))) {
u_int sub_sys_id = 0;
pci_read_config_dword(dev_a4t, PCI_SUBSYSTEM_ID, &sub_sys_id);
if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
found = 1;
pci_memaddr = dev_a4t->base_address[0];
cs->irq = dev_a4t->irq;
}
}
#else
for (; pci_index < 0xff; pci_index++) {
if (pcibios_find_device(I20_VENDOR_ID,
I20_DEVICE_ID,
pci_index,
&pci_bus,
&pci_device_fn) == PCIBIOS_SUCCESSFUL) {
u_int sub_sys_id = 0;
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_SUBSYSTEM_ID, &sub_sys_id);
if (sub_sys_id == ((A4T_SUBSYS_ID << 16) | A4T_SUBVEN_ID)) {
found = 1;
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &pci_irq);
cs->irq = pci_irq;
pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &pci_memaddr);
break;
}
}
}
#endif /* COMPAT_HAS_NEW_PCI */
if (!found) {
printk(KERN_WARNING "HiSax: %s: Card not found\n", CardType[card->typ]);
return (0);
}
#ifndef COMPAT_HAS_NEW_PCI
pci_index++;
#endif
if (!cs->irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: %s: No IRQ\n", CardType[card->typ]);
return (0);
}
if (!pci_memaddr) {
printk(KERN_WARNING "HiSax: %s: No Memory base address\n", CardType[card->typ]);
return (0);
}
pci_memaddr &= PCI_BASE_ADDRESS_MEM_MASK;
cs->hw.ax.base = (u_int) ioremap(pci_memaddr, 4096);
/* Check suspecious address */
pI20_Regs = (I20_REGISTER_FILE *) (cs->hw.ax.base);
if ((pI20_Regs->i20IntStatus & 0x8EFFFFFF) != 0) {
printk(KERN_WARNING "HiSax: %s address %x-%x suspecious\n",
CardType[card->typ], cs->hw.ax.base, cs->hw.ax.base + 4096);
iounmap((void *) cs->hw.ax.base);
cs->hw.ax.base = 0;
return (0);
}
cs->hw.ax.isac_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.jade_adr = cs->hw.ax.base + PO_OFFSET;
cs->hw.ax.isac_ale = GCS_1;
cs->hw.ax.jade_ale = GCS_3;
#else
printk(KERN_WARNING "HiSax: %s: NO_PCI_BIOS\n", CardType[card->typ]);
printk(KERN_WARNING "HiSax: %s: unable to configure\n", CardType[card->typ]);
return (0);
#endif /* CONFIG_PCI */
printk(KERN_INFO "HiSax: %s: Card configured at 0x%X IRQ %d\n",
CardType[card->typ], cs->hw.ax.base, cs->irq);
reset_bkm(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadJADE;
cs->BC_Write_Reg = &WriteJADE;
cs->BC_Send_Data = &jade_fill_fifo;
cs->cardmsg = &BKM_card_msg;
ISACVersion(cs, "Telekom A4T:");
/* Jade version */
JadeVersion(cs, "Telekom A4T:");
return (1);
}

511
drivers/isdn/hisax/bkm_a8.c Normal file
View File

@ -0,0 +1,511 @@
/* $Id$
* bkm_a8.c low level stuff for Scitel Quadro (4*S0, passive)
* derived from the original file sedlbauer.c
* derived from the original file niccy.c
* derived from the original file netjet.c
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isac.h"
#include "ipac.h"
#include "hscx.h"
#include "isdnl1.h"
#include "bkm_ax.h"
#include <linux/pci.h>
#ifndef COMPAT_HAS_NEW_PCI
#include <linux/bios32.h>
#endif
#define ATTEMPT_PCI_REMAPPING /* Required for PLX rev 1 */
extern const char *CardType[];
const char sct_quadro_revision[] = "$Revision$";
/* To survive the startup phase */
typedef struct {
u_int active; /* true/false */
u_int base; /* ipac base address */
} IPAC_STATE;
static IPAC_STATE ipac_state[4 + 1] __initdata =
{
{0, 0}, /* dummy */
{0, 0}, /* SCT_1 */
{0, 0}, /* SCT_2 */
{0, 0}, /* SCT_3 */
{0, 0} /* SCT_4 */
};
static const char *sct_quadro_subtypes[] =
{
"",
"#1",
"#2",
"#3",
"#4"
};
#define wordout(addr,val) outw(val,addr)
#define wordin(addr) inw(addr)
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
long flags;
save_flags(flags);
cli();
wordout(ale, off);
ret = wordin(adr) & 0xFF;
restore_flags(flags);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo read without cli because it's allready done */
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
data[i] = wordin(adr) & 0xFF;
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
save_flags(flags);
cli();
wordout(ale, off);
wordout(adr, data);
restore_flags(flags);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo write without cli because it's allready done */
int i;
wordout(ale, off);
for (i = 0; i < size; i++)
wordout(adr, data[i]);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset | 0x80, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
readfifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
writefifo(cs->hw.ax.base, cs->hw.ax.data_adr, 0x80, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, offset + (hscx ? 0x40 : 0), value);
}
/* Check whether the specified ipac is already active or not */
static int
is_ipac_active(u_int ipac_nr)
{
return (ipac_state[ipac_nr].active);
}
/* Set the specific ipac to active */
static void
set_ipac_active(u_int ipac_nr, u_int active)
{
/* set activation state */
ipac_state[ipac_nr].active = active;
}
/*
* fast interrupt HSCX stuff goes here
*/
#define READHSCX(cs, nr, reg) readreg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.ax.base, \
cs->hw.ax.data_adr, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.ax.base, \
cs->hw.ax.data_adr, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static void
bkm_interrupt_ipac(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char ista, val, icnt = 20;
int i;
if (!cs) {
printk(KERN_WARNING "HiSax: Scitel Quadro: Spurious interrupt!\n");
return;
}
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
Start_IPAC:
if (cs->debug & L1_DEB_IPAC)
debugl1(cs, "IPAC ISTA %02X", ista);
if (ista & 0x0f) {
val = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, HSCX_ISTA + 0x40);
if (ista & 0x01)
val |= 0x01;
if (ista & 0x04)
val |= 0x02;
if (ista & 0x08)
val |= 0x04;
if (val) {
hscx_int_main(cs, val);
}
}
if (ista & 0x20) {
val = 0xfe & readreg(cs->hw.ax.base, cs->hw.ax.data_adr, ISAC_ISTA | 0x80);
if (val) {
isac_interrupt(cs, val);
}
}
if (ista & 0x10) {
val = 0x01;
isac_interrupt(cs, val);
}
ista = readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ISTA);
if ((ista & 0x3f) && icnt) {
icnt--;
goto Start_IPAC;
}
if (!icnt)
printk(KERN_WARNING "HiSax: %s (%s) IRQ LOOP\n",
CardType[cs->typ],
sct_quadro_subtypes[cs->subtyp]);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xFF);
writereg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_MASK, 0xC0);
/* Read out all interrupt sources from currently not active ipacs */
/* "Handle" all interrupts from currently not active ipac by reading the regs */
for (i = SCT_1; i <= SCT_4; i++)
if (!is_ipac_active(i)) {
u_int base = ipac_state[i].base;
if (readreg(base, base + 4, 0xC1)) {
readreg(base, base + 4, 0xA0);
readreg(base, base + 4, 0xA4);
readreg(base, base + 4, 0x20);
readreg(base, base + 4, 0x24);
readreg(base, base + 4, 0x60);
readreg(base, base + 4, 0x64);
readreg(base, base + 4, 0xC1);
readreg(base, base + 4, ISAC_CIR0 + 0x80);
}
}
}
void
release_io_sct_quadro(struct IsdnCardState *cs)
{
/* ?? */
}
static void
enable_bkm_int(struct IsdnCardState *cs, unsigned bEnable)
{
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
if (bEnable)
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) | 0x41));
else
/* Issue general di only if no ipac is active */
if (!is_ipac_active(SCT_1) &&
!is_ipac_active(SCT_2) &&
!is_ipac_active(SCT_3) &&
!is_ipac_active(SCT_4))
wordout(cs->hw.ax.plx_adr + 0x4C, (wordin(cs->hw.ax.plx_adr + 0x4C) & ~0x41));
}
}
static void
reset_bkm(struct IsdnCardState *cs)
{
long flags;
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
if (!is_ipac_active(SCT_1) &&
!is_ipac_active(SCT_2) &&
!is_ipac_active(SCT_3) &&
!is_ipac_active(SCT_4)) {
/* Issue total reset only if no ipac is active */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) & ~4));
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
/* Remove the soft reset */
wordout(cs->hw.ax.plx_adr + 0x50, (wordin(cs->hw.ax.plx_adr + 0x50) | 4));
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10 * HZ) / 1000);
restore_flags(flags);
}
}
}
static int
BKM_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
switch (mt) {
case CARD_RESET:
/* Disable ints */
set_ipac_active(cs->subtyp, 0);
enable_bkm_int(cs, 0);
reset_bkm(cs);
return (0);
case CARD_RELEASE:
/* Sanity */
set_ipac_active(cs->subtyp, 0);
enable_bkm_int(cs, 0);
reset_bkm(cs);
release_io_sct_quadro(cs);
return (0);
case CARD_SETIRQ:
return (request_irq(cs->irq, &bkm_interrupt_ipac, I4L_IRQ_FLAG | SA_SHIRQ, "HiSax", cs));
case CARD_INIT:
cs->debug |= L1_DEB_IPAC;
set_ipac_active(cs->subtyp, 1);
inithscxisac(cs, 3);
/* Enable ints */
enable_bkm_int(cs, 1);
return (0);
case CARD_TEST:
return (0);
}
return (0);
}
#ifdef COMPAT_HAS_NEW_PCI
static struct pci_dev *dev_a8 __initdata = NULL;
#else
static int pci_index __initdata = 0;
#endif
__initfunc(int
setup_sct_quadro(struct IsdnCard *card))
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
#if CONFIG_PCI
u_char pci_bus = 0, pci_device_fn = 0, pci_irq = 0, pci_rev_id;
u_int found = 0;
u_int pci_ioaddr1, pci_ioaddr2, pci_ioaddr3, pci_ioaddr4, pci_ioaddr5;
#endif
strcpy(tmp, sct_quadro_revision);
printk(KERN_INFO "HiSax: T-Berkom driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ == ISDN_CTYPE_SCT_QUADRO) {
cs->subtyp = SCT_1; /* Preset */
} else
return (0);
/* Identify subtype by para[0] */
if (card->para[0] >= SCT_1 && card->para[0] <= SCT_4)
cs->subtyp = card->para[0];
else
printk(KERN_WARNING "HiSax: %s: Invalid subcontroller in configuration, default to 1\n",
CardType[card->typ]);
#if CONFIG_PCI
#ifdef COMPAT_HAS_NEW_PCI
if (!pci_present()) {
printk(KERN_ERR "bkm_a4t: no PCI bus present\n");
return (0);
}
if ((dev_a8 = pci_find_device(PLX_VENDOR_ID, PLX_DEVICE_ID, dev_a8))) {
u_int sub_sys_id = 0;
pci_read_config_dword(dev_a8, PCI_SUBSYSTEM_ID, &sub_sys_id);
if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
found = 1;
pci_ioaddr1 = dev_a8->base_address[1];
pci_irq = dev_a8->irq;
pci_bus = dev_a8->bus->number;
pci_device_fn = dev_a8->devfn;
}
}
#else
for (; pci_index < 0xff; pci_index++) {
if (pcibios_find_device(
PLX_VENDOR_ID,
PLX_DEVICE_ID,
pci_index,
&pci_bus,
&pci_device_fn) == PCIBIOS_SUCCESSFUL) {
u_int sub_sys_id = 0;
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_SUBSYSTEM_ID, &sub_sys_id);
if (sub_sys_id == ((SCT_SUBSYS_ID << 16) | SCT_SUBVEN_ID)) {
found = 1;
pcibios_read_config_byte(pci_bus, pci_device_fn,
PCI_INTERRUPT_LINE, &pci_irq);
pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, &pci_ioaddr1);
cs->irq = pci_irq;
break;
}
}
}
#endif /* COMPAT_HAS_NEW_PCI */
if (!found) {
printk(KERN_WARNING "HiSax: %s (%s): Card not found\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
#ifndef COMPAT_HAS_NEW_PCI
pci_index++; /* need for more as one card */
#endif
if (!pci_irq) { /* IRQ range check ?? */
printk(KERN_WARNING "HiSax: %s (%s): No IRQ\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
#ifdef ATTEMPT_PCI_REMAPPING
/* HACK: PLX revision 1 bug: PLX address bit 7 must not be set */
pcibios_read_config_byte(pci_bus, pci_device_fn, PCI_REVISION_ID, &pci_rev_id);
if ((pci_ioaddr1 & 0x80) && (pci_rev_id == 1)) {
printk(KERN_WARNING "HiSax: %s (%s): PLX rev 1, remapping required!\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
/* Restart PCI negotiation */
pcibios_write_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, (u_int) - 1);
/* Move up by 0x80 byte */
pci_ioaddr1 += 0x80;
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pcibios_write_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, pci_ioaddr1);
#ifdef COMPAT_HAS_NEW_PCI
dev_a8->base_address[1] = pci_ioaddr1;
#endif /* COMPAT_HAS_NEW_PCI */
}
/* End HACK */
#endif
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_1, &pci_ioaddr1);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_2, &pci_ioaddr2);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_3, &pci_ioaddr3);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_4, &pci_ioaddr4);
pcibios_read_config_dword(pci_bus, pci_device_fn, PCI_BASE_ADDRESS_5, &pci_ioaddr5);
if (!pci_ioaddr1 || !pci_ioaddr2 || !pci_ioaddr3 || !pci_ioaddr4 || !pci_ioaddr5) {
printk(KERN_WARNING "HiSax: %s (%s): No IO base address(es)\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
return (0);
}
pci_ioaddr1 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr2 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr3 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr4 &= PCI_BASE_ADDRESS_IO_MASK;
pci_ioaddr5 &= PCI_BASE_ADDRESS_IO_MASK;
/* Take over */
cs->irq = pci_irq;
/* pci_ioaddr1 is unique to all subdevices */
/* pci_ioaddr2 is for the fourth subdevice only */
/* pci_ioaddr3 is for the third subdevice only */
/* pci_ioaddr4 is for the second subdevice only */
/* pci_ioaddr5 is for the first subdevice only */
cs->hw.ax.plx_adr = pci_ioaddr1;
/* Enter all ipac_base addresses */
ipac_state[SCT_1].base = pci_ioaddr5 + 0x00;
ipac_state[SCT_2].base = pci_ioaddr4 + 0x08;
ipac_state[SCT_3].base = pci_ioaddr3 + 0x10;
ipac_state[SCT_4].base = pci_ioaddr2 + 0x20;
/* For isac and hscx control path */
cs->hw.ax.base = ipac_state[cs->subtyp].base;
/* For isac and hscx data path */
cs->hw.ax.data_adr = cs->hw.ax.base + 4;
#else
printk(KERN_WARNING "HiSax: %s (%s): NO_PCI_BIOS\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
printk(KERN_WARNING "HiSax: %s (%s): Unable to configure\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp]);
return (0);
#endif /* CONFIG_PCI */
printk(KERN_INFO "HiSax: %s (%s) configured at 0x%.4X, 0x%.4X, 0x%.4X and IRQ %d\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp],
cs->hw.ax.plx_adr,
cs->hw.ax.base,
cs->hw.ax.data_adr,
cs->irq);
test_and_set_bit(HW_IPAC, &cs->HW_Flags);
/* Disable all currently not active ipacs */
if (!is_ipac_active(SCT_1))
set_ipac_active(SCT_1, 0);
if (!is_ipac_active(SCT_2))
set_ipac_active(SCT_2, 0);
if (!is_ipac_active(SCT_3))
set_ipac_active(SCT_3, 0);
if (!is_ipac_active(SCT_4))
set_ipac_active(SCT_4, 0);
/* Perfom general reset (if possible) */
reset_bkm(cs);
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &BKM_card_msg;
printk(KERN_INFO "HiSax: %s (%s): IPAC Version %d\n",
CardType[card->typ],
sct_quadro_subtypes[cs->subtyp],
readreg(cs->hw.ax.base, cs->hw.ax.data_adr, IPAC_ID));
return (1);
}

130
drivers/isdn/hisax/bkm_ax.h Normal file
View File

@ -0,0 +1,130 @@
/* $Id$
* bkm_ax.h low level decls for T-Berkom cards A4T and Scitel Quadro (4*S0, passive)
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log$
*
*
*/
#ifndef __BKM_AX_H__
#define __BKM_AX_H__
/* Supported boards (subtypes) */
#define SCT_1 1
#define SCT_2 2
#define SCT_3 3
#define SCT_4 4
#define BKM_A4T 5
/* A4T */
#define I20_DEVICE_ID 0x6120 /* I20 PCI device ID */
#define I20_VENDOR_ID 0x11DE /* I20 PCI vendor ID */
#define A4T_SUBVEN_ID 0x0871
#define A4T_SUBSYS_ID 0xFFA4
/* Scitel Quadro */
#define PLX_DEVICE_ID 0x9050 /* Scitel Quadro PLX */
#define PLX_VENDOR_ID 0x10B5
#define SCT_SUBVEN_ID 0x0871
#define SCT_SUBSYS_ID 0xFFA8
#define PLX_ADDR_PLX 0x14 /* Addr PLX configuration */
#define PLX_ADDR_ISAC 0x18 /* Addr ISAC */
#define PLX_ADDR_HSCX 0x1C /* Addr HSCX */
#define PLX_ADDR_ALE 0x20 /* Addr ALE */
#define PLX_ADDR_ALEPLUS 0x24 /* Next Addr behind ALE */
#define PLX_SUBVEN 0x2C /* Offset SubVendor */
#define PLX_SUBSYS 0x2E /* Offset SubSystem */
/* Application specific registers I20 (Siemens SZB6120H) */
typedef struct {
/* Video front end horizontal configuration register */
volatile u_int i20VFEHorzCfg; /* Offset 00 */
/* Video front end vertical configuration register */
volatile u_int i20VFEVertCfg; /* Offset 04 */
/* Video front end scaler and pixel format register */
volatile u_int i20VFEScaler; /* Offset 08 */
/* Video display top register */
volatile u_int i20VDispTop; /* Offset 0C */
/* Video display bottom register */
volatile u_int i20VDispBottom; /* Offset 10 */
/* Video stride, status and frame grab register */
volatile u_int i20VidFrameGrab;/* Offset 14 */
/* Video display configuration register */
volatile u_int i20VDispCfg; /* Offset 18 */
/* Video masking map top */
volatile u_int i20VMaskTop; /* Offset 1C */
/* Video masking map bottom */
volatile u_int i20VMaskBottom; /* Offset 20 */
/* Overlay control register */
volatile u_int i20OvlyControl; /* Offset 24 */
/* System, PCI and general purpose pins control register */
volatile u_int i20SysControl; /* Offset 28 */
#define sysRESET 0x01000000 /* bit 24:Softreset (Low) */
/* GPIO 4...0: Output fixed for our cfg! */
#define sysCFG 0x000000E0 /* GPIO 7,6,5: Input */
/* General purpose pins and guest bus control register */
volatile u_int i20GuestControl;/* Offset 2C */
#define guestWAIT_CFG 0x00005555 /* 4 PCI waits for all */
#define guestISDN_INT_E 0x01000000 /* ISDN Int en (low) */
#define guestVID_INT_E 0x02000000 /* Video interrupt en (low) */
#define guestADI1_INT_R 0x04000000 /* ADI #1 int req (low) */
#define guestADI2_INT_R 0x08000000 /* ADI #2 int req (low) */
#define guestISDN_RES 0x10000000 /* ISDN reset bit (high) */
#define guestADI1_INT_S 0x20000000 /* ADI #1 int pending (low) */
#define guestADI2_INT_S 0x40000000 /* ADI #2 int pending (low) */
#define guestISDN_INT_S 0x80000000 /* ISAC int pending (low) */
#define g_A4T_JADE_RES 0x01000000 /* JADE Reset (High) */
#define g_A4T_ISAR_RES 0x02000000 /* ISAR Reset (High) */
#define g_A4T_ISAC_RES 0x04000000 /* ISAC Reset (High) */
#define g_A4T_JADE_BOOTR 0x08000000 /* JADE enable boot SRAM (Low) NOT USED */
#define g_A4T_ISAR_BOOTR 0x10000000 /* ISAR enable boot SRAM (Low) NOT USED */
#define g_A4T_JADE_INT_S 0x20000000 /* JADE interrupt pnd (Low) */
#define g_A4T_ISAR_INT_S 0x40000000 /* ISAR interrupt pnd (Low) */
#define g_A4T_ISAC_INT_S 0x80000000 /* ISAC interrupt pnd (Low) */
volatile u_int i20CodeSource; /* Offset 30 */
volatile u_int i20CodeXferCtrl;/* Offset 34 */
volatile u_int i20CodeMemPtr; /* Offset 38 */
volatile u_int i20IntStatus; /* Offset 3C */
volatile u_int i20IntCtrl; /* Offset 40 */
#define intISDN 0x40000000 /* GIRQ1En (ISAC/ADI) (High) */
#define intVID 0x20000000 /* GIRQ0En (VSYNC) (High) */
#define intCOD 0x10000000 /* CodRepIrqEn (High) */
#define intPCI 0x01000000 /* PCI IntA enable (High) */
volatile u_int i20I2CCtrl; /* Offset 44 */
} I20_REGISTER_FILE, *PI20_REGISTER_FILE;
/*
* Postoffice structure for A4T
*
*/
#define PO_OFFSET 0x00000200 /* Postoffice offset from base */
#define GCS_0 0x00000000 /* Guest bus chip selects */
#define GCS_1 0x00100000
#define GCS_2 0x00200000
#define GCS_3 0x00300000
#define PO_READ 0x00000000 /* R/W from/to guest bus */
#define PO_WRITE 0x00800000
#define PO_PEND 0x02000000
#define POSTOFFICE(postoffice) *(volatile unsigned int*)(postoffice)
/* Wait unlimited (don't worry) */
#define __WAITI20__(postoffice) \
do { \
while ((POSTOFFICE(postoffice) & PO_PEND)) ; \
} while (0)
#endif /* __BKM_AX_H__ */

1301
drivers/isdn/hisax/hfc_pci.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,243 @@
/* $Id$
* specific defines for CCD's HFC 2BDS0 PCI chips
*
* Author Werner Cornelius (werner@isdn4linux.de)
*
* Copyright 1999 by Werner Cornelius (werner@isdn4linux.de)
*
* 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, 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.
*
* $Log$
*
*
*/
/* defines for PCI config */
#define PCI_VENDOR_CCD 0x1397
#define PCI_CCD_PCI_ID 0x2BD0
// #define PCI_VENDOR_CCD 0x1043
// #define PCI_CCD_PCI_ID 0x675
#define PCI_ENA_MEMIO 0x02
#define PCI_ENA_MASTER 0x04
/* GCI/IOM bus monitor registers */
#define HCFPCI_C_I 0x08
#define HFCPCI_TRxR 0x0C
#define HFCPCI_MON1_D 0x28
#define HFCPCI_MON2_D 0x2C
/* GCI/IOM bus timeslot registers */
#define HFCPCI_B1_SSL 0x80
#define HFCPCI_B2_SSL 0x84
#define HFCPCI_AUX1_SSL 0x88
#define HFCPCI_AUX2_SSL 0x8C
#define HFCPCI_B1_RSL 0x90
#define HFCPCI_B2_RSL 0x94
#define HFCPCI_AUX1_RSL 0x98
#define HFCPCI_AUX2_RSL 0x9C
/* GCI/IOM bus data registers */
#define HFCPCI_B1_D 0xA0
#define HFCPCI_B2_D 0xA4
#define HFCPCI_AUX1_D 0xA8
#define HFCPCI_AUX2_D 0xAC
/* GCI/IOM bus configuration registers */
#define HFCPCI_MST_EMOD 0xB4
#define HFCPCI_MST_MODE 0xB8
#define HFCPCI_CONNECT 0xBC
/* Interrupt and status registers */
#define HFCPCI_FIFO_EN 0x44
#define HFCPCI_TRM 0x48
#define HFCPCI_B_MODE 0x4C
#define HFCPCI_CHIP_ID 0x58
#define HFCPCI_CIRM 0x60
#define HFCPCI_CTMT 0x64
#define HFCPCI_INT_M1 0x68
#define HFCPCI_INT_M2 0x6C
#define HFCPCI_INT_S1 0x78
#define HFCPCI_INT_S2 0x7C
#define HFCPCI_STATUS 0x70
/* S/T section registers */
#define HFCPCI_STATES 0xC0
#define HFCPCI_SCTRL 0xC4
#define HFCPCI_SCTRL_E 0xC8
#define HFCPCI_SCTRL_R 0xCC
#define HFCPCI_SQ 0xD0
#define HFCPCI_CLKDEL 0xDC
#define HFCPCI_B1_REC 0xF0
#define HFCPCI_B1_SEND 0xF0
#define HFCPCI_B2_REC 0xF4
#define HFCPCI_B2_SEND 0xF4
#define HFCPCI_D_REC 0xF8
#define HFCPCI_D_SEND 0xF8
#define HFCPCI_E_REC 0xFC
/* bits in status register (READ) */
#define HFCPCI_PCI_PROC 0x02
#define HFCPCI_NBUSY 0x04
#define HFCPCI_TIMER_ELAP 0x10
#define HFCPCI_STATINT 0x20
#define HFCPCI_FRAMEINT 0x40
#define HFCPCI_ANYINT 0x80
/* bits in CTMT (Write) */
#define HFCPCI_CLTIMER 0x80
#define HFCPCI_TIM3_125 0x00
#define HFCPCI_TIM25 0x10
#define HFCPCI_TIM50 0x14
#define HFCPCI_TIM400 0x18
#define HFCPCI_TIM800 0x1C
#define HFCPCI_AUTO_TIMER 0x20
#define HFCPCI_TRANSB2 0x02
#define HFCPCI_TRANSB1 0x01
/* bits in CIRM (Write) */
#define HFCPCI_AUX_MSK 0x07
#define HFCPCI_RESET 0x08
#define HFCPCI_B1_REV 0x40
#define HFCPCI_B2_REV 0x80
/* bits in INT_M1 and INT_S1 */
#define HFCPCI_INTS_B1TRANS 0x01
#define HFCPCI_INTS_B2TRANS 0x02
#define HFCPCI_INTS_DTRANS 0x04
#define HFCPCI_INTS_B1REC 0x08
#define HFCPCI_INTS_B2REC 0x10
#define HFCPCI_INTS_DREC 0x20
#define HFCPCI_INTS_L1STATE 0x40
#define HFCPCI_INTS_TIMER 0x80
/* bits in INT_M2 */
#define HFCPCI_PROC_TRANS 0x01
#define HFCPCI_GCI_I_CHG 0x02
#define HFCPCI_GCI_MON_REC 0x04
#define HFCPCI_IRQ_ENABLE 0x08
#define HFCPCI_PMESEL 0x80
/* bits in STATES */
#define HFCPCI_STATE_MSK 0x0F
#define HFCPCI_LOAD_STATE 0x10
#define HFCPCI_ACTIVATE 0x20
#define HFCPCI_DO_ACTION 0x40
#define HFCPCI_NT_G2_G3 0x80
/* bits in HFCD_MST_MODE */
#define HFCPCI_MASTER 0x01
#define HFCPCI_SLAVE 0x00
/* remaining bits are for codecs control */
/* bits in HFCD_SCTRL */
#define SCTRL_B1_ENA 0x01
#define SCTRL_B2_ENA 0x02
#define SCTRL_MODE_TE 0x00
#define SCTRL_MODE_NT 0x04
#define SCTRL_LOW_PRIO 0x08
#define SCTRL_SQ_ENA 0x10
#define SCTRL_TEST 0x20
#define SCTRL_NONE_CAP 0x40
#define SCTRL_PWR_DOWN 0x80
/* bits in SCTRL_E */
#define HFCPCI_AUTO_AWAKE 0x01
#define HFCPCI_DBIT_1 0x04
#define HFCPCI_IGNORE_COL 0x08
#define HFCPCI_CHG_B1_B2 0x80
/****************************/
/* bits in FIFO_EN register */
/****************************/
#define HFCPCI_FIFOEN_B1 0x03
#define HFCPCI_FIFOEN_B2 0x0C
#define HFCPCI_FIFOEN_DTX 0x10
/***********************************/
/* definitions of fifo memory area */
/***********************************/
#define MAX_D_FRAMES 15
#define MAX_B_FRAMES 31
#define B_SUB_VAL 0x200
#define B_FIFO_SIZE (0x2000 - B_SUB_VAL)
#define D_FIFO_SIZE 512
#define D_FREG_MASK 0xF
typedef struct {
unsigned short z1; /* Z1 pointer 16 Bit */
unsigned short z2; /* Z2 pointer 16 Bit */
} z_type;
typedef struct {
u_char data[D_FIFO_SIZE]; /* FIFO data space */
u_char fill1[0x20A0-D_FIFO_SIZE]; /* reserved, do not use */
u_char f1,f2; /* f pointers */
u_char fill2[0x20C0-0x20A2]; /* reserved, do not use */
z_type za[MAX_D_FRAMES+1]; /* mask index with D_FREG_MASK for access */
u_char fill3[0x4000-0x2100]; /* align 16K */
} dfifo_type;
typedef struct {
z_type za[MAX_B_FRAMES+1]; /* only range 0x0..0x1F allowed */
u_char f1,f2; /* f pointers */
u_char fill[0x2100-0x2082]; /* alignment */
} bzfifo_type;
typedef union {
struct {
dfifo_type d_tx; /* D-send channel */
dfifo_type d_rx; /* D-receive channel */
} d_chan;
struct {
u_char fill1[0x200];
u_char txdat_b1[B_FIFO_SIZE];
bzfifo_type txbz_b1;
bzfifo_type txbz_b2;
u_char txdat_b2[B_FIFO_SIZE];
u_char fill2[D_FIFO_SIZE];
u_char rxdat_b1[B_FIFO_SIZE];
bzfifo_type rxbz_b1;
bzfifo_type rxbz_b2;
u_char rxdat_b2[B_FIFO_SIZE];
} b_chans;
u_char fill[32768];
} fifo_area;
#define Write_hfc(a,b,c) (*(((u_char *)a->hw.hfcpci.pci_io)+b) = c)
#define Read_hfc(a,b) (*(((u_char *)a->hw.hfcpci.pci_io)+b))
extern void main_irq_hcpci(struct BCState *bcs);
extern void inithfcpci(struct IsdnCardState *cs);
extern void releasehfcpci(struct IsdnCardState *cs);

247
drivers/isdn/hisax/isurf.c Normal file
View File

@ -0,0 +1,247 @@
/* $Id$
* isurf.c low level stuff for Siemens I-Surf/I-Talk cards
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include <linux/config.h>
#include "hisax.h"
#include "isac.h"
#include "isar.h"
#include "isdnl1.h"
extern const char *CardType[];
static const char *ISurf_revision = "$Revision$";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
#define ISURF_ISAR_RESET 1
#define ISURF_ISAC_RESET 2
#define ISURF_ISAR_EA 4
#define ISURF_ARCOFI_RESET 8
#define ISURF_RESET (ISURF_ISAR_RESET | ISURF_ISAC_RESET | ISURF_ARCOFI_RESET)
#define ISURF_ISAR_OFFSET 0
#define ISURF_ISAC_OFFSET 0x100
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readb(cs->hw.isurf.isac + offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writeb(value, cs->hw.isurf.isac + offset); mb();
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
register int i;
for (i = 0; i < size; i++)
data[i] = readb(cs->hw.isurf.isac);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
register int i;
for (i = 0; i < size; i++){
writeb(data[i], cs->hw.isurf.isac);mb();
}
}
/* ISAR access routines
* mode = 0 access with IRQ on
* mode = 1 access with IRQ off
* mode = 2 access with IRQ off and using last offset
*/
static u_char
ReadISAR(struct IsdnCardState *cs, int mode, u_char offset)
{
return(readb(cs->hw.isurf.isar + offset));
}
static void
WriteISAR(struct IsdnCardState *cs, int mode, u_char offset, u_char value)
{
writeb(value, cs->hw.isurf.isar + offset);mb();
}
static void
isurf_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val;
int cnt = 20;
if (!cs) {
printk(KERN_WARNING "ISurf: Spurious interrupt!\n");
return;
}
val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
Start_ISAR:
if (val & ISAR_IRQSTA)
isar_int_main(cs);
val = readb(cs->hw.isurf.isac + ISAC_ISTA);
Start_ISAC:
if (val)
isac_interrupt(cs, val);
val = readb(cs->hw.isurf.isar + ISAR_IRQBIT);
if ((val & ISAR_IRQSTA) && --cnt) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "ISAR IntStat after IntRoutine");
goto Start_ISAR;
}
val = readb(cs->hw.isurf.isac + ISAC_ISTA);
if (val && --cnt) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (!cnt)
printk(KERN_WARNING "ISurf IRQ LOOP\n");
writeb(0, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
writeb(0xFF, cs->hw.isurf.isac + ISAC_MASK);mb();
writeb(0, cs->hw.isurf.isac + ISAC_MASK);mb();
writeb(ISAR_IRQMSK, cs->hw.isurf.isar + ISAR_IRQBIT); mb();
}
void
release_io_isurf(struct IsdnCardState *cs)
{
release_region(cs->hw.isurf.reset, 1);
}
static void
reset_isurf(struct IsdnCardState *cs, u_char chips)
{
long flags;
printk(KERN_INFO "ISurf: resetting card\n");
byteout(cs->hw.isurf.reset, chips); /* Reset On */
save_flags(flags);
sti();
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
byteout(cs->hw.isurf.reset, ISURF_ISAR_EA); /* Reset Off */
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((10*HZ)/1000);
restore_flags(flags);
}
static int
ISurf_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
switch (mt) {
case CARD_RESET:
reset_isurf(cs, ISURF_RESET);
return(0);
case CARD_RELEASE:
release_io_isurf(cs);
return(0);
case CARD_SETIRQ:
return(request_irq(cs->irq, &isurf_interrupt,
I4L_IRQ_FLAG, "HiSax", cs));
case CARD_INIT:
clear_pending_isac_ints(cs);
writeb(0, cs->hw.isurf.isar+ISAR_IRQBIT);mb();
initisac(cs);
initisar(cs);
/* Reenable ISAC IRQ */
cs->writeisac(cs, ISAC_MASK, 0);
/* RESET Receiver and Transmitter */
cs->writeisac(cs, ISAC_CMDR, 0x41);
return(0);
case CARD_TEST:
return(0);
case CARD_LOAD_FIRM:
if (isar_load_firmware(cs, arg))
return(1);
ll_run(cs);
reset_isurf(cs, ISURF_ISAR_EA | ISURF_ISAC_RESET |
ISURF_ARCOFI_RESET);
initisac(cs);
cs->writeisac(cs, ISAC_MASK, 0);
cs->writeisac(cs, ISAC_CMDR, 0x41);
return(0);
}
return(0);
}
__initfunc(int
setup_isurf(struct IsdnCard *card))
{
int ver;
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, ISurf_revision);
printk(KERN_INFO "HiSax: ISurf driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_ISURF)
return(0);
if (card->para[1] && card->para[2]) {
cs->hw.isurf.reset = card->para[1];
cs->hw.isurf.isar = card->para[2] + ISURF_ISAR_OFFSET;
cs->hw.isurf.isac = card->para[2] + ISURF_ISAC_OFFSET;
cs->irq = card->para[0];
} else {
printk(KERN_WARNING "HiSax: %s port/mem not set\n",
CardType[card->typ]);
return (0);
}
if (check_region(cs->hw.isurf.reset, 1)) {
printk(KERN_WARNING
"HiSax: %s config port %x already in use\n",
CardType[card->typ],
cs->hw.isurf.reset);
return (0);
} else {
request_region(cs->hw.isurf.reset, 1, "isurf isdn");
}
printk(KERN_INFO
"ISurf: defined at 0x%x 0x%x IRQ %d\n",
cs->hw.isurf.reset,
cs->hw.isurf.isar,
cs->irq);
cs->cardmsg = &ISurf_card_msg;
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->bcs[0].hw.isar.reg = &cs->hw.isurf.isar_r;
cs->bcs[1].hw.isar.reg = &cs->hw.isurf.isar_r;
reset_isurf(cs, ISURF_RESET);
test_and_set_bit(HW_ISAR, &cs->HW_Flags);
ISACVersion(cs, "ISurf:");
cs->BC_Read_Reg = &ReadISAR;
cs->BC_Write_Reg = &WriteISAR;
cs->BC_Send_Data = &isar_fill_fifo;
ver = ISARVersion(cs, "ISurf:");
if (ver < 0) {
printk(KERN_WARNING
"ISurf: wrong ISAR version (ret = %d)\n", ver);
release_io_isurf(cs);
return (0);
}
return (1);
}

323
drivers/isdn/hisax/jade.c Normal file
View File

@ -0,0 +1,323 @@
/* $Id$
*
* jade.c JADE stuff (derived from original hscx.c)
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "hscx.h"
#include "jade.h"
#include "isdnl1.h"
#include <linux/interrupt.h>
HISAX_INITFUNC(int
JadeVersion(struct IsdnCardState *cs, char *s))
{
int ver,i;
int to = 50;
cs->BC_Write_Reg(cs, -1, 0x50, 0x19);
i=0;
while (to) {
udelay(1);
ver = cs->BC_Read_Reg(cs, -1, 0x60);
to--;
if (ver)
break;
if (!to) {
printk(KERN_INFO "%s JADE version not obtainable\n", s);
return (0);
}
}
/* Wait for the JADE */
udelay(10);
/* Read version */
ver = cs->BC_Read_Reg(cs, -1, 0x60);
printk(KERN_INFO "%s JADE version: %d\n", s, ver);
return (1);
}
/* Write to indirect accessible jade register set */
static void
jade_write_indirect(struct IsdnCardState *cs, u_char reg, u_char value)
{
int to = 50;
long flags;
u_char ret;
save_flags(flags);
cli();
/* Write the data */
cs->BC_Write_Reg(cs, -1, COMM_JADE+1, value);
/* Say JADE we wanna write indirect reg 'reg' */
cs->BC_Write_Reg(cs, -1, COMM_JADE, reg);
to = 50;
/* Wait for RDY goes high */
while (to) {
udelay(1);
ret = cs->BC_Read_Reg(cs, -1, COMM_JADE);
to--;
if (ret & 1)
/* Got acknowledge */
break;
if (!to) {
restore_flags(flags);
printk(KERN_INFO "Can not see ready bit from JADE DSP (reg=0x%X, value=0x%X)\n", reg, value);
return;
}
}
restore_flags(flags);
}
void
modejade(struct BCState *bcs, int mode, int bc)
{
struct IsdnCardState *cs = bcs->cs;
int jade = bcs->hw.hscx.hscx;
if (cs->debug & L1_DEB_HSCX) {
char tmp[40];
sprintf(tmp, "jade %c mode %d ichan %d",
'A' + jade, mode, bc);
debugl1(cs, tmp);
}
bcs->mode = mode;
bcs->channel = bc;
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (mode == L1_MODE_TRANS ? jadeMODE_TMO:0x00));
cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR0, (jadeCCR0_PU|jadeCCR0_ITF));
cs->BC_Write_Reg(cs, jade, jade_HDLC_CCR1, 0x00);
jade_write_indirect(cs, jade_HDLC1SERRXPATH, 0x08);
jade_write_indirect(cs, jade_HDLC2SERRXPATH, 0x08);
jade_write_indirect(cs, jade_HDLC1SERTXPATH, 0x00);
jade_write_indirect(cs, jade_HDLC2SERTXPATH, 0x00);
cs->BC_Write_Reg(cs, jade, jade_HDLC_XCCR, 0x07);
cs->BC_Write_Reg(cs, jade, jade_HDLC_RCCR, 0x07);
if (bc == 0) {
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x00);
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x00);
} else {
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAX, 0x04);
cs->BC_Write_Reg(cs, jade, jade_HDLC_TSAR, 0x04);
}
switch (mode) {
case (L1_MODE_NULL):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, jadeMODE_TMO);
break;
case (L1_MODE_TRANS):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_TMO|jadeMODE_RAC|jadeMODE_XAC));
break;
case (L1_MODE_HDLC):
cs->BC_Write_Reg(cs, jade, jade_HDLC_MODE, (jadeMODE_RAC|jadeMODE_XAC));
break;
}
if (mode) {
cs->BC_Write_Reg(cs, jade, jade_HDLC_RCMD, (jadeRCMD_RRES|jadeRCMD_RMC));
cs->BC_Write_Reg(cs, jade, jade_HDLC_XCMD, jadeXCMD_XRES);
/* Unmask ints */
cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0xF8);
}
else
/* Mask ints */
cs->BC_Write_Reg(cs, jade, jade_HDLC_IMR, 0x00);
}
void
jade_sched_event(struct BCState *bcs, int event)
{
bcs->event |= 1 << event;
queue_task(&bcs->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
static void
jade_l2l1(struct PStack *st, int pr, void *arg)
{
struct sk_buff *skb = arg;
long flags;
switch (pr) {
case (PH_DATA | REQUEST):
save_flags(flags);
cli();
if (st->l1.bcs->tx_skb) {
skb_queue_tail(&st->l1.bcs->squeue, skb);
restore_flags(flags);
} else {
st->l1.bcs->tx_skb = skb;
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->hw.hscx.count = 0;
restore_flags(flags);
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
}
break;
case (PH_PULL | INDICATION):
if (st->l1.bcs->tx_skb) {
printk(KERN_WARNING "jade_l2l1: this shouldn't happen\n");
break;
}
test_and_set_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
st->l1.bcs->tx_skb = skb;
st->l1.bcs->hw.hscx.count = 0;
st->l1.bcs->cs->BC_Send_Data(st->l1.bcs);
break;
case (PH_PULL | REQUEST):
if (!st->l1.bcs->tx_skb) {
test_and_clear_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
st->l1.l1l2(st, PH_PULL | CONFIRM, NULL);
} else
test_and_set_bit(FLG_L1_PULL_REQ, &st->l1.Flags);
break;
case (PH_ACTIVATE | REQUEST):
test_and_set_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
modejade(st->l1.bcs, st->l1.mode, st->l1.bc);
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | REQUEST):
l1_msg_b(st, pr, arg);
break;
case (PH_DEACTIVATE | CONFIRM):
test_and_clear_bit(BC_FLG_ACTIV, &st->l1.bcs->Flag);
test_and_clear_bit(BC_FLG_BUSY, &st->l1.bcs->Flag);
modejade(st->l1.bcs, 0, st->l1.bc);
st->l1.l1l2(st, PH_DEACTIVATE | CONFIRM, NULL);
break;
}
}
void
close_jadestate(struct BCState *bcs)
{
modejade(bcs, 0, bcs->channel);
if (test_and_clear_bit(BC_FLG_INIT, &bcs->Flag)) {
if (bcs->hw.hscx.rcvbuf) {
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
}
if (bcs->blog) {
kfree(bcs->blog);
bcs->blog = NULL;
}
discard_queue(&bcs->rqueue);
discard_queue(&bcs->squeue);
if (bcs->tx_skb) {
idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
}
}
}
static int
open_jadestate(struct IsdnCardState *cs, struct BCState *bcs)
{
if (!test_and_set_bit(BC_FLG_INIT, &bcs->Flag)) {
if (!(bcs->hw.hscx.rcvbuf = kmalloc(HSCX_BUFMAX, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for hscx.rcvbuf\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
return (1);
}
if (!(bcs->blog = kmalloc(MAX_BLOG_SPACE, GFP_ATOMIC))) {
printk(KERN_WARNING
"HiSax: No memory for bcs->blog\n");
test_and_clear_bit(BC_FLG_INIT, &bcs->Flag);
kfree(bcs->hw.hscx.rcvbuf);
bcs->hw.hscx.rcvbuf = NULL;
return (2);
}
skb_queue_head_init(&bcs->rqueue);
skb_queue_head_init(&bcs->squeue);
}
bcs->tx_skb = NULL;
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
bcs->event = 0;
bcs->hw.hscx.rcvidx = 0;
bcs->tx_cnt = 0;
return (0);
}
int
setstack_jade(struct PStack *st, struct BCState *bcs)
{
bcs->channel = st->l1.bc;
if (open_jadestate(st->l1.hardware, bcs))
return (-1);
st->l1.bcs = bcs;
st->l2.l2l1 = jade_l2l1;
setstack_manager(st);
bcs->st = st;
setstack_l1_B(st);
return (0);
}
HISAX_INITFUNC(void
clear_pending_jade_ints(struct IsdnCardState *cs))
{
int val;
char tmp[64];
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
val = cs->BC_Read_Reg(cs, 1, jade_HDLC_ISR);
sprintf(tmp, "jade B ISTA %x", val);
debugl1(cs, tmp);
val = cs->BC_Read_Reg(cs, 0, jade_HDLC_ISR);
sprintf(tmp, "jade A ISTA %x", val);
debugl1(cs, tmp);
val = cs->BC_Read_Reg(cs, 1, jade_HDLC_STAR);
sprintf(tmp, "jade B STAR %x", val);
debugl1(cs, tmp);
val = cs->BC_Read_Reg(cs, 0, jade_HDLC_STAR);
sprintf(tmp, "jade A STAR %x", val);
debugl1(cs, tmp);
/* Unmask ints */
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0xF8);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0xF8);
}
HISAX_INITFUNC(void
initjade(struct IsdnCardState *cs))
{
cs->bcs[0].BC_SetStack = setstack_jade;
cs->bcs[1].BC_SetStack = setstack_jade;
cs->bcs[0].BC_Close = close_jadestate;
cs->bcs[1].BC_Close = close_jadestate;
cs->bcs[0].hw.hscx.hscx = 0;
cs->bcs[1].hw.hscx.hscx = 1;
/* Stop DSP audio tx/rx */
jade_write_indirect(cs, 0x11, 0x0f);
jade_write_indirect(cs, 0x17, 0x2f);
/* Transparent Mode, RxTx inactive, No Test, No RFS/TFS */
cs->BC_Write_Reg(cs, 0, jade_HDLC_MODE, jadeMODE_TMO);
cs->BC_Write_Reg(cs, 1, jade_HDLC_MODE, jadeMODE_TMO);
/* Power down, 1-Idle, RxTx least significant bit first */
cs->BC_Write_Reg(cs, 0, jade_HDLC_CCR0, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_CCR0, 0x00);
/* Mask all interrupts */
cs->BC_Write_Reg(cs, 0, jade_HDLC_IMR, 0x00);
cs->BC_Write_Reg(cs, 1, jade_HDLC_IMR, 0x00);
/* Setup host access to hdlc controller */
jade_write_indirect(cs, jade_HDLCCNTRACCESS, (jadeINDIRECT_HAH1|jadeINDIRECT_HAH2));
/* Unmask HDLC int (don´t forget DSP int later on)*/
cs->BC_Write_Reg(cs, -1,jade_INT, (jadeINT_HDLC1|jadeINT_HDLC2));
/* once again TRANSPARENT */
modejade(cs->bcs, 0, 0);
modejade(cs->bcs + 1, 0, 0);
}

134
drivers/isdn/hisax/jade.h Normal file
View File

@ -0,0 +1,134 @@
/* $Id$
* jade.h JADE specific defines
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
*
* $Log$
*
*/
/* All Registers original Siemens Spec */
#ifndef __JADE_H__
#define __JADE_H__
/* Special registers for access to indirect accessible JADE regs */
#define DIRECT_IO_JADE 0x0000 /* Jade direct io access area */
#define COMM_JADE 0x0040 /* Jade communication area */
/********************************************************************/
/* JADE-HDLC registers */
/********************************************************************/
#define jade_HDLC_RFIFO 0x00 /* R */
#define jade_HDLC_XFIFO 0x00 /* W */
#define jade_HDLC_STAR 0x20 /* R */
#define jadeSTAR_XDOV 0x80
#define jadeSTAR_XFW 0x40 /* Does not work*/
#define jadeSTAR_XCEC 0x20
#define jadeSTAR_RCEC 0x10
#define jadeSTAR_BSY 0x08
#define jadeSTAR_RNA 0x04
#define jadeSTAR_STR 0x02
#define jadeSTAR_STX 0x01
#define jade_HDLC_XCMD 0x20 /* W */
#define jadeXCMD_XF 0x80
#define jadeXCMD_XME 0x40
#define jadeXCMD_XRES 0x20
#define jadeXCMD_STX 0x01
#define jade_HDLC_RSTA 0x21 /* R */
#define jadeRSTA_VFR 0x80
#define jadeRSTA_RDO 0x40
#define jadeRSTA_CRC 0x20
#define jadeRSTA_RAB 0x10
#define jadeRSTA_MASK 0xF0
#define jade_HDLC_MODE 0x22 /* RW*/
#define jadeMODE_TMO 0x80
#define jadeMODE_RAC 0x40
#define jadeMODE_XAC 0x20
#define jadeMODE_TLP 0x10
#define jadeMODE_ERFS 0x02
#define jadeMODE_ETFS 0x01
#define jade_HDLC_RBCH 0x24 /* R */
#define jade_HDLC_RBCL 0x25 /* R */
#define jade_HDLC_RCMD 0x25 /* W */
#define jadeRCMD_RMC 0x80
#define jadeRCMD_RRES 0x40
#define jadeRCMD_RMD 0x20
#define jadeRCMD_STR 0x02
#define jade_HDLC_CCR0 0x26 /* RW*/
#define jadeCCR0_PU 0x80
#define jadeCCR0_ITF 0x40
#define jadeCCR0_C32 0x20
#define jadeCCR0_CRL 0x10
#define jadeCCR0_RCRC 0x08
#define jadeCCR0_XCRC 0x04
#define jadeCCR0_RMSB 0x02
#define jadeCCR0_XMSB 0x01
#define jade_HDLC_CCR1 0x27 /* RW*/
#define jadeCCR1_RCS0 0x80
#define jadeCCR1_RCONT 0x40
#define jadeCCR1_RFDIS 0x20
#define jadeCCR1_XCS0 0x10
#define jadeCCR1_XCONT 0x08
#define jadeCCR1_XFDIS 0x04
#define jade_HDLC_TSAR 0x28 /* RW*/
#define jade_HDLC_TSAX 0x29 /* RW*/
#define jade_HDLC_RCCR 0x2A /* RW*/
#define jade_HDLC_XCCR 0x2B /* RW*/
#define jade_HDLC_ISR 0x2C /* R */
#define jade_HDLC_IMR 0x2C /* W */
#define jadeISR_RME 0x80
#define jadeISR_RPF 0x40
#define jadeISR_RFO 0x20
#define jadeISR_XPR 0x10
#define jadeISR_XDU 0x08
#define jadeISR_ALLS 0x04
#define jade_INT 0x75
#define jadeINT_HDLC1 0x02
#define jadeINT_HDLC2 0x01
#define jadeINT_DSP 0x04
#define jade_INTR 0x70
/********************************************************************/
/* Indirect accessible JADE registers of common interest */
/********************************************************************/
#define jade_CHIPVERSIONNR 0x00 /* Does not work*/
#define jade_HDLCCNTRACCESS 0x10
#define jadeINDIRECT_HAH1 0x02
#define jadeINDIRECT_HAH2 0x01
#define jade_HDLC1SERRXPATH 0x1D
#define jade_HDLC1SERTXPATH 0x1E
#define jade_HDLC2SERRXPATH 0x1F
#define jade_HDLC2SERTXPATH 0x20
#define jadeINDIRECT_SLIN1 0x10
#define jadeINDIRECT_SLIN0 0x08
#define jadeINDIRECT_LMOD1 0x04
#define jadeINDIRECT_LMOD0 0x02
#define jadeINDIRECT_HHR 0x01
#define jadeINDIRECT_HHX 0x01
#define jade_RXAUDIOCH1CFG 0x11
#define jade_RXAUDIOCH2CFG 0x14
#define jade_TXAUDIOCH1CFG 0x17
#define jade_TXAUDIOCH2CFG 0x1A
extern int JadeVersion(struct IsdnCardState *cs, char *s);
extern void jade_sched_event(struct BCState *bcs, int event);
extern void modejade(struct BCState *bcs, int mode, int bc);
extern void clear_pending_jade_ints(struct IsdnCardState *cs);
extern void initjade(struct IsdnCardState *cs);
#endif /* __JADE_H__ */

View File

@ -0,0 +1,244 @@
/* $Id$
*
* jade_irq.c Low level JADE IRQ stuff (derived from original hscx_irq.c)
*
* Author Roland Klabunde (R.Klabunde@Berkom.de)
*
* $Log$
*
*/
static inline void
waitforCEC(struct IsdnCardState *cs, int jade, int reg)
{
int to = 50;
int mask = (reg == jade_HDLC_XCMD ? jadeSTAR_XCEC : jadeSTAR_RCEC);
while ((READJADE(cs, jade, jade_HDLC_STAR) & mask) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "HiSax: waitforCEC (jade) timeout\n");
}
static inline void
waitforXFW(struct IsdnCardState *cs, int jade)
{
/* Does not work on older jade versions, don't care */
}
static inline void
WriteJADECMDR(struct IsdnCardState *cs, int jade, int reg, u_char data)
{
long flags;
save_flags(flags);
cli();
waitforCEC(cs, jade, reg);
WRITEJADE(cs, jade, reg, data);
restore_flags(flags);
}
static void
jade_empty_fifo(struct BCState *bcs, int count)
{
u_char *ptr;
struct IsdnCardState *cs = bcs->cs;
long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_empty_fifo");
if (bcs->hw.hscx.rcvidx + count > HSCX_BUFMAX) {
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "jade_empty_fifo: incoming packet too large");
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
bcs->hw.hscx.rcvidx = 0;
return;
}
ptr = bcs->hw.hscx.rcvbuf + bcs->hw.hscx.rcvidx;
bcs->hw.hscx.rcvidx += count;
save_flags(flags);
cli();
READJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_RCMD, jadeRCMD_RMC);
restore_flags(flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "jade_empty_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, bcs->blog);
}
}
static void
jade_fill_fifo(struct BCState *bcs)
{
struct IsdnCardState *cs = bcs->cs;
int more, count;
int fifo_size = 32;
u_char *ptr;
long flags;
if ((cs->debug & L1_DEB_HSCX) && !(cs->debug & L1_DEB_HSCX_FIFO))
debugl1(cs, "jade_fill_fifo");
if (!bcs->tx_skb)
return;
if (bcs->tx_skb->len <= 0)
return;
more = (bcs->mode == L1_MODE_TRANS) ? 1 : 0;
if (bcs->tx_skb->len > fifo_size) {
more = !0;
count = fifo_size;
} else
count = bcs->tx_skb->len;
waitforXFW(cs, bcs->hw.hscx.hscx);
save_flags(flags);
cli();
ptr = bcs->tx_skb->data;
skb_pull(bcs->tx_skb, count);
bcs->tx_cnt -= count;
bcs->hw.hscx.count += count;
WRITEJADEFIFO(cs, bcs->hw.hscx.hscx, ptr, count);
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, more ? jadeXCMD_XF : (jadeXCMD_XF|jadeXCMD_XME));
restore_flags(flags);
if (cs->debug & L1_DEB_HSCX_FIFO) {
char *t = bcs->blog;
t += sprintf(t, "jade_fill_fifo %c cnt %d",
bcs->hw.hscx.hscx ? 'B' : 'A', count);
QuickHex(t, ptr, count);
debugl1(cs, bcs->blog);
}
}
static inline void
jade_interrupt(struct IsdnCardState *cs, u_char val, u_char jade)
{
u_char r;
struct BCState *bcs = cs->bcs + jade;
struct sk_buff *skb;
int fifo_size = 32;
int count;
int i_jade = (int) jade; /* To satisfy the compiler */
if (!test_bit(BC_FLG_INIT, &bcs->Flag))
return;
if (val & 0x80) { /* RME */
r = READJADE(cs, i_jade, jade_HDLC_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!(r & 0x80))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %s invalid frame", (jade ? "B":"A"));
if ((r & 0x40) && bcs->mode)
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c RDO mode=%d", 'A'+jade, bcs->mode);
if (!(r & 0x20))
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c CRC error", 'A'+jade);
WriteJADECMDR(cs, jade, jade_HDLC_RCMD, jadeRCMD_RMC);
} else {
count = READJADE(cs, i_jade, jade_HDLC_RBCL) & 0x1F;
if (count == 0)
count = fifo_size;
jade_empty_fifo(bcs, count);
if ((count = bcs->hw.hscx.rcvidx - 1) > 0) {
if (cs->debug & L1_DEB_HSCX_FIFO)
debugl1(cs, "HX Frame %d", count);
if (!(skb = dev_alloc_skb(count)))
printk(KERN_WARNING "JADE %s receive out of memory\n", (jade ? "B":"A"));
else {
SET_SKB_FREE(skb);
memcpy(skb_put(skb, count), bcs->hw.hscx.rcvbuf, count);
skb_queue_tail(&bcs->rqueue, skb);
}
}
}
bcs->hw.hscx.rcvidx = 0;
jade_sched_event(bcs, B_RCVBUFREADY);
}
if (val & 0x40) { /* RPF */
jade_empty_fifo(bcs, fifo_size);
if (bcs->mode == L1_MODE_TRANS) {
/* receive audio data */
if (!(skb = dev_alloc_skb(fifo_size)))
printk(KERN_WARNING "HiSax: receive out of memory\n");
else {
SET_SKB_FREE(skb);
memcpy(skb_put(skb, fifo_size), bcs->hw.hscx.rcvbuf, fifo_size);
skb_queue_tail(&bcs->rqueue, skb);
}
bcs->hw.hscx.rcvidx = 0;
jade_sched_event(bcs, B_RCVBUFREADY);
}
}
if (val & 0x10) { /* XPR */
if (bcs->tx_skb) {
if (bcs->tx_skb->len) {
jade_fill_fifo(bcs);
return;
} else {
if (bcs->st->lli.l1writewakeup &&
(PACKET_NOACK != bcs->tx_skb->pkt_type))
bcs->st->lli.l1writewakeup(bcs->st, bcs->hw.hscx.count);
idev_kfree_skb(bcs->tx_skb, FREE_WRITE);
bcs->hw.hscx.count = 0;
bcs->tx_skb = NULL;
}
}
if ((bcs->tx_skb = skb_dequeue(&bcs->squeue))) {
bcs->hw.hscx.count = 0;
test_and_set_bit(BC_FLG_BUSY, &bcs->Flag);
jade_fill_fifo(bcs);
} else {
test_and_clear_bit(BC_FLG_BUSY, &bcs->Flag);
jade_sched_event(bcs, B_XMTBUFREADY);
}
}
}
static inline void
jade_int_main(struct IsdnCardState *cs, u_char val, int jade)
{
struct BCState *bcs;
bcs = cs->bcs + jade;
if (val & jadeISR_RFO) {
/* handled with RDO */
val &= ~jadeISR_RFO;
}
if (val & jadeISR_XDU) {
/* relevant in HDLC mode only */
/* don't reset XPR here */
if (bcs->mode == 1)
jade_fill_fifo(bcs);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
if (bcs->tx_skb) {
skb_push(bcs->tx_skb, bcs->hw.hscx.count);
bcs->tx_cnt += bcs->hw.hscx.count;
bcs->hw.hscx.count = 0;
}
WriteJADECMDR(cs, bcs->hw.hscx.hscx, jade_HDLC_XCMD, jadeXCMD_XRES);
if (cs->debug & L1_DEB_WARN)
debugl1(cs, "JADE %c EXIR %x Lost TX", 'A'+jade, val);
}
}
if (val & (jadeISR_RME|jadeISR_RPF|jadeISR_XPR)) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "JADE %c interrupt %x", 'A'+jade, val);
jade_interrupt(cs, val, jade);
}
}

329
drivers/isdn/hisax/saphir.c Normal file
View File

@ -0,0 +1,329 @@
/* $Id$
* saphir.c low level stuff for HST Saphir 1
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* Thanks to HST High Soft Tech GmbH
*
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isac.h"
#include "hscx.h"
#include "isdnl1.h"
extern const char *CardType[];
static char *saphir_rev = "$Revision$";
#define byteout(addr,val) outb(val,addr)
#define bytein(addr) inb(addr)
#define ISAC_DATA 0
#define HSCX_DATA 1
#define ADDRESS_REG 2
#define IRQ_REG 3
#define SPARE_REG 4
#define RESET_REG 5
static inline u_char
readreg(unsigned int ale, unsigned int adr, u_char off)
{
register u_char ret;
long flags;
save_flags(flags);
cli();
byteout(ale, off);
ret = bytein(adr);
restore_flags(flags);
return (ret);
}
static inline void
readfifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo read without cli because it's allready done */
byteout(ale, off);
insb(adr, data, size);
}
static inline void
writereg(unsigned int ale, unsigned int adr, u_char off, u_char data)
{
long flags;
save_flags(flags);
cli();
byteout(ale, off);
byteout(adr, data);
restore_flags(flags);
}
static inline void
writefifo(unsigned int ale, unsigned int adr, u_char off, u_char * data, int size)
{
/* fifo write without cli because it's allready done */
byteout(ale, off);
outsb(adr, data, size);
}
/* Interface functions */
static u_char
ReadISAC(struct IsdnCardState *cs, u_char offset)
{
return (readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset));
}
static void
WriteISAC(struct IsdnCardState *cs, u_char offset, u_char value)
{
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, offset, value);
}
static void
ReadISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
readfifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
}
static void
WriteISACfifo(struct IsdnCardState *cs, u_char * data, int size)
{
writefifo(cs->hw.saphir.ale, cs->hw.saphir.isac, 0, data, size);
}
static u_char
ReadHSCX(struct IsdnCardState *cs, int hscx, u_char offset)
{
return (readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
offset + (hscx ? 0x40 : 0)));
}
static void
WriteHSCX(struct IsdnCardState *cs, int hscx, u_char offset, u_char value)
{
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx,
offset + (hscx ? 0x40 : 0), value);
}
#define READHSCX(cs, nr, reg) readreg(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0))
#define WRITEHSCX(cs, nr, reg, data) writereg(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, reg + (nr ? 0x40 : 0), data)
#define READHSCXFIFO(cs, nr, ptr, cnt) readfifo(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
#define WRITEHSCXFIFO(cs, nr, ptr, cnt) writefifo(cs->hw.saphir.ale, \
cs->hw.saphir.hscx, (nr ? 0x40 : 0), ptr, cnt)
#include "hscx_irq.c"
static void
saphir_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *cs = dev_id;
u_char val, stat = 0;
if (!cs) {
printk(KERN_WARNING "saphir: Spurious interrupt!\n");
return;
}
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
Start_HSCX:
if (val) {
hscx_int_main(cs, val);
stat |= 1;
}
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
Start_ISAC:
if (val) {
isac_interrupt(cs, val);
stat |= 2;
}
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_ISTA + 0x40);
if (val) {
if (cs->debug & L1_DEB_HSCX)
debugl1(cs, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_ISTA);
if (val) {
if (cs->debug & L1_DEB_ISAC)
debugl1(cs, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
/* Watchdog */
if (cs->hw.saphir.timer.function) {
del_timer(&cs->hw.saphir.timer);
cs->hw.saphir.timer.expires = jiffies + 1*HZ;
add_timer(&cs->hw.saphir.timer);
} else
printk(KERN_WARNING "saphir: Spurious timer!\n");
if (stat & 1) {
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK, 0);
writereg(cs->hw.saphir.ale, cs->hw.saphir.hscx, HSCX_MASK + 0x40, 0);
}
if (stat & 2) {
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0xFF);
writereg(cs->hw.saphir.ale, cs->hw.saphir.isac, ISAC_MASK, 0);
}
}
static void
SaphirWatchDog(struct IsdnCardState *cs)
{
/* 5 sec WatchDog, so read at least every 4 sec */
cs->readisac(cs, ISAC_RBCH);
del_timer(&cs->hw.saphir.timer);
cs->hw.saphir.timer.expires = jiffies + 1*HZ;
add_timer(&cs->hw.saphir.timer);
}
void
release_io_saphir(struct IsdnCardState *cs)
{
long flags;
save_flags(flags);
cli();
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, 0xff);
del_timer(&cs->hw.saphir.timer);
cs->hw.saphir.timer.function = NULL;
restore_flags(flags);
if (cs->hw.saphir.cfg_reg)
release_region(cs->hw.saphir.cfg_reg, 6);
}
static int
saphir_reset(struct IsdnCardState *cs)
{
long flags;
u_char irq_val;
switch(cs->irq) {
case 5: irq_val = 0;
break;
case 3: irq_val = 1;
break;
case 11:
irq_val = 2;
break;
case 12:
irq_val = 3;
break;
case 15:
irq_val = 4;
break;
default:
printk(KERN_WARNING "HiSax: saphir wrong IRQ %d\n",
cs->irq);
return (1);
}
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
save_flags(flags);
sti();
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 1);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
byteout(cs->hw.saphir.cfg_reg + RESET_REG, 0);
current->state = TASK_INTERRUPTIBLE;
schedule_timeout((30*HZ)/1000); /* Timeout 30ms */
restore_flags(flags);
byteout(cs->hw.saphir.cfg_reg + IRQ_REG, irq_val);
byteout(cs->hw.saphir.cfg_reg + SPARE_REG, 0x02);
return (0);
}
static int
saphir_card_msg(struct IsdnCardState *cs, int mt, void *arg)
{
switch (mt) {
case CARD_RESET:
saphir_reset(cs);
return(0);
case CARD_RELEASE:
release_io_saphir(cs);
return(0);
case CARD_SETIRQ:
return(request_irq(cs->irq, &saphir_interrupt,
I4L_IRQ_FLAG, "HiSax", cs));
case CARD_INIT:
inithscxisac(cs, 3);
return(0);
case CARD_TEST:
return(0);
}
return(0);
}
__initfunc(int
setup_saphir(struct IsdnCard *card))
{
struct IsdnCardState *cs = card->cs;
char tmp[64];
strcpy(tmp, saphir_rev);
printk(KERN_INFO "HiSax: HST Saphir driver Rev. %s\n", HiSax_getrev(tmp));
if (cs->typ != ISDN_CTYPE_HSTSAPHIR)
return (0);
/* IO-Ports */
cs->hw.saphir.cfg_reg = card->para[1];
cs->hw.saphir.isac = card->para[1] + ISAC_DATA;
cs->hw.saphir.hscx = card->para[1] + HSCX_DATA;
cs->hw.saphir.ale = card->para[1] + ADDRESS_REG;
cs->irq = card->para[0];
if (check_region((cs->hw.saphir.cfg_reg), 6)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
cs->hw.saphir.cfg_reg,
cs->hw.saphir.cfg_reg + 5);
return (0);
} else
request_region(cs->hw.saphir.cfg_reg,6, "saphir");
printk(KERN_INFO
"HiSax: %s config irq:%d io:0x%X\n",
CardType[cs->typ], cs->irq,
cs->hw.saphir.cfg_reg);
cs->hw.saphir.timer.function = (void *) SaphirWatchDog;
cs->hw.saphir.timer.data = (long) cs;
init_timer(&cs->hw.saphir.timer);
cs->hw.saphir.timer.expires = jiffies + 4*HZ;
add_timer(&cs->hw.saphir.timer);
if (saphir_reset(cs)) {
release_io_saphir(cs);
return (0);
}
cs->readisac = &ReadISAC;
cs->writeisac = &WriteISAC;
cs->readisacfifo = &ReadISACfifo;
cs->writeisacfifo = &WriteISACfifo;
cs->BC_Read_Reg = &ReadHSCX;
cs->BC_Write_Reg = &WriteHSCX;
cs->BC_Send_Data = &hscx_fill_fifo;
cs->cardmsg = &saphir_card_msg;
ISACVersion(cs, "saphir:");
if (HscxVersion(cs, "saphir:")) {
printk(KERN_WARNING
"saphir: wrong HSCX versions check IO address\n");
release_io_saphir(cs);
return (0);
}
return (1);
}