Initial version
This commit is contained in:
parent
c10db89681
commit
c618e1bea3
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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__ */
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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__ */
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue