Initial revision

This commit is contained in:
Karsten Keil 1996-10-13 20:04:59 +00:00
parent fc5476a55d
commit 31d2853652
24 changed files with 12096 additions and 0 deletions

View File

@ -0,0 +1,42 @@
L_OBJS :=
M_OBJS :=
O_OBJS := isdnl1.o config.o buffers.o tei.o isdnl2.o isdnl3.o \
llglue.o q931.o callc.o fsm.o
# EXTRA_CFLAGS += -S
ifeq ($(CONFIG_HISAX_EURO),y)
O_OBJS += l3dss1.o
endif
ifeq ($(CONFIG_HISAX_EURO),y)
O_OBJS += l3_1tr6.o
endif
ifeq ($(CONFIG_HISAX_16_0),y)
O_OBJS += teles0.o
endif
ifeq ($(CONFIG_HISAX_16_3),y)
O_OBJS += teles3.o
endif
ifeq ($(CONFIG_HISAX_AVM_A1),y)
O_OBJS += avm_a1.o
endif
ifeq ($(CONFIG_HISAX_ELSA_PCC),y)
O_OBJS += elsa.o
endif
O_TARGET :=
ifeq ($(CONFIG_ISDN_DRV_HISAX),y)
O_TARGET += hisax.o
else
ifeq ($(CONFIG_ISDN_DRV_HISAX),m)
O_TARGET += hisax.o
M_OBJS += hisax.o
endif
endif
include $(TOPDIR)/Rules.make

971
drivers/isdn/hisax/avm_a1.c Normal file
View File

@ -0,0 +1,971 @@
/* $Id$
*
* avm_a1.c low level stuff for AVM A1 (Fritz) isdn cards
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
*
* $Log$
*
*/
#define __NO_VERSION__
#include "siemens.h"
#include "hisax.h"
#include "avm_a1.h"
#include "isdnl1.h"
#include <linux/kernel_stat.h>
extern const char *CardType[];
#define byteout(addr,val) outb_p(val,addr)
#define bytein(addr) inb_p(addr)
static inline byte
readreg(unsigned int adr, byte off)
{
return (bytein(adr + off));
}
static inline void
writereg(unsigned int adr, byte off, byte data)
{
byteout(adr +off , data);
}
static inline void
read_fifo(unsigned int adr, byte * data, int size)
{
insb(adr - 0x400 , data, size);
}
static void
write_fifo(unsigned int adr, byte * data, int size)
{
outsb(adr -0x400 , data, size);
}
static inline void
waitforCEC(int adr)
{
int to = 50;
while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "AVM A1: waitforCEC timeout\n");
}
static inline void
waitforXFW(int adr)
{
int to = 50;
while ((!(readreg(adr, HSCX_STAR) & 0x44)==0x40) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "AVM A1: waitforXFW timeout\n");
}
static inline void
writehscxCMDR(int adr, byte data)
{
long flags;
save_flags(flags);
cli();
waitforCEC(adr);
writereg(adr, HSCX_CMDR, data);
restore_flags(flags);
}
/*
* fast interrupt here
*/
static void
hscxreport(struct IsdnCardState *sp, int hscx)
{
printk(KERN_DEBUG "HSCX %d\n", hscx);
printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
}
void
avm_a1_report(struct IsdnCardState *sp)
{
printk(KERN_DEBUG "ISAC\n");
printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
hscxreport(sp, 0);
hscxreport(sp, 1);
}
/*
* HSCX stuff goes here
*/
static void
hscx_empty_fifo(struct HscxState *hsp, int count)
{
byte *ptr;
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh = hsp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_empty_fifo");
if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
HSCX_RBUF_BPPS)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "hscx_empty_fifo: incoming packet too large");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
return;
}
ptr = DATAPTR(ibh);
ptr += hsp->rcvptr;
hsp->rcvptr += count;
save_flags(flags);
cli();
read_fifo(sp->hscx[hsp->hscx], ptr, count);
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_empty_fifo %c cnt %d",
hsp->hscx?'B':'A',count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
hscx_fill_fifo(struct HscxState *hsp)
{
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh;
int more, count;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_fill_fifo");
ibh = hsp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - hsp->sendptr;
if (count <= 0)
return;
more = (hsp->mode == 1)?1:0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += hsp->sendptr;
hsp->sendptr += count;
waitforXFW(sp->hscx[hsp->hscx]);
save_flags(flags);
cli();
write_fifo(sp->hscx[hsp->hscx], ptr, count);
writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_fill_fifo %c cnt %d",
hsp->hscx?'B':'A', count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static inline void
hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
{
byte r;
struct HscxState *hsp = sp->hs + hscx;
int count, err;
char tmp[32];
if (!hsp->init)
return;
if (val & 0x80) { /* RME */
r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!r & 0x80)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX invalid frame");
if ((r & 0x40) && hsp->mode)
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX RDO mode=%d",
hsp->mode);
debugl1(sp, tmp);
}
if (!r & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX CRC error");
if (hsp->rcvibh)
BufPoolRelease(hsp->rcvibh);
hsp->rcvibh = NULL;
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRME;
}
if (!hsp->rcvibh)
if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *) 1, 1)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RME out of buffers");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRME;
} else
hsp->rcvptr = 0;
count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
if (count == 0)
count = 32;
hscx_empty_fifo(hsp, count);
hsp->rcvibh->datasize = hsp->rcvptr - 1;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!hsp->rcvibh) {
if (hsp->mode == 1)
err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
GFP_ATOMIC, (void *)1, 2);
else
err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *)1, 2);
if (err) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RPF out of buffers");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRPF;
} else
hsp->rcvptr = 0;
}
hscx_empty_fifo(hsp, 32);
if (hsp->mode == 1) {
/* receive audio data */
hsp->rcvibh->datasize = hsp->rcvptr;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
}
afterRPF:
if (val & 0x10) { /* XPR */
if (hsp->xmtibh)
if (hsp->xmtibh->datasize > hsp->sendptr) {
hscx_fill_fifo(hsp);
goto afterXPR;
} else {
if (hsp->releasebuf)
BufPoolRelease(hsp->xmtibh);
hsp->sendptr = 0;
if (hsp->st->l4.l1writewakeup)
hsp->st->l4.l1writewakeup(hsp->st);
hsp->xmtibh = NULL;
}
if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
hsp->releasebuf = !0;
hscx_fill_fifo(hsp);
} else
hscx_sched_event(hsp, HSCX_XMTBUFREADY);
}
afterXPR:
}
/*
* ISAC stuff goes here
*/
static void
isac_empty_fifo(struct IsdnCardState *sp, int count)
{
byte *ptr;
struct BufHeader *ibh = sp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
if (sp->debug & L1_DEB_ISAC)
debugl1(sp, "isac_empty_fifo");
if (sp->rcvptr >= 3072) {
if (sp->debug & L1_DEB_WARN) {
char tmp[40];
sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
debugl1(sp, tmp);
}
return;
}
ptr = DATAPTR(ibh);
ptr += sp->rcvptr;
sp->rcvptr += count;
save_flags(flags);
cli();
read_fifo(sp->isac, ptr, count);
writereg(sp->isac, ISAC_CMDR, 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_empty_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
isac_fill_fifo(struct IsdnCardState *sp)
{
struct BufHeader *ibh;
int count, more;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
debugl1(sp, "isac_fill_fifo");
ibh = sp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - sp->sendptr;
if (count <= 0)
return;
if (count >= 3072)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += sp->sendptr;
sp->sendptr += count;
save_flags(flags);
cli();
write_fifo(sp->isac, ptr, count);
writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_fill_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
ph_command(struct IsdnCardState *sp, unsigned int command)
{
if (sp->debug & L1_DEB_ISAC) {
char tmp[32];
sprintf(tmp, "ph_command %d", command);
debugl1(sp, tmp);
}
writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
}
static inline void
isac_interrupt(struct IsdnCardState *sp, byte val) {
byte exval;
unsigned int count;
char tmp[32];
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "ISAC interrupt %x", val);
debugl1(sp, tmp);
}
if (val & 0x80) { /* RME */
exval = readreg(sp->isac, ISAC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RDO");
if (!exval & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC CRC error");
if (sp->rcvibh)
BufPoolRelease(sp->rcvibh);
sp->rcvibh = NULL;
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRME;
}
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC,(void *) 1, 3)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRME;
} else
sp->rcvptr = 0;
count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
if (count == 0)
count = 32;
isac_empty_fifo(sp, count);
sp->rcvibh->datasize = sp->rcvptr;
BufQueueLink(&(sp->rq), sp->rcvibh);
sp->rcvibh = NULL;
isac_sched_event(sp, ISAC_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC, (void *) 1, 4)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRPF;
} else
sp->rcvptr = 0;
isac_empty_fifo(sp, 32);
}
afterRPF:
if (val & 0x20) { /* RSC */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (sp->xmtibh)
if (sp->xmtibh->datasize > sp->sendptr) {
isac_fill_fifo(sp);
goto afterXPR;
} else {
if (sp->releasebuf)
BufPoolRelease(sp->xmtibh);
sp->xmtibh = NULL;
sp->sendptr = 0;
}
if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
sp->releasebuf = !0;
isac_fill_fifo(sp);
} else
isac_sched_event(sp, ISAC_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
& 0xf;
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "l1state %d", sp->ph_state);
debugl1(sp, tmp);
}
isac_new_ph(sp);
}
if (val & 0x02) { /* SIN */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = readreg(sp->isac, ISAC_EXIR);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "ISAC EXIR %02x", exval);
debugl1(sp, tmp);
}
}
}
static inline void
hscx_int_main(struct IsdnCardState *sp, byte val) {
byte exval;
struct HscxState *hsp;
char tmp[32];
if (val & 0x01) {
hsp = sp->hs + 1;
exval = readreg(sp->hscx[1], HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0xf8) {
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B interrupt %x", val);
debugl1(sp, tmp);
}
hscx_interrupt(sp, val, 1);
}
if (val & 0x02) {
hsp = sp->hs;
exval = readreg(sp->hscx[0], HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->hscx[hsp->hscx],0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0x04) {
exval = readreg(sp->hscx[0], HSCX_ISTA);
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A interrupt %x", exval);
debugl1(sp, tmp);
}
hscx_interrupt(sp, exval, 0);
}
}
static void
avm_a1_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *sp;
byte val, sval, stat=0;
char tmp[32];
sp = (struct IsdnCardState *) irq2dev_map[intno];
if (!sp) {
printk(KERN_WARNING "AVM A1: Spurious interrupt!\n");
return;
}
while (((sval=bytein(sp->cfg_reg))& 0xf) !=0x7) {
if (!(sval & AVM_A1_STAT_TIMER)) {
byteout(sp->cfg_reg,0x14);
byteout(sp->cfg_reg,0x18);
sval=bytein(sp->cfg_reg);
} else
if (sp->debug & L1_DEB_INTSTAT) {
sprintf(tmp, "avm IntStatus %x", sval);
debugl1(sp, tmp);
}
if (!(sval & AVM_A1_STAT_HSCX)) {
val = readreg(sp->hscx[1], HSCX_ISTA);
if (val) {
hscx_int_main(sp,val);
stat |= 1;
}
}
if (!(sval & AVM_A1_STAT_ISAC)) {
val = readreg(sp->isac, ISAC_ISTA);
if (val) {
isac_interrupt(sp,val);
stat |= 2;
}
}
}
if (stat & 1) {
writereg(sp->hscx[0], HSCX_MASK, 0xFF);
writereg(sp->hscx[1], HSCX_MASK, 0xFF);
writereg(sp->hscx[0], HSCX_MASK, 0x0);
writereg(sp->hscx[1], HSCX_MASK, 0x0);
}
if (stat & 2) {
writereg(sp->isac, ISAC_MASK, 0xFF);
writereg(sp->isac, ISAC_MASK, 0x0);
}
}
static void
initisac(struct IsdnCardState *sp)
{
unsigned int adr=sp->isac;
/* 16.3 IOM 2 Mode */
writereg(adr, ISAC_MASK, 0xff);
writereg(adr, ISAC_ADF2, 0x80);
writereg(adr, ISAC_SQXR, 0x2f);
writereg(adr, ISAC_SPCR, 0x0);
writereg(adr, ISAC_ADF1, 0x2);
writereg(adr, ISAC_STCR, 0x70);
writereg(adr, ISAC_MODE, 0xc9);
writereg(adr, ISAC_TIMR, 0x0);
writereg(adr, ISAC_ADF1, 0x0);
writereg(adr, ISAC_CMDR, 0x41);
writereg(adr, ISAC_CIX0, (1 << 2) | 3);
writereg(adr, ISAC_MASK, 0xff);
writereg(adr, ISAC_MASK, 0x0);
}
static void
modehscx(struct HscxState *hs, int mode, int ichan)
{
struct IsdnCardState *sp = hs->sp;
int hscx = hs->hscx;
if (sp->debug & L1_DEB_HSCX) {
char tmp[40];
sprintf(tmp, "hscx %c mode %d ichan %d",
'A'+hscx, mode, ichan);
debugl1(sp, tmp);
}
hs->mode = mode;
writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
switch (mode) {
case (0):
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
break;
case (1):
if (ichan == 0) {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
} else {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
}
writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
break;
case (2):
if (ichan == 0) {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
} else {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
}
writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
break;
}
writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
}
inline static void
release_ioregs(struct IsdnCard *card, int mask) {
release_region(card->sp->cfg_reg, 8);
if (mask & 1) release_region(card->sp->isac, 32);
if (mask & 2) release_region(card->sp->isac - 0x400, 1);
if (mask & 4) release_region(card->sp->hscx[0], 32);
if (mask & 8) release_region(card->sp->hscx[0] -0x400, 1);
if (mask & 0x10) release_region(card->sp->hscx[1], 32);
if (mask & 0x20) release_region(card->sp->hscx[1] -0x400, 1);
}
void release_io_avm_a1(struct IsdnCard *card) {
release_ioregs(card, 0x3f);
}
static void
clear_pending_ints(struct IsdnCardState *sp)
{
int val;
char tmp[64];
val = readreg(sp->hscx[1], HSCX_ISTA);
sprintf(tmp, "HSCX B ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readreg(sp->hscx[1], HSCX_EXIR);
sprintf(tmp, "HSCX B EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x02) {
val = readreg(sp->hscx[0], HSCX_EXIR);
sprintf(tmp, "HSCX A EXIR %x", val);
debugl1(sp, tmp);
}
val = readreg(sp->hscx[0], HSCX_ISTA);
sprintf(tmp, "HSCX A ISTA %x", val);
debugl1(sp, tmp);
val = readreg(sp->hscx[1], HSCX_STAR);
sprintf(tmp, "HSCX B STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->hscx[0], HSCX_STAR);
sprintf(tmp, "HSCX A STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_STAR);
sprintf(tmp, "ISAC STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_MODE);
sprintf(tmp, "ISAC MODE %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_ADF2);
sprintf(tmp, "ISAC ADF2 %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_ISTA);
sprintf(tmp, "ISAC ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readreg(sp->isac, ISAC_EXIR);
sprintf(tmp, "ISAC EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x04) {
val = readreg(sp->isac, ISAC_CIR0);
sprintf(tmp, "ISAC CIR0 %x", val);
debugl1(sp, tmp);
}
writereg(sp->isac, ISAC_MASK, 0);
writereg(sp->isac, ISAC_CMDR, 0x41);
}
int
initavm_a1(struct IsdnCardState *sp)
{
int ret;
char tmp[40];
sp->counter = kstat.interrupts[sp->irq];
sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
debugl1(sp, tmp);
clear_pending_ints(sp);
ret = get_irq(sp->cardnr,&avm_a1_interrupt);
if (ret) {
initisac(sp);
sp->modehscx(sp->hs, 0, 0);
sp->modehscx(sp->hs + 1, 0, 0);
sprintf(tmp, "IRQ %d count %d", sp->irq,
kstat.interrupts[sp->irq]);
debugl1(sp, tmp);
if (kstat.interrupts[sp->irq]==sp->counter) {
printk(KERN_WARNING
"AVM A1: IRQ(%d) getting no interrupts during init\n",
sp->irq);
irq2dev_map[sp->irq] = NULL;
free_irq(sp->irq, NULL);
return(0);
}
}
return(ret);
}
int
setup_avm_a1(struct IsdnCard *card)
{
int timout;
byte val, verA, verB;
struct IsdnCardState *sp = card->sp;
if (sp->typ != ISDN_CTYPE_A1)
return(0);
sp->cfg_reg = card->para[1] + 0x1800;
sp->isac = card->para[1] + 0x1400;
sp->hscx[0] = card->para[1] + 0x400;
sp->hscx[1] = card->para[1] + 0xc00;
sp->irq = card->para[0];
if (check_region((sp->cfg_reg) ,8)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
sp->cfg_reg,
sp->cfg_reg + 8);
return (0);
} else {
request_region(sp->cfg_reg, 8, "avm cfg");
}
if (check_region((sp->isac) , 32)) {
printk(KERN_WARNING
"HiSax: %s isac ports %x-%x already in use\n",
CardType[sp->typ],
sp->isac,
sp->isac + 32);
release_ioregs(card, 0);
return(0);
} else {
request_region(sp->isac, 32, "HiSax isac");
}
if (check_region((sp->isac -0x400) , 1)) {
printk(KERN_WARNING
"HiSax: %s isac fifo port %x already in use\n",
CardType[sp->typ],
sp->isac -0x400);
release_ioregs(card, 1);
return(0);
} else {
request_region(sp->isac -0x400, 1, "HiSax isac fifo");
}
if (check_region((sp->hscx[0]) , 32)) {
printk(KERN_WARNING
"HiSax: %s hscx A ports %x-%x already in use\n",
CardType[sp->typ],
sp->hscx[0],
sp->hscx[0] + 32);
release_ioregs(card, 3);
return(0);
} else {
request_region(sp->hscx[0], 32, "HiSax hscx A");
}
if (check_region((sp->hscx[0] -0x400) , 1)) {
printk(KERN_WARNING
"HiSax: %s hscx A fifo port %x already in use\n",
CardType[sp->typ],
sp->hscx[0] -0x400);
release_ioregs(card, 7);
return(0);
} else {
request_region(sp->hscx[0] -0x400, 1, "HiSax hscx A fifo");
}
if (check_region((sp->hscx[1]) , 32)) {
printk(KERN_WARNING
"HiSax: %s hscx B ports %x-%x already in use\n",
CardType[sp->typ],
sp->hscx[1],
sp->hscx[1] + 32);
release_ioregs(card, 0xf);
return(0);
} else {
request_region(sp->hscx[1], 32, "HiSax hscx B");
}
if (check_region((sp->hscx[1] -0x400) , 1)) {
printk(KERN_WARNING
"HiSax: %s hscx B fifo port %x already in use\n",
CardType[sp->typ],
sp->hscx[1] -0x400);
release_ioregs(card, 0x1f);
return(0);
} else {
request_region(sp->hscx[1] -0x400, 1, "HiSax hscx B fifo");
}
byteout(sp->cfg_reg,0x0);
cli();
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
byteout(sp->cfg_reg,0x1);
cli();
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
byteout(sp->cfg_reg,0x0);
cli();
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
val = sp->irq;
if (val==9) val=2;
byteout(sp->cfg_reg+1,val);
cli();
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
byteout(sp->cfg_reg,0x0);
cli();
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
val=bytein(sp->cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
sp->cfg_reg,val);
val=bytein(sp->cfg_reg+3);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
sp->cfg_reg+3,val);
val=bytein(sp->cfg_reg+2);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
sp->cfg_reg+2,val);
byteout(sp->cfg_reg,0x14);
byteout(sp->cfg_reg,0x18);
val=bytein(sp->cfg_reg);
printk(KERN_INFO "AVM A1: Byte at %x is %x\n",
sp->cfg_reg,val);
printk(KERN_NOTICE
"HiSax: %s found,irq:%d isac:%x/%x cfg:%x\n",
CardType[sp->typ], sp->irq,
sp->isac, sp->isac -0x400, sp->cfg_reg);
printk(KERN_NOTICE
"HiSax: hscx A:%x/%x hscx B:%x/%x\n",
sp->hscx[0], sp->hscx[0] -0x400,
sp->hscx[1], sp->hscx[1] -0x400);
verA = readreg(sp->hscx[0],HSCX_VSTR) & 0xf;
verB = readreg(sp->hscx[1],HSCX_VSTR) & 0xf;
printk(KERN_INFO "AVM A1: HSCX version A: %s B: %s\n",
HscxVersion[verA], HscxVersion[verB]);
val = readreg(sp->isac, ISAC_RBCH);
printk(KERN_INFO "AVM A1: ISAC version %d.%d\n",
(val>>6)&1, (val>>5)&1);
if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
printk(KERN_WARNING
"AVM A1: wrong HSCX versions check IO address\n");
release_io_avm_a1(card);
return (0);
}
sp->modehscx = &modehscx;
sp->ph_command = &ph_command;
sp->hscx_fill_fifo = &hscx_fill_fifo;
sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}

View File

@ -0,0 +1,323 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include <linux/mm.h>
#include <linux/malloc.h>
#undef SMALLOC_DEBUG
void
BufPoolInit(struct BufPool *bp, int order, int bpps,
int maxpages)
{
#ifdef DEBUG_MAGIC
generateerror
bp->magic = 010167;
#endif
#if 0
printk(KERN_DEBUG "BufPoolInit bp %x\n", bp);
#endif
bp->freelist = NULL;
bp->pageslist = NULL;
bp->pageorder = order;
bp->pagescount = 0;
bp->bpps = bpps;
bp->bufsize = BUFFER_SIZE(order, bpps);
bp->maxpages = maxpages;
}
int
BufPoolAdd(struct BufPool *bp, int priority)
{
struct Pages *ptr;
byte *bptr;
int i;
struct BufHeader *bh = NULL, *prev, *first;
#if 0
printk(KERN_DEBUG "BufPoolAdd bp %x\n", bp);
#endif
ptr = (struct Pages *) __get_free_pages(priority, bp->pageorder, 0);
if (!ptr) {
printk(KERN_WARNING "BufPoolAdd couldn't get pages!\n");
return (-1);
}
#if 0
printk(KERN_DEBUG "Order %d pages allocated at %x\n", bp->pageorder, ptr);
#endif
ptr->next = bp->pageslist;
bp->pageslist = ptr;
bp->pagescount++;
bptr = (byte *) ptr + sizeof(struct Pages *);
i = bp->bpps;
first = (struct BufHeader *) bptr;
prev = NULL;
while (i--) {
bh = (struct BufHeader *) bptr;
#ifdef DEBUG_MAGIC
bh->magic = 020167;
#endif
bh->next = prev;
prev = bh;
bh->bp = bp;
bptr += PART_SIZE(bp->pageorder, bp->bpps);
}
first->next = bp->freelist;
bp->freelist = bh;
return (0);
}
void
BufPoolFree(struct BufPool *bp)
{
struct Pages *p;
#if 0
printk(KERN_DEBUG "BufPoolFree bp %x\n", bp);
#endif
while (bp->pagescount--) {
p = bp->pageslist->next;
free_pages((unsigned long) bp->pageslist, bp->pageorder);
#if 0
printk(KERN_DEBUG "Free pages %x order %d\n", bp->pageslist, bp->pageorder);
#endif
bp->pageslist = p;
}
}
int
BufPoolGet(struct BufHeader **bh,
struct BufPool *bp, int priority, void *heldby, int where)
{
long flags;
int i;
#ifdef DEBUG_MAGIC
if (bp->magic != 010167) {
printk(KERN_DEBUG "BufPoolGet: not a BufHeader\n");
return (-1);
}
#endif
save_flags(flags);
cli();
i = 0;
while (!0) {
if (bp->freelist) {
*bh = bp->freelist;
bp->freelist = bp->freelist->next;
(*bh)->heldby = heldby;
(*bh)->where = where;
restore_flags(flags);
return (0);
}
if ((i == 0) && (bp->pagescount < bp->maxpages)) {
if (BufPoolAdd(bp, priority)) {
restore_flags(flags);
return -1;
}
i++;
} else {
*bh = NULL;
restore_flags(flags);
return (-1);
}
}
}
void
BufPoolRelease(struct BufHeader *bh)
{
struct BufPool *bp;
long flags;
#ifdef DEBUG_MAGIC
if (bh->magic != 020167) {
printk(KERN_DEBUG "BufPoolRelease: not a BufHeader\n");
printk(KERN_DEBUG "called from %x\n", __builtin_return_address(0));
return;
}
#endif
bp = bh->bp;
#ifdef DEBUG_MAGIC
if (bp->magic != 010167) {
printk(KERN_DEBUG "BufPoolRelease: not a BufPool\n");
return;
}
#endif
save_flags(flags);
cli();
bh->next = bp->freelist;
bp->freelist = bh;
restore_flags(flags);
}
void
BufQueueLink(struct BufQueue *bq,
struct BufHeader *bh)
{
unsigned long flags;
save_flags(flags);
cli();
if (!bq->head)
bq->head = bh;
if (bq->tail)
bq->tail->next = bh;
bq->tail = bh;
bh->next = NULL;
restore_flags(flags);
}
void
BufQueueLinkFront(struct BufQueue *bq,
struct BufHeader *bh)
{
unsigned long flags;
save_flags(flags);
cli();
bh->next = bq->head;
bq->head = bh;
if (!bq->tail)
bq->tail = bh;
restore_flags(flags);
}
int
BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq)
{
long flags;
save_flags(flags);
cli();
if (bq->head) {
if (bq->tail == bq->head)
bq->tail = NULL;
*bh = bq->head;
bq->head = (*bh)->next;
restore_flags(flags);
return (0);
} else {
restore_flags(flags);
return (-1);
}
}
void
BufQueueInit(struct BufQueue *bq)
{
#ifdef DEBUG_MAGIC
bq->magic = 030167;
#endif
bq->head = NULL;
bq->tail = NULL;
}
void
BufQueueRelease(struct BufQueue *bq)
{
struct BufHeader *bh;
while (bq->head) {
BufQueueUnlink(&bh, bq);
BufPoolRelease(bh);
}
}
int
BufQueueLength(struct BufQueue *bq)
{
int i = 0;
struct BufHeader *bh;
bh = bq->head;
while (bh) {
i++;
bh = bh->next;
}
return (i);
}
void
BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
int releasetoo)
{
long flags;
struct BufHeader *sp;
save_flags(flags);
cli();
while (!0) {
sp = q->head;
if (!sp)
break;
if ((sp->primitive == pr) && (sp->heldby == heldby)) {
q->head = sp->next;
if (q->tail == sp)
q->tail = NULL;
if (releasetoo)
BufPoolRelease(sp);
} else
break;
}
sp = q->head;
if (sp)
while (sp->next) {
if ((sp->next->primitive == pr) && (sp->next->heldby == heldby)) {
if (q->tail == sp->next)
q->tail = sp;
if (releasetoo)
BufPoolRelease(sp->next);
sp->next = sp->next->next;
} else
sp = sp->next;
}
restore_flags(flags);
}
void
Sfree(byte * ptr)
{
#ifdef SMALLOC_DEBUG
printk(KERN_DEBUG "Sfree %x\n", (unsigned int)ptr);
#endif
kfree(ptr);
}
byte *
Smalloc(int size, int pr, char *why)
{
byte *p;
p = (byte *) kmalloc(size, pr);
#ifdef SMALLOC_DEBUG
printk(KERN_DEBUG "Smalloc %s size %d res %x\n", why, size, (unsigned int)p);
#endif
return (p);
}

1505
drivers/isdn/hisax/callc.c Normal file

File diff suppressed because it is too large Load Diff

219
drivers/isdn/hisax/config.c Normal file
View File

@ -0,0 +1,219 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
*
* $Log$
*
*
*/
#include <linux/types.h>
#include <linux/stddef.h>
#include <linux/timer.h>
#include "hisax.h"
/*
* This structure array contains one entry per card. An entry looks
* like this:
*
* { type, protocol, p0, p1, p2, NULL }
*
* type
* 1 Teles 16.0 p0=irq p1=membase p2=iobase
* 2 Teles 8.0 p0=irq p1=membase
* 3 Teles 16.3 p0=irq p1=iobase
* 4 Creatix PNP p0=irq p1=IO0 (ISAC) p2=IO1 (HSCX)
* 5 AVM A1 (Fritz) p0=irq p1=iobase
* 6 ELSA PCC16 [p0=iobase] or nothing (autodetect)
*
*
* protocol can be either ISDN_PTYPE_EURO or ISDN_PTYPE_1TR6
*
*
*/
#define EMPTY_CARD {0, 0, {0, 0, 0}, NULL}
struct IsdnCard cards[] =
{
{ISDN_CTYPE_16_0, ISDN_PTYPE_EURO,{15,0xd0000,0xd80}, NULL}, /* example */
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
EMPTY_CARD,
};
extern char *HiSax_id;
extern char *l1_revision;
extern int HiSax_Installed;
static char *HiSax_getrev(const char *revision)
{
char *rev;
char *p;
if ((p = strchr(revision, ':'))) {
rev = p + 2;
p = strchr(rev, '$');
*--p = 0;
} else
rev = "???";
return rev;
}
int nrcards;
typedef struct {
int typ;
unsigned int protocol;
unsigned int para[3];
} io_type;
#define EMPTY_IO_TYPE {0, 0, {0, 0, 0}}
io_type io[] =
{
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
EMPTY_IO_TYPE,
};
void
HiSax_mod_dec_use_count(void)
{
MOD_DEC_USE_COUNT;
}
void
HiSax_mod_inc_use_count(void)
{
MOD_INC_USE_COUNT;
}
#ifdef MODULE
#define HiSax_init init_module
#else
void HiSax_setup(char *str, int *ints)
{
int i, j, argc;
static char sid[20];
argc = ints[0];
i = 0;
j = 1;
while (argc && (i<16)) {
if (argc) {
io[i].typ = ints[j];
j++; argc--;
}
if (argc) {
io[i].protocol = ints[j];
j++; argc--;
}
if (argc) {
io[i].para[0] = ints[j];
j++; argc--;
}
if (argc) {
io[i].para[1] = ints[j];
j++; argc--;
}
if (argc) {
io[i].para[2] = ints[j];
j++; argc--;
}
i++;
}
if (strlen(str)) {
strcpy(sid,str);
HiSax_id = sid;
}
}
#endif
int
HiSax_init(void)
{
int i,j;
char tmp[256];
nrcards = 0;
printk(KERN_NOTICE "HiSax: Driver for Siemens Chipset ISDN cards\n");
printk(KERN_NOTICE "HiSax: Revision (");
strcpy(tmp,l1_revision);
printk("%s)\n",HiSax_getrev(tmp));
for (i = 0; i < 16; i++) {
if ((io[i].typ>0) && (io[i].typ<=ISDN_CTYPE_COUNT)) {
cards[i].typ = io[i].typ;
cards[i].protocol = io[i].protocol;
for (j=0;j<3;j++)
cards[i].para[j] = io[i].para[j];
}
}
for (i = 0; i < 16; i++)
if (cards[i].typ>0)
nrcards++;
printk(KERN_DEBUG "HiSax: Total %d card%s defined\n",
nrcards, (nrcards > 1) ? "s" : "");
if (HiSax_inithardware()) {
/* Install only, if at least one card found */
Isdnl2New();
TeiNew();
CallcNew();
ll_init();
/* No symbols to export, hide all symbols */
register_symtab(NULL);
#ifdef MODULE
printk(KERN_NOTICE "HiSax: module installed\n");
#endif
HiSax_Installed = 1;
return (0);
} else
return -EIO;
}
#ifdef MODULE
void
cleanup_module(void)
{
ll_stop();
TeiFree();
Isdnl2Free();
CallcFree();
HiSax_closehardware();
HiSax_Installed = 0;
ll_unload();
printk(KERN_NOTICE "HiSax module removed\n");
}
#endif

1109
drivers/isdn/hisax/elsa.c Normal file

File diff suppressed because it is too large Load Diff

45
drivers/isdn/hisax/elsa.h Normal file
View File

@ -0,0 +1,45 @@
/* $Id$
*
* elsa.h Header for Elsa ISDN cards
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
* Thanks to Elsa GmbH for documents and informations
*
*
* $Log$
*
*/
#define CARD_ISAC 0
#define CARD_HSCX 2
#define CARD_ALE 3
#define CARD_CONTROL 4
#define CARD_CONFIG 5
#define CARD_START_TIMER 6
#define CARD_TRIG_IRQ 7
/*** ***
*** Makros als Befehle fuer die Kartenregister ***
*** (mehrere Befehle werden durch Bit-Oderung kombiniert) ***
*** ***/
/* Config-Register (Read) */
#define TIMER_RUN 0x02 /* Bit 1 des Config-Reg */
#define TOGGLE 0x04 /* Bit 2 Config-Reg toggelt bei Zugriffen */
#define IRQ_INDEX 0x38 /* Bit 3,4,5 des Config-Reg */
/* Control-Register (Write) */
#define LINE_LED 0x02 /* Bit 1 Gelbe LED */
#define STAT_LED 0x08 /* Bit 3 Gruene LED */
#define ISDN_RESET 0x20 /* Bit 5 Reset-Leitung */
#define ENABLE_TIM_INT 0x80 /* Bit 7 Freigabe Timer Interrupt */
/* ALE-Register (Read) */
#define HW_RELEASE 0x07 /* Bit 0-2 Hardwarerkennung */
#define S0_POWER_BAD 0x08 /* Bit 3 S0-Bus Spannung fehlt */
extern void elsa_report(struct IsdnCardState *sp);
extern void release_io_elsa(struct IsdnCard *card);
extern int setup_elsa(struct IsdnCard *card);
extern int initelsa(struct IsdnCardState *sp);

159
drivers/isdn/hisax/fsm.c Normal file
View File

@ -0,0 +1,159 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
void
FsmNew(struct Fsm *fsm,
struct FsmNode *fnlist, int fncount)
{
int i;
fsm->jumpmatrix = (int *) Smalloc(4L * fsm->state_count * fsm->event_count,
GFP_KERNEL, "Fsm jumpmatrix");
memset(fsm->jumpmatrix, 0, 4L * fsm->state_count * fsm->event_count);
for (i = 0; i < fncount; i++)
fsm->jumpmatrix[fsm->state_count * fnlist[i].event +
fnlist[i].state] = (int) fnlist[i].routine;
}
void
FsmFree(struct Fsm *fsm)
{
Sfree((void *) fsm->jumpmatrix);
}
int
FsmEvent(struct FsmInst *fi, int event, void *arg)
{
void (*r) (struct FsmInst *, int, void *);
char str[80];
r = (void (*)) fi->fsm->jumpmatrix[fi->fsm->state_count * event + fi->state];
if (r) {
if (fi->debug) {
sprintf(str, "State %s Event %s",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
fi->printdebug(fi, str);
}
r(fi, event, arg);
return (0);
} else {
if (fi->debug) {
sprintf(str, "State %s Event %s no routine",
fi->fsm->strState[fi->state],
fi->fsm->strEvent[event]);
fi->printdebug(fi, str);
}
return (!0);
}
}
void
FsmChangeState(struct FsmInst *fi, int newstate)
{
char str[80];
fi->state = newstate;
if (fi->debug) {
sprintf(str, "ChangeState %s",
fi->fsm->strState[newstate]);
fi->printdebug(fi, str);
}
}
static void
FsmExpireTimer(struct FsmTimer *ft)
{
FsmEvent(ft->fi, ft->event, ft->arg);
}
void
FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft)
{
ft->fi = fi;
ft->tl.function = (void *) FsmExpireTimer;
ft->tl.data = (long) ft;
init_timer(&ft->tl);
}
void
FsmDelTimer(struct FsmTimer *ft, int where)
{
long flags;
#if 0
if (ft->fi->debug) {
sprintf(str, "FsmDelTimer %lx %d", ft, where);
ft->fi->printdebug(ft->fi, str);
}
#endif
save_flags(flags);
cli();
if (ft->tl.next)
del_timer(&ft->tl);
restore_flags(flags);
}
int
FsmAddTimer(struct FsmTimer *ft,
int millisec, int event, void *arg, int where)
{
#if 0
if (ft->fi->debug) {
sprintf(str, "FsmAddTimer %lx %d %d", ft, millisec, where);
ft->fi->printdebug(ft->fi, str);
}
#endif
if (ft->tl.next) {
printk(KERN_WARNING "FsmAddTimer: timer already active!\n");
return -1;
}
init_timer(&ft->tl);
ft->event = event;
ft->arg = arg;
ft->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&ft->tl);
return 0;
}
int
FsmTimerRunning(struct FsmTimer *ft)
{
return (ft->tl.next != NULL);
}
void
jiftime(char *s, long mark)
{
s += 8;
*s-- = '\0';
*s-- = mark % 10 + '0';
mark /= 10;
*s-- = mark % 10 + '0';
mark /= 10;
*s-- = '.';
*s-- = mark % 10 + '0';
mark /= 10;
*s-- = mark % 6 + '0';
mark /= 6;
*s-- = ':';
*s-- = mark % 10 + '0';
mark /= 10;
*s-- = mark % 10 + '0';
}

516
drivers/isdn/hisax/hisax.h Normal file
View File

@ -0,0 +1,516 @@
/* $Id$
*
* Basic declarations, defines and prototypes
*
* $Log$
*
*
*/
#include <linux/module.h>
#include <linux/autoconf.h>
#include <linux/version.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/major.h>
#include <asm/segment.h>
#include <asm/io.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/signal.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/ioport.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/isdnif.h>
#include <linux/tty.h>
#define PH_ACTIVATE 1
#define PH_DATA 2
#define PH_DEACTIVATE 3
#define MDL_ASSIGN 4
#define DL_UNIT_DATA 5
#define SC_STARTUP 6
#define CC_ESTABLISH 7
#define DL_ESTABLISH 8
#define DL_DATA 9
#define CC_S_STATUS_ENQ 10
#define CC_CONNECT 15
#define CC_CONNECT_ACKNOWLEDGE 16
#define CO_EOF 17
#define SC_DISCONNECT 18
#define CO_DTMF 19
#define DL_RELEASE 20
#define CO_ALARM 22
#define CC_REJECT 23
#define CC_SETUP_REQ 24
#define CC_SETUP_CNF 25
#define CC_SETUP_IND 26
#define CC_SETUP_RSP 27
#define CC_SETUP_COMPLETE_IND 28
#define CC_DISCONNECT_REQ 29
#define CC_DISCONNECT_IND 30
#define CC_RELEASE_CNF 31
#define CC_RELEASE_IND 32
#define CC_RELEASE_REQ 33
#define CC_REJECT_REQ 34
#define CC_PROCEEDING_IND 35
#define CC_DLRL 36
#define CC_DLEST 37
#define CC_ALERTING_REQ 38
#define CC_ALERTING_IND 39
#define DL_STOP 40
#define DL_START 41
#define MDL_NOTEIPROC 46
#define LC_ESTABLISH 47
#define LC_RELEASE 48
#define PH_REQUEST_PULL 49
#define PH_PULL_ACK 50
#define PH_DATA_PULLED 51
#define CC_INFO_CHARGE 52
/*
* Message-Types
*/
#define MT_ALERTING 0x01
#define MT_CALL_PROCEEDING 0x02
#define MT_CONNECT 0x07
#define MT_CONNECT_ACKNOWLEDGE 0x0f
#define MT_PROGRESS 0x03
#define MT_SETUP 0x05
#define MT_SETUP_ACKNOWLEDGE 0x0d
#define MT_RESUME 0x26
#define MT_RESUME_ACKNOWLEDGE 0x2e
#define MT_RESUME_REJECT 0x22
#define MT_SUSPEND 0x25
#define MT_SUSPEND_ACKNOWLEDGE 0x2d
#define MT_SUSPEND_REJECT 0x21
#define MT_USER_INFORMATION 0x20
#define MT_DISCONNECT 0x45
#define MT_RELEASE 0x4d
#define MT_RELEASE_COMPLETE 0x5a
#define MT_RESTART 0x46
#define MT_RESTART_ACKNOWLEDGE 0x4e
#define MT_SEGMENT 0x60
#define MT_CONGESTION_CONTROL 0x79
#define MT_INFORMATION 0x7b
#define MT_FACILITY 0x62
#define MT_NOTIFY 0x6e
#define MT_STATUS 0x7d
#define MT_STATUS_ENQUIRY 0x75
#define IE_CAUSE 0x08
struct HscxIoctlArg {
int channel;
int mode;
int transbufsize;
};
#ifdef __KERNEL__
#undef DEBUG_MAGIC
#define HSCX_SBUF_ORDER 1
#define HSCX_SBUF_BPPS 2
#define HSCX_SBUF_MAXPAGES 3
#define HSCX_RBUF_ORDER 1
#define HSCX_RBUF_BPPS 2
#define HSCX_RBUF_MAXPAGES 3
#define HSCX_SMALLBUF_ORDER 0
#define HSCX_SMALLBUF_BPPS 40
#define HSCX_SMALLBUF_MAXPAGES 1
#define ISAC_SBUF_ORDER 0
#define ISAC_SBUF_BPPS 16
#define ISAC_SBUF_MAXPAGES 1
#define ISAC_RBUF_ORDER 0
#define ISAC_RBUF_BPPS 16
#define ISAC_RBUF_MAXPAGES 1
#define ISAC_SMALLBUF_ORDER 0
#define ISAC_SMALLBUF_BPPS 40
#define ISAC_SMALLBUF_MAXPAGES 1
#define byte unsigned char
#define MAX_WINDOW 8
byte *Smalloc(int size, int pr, char *why);
void Sfree(byte * ptr);
/*
* Statemachine
*/
struct Fsm {
int *jumpmatrix;
int state_count, event_count;
char **strEvent, **strState;
};
struct FsmInst {
struct Fsm *fsm;
int state;
int debug;
void *userdata;
int userint;
void (*printdebug) (struct FsmInst *, char *);
};
struct FsmNode {
int state, event;
void (*routine) (struct FsmInst *, int, void *);
};
struct FsmTimer {
struct FsmInst *fi;
struct timer_list tl;
int event;
void *arg;
};
struct BufHeader {
#ifdef DEBUG_MAGIC
int magic;
#endif
struct BufHeader *next;
struct BufPool *bp;
int datasize;
byte primitive, where;
void *heldby;
};
struct Pages {
struct Pages *next;
};
struct BufPool {
#ifdef DEBUG_MAGIC
int magic;
#endif
struct BufHeader *freelist;
struct Pages *pageslist;
int pageorder;
int pagescount;
int bpps;
int bufsize;
int maxpages;
};
struct BufQueue {
#ifdef DEBUG_MAGIC
int magic;
#endif
struct BufHeader *head, *tail;
};
struct Layer1 {
void *hardware;
int hscx;
struct BufPool *sbufpool, *rbufpool, *smallpool;
struct PStack **stlistp;
int act_state;
void (*l1l2) (struct PStack *, int, struct BufHeader *);
void (*l1man) (struct PStack *, int, void *);
int hscxmode, hscxchannel, requestpull;
};
struct Layer2 {
int sap, tei, ces;
int extended, laptype;
int uihsize, ihsize;
int vs, va, vr;
struct BufQueue i_queue;
int window, orig;
int rejexp;
int debug;
struct BufHeader *windowar[MAX_WINDOW];
int sow;
struct FsmInst l2m;
void (*l2l1) (struct PStack *, int, struct BufHeader *);
void (*l2l1discardq) (struct PStack *, int, void *, int);
void (*l2man) (struct PStack *, int, void *);
void (*l2l3) (struct PStack *, int, void *);
void (*l2tei) (struct PStack *, int, void *);
struct FsmTimer t200_timer, t203_timer;
int t200, n200, t203;
int rc, t200_running;
char debug_id[32];
};
struct Layer3 {
void (*l3l4) (struct PStack *, int, struct BufHeader *);
void (*l3l2) (struct PStack *, int, void *);
int state, callref;
int debug;
int channr;
};
struct Layer4 {
void (*l4l3) (struct PStack *, int, void *);
void *userdata;
void (*l1writewakeup) (struct PStack *);
void (*l2writewakeup) (struct PStack *);
};
struct Management {
void (*manl1) (struct PStack *, int, void *);
void (*manl2) (struct PStack *, int, void *);
void (*teil2) (struct PStack *, int, void *);
};
struct Param {
int cause;
int bchannel;
int callref; /* TEI-Number */
int itc;
int info; /* Service-Indicator */
int info2; /* Service-Indicator, second octet */
char calling[40]; /* Called Id */
char called[40]; /* Caller Id */
int chargeinfo; /* Charge Info - only for 1tr6 in
* the moment
*/
int spv; /* SPV Flag */
};
struct PStack {
struct PStack *next;
struct Layer1 l1;
struct Layer2 l2;
struct Layer3 l3;
struct Layer4 l4;
struct Management ma;
struct Param *pa;
int protocol; /* EDSS1 or 1TR6 */
};
struct HscxState {
int inuse, init, active;
struct BufPool sbufpool, rbufpool, smallpool;
struct IsdnCardState *sp;
int hscx, mode;
int transbufsize, receive;
struct BufHeader *rcvibh, *xmtibh;
int rcvptr, sendptr;
struct PStack *st;
struct tq_struct tqueue;
int event;
struct BufQueue rq, sq;
int releasebuf;
#ifdef DEBUG_MAGIC
int magic; /* 301270 */
#endif
};
struct IsdnCardState {
#ifdef DEBUG_MAGIC
int magic;
#endif
int typ;
int protocol;
unsigned int irq;
unsigned int cfg_reg;
unsigned int membase;
unsigned int isac;
unsigned int hscx[2];
unsigned int counter;
void (*ph_command) (struct IsdnCardState *, unsigned int);
void (*modehscx) (struct HscxState *, int, int);
void (*hscx_fill_fifo) (struct HscxState *);
void (*isac_fill_fifo) (struct IsdnCardState *);
struct BufPool sbufpool, rbufpool, smallpool;
struct PStack *stlist;
struct BufHeader *xmtibh, *rcvibh;
int rcvptr, sendptr;
int event;
struct tq_struct tqueue;
int ph_active;
struct BufQueue rq, sq;
int cardnr, ph_state;
struct PStack *teistack;
struct HscxState hs[2];
int dlogflag;
char *dlogspace;
int debug;
int releasebuf;
};
#define ISDN_CTYPE_16_0 1
#define ISDN_CTYPE_8_0 2
#define ISDN_CTYPE_16_3 3
#define ISDN_CTYPE_PNP 4
#define ISDN_CTYPE_A1 5
#define ISDN_CTYPE_ELSA 6
#define ISDN_CTYPE_COUNT 6
#ifdef CONFIG_HISAX_16_0
#define CARD_TELES0 (1<< ISDN_CTYPE_16_0) | (1<< ISDN_CTYPE_8_0)
#else
#define CARD_TELES0 0
#endif
#ifdef CONFIG_HISAX_16_3
#define CARD_TELES3 (1<< ISDN_CTYPE_16_3) | (1<< ISDN_CTYPE_PNP)
#else
#define CARD_TELES3 0
#endif
#ifdef CONFIG_HISAX_AVM_A1
#define CARD_AVM_A1 (1<< ISDN_CTYPE_A1)
#else
#define CARD_AVM_A1 0
#endif
#ifdef CONFIG_HISAX_ELSA_PCC
#define CARD_ELSA (1<< ISDN_CTYPE_ELSA)
#else
#define CARD_ELSA 0
#endif
#define SUPORTED_CARDS (CARD_TELES0 | CARD_TELES3 | CARD_AVM_A1 | CARD_ELSA)
struct IsdnCard {
int typ;
int protocol; /* EDSS1 or 1TR6 */
unsigned int para[3];
struct IsdnCardState *sp;
};
#define DATAPTR(x) ((byte *)x+sizeof(struct BufHeader))
#define LAPD 0
#define LAPB 1
void BufPoolInit(struct BufPool *bp, int order, int bpps,
int maxpages);
int BufPoolAdd(struct BufPool *bp, int priority);
void BufPoolFree(struct BufPool *bp);
int BufPoolGet(struct BufHeader **bh, struct BufPool *bp,
int priority, void *heldby, int where);
void BufPoolRelease(struct BufHeader *bh);
void BufQueueLink(struct BufQueue *bq, struct BufHeader *bh);
int BufQueueUnlink(struct BufHeader **bh, struct BufQueue *bq);
void BufQueueInit(struct BufQueue *bq);
void BufQueueRelease(struct BufQueue *bq);
void BufQueueDiscard(struct BufQueue *q, int pr, void *heldby,
int releasetoo);
int BufQueueLength(struct BufQueue *bq);
void BufQueueLinkFront(struct BufQueue *bq, struct BufHeader *bh);
void l2down(struct PStack *st, byte pr, struct BufHeader *ibh);
void l2up(struct PStack *st, byte pr, struct BufHeader *ibh);
void acceptph(struct PStack *st, struct BufHeader *ibh);
void setstack_isdnl2(struct PStack *st, char *debug_id);
int HiSax_inithardware(void);
void HiSax_closehardware(void);
void setstack_HiSax(struct PStack *st, struct IsdnCardState *sp);
unsigned int randomces(void);
void setstack_isdnl3(struct PStack *st, int chan);
void HiSax_addlist(struct IsdnCardState *sp, struct PStack *st);
void releasestack_isdnl2(struct PStack *st);
void HiSax_rmlist(struct IsdnCardState *sp, struct PStack *st);
void newcallref(struct PStack *st);
int ll_init(void);
void ll_stop(void), ll_unload(void);
int setstack_hscx(struct PStack *st, struct HscxState *hs);
byte *findie(byte * p, int size, byte ie, int wanted_set);
int getcallref(byte * p);
void FsmNew(struct Fsm *fsm, struct FsmNode *fnlist, int fncount);
void FsmFree(struct Fsm *fsm);
int FsmEvent(struct FsmInst *fi, int event, void *arg);
void FsmChangeState(struct FsmInst *fi,int newstate);
void FsmInitTimer(struct FsmInst *fi, struct FsmTimer *ft);
int FsmAddTimer(struct FsmTimer *ft, int millisec,
int event, void *arg, int where);
void FsmDelTimer(struct FsmTimer *ft, int where);
int FsmTimerRunning(struct FsmTimer *ft);
void jiftime(char *s, long mark);
void CallcNew(void);
void CallcFree(void);
int CallcNewChan(void);
void CallcFreeChan(void);
int HiSax_command(isdn_ctrl * ic);
int HiSax_writebuf(int id, int chan, const u_char * buf, int count, int user);
void HiSax_putstatus(char *buf);
void HiSax_reportcard(int cardnr);
int ListLength(struct BufHeader *ibh);
int QuickHex(char *txt, byte *p, int cnt);
void LogFrame(struct IsdnCardState *sp, byte * p, int size);
void dlogframe(struct IsdnCardState *sp, byte * p, int size, char *comment);
void iecpy(byte * dest, byte * iestart, int ieoffset);
void setstack_transl2(struct PStack *st);
void releasestack_transl2(struct PStack *st);
void close_hscxstate(struct HscxState *);
void setstack_tei(struct PStack *st);
struct LcFsm {
struct FsmInst lcfi;
int type;
struct Channel *ch;
void (*lccall) (struct LcFsm *, int, void *);
struct PStack *st;
int l2_establish;
int l2_start;
struct FsmTimer act_timer;
char debug_id[32];
};
struct Channel {
struct PStack ds, is;
struct IsdnCardState *sp;
int hscx;
int chan;
int incoming;
struct FsmInst fi;
struct LcFsm lc_d, lc_b;
struct Param para;
int debug;
#ifdef DEBUG_MAGIC
int magic; /* 301272 */
#endif
int l2_protocol, l2_active_protocol;
int l2_primitive, l2_headersize;
int data_open;
int outcallref;
int impair;
struct FsmTimer icall_timer;
};
#define PART_SIZE(order,bpps) (( (PAGE_SIZE<<order) -\
sizeof(void *))/bpps)
#define BUFFER_SIZE(order,bpps) (PART_SIZE(order,bpps)-\
sizeof(struct BufHeader))
#endif
void Isdnl2New(void);
void Isdnl2Free(void);
void TeiNew(void);
void TeiFree(void);

916
drivers/isdn/hisax/isdnl1.c Normal file
View File

@ -0,0 +1,916 @@
/* $Id$
*
* isdnl1.c common low level stuff for Siemens Chipsetbased isdn cards
* based on the teles driver from Jan den Ouden
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
*
* $Log$
*
*
*/
const char *l1_revision = "$Revision$";
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl1.h"
#if CARD_TELES0
#include "teles0.h"
#endif
#if CARD_TELES3
#include "teles3.h"
#endif
#if CARD_AVM_A1
#include "avm_a1.h"
#endif
#if CARD_ELSA
#include "elsa.h"
#endif
#define INCLUDE_INLINE_FUNCS
#include <linux/tqueue.h>
#include <linux/interrupt.h>
const char *CardType[] = {"No Card","Teles 16.0","Teles 8.0","Teles 16.3",
"Creatix PNP","AVM A1","Elsa ML PCC16"};
extern void tei_handler(struct PStack *st, byte pr,
struct BufHeader *ibh);
extern struct IsdnCard cards[];
extern int nrcards;
void debugl1(struct IsdnCardState *sp, char *msg)
{
char tmp[256], tm[32];
jiftime(tm, jiffies);
sprintf(tmp, "%s Card %d %s\n", tm, sp->cardnr, msg);
HiSax_putstatus(tmp);
}
/*
* HSCX stuff goes here
*/
void
hscx_sched_event(struct HscxState *hsp, int event)
{
hsp->event |= 1 << event;
queue_task_irq_off(&hsp->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
/*
* ISAC stuff goes here
*/
void
isac_sched_event(struct IsdnCardState *sp, int event)
{
sp->event |= 1 << event;
queue_task_irq_off(&sp->tqueue, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
int
act_wanted(struct IsdnCardState *sp)
{
struct PStack *st;
st = sp->stlist;
while (st)
if (st->l1.act_state)
return (!0);
else
st = st->next;
return (0);
}
void
isac_new_ph(struct IsdnCardState *sp)
{
int enq;
enq = act_wanted(sp);
switch (sp->ph_state) {
case (0):
case (6):
if (enq)
sp->ph_command(sp, 0);
else
sp->ph_command(sp, 15);
break;
case (7):
if (enq)
sp->ph_command(sp, 9);
break;
case (12):
sp->ph_command(sp, 8);
sp->ph_active = 5;
isac_sched_event(sp, ISAC_PHCHANGE);
if (!sp->xmtibh)
if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
sp->sendptr = 0;
if (sp->xmtibh)
sp->isac_fill_fifo(sp);
break;
case (13):
sp->ph_command(sp, 9);
sp->ph_active = 5;
isac_sched_event(sp, ISAC_PHCHANGE);
if (!sp->xmtibh)
if (!BufQueueUnlink(&sp->xmtibh, &sp->sq))
sp->sendptr = 0;
if (sp->xmtibh)
sp->isac_fill_fifo(sp);
break;
case (4):
case (8):
break;
default:
sp->ph_active = 0;
break;
}
}
static void
restart_ph(struct IsdnCardState *sp)
{
switch (sp->ph_active) {
case (0):
if (sp->ph_state == 6)
sp->ph_command(sp, 0);
else
sp->ph_command(sp, 1);
sp->ph_active = 1;
break;
}
}
static void
act_ivated(struct IsdnCardState *sp)
{
struct PStack *st;
st = sp->stlist;
while (st) {
if (st->l1.act_state == 1) {
st->l1.act_state = 2;
st->l1.l1man(st, PH_ACTIVATE, NULL);
}
st = st->next;
}
}
static void
process_new_ph(struct IsdnCardState *sp)
{
if (sp->ph_active == 5)
act_ivated(sp);
}
static void
process_xmt(struct IsdnCardState *sp)
{
struct PStack *stptr;
if (sp->xmtibh)
return;
stptr = sp->stlist;
while (stptr != NULL)
if (stptr->l1.requestpull) {
stptr->l1.requestpull = 0;
stptr->l1.l1l2(stptr, PH_PULL_ACK, NULL);
break;
} else
stptr = stptr->next;
}
static void
process_rcv(struct IsdnCardState *sp)
{
struct BufHeader *ibh, *cibh;
struct PStack *stptr;
byte *ptr;
int found, broadc;
char tmp[64];
while (!BufQueueUnlink(&ibh, &sp->rq)) {
stptr = sp->stlist;
ptr = DATAPTR(ibh);
broadc = (ptr[1] >> 1) == 127;
if (broadc) {
if (sp->dlogflag && (!(ptr[0] >> 2))) {
LogFrame(sp, ptr, ibh->datasize);
dlogframe(sp, ptr + 3, ibh->datasize - 3,
"Q.931 frame network->user broadcast");
}
while (stptr != NULL) {
if ((ptr[0] >> 2) == stptr->l2.sap)
if (!BufPoolGet(&cibh, &sp->rbufpool, GFP_ATOMIC,
(void *) 1, 5)) {
memcpy(DATAPTR(cibh), DATAPTR(ibh), ibh->datasize);
cibh->datasize = ibh->datasize;
stptr->l1.l1l2(stptr, PH_DATA, cibh);
} else
printk(KERN_WARNING "HiSax: isdn broadcast buffer shortage\n");
stptr = stptr->next;
}
BufPoolRelease(ibh);
} else {
found = 0;
while (stptr != NULL)
if (((ptr[0] >> 2) == stptr->l2.sap) &&
((ptr[1] >> 1) == stptr->l2.tei)) {
stptr->l1.l1l2(stptr, PH_DATA, ibh);
found = !0;
break;
} else
stptr = stptr->next;
if (!found) {
/* BD 10.10.95
* Print out D-Channel msg not processed
* by isdn4linux
*/
if ((!(ptr[0] >> 2)) && (!(ptr[2] & 0x01))) {
sprintf(tmp,
"Q.931 frame network->user with tei %d (not for us)",
ptr[1] >> 1);
LogFrame(sp, ptr, ibh->datasize);
dlogframe(sp, ptr + 4, ibh->datasize - 4, tmp);
}
BufPoolRelease(ibh);
}
}
}
}
static void
isac_bh(struct IsdnCardState *sp)
{
if (!sp)
return;
if (clear_bit(ISAC_PHCHANGE, &sp->event))
process_new_ph(sp);
if (clear_bit(ISAC_RCVBUFREADY, &sp->event))
process_rcv(sp);
if (clear_bit(ISAC_XMTBUFREADY, &sp->event))
process_xmt(sp);
}
static void
l2l1(struct PStack *st, int pr,
struct BufHeader *ibh)
{
struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
switch (pr) {
case (PH_DATA):
if (sp->xmtibh)
BufQueueLink(&sp->sq, ibh);
else {
sp->xmtibh = ibh;
sp->sendptr = 0;
sp->releasebuf = !0;
sp->isac_fill_fifo(sp);
}
break;
case (PH_DATA_PULLED):
if (sp->xmtibh) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, " l2l1 xmtibh exist this shouldn't happen");
break;
}
sp->xmtibh = ibh;
sp->sendptr = 0;
sp->releasebuf = 0;
sp->isac_fill_fifo(sp);
break;
case (PH_REQUEST_PULL):
if (!sp->xmtibh) {
st->l1.requestpull = 0;
st->l1.l1l2(st, PH_PULL_ACK, NULL);
} else
st->l1.requestpull = !0;
break;
}
}
static void
hscx_process_xmt(struct HscxState *hsp)
{
struct PStack *st = hsp->st;
if (hsp->xmtibh)
return;
if (st->l1.requestpull) {
st->l1.requestpull = 0;
st->l1.l1l2(st, PH_PULL_ACK, NULL);
}
if (!hsp->active)
if ((!hsp->xmtibh) && (!hsp->sq.head))
hsp->sp->modehscx(hsp, 0, 0);
}
static void
hscx_process_rcv(struct HscxState *hsp)
{
struct BufHeader *ibh;
#ifdef DEBUG_MAGIC
if (hsp->magic != 301270) {
printk(KERN_DEBUG "hscx_process_rcv magic not 301270\n");
return;
}
#endif
while (!BufQueueUnlink(&ibh, &hsp->rq)) {
hsp->st->l1.l1l2(hsp->st, PH_DATA, ibh);
}
}
static void
hscx_bh(struct HscxState *hsp)
{
if (!hsp)
return;
if (clear_bit(HSCX_RCVBUFREADY, &hsp->event))
hscx_process_rcv(hsp);
if (clear_bit(HSCX_XMTBUFREADY, &hsp->event))
hscx_process_xmt(hsp);
}
/*
* interrupt stuff ends here
*/
void
HiSax_addlist(struct IsdnCardState *sp,
struct PStack *st)
{
st->next = sp->stlist;
sp->stlist = st;
}
void
HiSax_rmlist(struct IsdnCardState *sp,
struct PStack *st)
{
struct PStack *p;
if (sp->stlist == st)
sp->stlist = st->next;
else {
p = sp->stlist;
while (p)
if (p->next == st) {
p->next = st->next;
return;
} else
p = p->next;
}
}
static void
check_ph_act(struct IsdnCardState *sp)
{
struct PStack *st = sp->stlist;
while (st) {
if (st->l1.act_state)
return;
st = st->next;
}
sp->ph_active = 0;
}
static void
HiSax_manl1(struct PStack *st, int pr,
void *arg)
{
struct IsdnCardState *sp = (struct IsdnCardState *)
st->l1.hardware;
long flags;
switch (pr) {
case (PH_ACTIVATE):
save_flags(flags);
cli();
if (sp->ph_active == 5) {
st->l1.act_state = 2;
restore_flags(flags);
st->l1.l1man(st, PH_ACTIVATE, NULL);
} else {
st->l1.act_state = 1;
if (sp->ph_active == 0)
restart_ph(sp);
restore_flags(flags);
}
break;
case (PH_DEACTIVATE):
st->l1.act_state = 0;
check_ph_act(sp);
break;
}
}
static void
HiSax_l2l1discardq(struct PStack *st, int pr,
void *heldby, int releasetoo)
{
struct IsdnCardState *sp = (struct IsdnCardState *) st->l1.hardware;
#ifdef DEBUG_MAGIC
if (sp->magic != 301271) {
printk(KERN_DEBUG "isac_discardq magic not 301271\n");
return;
}
#endif
BufQueueDiscard(&sp->sq, pr, heldby, releasetoo);
}
void
setstack_HiSax(struct PStack *st, struct IsdnCardState *sp)
{
st->l1.hardware = sp;
st->l1.sbufpool = &(sp->sbufpool);
st->l1.rbufpool = &(sp->rbufpool);
st->l1.smallpool = &(sp->smallpool);
st->protocol = sp->protocol;
setstack_tei(st);
st->l1.stlistp = &(sp->stlist);
st->l1.act_state = 0;
st->l2.l2l1 = l2l1;
st->l2.l2l1discardq = HiSax_l2l1discardq;
st->ma.manl1 = HiSax_manl1;
st->l1.requestpull = 0;
}
void
init_hscxstate(struct IsdnCardState *sp,
int hscx)
{
struct HscxState *hsp = sp->hs + hscx;
hsp->sp = sp;
hsp->hscx = hscx;
hsp->tqueue.next = 0;
hsp->tqueue.sync = 0;
hsp->tqueue.routine = (void *) (void *) hscx_bh;
hsp->tqueue.data = hsp;
hsp->inuse = 0;
hsp->init = 0;
hsp->active = 0;
#ifdef DEBUG_MAGIC
hsp->magic = 301270;
#endif
}
int
get_irq(int cardnr, void *routine)
{
struct IsdnCard *card = cards + cardnr;
long flags;
save_flags(flags);
cli();
if (request_irq(card->sp->irq, routine,
SA_INTERRUPT, "HiSax", NULL)) {
printk(KERN_WARNING "HiSax: couldn't get interrupt %d\n",
card->sp->irq);
restore_flags(flags);
return (0);
}
irq2dev_map[card->sp->irq] = (void *) card->sp;
restore_flags(flags);
return (1);
}
static void
release_irq(int cardnr)
{
struct IsdnCard *card = cards + cardnr;
irq2dev_map[card->sp->irq] = NULL;
free_irq(card->sp->irq, NULL);
}
void
close_hscxstate(struct HscxState *hs)
{
hs->sp->modehscx(hs, 0, 0);
hs->inuse = 0;
if (hs->init) {
BufPoolFree(&hs->smallpool);
BufPoolFree(&hs->rbufpool);
BufPoolFree(&hs->sbufpool);
}
hs->init = 0;
}
static void
closecard(int cardnr)
{
struct IsdnCardState *sp = cards[cardnr].sp;
Sfree(sp->dlogspace);
BufPoolFree(&sp->smallpool);
BufPoolFree(&sp->rbufpool);
BufPoolFree(&sp->sbufpool);
close_hscxstate(sp->hs + 1);
close_hscxstate(sp->hs);
switch (sp->typ) {
#if CARD_TELES0
case ISDN_CTYPE_16_0:
case ISDN_CTYPE_8_0:
release_io_teles0(&cards[cardnr]);
break;
#endif
#if CARD_TELES3
case ISDN_CTYPE_PNP:
case ISDN_CTYPE_16_3:
release_io_teles3(&cards[cardnr]);
break;
#endif
#if CARD_AVM_A1
case ISDN_CTYPE_A1:
release_io_avm_a1(&cards[cardnr]);
break;
#endif
#if CARD_ELSA
case ISDN_CTYPE_ELSA:
release_io_elsa(&cards[cardnr]);
break;
#endif
default:
break;
}
}
static int
checkcard(int cardnr)
{
int ret=0;
struct IsdnCard *card = cards + cardnr;
struct IsdnCardState *sp;
sp = (struct IsdnCardState *)
Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
"struct IsdnCardState");
card->sp = sp;
sp->cardnr = cardnr;
sp->cfg_reg = 0;
sp->protocol = card->protocol;
if ((card->typ>0) && (card->typ<31)) {
if (!((1<<card->typ) & SUPORTED_CARDS)) {
printk(KERN_WARNING
"HiSax: Support for %s Card not selected\n",
CardType[card->typ]);
return(0);
}
} else {
printk(KERN_WARNING
"HiSax: Card Type %d out of range\n",
card->typ);
return (0);
}
sp->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
sp->typ = card->typ;
printk(KERN_NOTICE
"HiSax: Card %d Protocol %s\n", cardnr+1,
(card->protocol == ISDN_PTYPE_1TR6) ? "1TR6" : "EDSS1");
switch (card->typ) {
#if CARD_TELES0
case ISDN_CTYPE_16_0:
case ISDN_CTYPE_8_0:
ret=setup_teles0(card);
break;
#endif
#if CARD_TELES3
case ISDN_CTYPE_PNP:
case ISDN_CTYPE_16_3:
ret=setup_teles3(card);
break;
#endif
#if CARD_AVM_A1
case ISDN_CTYPE_A1:
ret=setup_avm_a1(card);
break;
#endif
#if CARD_ELSA
case ISDN_CTYPE_ELSA:
ret=setup_elsa(card);
break;
#endif
default:
printk(KERN_WARNING "HiSax: Unknown Card Typ %d\n",
card->typ);
Sfree(sp->dlogspace);
return(0);
}
if (!ret) {
Sfree(sp->dlogspace);
return (0);
}
BufPoolInit(&sp->sbufpool, ISAC_SBUF_ORDER, ISAC_SBUF_BPPS,
ISAC_SBUF_MAXPAGES);
BufPoolInit(&sp->rbufpool, ISAC_RBUF_ORDER, ISAC_RBUF_BPPS,
ISAC_RBUF_MAXPAGES);
BufPoolInit(&sp->smallpool, ISAC_SMALLBUF_ORDER, ISAC_SMALLBUF_BPPS,
ISAC_SMALLBUF_MAXPAGES);
sp->rcvibh = NULL;
sp->rcvptr = 0;
sp->xmtibh = NULL;
sp->sendptr = 0;
sp->event = 0;
sp->tqueue.next = 0;
sp->tqueue.sync = 0;
sp->tqueue.routine = (void *) (void *) isac_bh;
sp->tqueue.data = sp;
BufQueueInit(&sp->rq);
BufQueueInit(&sp->sq);
sp->stlist = NULL;
sp->ph_active = 0;
sp->dlogflag = 0;
sp->debug = 0xff;
sp->releasebuf = 0;
#ifdef DEBUG_MAGIC
sp->magic = 301271;
#endif
init_hscxstate(sp, 0);
init_hscxstate(sp, 1);
switch (card->typ) {
#if CARD_TELES0
case ISDN_CTYPE_16_0:
case ISDN_CTYPE_8_0:
ret=initteles0(sp);
break;
#endif
#if CARD_TELES3
case ISDN_CTYPE_PNP:
case ISDN_CTYPE_16_3:
ret=initteles3(sp);
break;
#endif
#if CARD_AVM_A1
case ISDN_CTYPE_A1:
ret=initavm_a1(sp);
break;
#endif
#if CARD_ELSA
case ISDN_CTYPE_ELSA:
ret=initelsa(sp);
break;
#endif
default:
ret=0;
break;
}
if (!ret) {
closecard(cardnr);
return(0);
}
return(1);
}
void
HiSax_shiftcards(int idx)
{
int i;
for (i = idx; i < 15; i++)
memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
}
int
HiSax_inithardware(void)
{
int foundcards = 0;
int i = 0;
while (i < nrcards) {
if (cards[i].typ<1)
break;
if (checkcard(i)) {
foundcards++;
i++;
} else {
printk(KERN_WARNING "HiSax: Card %s not installed !\n",
CardType[cards[i].typ]);
Sfree((void *) cards[i].sp);
cards[i].sp = NULL;
HiSax_shiftcards(i);
}
}
return foundcards;
}
void
HiSax_closehardware(void)
{
int i;
for (i = 0; i < nrcards; i++)
if (cards[i].sp) {
release_irq(i);
closecard(i);
Sfree((void *) cards[i].sp);
cards[i].sp = NULL;
}
}
static void
hscx_l2l1(struct PStack *st, int pr,
struct BufHeader *ibh)
{
struct IsdnCardState *sp = (struct IsdnCardState *)
st->l1.hardware;
struct HscxState *hsp = sp->hs + st->l1.hscx;
long flags;
switch (pr) {
case (PH_DATA):
save_flags(flags);
cli();
if (hsp->xmtibh) {
BufQueueLink(&hsp->sq, ibh);
restore_flags(flags);
}
else {
restore_flags(flags);
hsp->xmtibh = ibh;
hsp->sendptr = 0;
hsp->releasebuf = !0;
sp->hscx_fill_fifo(hsp);
}
break;
case (PH_DATA_PULLED):
if (hsp->xmtibh) {
printk(KERN_WARNING "hscx_l2l1: this shouldn't happen\n");
break;
}
hsp->xmtibh = ibh;
hsp->sendptr = 0;
hsp->releasebuf = 0;
sp->hscx_fill_fifo(hsp);
break;
case (PH_REQUEST_PULL):
if (!hsp->xmtibh) {
st->l1.requestpull = 0;
st->l1.l1l2(st, PH_PULL_ACK, NULL);
} else
st->l1.requestpull = !0;
break;
}
}
extern struct IsdnBuffers *tracebuf;
static void
hscx_l2l1discardq(struct PStack *st, int pr, void *heldby,
int releasetoo)
{
struct IsdnCardState *sp = (struct IsdnCardState *)
st->l1.hardware;
struct HscxState *hsp = sp->hs + st->l1.hscx;
#ifdef DEBUG_MAGIC
if (hsp->magic != 301270) {
printk(KERN_DEBUG "hscx_discardq magic not 301270\n");
return;
}
#endif
BufQueueDiscard(&hsp->sq, pr, heldby, releasetoo);
}
static int
open_hscxstate(struct IsdnCardState *sp,
int hscx)
{
struct HscxState *hsp = sp->hs + hscx;
if (!hsp->init) {
BufPoolInit(&hsp->sbufpool, HSCX_SBUF_ORDER, HSCX_SBUF_BPPS,
HSCX_SBUF_MAXPAGES);
BufPoolInit(&hsp->rbufpool, HSCX_RBUF_ORDER, HSCX_RBUF_BPPS,
HSCX_RBUF_MAXPAGES);
BufPoolInit(&hsp->smallpool, HSCX_SMALLBUF_ORDER, HSCX_SMALLBUF_BPPS,
HSCX_SMALLBUF_MAXPAGES);
}
hsp->init = !0;
BufQueueInit(&hsp->rq);
BufQueueInit(&hsp->sq);
hsp->releasebuf = 0;
hsp->rcvibh = NULL;
hsp->xmtibh = NULL;
hsp->rcvptr = 0;
hsp->sendptr = 0;
hsp->event = 0;
return (0);
}
static void
hscx_manl1(struct PStack *st, int pr,
void *arg)
{
struct IsdnCardState *sp = (struct IsdnCardState *)st->l1.hardware;
struct HscxState *hsp = sp->hs + st->l1.hscx;
switch (pr) {
case (PH_ACTIVATE):
hsp->active = !0;
sp->modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
st->l1.l1man(st, PH_ACTIVATE, NULL);
break;
case (PH_DEACTIVATE):
if (!hsp->xmtibh)
sp->modehscx(hsp, 0, 0);
hsp->active = 0;
break;
}
}
int
setstack_hscx(struct PStack *st, struct HscxState *hs)
{
if (open_hscxstate(st->l1.hardware, hs->hscx))
return (-1);
st->l1.hscx = hs->hscx;
st->l2.l2l1 = hscx_l2l1;
st->ma.manl1 = hscx_manl1;
st->l2.l2l1discardq = hscx_l2l1discardq;
st->l1.sbufpool = &hs->sbufpool;
st->l1.rbufpool = &hs->rbufpool;
st->l1.smallpool = &hs->smallpool;
st->l1.act_state = 0;
st->l1.requestpull = 0;
hs->st = st;
return (0);
}
void
HiSax_reportcard(int cardnr)
{
struct IsdnCardState *sp = cards[cardnr].sp;
printk(KERN_DEBUG "HiSax: reportcard No %d\n",cardnr+1);
printk(KERN_DEBUG "HiSax: Type %s\n", CardType[sp->typ]);
printk(KERN_DEBUG "HiSax: debuglevel %x\n", sp->debug);
if (sp->debug) sp->debug =0;
else sp->debug =0xff;
}

View File

@ -0,0 +1,29 @@
/* $Id$
*
* $Log$
*
*
*/
/* DEBUG Level */
#define L1_DEB_WARN 0x01
#define L1_DEB_INTSTAT 0x02
#define L1_DEB_ISAC 0x04
#define L1_DEB_ISAC_FIFO 0x08
#define L1_DEB_HSCX 0x10
#define L1_DEB_HSCX_FIFO 0x20
#define ISAC_RCVBUFREADY 0
#define ISAC_XMTBUFREADY 1
#define ISAC_PHCHANGE 2
#define HSCX_RCVBUFREADY 0
#define HSCX_XMTBUFREADY 1
extern void debugl1(struct IsdnCardState *sp, char *msg);
extern void hscx_sched_event(struct HscxState *hsp, int event);
extern void isac_sched_event(struct IsdnCardState *sp, int event);
extern void isac_new_ph(struct IsdnCardState *sp);
extern get_irq(int cardnr, void *routine);

1320
drivers/isdn/hisax/isdnl2.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,86 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl3.h"
void
l3_debug(struct PStack *st, char *s)
{
char str[256], tm[32];
jiftime(tm, jiffies);
sprintf(str, "%s Channel %d l3 %s\n", tm, st->l3.channr, s);
HiSax_putstatus(str);
}
void
newl3state(struct PStack *st, int state)
{
char tmp[80];
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"newstate %d --> %d",st->l3.state, state);
l3_debug(st, tmp);
}
st->l3.state = state;
}
static void
no_l3_proto(struct PStack *st, int pr, void *arg) {
struct BufHeader *ibh = arg;
l3_debug(st, "no protocol");
if (ibh)
BufPoolRelease(ibh);
}
#ifdef CONFIG_HISAX_EURO
extern void setstack_dss1(struct PStack *st);
#endif
#ifdef CONFIG_HISAX_1TR6
extern void setstack_1tr6(struct PStack *st);
#endif
void
setstack_isdnl3(struct PStack *st, int chan)
{
char tmp[64];
st->l3.debug = L3_DEB_WARN;
st->l3.channr = chan;
#ifdef CONFIG_HISAX_EURO
if (st->protocol == ISDN_PTYPE_EURO) {
setstack_dss1(st);
} else
#endif
#ifdef CONFIG_HISAX_1TR6
if (st->protocol == ISDN_PTYPE_1TR6) {
setstack_1tr6(st);
} else
#endif
{
sprintf(tmp,"protocol %s not supported",
(st->protocol==ISDN_PTYPE_1TR6)?"1tr6":"euro");
l3_debug(st,tmp);
st->l4.l4l3 = no_l3_proto;
st->l2.l2l3 = no_l3_proto;
st->protocol = -1;
}
st->l3.state = 0;
st->l3.callref = 0;
}

View File

@ -0,0 +1,24 @@
/* $Id$
*
* $Log$
*
*/
#define SBIT(state) (1<<state)
#define ALL_STATES 0x00ffffff
#define PROTO_DIS_EURO 0x08
#define L3_DEB_WARN 0x01
#define L3_DEB_PROTERR 0x02
#define L3_DEB_STATE 0x04
#define L3_DEB_CHARGE 0x08
struct stateentry {
int state;
byte primitive;
void (*rout) (struct PStack *, byte, void *);
};
extern void l3_debug(struct PStack *st, char *s);
extern void newl3state(struct PStack *st, int state);

View File

@ -0,0 +1,595 @@
/* $Id$
*
* German 1TR6 D-channel protocol
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "l3_1tr6.h"
#include "isdnl3.h"
#define MsgHead(ptr, cref, mty, dis) \
*ptr++ = dis; \
*ptr++ = 0x1; \
*ptr++ = cref; \
*ptr++ = mty
static void
l3_1TR6_message(struct PStack *st, byte mt, byte pd)
{
struct BufHeader *dibh;
byte *p;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, mt, pd);
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
}
static void
l3_1tr6_setup(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *dibh;
byte *p;
char *teln;
st->l3.callref = st->pa->callref;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_N1_SETUP, PROTO_DIS_N1);
if ('S' == (st->pa->called[0] & 0x5f)) { /* SPV ??? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
*p++ = st->pa->info; /* 0 for all Services */
*p++ = st->pa->info2; /* 0 for all Services */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV (default) */
*p++ = st->pa->info; /* 0 for all Services */
*p++ = st->pa->info2; /* 0 for all Services */
}
if (st->pa->calling[0] != '\0') {
*p++ = WE0_origAddr;
*p++ = strlen(st->pa->calling) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
teln = st->pa->calling;
while (*teln)
*p++ = *teln++ & 0x7f;
}
*p++ = WE0_destAddr;
teln = st->pa->called;
if ('S' != (st->pa->called[0] & 0x5f)) { /* Keine SPV ??? */
*p++ = strlen(st->pa->called) + 1;
st->pa->spv = 0;
} else { /* SPV */
*p++ = strlen(st->pa->called);
teln++; /* skip S */
st->pa->spv = 1;
}
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
while (*teln)
*p++ = *teln++ & 0x7f;
*p++ = WE_Shift_F6;
/* Codesatz 6 fuer Service */
*p++ = WE6_serviceInd;
*p++ = 2; /* len=2 info,info2 */
*p++ = st->pa->info;
*p++ = st->pa->info2;
dibh->datasize = p - DATAPTR(dibh);
newl3state(st, 1);
st->l3.l3l2(st, DL_DATA, dibh);
}
static void
l3_1tr6_tu_setup(struct PStack *st, byte pr, void *arg)
{
byte *p;
int bcfound = 0;
char tmp[80];
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
p += st->l2.uihsize;
st->pa->callref = getcallref(p);
st->l3.callref = 0x80 + st->pa->callref;
/* Channel Identification */
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
WE0_chanID, 0))) {
st->pa->bchannel = p[2] & 0x3;
bcfound++;
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup without bchannel");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, WE6_serviceInd, 6))) {
st->pa->info = p[2];
st->pa->info2 = p[3];
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup without service indicator");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
WE0_destAddr, 0)))
iecpy(st->pa->called, p, 1);
else
strcpy(st->pa->called, "");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
WE0_origAddr, 0))) {
iecpy(st->pa->calling, p, 1);
} else
strcpy(st->pa->calling, "");
p = DATAPTR(ibh);
st->pa->spv = 0;
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
WE0_netSpecFac, 0))) {
if ((FAC_SPV == p[3]) || (FAC_Activate == p[3]))
st->pa->spv = 1;
}
BufPoolRelease(ibh);
/* Signal all services, linklevel takes care of Service-Indicator */
if (bcfound) {
if ((st->pa->info != 7) && (st->l3.debug & L3_DEB_WARN)) {
sprintf(tmp, "non-digital call: %s -> %s",
st->pa->calling,
st->pa->called);
l3_debug(st, tmp);
}
newl3state(st, 6);
st->l3.l3l4(st, CC_SETUP_IND, NULL);
}
}
static void
l3_1tr6_tu_setup_ack(struct PStack *st, byte pr, void *arg)
{
byte *p;
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
WE0_chanID, 0))) {
st->pa->bchannel = p[2] & 0x3;
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup answer without bchannel");
BufPoolRelease(ibh);
newl3state(st, 2);
}
static void
l3_1tr6_tu_call_sent(struct PStack *st, byte pr, void *arg)
{
byte *p;
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
WE0_chanID, 0))) {
st->pa->bchannel = p[2] & 0x3;
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup answer without bchannel");
BufPoolRelease(ibh);
newl3state(st, 3);
st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
}
static void
l3_1tr6_tu_alert(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 4);
st->l3.l3l4(st, CC_ALERTING_IND, NULL);
}
static void
l3_1tr6_tu_info(struct PStack *st, byte pr, void *arg)
{
byte *p;
int i,tmpcharge=0;
char a_charge[8], tmp[32];
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
WE6_chargingInfo, 6))) {
iecpy(a_charge, p, 1);
for (i = 0; i < strlen (a_charge); i++) {
tmpcharge *= 10;
tmpcharge += a_charge[i] & 0xf;
}
if (tmpcharge > st->pa->chargeinfo) {
st->pa->chargeinfo = tmpcharge;
st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
}
if (st->l3.debug & L3_DEB_CHARGE) {
sprintf(tmp, "charging info %d", st->pa->chargeinfo);
l3_debug(st, tmp);
}
} else if (st->l3.debug & L3_DEB_CHARGE)
l3_debug(st, "charging info not found");
BufPoolRelease(ibh);
}
static void
l3_1tr6_tu_info_s2(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
}
static void
l3_1tr6_tu_connect(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
st->pa->chargeinfo=0;
BufPoolRelease(ibh);
st->l3.l3l4(st, CC_SETUP_CNF, NULL);
newl3state(st, 10);
}
static void
l3_1tr6_tu_rel(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
l3_1TR6_message(st, MT_N1_REL_ACK, PROTO_DIS_N1);
st->l3.l3l4(st, CC_RELEASE_IND, NULL);
newl3state(st, 0);
}
static void
l3_1tr6_tu_rel_ack(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 0);
st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
}
static void
l3_1tr6_tu_disc(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
byte *p;
int i,tmpcharge=0;
char a_charge[8], tmp[32];
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
WE6_chargingInfo, 6))) {
iecpy(a_charge, p, 1);
for (i = 0; i < strlen (a_charge); i++) {
tmpcharge *= 10;
tmpcharge += a_charge[i] & 0xf;
}
if (tmpcharge > st->pa->chargeinfo) {
st->pa->chargeinfo = tmpcharge;
st->l3.l3l4 (st, CC_INFO_CHARGE, NULL);
}
if (st->l3.debug & L3_DEB_CHARGE) {
sprintf(tmp, "charging info %d", st->pa->chargeinfo);
l3_debug(st, tmp);
}
} else if (st->l3.debug & L3_DEB_CHARGE)
l3_debug(st, "charging info not found");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
WE0_cause, 0))) {
if (p[1] > 0) {
st->pa->cause = p[2];
} else {
st->pa->cause = 0;
}
} else if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "cause not found");
BufPoolRelease(ibh);
newl3state(st, 12);
st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
}
static void
l3_1tr6_tu_connect_ack(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
st->pa->chargeinfo = 0;
st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
newl3state(st, 10);
}
static void
l3_1tr6_alert(struct PStack *st, byte pr,
void *arg)
{
l3_1TR6_message(st, MT_N1_ALERT, PROTO_DIS_N1);
newl3state(st, 7);
}
static void
l3_1tr6_conn(struct PStack *st, byte pr,
void *arg)
{
struct BufHeader *dibh;
byte *p;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_N1_CONN, PROTO_DIS_N1);
if (st->pa->spv) { /* SPV ??? */
/* NSF SPV */
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_SPV; /* SPV */
*p++ = st->pa->info;
*p++ = st->pa->info2;
*p++ = WE0_netSpecFac;
*p++ = 4; /* Laenge */
*p++ = 0;
*p++ = FAC_Activate; /* aktiviere SPV */
*p++ = st->pa->info;
*p++ = st->pa->info2;
}
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
newl3state(st, 8);
}
static void
l3_1tr6_reset(struct PStack *st, byte pr, void *arg)
{
newl3state(st, 0);
}
static void
l3_1tr6_disconn_req(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *dibh;
byte *p;
byte rejflg;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 21);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_N1_DISC, PROTO_DIS_N1);
if (st->l3.state == 7) {
rejflg = 1;
*p++ = WE0_cause; /* Anruf abweisen */
*p++ = 0x01; /* Laenge = 1 */
*p++ = CAUSE_CallRejected;
} else {
rejflg = 0;
*p++ = WE0_cause;
*p++ = 0x0; /* Laenge = 0 normales Ausloesen */
}
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
newl3state(st, 11);
}
static void
l3_1tr6_rel_req(struct PStack *st, byte pr, void *arg)
{
l3_1TR6_message(st, MT_N1_REL, PROTO_DIS_N1);
newl3state(st, 19);
}
static struct stateentry downstl[] =
{
{SBIT(0),
CC_SETUP_REQ, l3_1tr6_setup},
{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)|
SBIT(10),
CC_DISCONNECT_REQ, l3_1tr6_disconn_req},
{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)|
SBIT(10)| SBIT(12),
CC_RELEASE_REQ, l3_1tr6_rel_req},
{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)|
SBIT(10)| SBIT(12)| SBIT(19),
CC_DLRL, l3_1tr6_reset},
{SBIT(6),
CC_REJECT_REQ, l3_1tr6_reset},
{SBIT(6)|SBIT(7),
CC_SETUP_RSP, l3_1tr6_conn},
{SBIT(6),
CC_ALERTING_REQ, l3_1tr6_alert},
};
static int downstl_len = sizeof(downstl) /
sizeof(struct stateentry);
static struct stateentry datastln1[] =
{
{SBIT(0),
MT_N1_SETUP, l3_1tr6_tu_setup},
{SBIT(0)| SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)|
SBIT(10)| SBIT(11)| SBIT(12),
MT_N1_REL, l3_1tr6_tu_rel},
{SBIT(1),
MT_N1_SETUP_ACK, l3_1tr6_tu_setup_ack},
{SBIT(1),
MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
{SBIT(1)| SBIT(2)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10),
MT_N1_DISC, l3_1tr6_tu_disc},
{SBIT(2), MT_N1_CALL_SENT, l3_1tr6_tu_call_sent},
{SBIT(2)| SBIT(3)| SBIT(4),
MT_N1_ALERT, l3_1tr6_tu_alert},
{SBIT(2)| SBIT(3)| SBIT(4),
MT_N1_CONN, l3_1tr6_tu_connect},
{SBIT(2),
MT_N1_INFO, l3_1tr6_tu_info_s2},
{SBIT(8),
MT_N1_CONN_ACK, l3_1tr6_tu_connect_ack},
{SBIT(10),
MT_N1_INFO, l3_1tr6_tu_info},
{SBIT(19),
MT_N1_REL_ACK, l3_1tr6_tu_rel_ack}
};
static int datastln1_len = sizeof(datastln1) /
sizeof(struct stateentry);
static void
up1tr6(struct PStack *st,
int pr, void *arg)
{
int i, mt, size;
byte *ptr;
struct BufHeader *ibh = arg;
char tmp[80];
if (pr == DL_DATA) {
ptr = DATAPTR(ibh);
ptr += st->l2.ihsize;
size = ibh->datasize - st->l2.ihsize;
} else if (pr == DL_UNIT_DATA) {
ptr = DATAPTR(ibh);
ptr += st->l2.uihsize;
size = ibh->datasize - st->l2.uihsize;
} else {
if (st->l3.debug & L3_DEB_WARN) {
sprintf(tmp, "up1tr6 unknown data typ %d state %d",
pr, st->l3.state);
l3_debug(st, tmp);
}
BufPoolRelease(ibh);
return;
}
if ((ptr[0] & 0xfe) != PROTO_DIS_N0) {
if (st->l3.debug & L3_DEB_PROTERR) {
sprintf(tmp, "up1tr6%sunexpected discriminator %x message len %d state %d",
(pr==DL_DATA)?" ":"(broadcast) ",
ptr[0], size, st->l3.state);
l3_debug(st, tmp);
}
BufPoolRelease(ibh);
return;
}
mt = ptr[3];
if (ptr[0] == PROTO_DIS_N0) {
BufPoolRelease(ibh);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"up1tr6%s N0 state %d mt %x unhandled",
(pr==DL_DATA)?" ":"(broadcast) ",
st->l3.state, mt);
l3_debug(st, tmp);
}
} else if (ptr[0] == PROTO_DIS_N1) {
for (i = 0; i < datastln1_len; i++)
if ((mt == datastln1[i].primitive) &&
((1<< st->l3.state) & datastln1[i].state))
break;
if (i == datastln1_len) {
BufPoolRelease(ibh);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"up1tr6%sstate %d mt %x unhandled",
(pr==DL_DATA)?" ":"(broadcast) ",
st->l3.state, mt);
l3_debug(st, tmp);
}
return;
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"up1tr6%sstate %d mt %x",
(pr==DL_DATA)?" ":"(broadcast) ",
st->l3.state, mt);
l3_debug(st, tmp);
}
datastln1[i].rout(st, pr, ibh);
}
}
}
static void
down1tr6(struct PStack *st,
int pr, void *arg)
{
int i;
struct BufHeader *ibh = arg;
char tmp[80];
for (i = 0; i < downstl_len; i++)
if ((pr == downstl[i].primitive)&&
((1<< st->l3.state) & downstl[i].state))
break;
if (i == downstl_len) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"down1tr6 state %d prim %d unhandled",
pr, st->l3.state);
l3_debug(st, tmp);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"down1tr6 state %d prim %d",
st->l3.state, pr);
l3_debug(st, tmp);
}
downstl[i].rout(st, pr, ibh);
}
}
void
setstack_1tr6(struct PStack *st)
{
st->l4.l4l3 = down1tr6;
st->l2.l2l3 = up1tr6;
}

View File

@ -0,0 +1,157 @@
/* $Id$
*
* German 1TR6 D-channel protocol defines
*
* $Log$
*
*
*/
#ifndef l3_1tr6
#define l3_1tr6
#define PROTO_DIS_N0 0x40
#define PROTO_DIS_N1 0x41
/*
* MsgType N0
*/
#define MT_N0_REG_IND 0x61
#define MT_N0_CANC_IND 0x62
#define MT_N0_FAC_STA 0x63
#define MT_N0_STA_ACK 0x64
#define MT_N0_STA_REJ 0x65
#define MT_N0_FAC_INF 0x66
#define MT_N0_INF_ACK 0x67
#define MT_N0_INF_REJ 0x68
#define MT_N0_CLOSE 0x75
#define MT_N0_CLO_ACK 0x77
/*
* MsgType N1
*/
#define MT_N1_ESC 0x00
#define MT_N1_ALERT 0x01
#define MT_N1_CALL_SENT 0x02
#define MT_N1_CONN 0x07
#define MT_N1_CONN_ACK 0x0F
#define MT_N1_SETUP 0x05
#define MT_N1_SETUP_ACK 0x0D
#define MT_N1_RES 0x26
#define MT_N1_RES_ACK 0x2E
#define MT_N1_RES_REJ 0x22
#define MT_N1_SUSP 0x25
#define MT_N1_SUSP_ACK 0x2D
#define MT_N1_SUSP_REJ 0x21
#define MT_N1_USER_INFO 0x20
#define MT_N1_DET 0x40
#define MT_N1_DISC 0x45
#define MT_N1_REL 0x4D
#define MT_N1_REL_ACK 0x5A
#define MT_N1_CANC_ACK 0x6E
#define MT_N1_CANC_REJ 0x67
#define MT_N1_CON_CON 0x69
#define MT_N1_FAC 0x60
#define MT_N1_FAC_ACK 0x68
#define MT_N1_FAC_CAN 0x66
#define MT_N1_FAC_REG 0x64
#define MT_N1_FAC_REJ 0x65
#define MT_N1_INFO 0x6D
#define MT_N1_REG_ACK 0x6C
#define MT_N1_REG_REJ 0x6F
#define MT_N1_STAT 0x63
/*
* W Elemente
*/
#define WE_Shift_F0 0x90
#define WE_Shift_F6 0x96
#define WE_Shift_OF0 0x98
#define WE_Shift_OF6 0x9E
#define WE0_cause 0x08
#define WE0_connAddr 0x0C
#define WE0_callID 0x10
#define WE0_chanID 0x18
#define WE0_netSpecFac 0x20
#define WE0_display 0x28
#define WE0_keypad 0x2C
#define WE0_origAddr 0x6C
#define WE0_destAddr 0x70
#define WE0_userInfo 0x7E
#define WE0_moreData 0xA0
#define WE0_congestLevel 0xB0
#define WE6_serviceInd 0x01
#define WE6_chargingInfo 0x02
#define WE6_date 0x03
#define WE6_facSelect 0x05
#define WE6_facStatus 0x06
#define WE6_statusCalled 0x07
#define WE6_addTransAttr 0x08
/*
* FacCodes
*/
#define FAC_Sperre 0x01
#define FAC_Sperre_All 0x02
#define FAC_Sperre_Fern 0x03
#define FAC_Sperre_Intl 0x04
#define FAC_Sperre_Interk 0x05
#define FAC_Forward1 0x02
#define FAC_Forward2 0x03
#define FAC_Konferenz 0x06
#define FAC_GrabBchan 0x0F
#define FAC_Reactivate 0x10
#define FAC_Konferenz3 0x11
#define FAC_Dienstwechsel1 0x12
#define FAC_Dienstwechsel2 0x13
#define FAC_NummernIdent 0x14
#define FAC_GBG 0x15
#define FAC_DisplayUebergeben 0x17
#define FAC_DisplayUmgeleitet 0x1A
#define FAC_Unterdruecke 0x1B
#define FAC_Deactivate 0x1E
#define FAC_Activate 0x1D
#define FAC_SPV 0x1F
#define FAC_Rueckwechsel 0x23
#define FAC_Umleitung 0x24
/*
* Cause codes
*/
#define CAUSE_InvCRef 0x01
#define CAUSE_BearerNotImpl 0x03
#define CAUSE_CIDunknown 0x07
#define CAUSE_CIDinUse 0x08
#define CAUSE_NoChans 0x0A
#define CAUSE_FacNotImpl 0x10
#define CAUSE_FacNotSubscr 0x11
#define CAUSE_OutgoingBarred 0x20
#define CAUSE_UserAccessBusy 0x21
#define CAUSE_NegativeGBG 0x22
#define CAUSE_UnknownGBG 0x23
#define CAUSE_NoSPVknown 0x25
#define CAUSE_DestNotObtain 0x35
#define CAUSE_NumberChanged 0x38
#define CAUSE_OutOfOrder 0x39
#define CAUSE_NoUserResponse 0x3A
#define CAUSE_UserBusy 0x3B
#define CAUSE_IncomingBarred 0x3D
#define CAUSE_CallRejected 0x3E
#define CAUSE_NetworkCongestion 0x59
#define CAUSE_RemoteUser 0x5A
#define CAUSE_LocalProcErr 0x70
#define CAUSE_RemoteProcErr 0x71
#define CAUSE_RemoteUserSuspend 0x72
#define CAUSE_RemoteUserResumed 0x73
#define CAUSE_UserInfoDiscarded 0x7F
#endif

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

@ -0,0 +1,511 @@
/* $Id$
*
* EURO/DSS1 D-channel protocol
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include "isdnl3.h"
#define MsgHead(ptr, cref, mty) \
*ptr++ = 0x8; \
*ptr++ = 0x1; \
*ptr++ = cref; \
*ptr++ = mty
static void
l3_message(struct PStack *st, byte mt)
{
struct BufHeader *dibh;
byte *p;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 18);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, mt);
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
}
static void
l3s3(struct PStack *st, byte pr, void *arg)
{
l3_message(st, MT_RELEASE);
newl3state(st, 19);
}
static void
l3s4(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 0);
st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
}
static void
l3s4_1(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 19);
l3_message(st, MT_RELEASE);
st->l3.l3l4(st, CC_RELEASE_CNF, NULL);
}
static void
l3s5(struct PStack *st, byte pr,
void *arg)
{
struct BufHeader *dibh;
byte *p;
char *teln;
st->l3.callref = st->pa->callref;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 19);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_SETUP);
/*
* Set Bearer Capability, Map info from 1TR6-convention to EDSS1
*/
*p++ = 0xa1;
switch (st->pa->info) {
case 1: /* Telephony */
*p++ = 0x4; /* BC-IE-code */
*p++ = 0x3; /* Length */
*p++ = 0x90; /* Coding Std. national, 3.1 kHz audio */
*p++ = 0x90; /* Circuit-Mode 64kbps */
*p++ = 0xa3; /* A-Law Audio */
break;
case 5: /* Datatransmission 64k, BTX */
case 7: /* Datatransmission 64k */
default:
*p++ = 0x4; /* BC-IE-code */
*p++ = 0x2; /* Length */
*p++ = 0x88; /* Coding Std. nat., unrestr. dig. Inform. */
*p++ = 0x90; /* Packet-Mode 64kbps */
break;
}
/*
* What about info2? Mapping to High-Layer-Compatibility?
*/
if (st->pa->calling[0] != '\0') {
*p++ = 0x6c;
*p++ = strlen(st->pa->calling) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
teln = st->pa->calling;
while (*teln)
*p++ = *teln++ & 0x7f;
}
*p++ = 0x70;
*p++ = strlen(st->pa->called) + 1;
/* Classify as AnyPref. */
*p++ = 0x81; /* Ext = '1'B, Type = '000'B, Plan = '0001'B. */
teln = st->pa->called;
while (*teln)
*p++ = *teln++ & 0x7f;
dibh->datasize = p - DATAPTR(dibh);
newl3state(st, 1);
st->l3.l3l2(st, DL_DATA, dibh);
}
static void
l3s6(struct PStack *st, byte pr, void *arg)
{
byte *p;
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.ihsize, ibh->datasize - st->l2.ihsize,
0x18, 0))) {
st->pa->bchannel = p[2] & 0x3;
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup answer without bchannel");
BufPoolRelease(ibh);
newl3state(st, 3);
st->l3.l3l4(st, CC_PROCEEDING_IND, NULL);
}
static void
l3s7(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 12);
st->l3.l3l4(st, CC_DISCONNECT_IND, NULL);
}
static void
l3s8(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
st->l3.l3l4(st, CC_SETUP_CNF, NULL);
newl3state(st, 10);
}
static void
l3s11(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 4);
st->l3.l3l4(st, CC_ALERTING_IND, NULL);
}
static void
l3s12(struct PStack *st, byte pr, void *arg)
{
byte *p;
int bcfound = 0;
char tmp[80];
struct BufHeader *ibh = arg;
p = DATAPTR(ibh);
p += st->l2.uihsize;
st->pa->callref = getcallref(p);
st->l3.callref = 0x80 + st->pa->callref;
/*
* Channel Identification
*/
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
0x18, 0))) {
st->pa->bchannel = p[2] & 0x3;
bcfound++ ;
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup without bchannel");
p = DATAPTR(ibh);
/*
* Bearer Capabilities
*/
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize, 0x04, 0))) {
switch (p[2] & 0x1f) {
case 0x00:
/* Speech */
case 0x10:
/* 3.1 Khz audio */
st->pa->info = 1;
break;
case 0x08:
/* Unrestricted digital information */
st->pa->info = 7;
break;
case 0x09:
/* Restricted digital information */
st->pa->info = 2;
break;
case 0x11:
/* Unrestr. digital information with tones/announcements */
st->pa->info = 3;
break;
case 0x18:
/* Video */
st->pa->info = 4;
break;
default:
st->pa->info = 0;
}
} else
if (st->l3.debug & L3_DEB_WARN)
l3_debug(st, "setup without bearer capabilities");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
0x70, 0)))
iecpy(st->pa->called, p, 1);
else
strcpy(st->pa->called, "");
p = DATAPTR(ibh);
if ((p = findie(p + st->l2.uihsize, ibh->datasize - st->l2.uihsize,
0x6c, 0)))
iecpy(st->pa->calling, p, 2);
else
strcpy(st->pa->calling, "");
BufPoolRelease(ibh);
if (bcfound) {
if ((st->pa->info != 7) && (st->l3.debug & L3_DEB_WARN)) {
sprintf(tmp, "non-digital call: %s -> %s",
st->pa->calling,
st->pa->called);
l3_debug(st, tmp);
}
newl3state(st, 6);
st->l3.l3l4(st, CC_SETUP_IND, NULL);
}
}
static void
l3s13(struct PStack *st, byte pr, void *arg)
{
newl3state(st, 0);
}
static void
l3s16(struct PStack *st, byte pr,
void *arg)
{
st->l3.callref = 0x80 + st->pa->callref;
l3_message(st, MT_CONNECT);
newl3state(st, 8);
}
static void
l3s17(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
st->l3.l3l4(st, CC_SETUP_COMPLETE_IND, NULL);
newl3state(st, 10);
}
static void
l3s18(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *dibh;
byte *p;
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_DISCONNECT);
*p++ = IE_CAUSE;
*p++ = 0x2;
*p++ = 0x80;
*p++ = 0x90;
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
newl3state(st, 11);
}
static void
l3s19(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *ibh = arg;
BufPoolRelease(ibh);
newl3state(st, 0);
l3_message(st, MT_RELEASE_COMPLETE);
st->l3.l3l4(st, CC_RELEASE_IND, NULL);
}
static void
l3s20(struct PStack *st, byte pr,
void *arg)
{
l3_message(st, MT_ALERTING);
newl3state(st, 7);
}
/* Status enquire answer */
static void
l3s21(struct PStack *st, byte pr, void *arg)
{
struct BufHeader *dibh = arg;
byte *p;
BufPoolRelease(dibh);
BufPoolGet(&dibh, st->l1.sbufpool, GFP_ATOMIC, (void *) st, 20);
p = DATAPTR(dibh);
p += st->l2.ihsize;
MsgHead(p, st->l3.callref, MT_STATUS);
*p++ = IE_CAUSE;
*p++ = 0x2;
*p++ = 0x80;
*p++ = 0x9E; /* answer status enquire */
*p++ = 0x14; /* CallState */
*p++ = 0x1;
*p++ = st->l3.state & 0x3f;
dibh->datasize = p - DATAPTR(dibh);
st->l3.l3l2(st, DL_DATA, dibh);
}
static struct stateentry downstatelist[] =
{
{SBIT(0),
CC_SETUP_REQ,l3s5},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)| SBIT(10),
CC_DISCONNECT_REQ,l3s18},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)| SBIT(10)|
SBIT(11)| SBIT(12),
CC_RELEASE_REQ,l3s3},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(6)| SBIT(7)| SBIT(8)| SBIT(10)|
SBIT(19),
CC_DLRL,l3s13},
{SBIT(6),
CC_ALERTING_REQ,l3s20},
{SBIT(6)| SBIT(7),
CC_SETUP_RSP,l3s16},
};
static int downsllen = sizeof(downstatelist) /
sizeof(struct stateentry);
static struct stateentry datastatelist[] =
{
{ALL_STATES,
MT_STATUS_ENQUIRY,l3s21},
{SBIT(0)| SBIT(6),
MT_SETUP,l3s12},
{SBIT(1),
MT_CALL_PROCEEDING,l3s6},
{SBIT(1),
MT_SETUP_ACKNOWLEDGE,l3s6},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(11)| SBIT(19),
MT_RELEASE_COMPLETE,l3s4},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10)| SBIT(11),
MT_RELEASE,l3s19},
{SBIT(1)| SBIT(3)| SBIT(4)| SBIT(7)| SBIT(8)| SBIT(10),
MT_DISCONNECT,l3s7},
{SBIT(3)| SBIT(4),
MT_CONNECT,l3s8},
{SBIT(3),
MT_ALERTING,l3s11},
{SBIT(7)| SBIT(8)| SBIT(10),
MT_RELEASE_COMPLETE,l3s4_1},
{SBIT(8),
MT_CONNECT_ACKNOWLEDGE,l3s17},
};
static int datasllen = sizeof(datastatelist) /
sizeof(struct stateentry);
static void
dss1up(struct PStack *st,
int pr, void *arg)
{
int i, mt, size;
byte *ptr;
struct BufHeader *ibh = arg;
char tmp[80];
if (pr == DL_DATA) {
ptr = DATAPTR(ibh);
ptr += st->l2.ihsize;
size = ibh->datasize - st->l2.ihsize;
} else if (pr == DL_UNIT_DATA) {
ptr = DATAPTR(ibh);
ptr += st->l2.uihsize;
size = ibh->datasize - st->l2.uihsize;
} else {
if (st->l3.debug & L3_DEB_WARN) {
sprintf(tmp, "dss1up unknown data typ %d state %d",
pr, st->l3.state);
l3_debug(st, tmp);
}
BufPoolRelease(ibh);
return;
}
if (ptr[0] != PROTO_DIS_EURO) {
if (st->l3.debug & L3_DEB_PROTERR) {
sprintf(tmp, "dss1up%sunexpected discriminator %x message len %d state %d",
(pr==DL_DATA)?" ":"(broadcast) ",
ptr[0], size, st->l3.state);
l3_debug(st, tmp);
}
BufPoolRelease(ibh);
return;
}
mt = ptr[3];
for (i = 0; i < datasllen; i++)
if ((mt == datastatelist[i].primitive) &&
((1<< st->l3.state) & datastatelist[i].state))
break;
if (i == datasllen) {
BufPoolRelease(ibh);
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"dss1up%sstate %d mt %x unhandled",
(pr==DL_DATA)?" ":"(broadcast) ",
st->l3.state, mt);
l3_debug(st, tmp);
}
return;
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"dss1up%sstate %d mt %x",
(pr==DL_DATA)?" ":"(broadcast) ",
st->l3.state, mt);
l3_debug(st, tmp);
}
datastatelist[i].rout(st, pr, ibh);
}
}
static void
dss1down(struct PStack *st,
int pr, void *arg)
{
int i;
struct BufHeader *ibh = arg;
char tmp[80];
for (i = 0; i < downsllen; i++)
if ((pr == downstatelist[i].primitive)&&
((1<< st->l3.state) & downstatelist[i].state))
break;
if (i == downsllen) {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"dss1down state %d prim %d unhandled",
pr, st->l3.state);
l3_debug(st, tmp);
}
} else {
if (st->l3.debug & L3_DEB_STATE) {
sprintf(tmp,"dss1down state %d prim %d",
st->l3.state, pr);
l3_debug(st, tmp);
}
downstatelist[i].rout(st, pr, ibh);
}
}
void
setstack_dss1(struct PStack *st)
{
st->l4.l4l3 = dss1down;
st->l2.l2l3 = dss1up;
}

157
drivers/isdn/hisax/llglue.c Normal file
View File

@ -0,0 +1,157 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*/
#define __NO_VERSION__
#include "hisax.h"
#include <linux/malloc.h>
#include <linux/timer.h>
extern struct Channel *chanlist;
int HiSax_Installed=0;
int drid;
char *HiSax_id = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
isdn_if iif;
#define HISAX_STATUS_BUFSIZE 4096
static byte *HiSax_status_buf = NULL;
static byte *HiSax_status_read = NULL;
static byte *HiSax_status_write = NULL;
static byte *HiSax_status_end = NULL;
int
HiSax_readstatus(byte * buf, int len, int user, int id, int channel)
{
int count;
byte *p;
for (p = buf, count = 0; count < len; p++, count++) {
if (user)
put_fs_byte(*HiSax_status_read++, p);
else
*p++ = *HiSax_status_read++;
if (HiSax_status_read > HiSax_status_end)
HiSax_status_read = HiSax_status_buf;
}
return count;
}
void
HiSax_putstatus(char *buf)
{
long flags;
int len, count, i;
byte *p;
isdn_ctrl ic;
save_flags(flags);
cli();
count = 0;
len = strlen(buf);
if (!HiSax_Installed) {
printk(KERN_DEBUG "HiSax: %s", buf);
restore_flags(flags);
return;
}
for (p = buf, i = len; i > 0; i--, p++) {
*HiSax_status_write++ = *p;
if (HiSax_status_write > HiSax_status_end)
HiSax_status_write = HiSax_status_buf;
count++;
}
restore_flags(flags);
if (count) {
ic.command = ISDN_STAT_STAVAIL;
ic.driver = drid;
ic.arg = count;
iif.statcallb(&ic);
}
}
int
ll_init(void)
{
long flags;
isdn_ctrl ic;
save_flags(flags);
cli();
HiSax_status_buf = Smalloc(HISAX_STATUS_BUFSIZE,
GFP_KERNEL, "HiSax_status_buf");
if (!HiSax_status_buf) {
printk(KERN_ERR "HiSax: Could not allocate status-buffer\n");
restore_flags(flags);
return (-EIO);
} else {
HiSax_status_read = HiSax_status_buf;
HiSax_status_write = HiSax_status_buf;
HiSax_status_end = HiSax_status_buf + HISAX_STATUS_BUFSIZE - 1;
}
iif.channels = CallcNewChan();
iif.maxbufsize = BUFFER_SIZE(HSCX_SBUF_ORDER, HSCX_SBUF_BPPS);
iif.features =
ISDN_FEATURE_L2_X75I |
ISDN_FEATURE_L2_HDLC |
ISDN_FEATURE_L2_TRANS |
ISDN_FEATURE_L3_TRANS |
#ifdef CONFIG_HISAX_EURO
ISDN_FEATURE_P_1TR6 |
#endif
#ifdef CONFIG_HISAX_EURO
ISDN_FEATURE_P_EURO |
#endif
0;
iif.command = HiSax_command;
iif.writebuf = HiSax_writebuf;
iif.writecmd = NULL;
iif.readstat = HiSax_readstatus;
strncpy(iif.id, HiSax_id, sizeof(iif.id) - 1);
register_isdn(&iif);
drid = iif.channels;
ic.driver = drid;
ic.command = ISDN_STAT_RUN;
iif.statcallb(&ic);
restore_flags(flags);
return 0;
}
void
ll_stop(void)
{
isdn_ctrl ic;
ic.command = ISDN_STAT_STOP;
ic.driver = drid;
iif.statcallb(&ic);
CallcFreeChan();
}
void
ll_unload(void)
{
isdn_ctrl ic;
ic.command = ISDN_STAT_UNLOAD;
ic.driver = drid;
iif.statcallb(&ic);
if (HiSax_status_buf)
Sfree(HiSax_status_buf);
HiSax_status_read = NULL;
HiSax_status_write = NULL;
HiSax_status_end = NULL;
}

1163
drivers/isdn/hisax/q931.c Normal file

File diff suppressed because it is too large Load Diff

252
drivers/isdn/hisax/tei.c Normal file
View File

@ -0,0 +1,252 @@
/* $Id$
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
* based on the teles driver from Jan den Ouden
*
* Thanks to Jan den Ouden
* Fritz Elfert
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include "hisax.h"
extern struct IsdnCard cards[];
extern int nrcards;
static struct PStack *
findces(struct PStack *st, int ces)
{
struct PStack *ptr = *(st->l1.stlistp);
while (ptr)
if (ptr->l2.ces == ces)
return (ptr);
else
ptr = ptr->next;
return (NULL);
}
static struct PStack *
findtei(struct PStack *st, int tei)
{
struct PStack *ptr = *(st->l1.stlistp);
if (tei == 127)
return (NULL);
while (ptr)
if (ptr->l2.tei == tei)
return (ptr);
else
ptr = ptr->next;
return (NULL);
}
void
tei_handler(struct PStack *st,
byte pr, struct BufHeader *ibh)
{
byte *bp;
unsigned int tces;
struct PStack *otsp, *ptr;
unsigned int data;
if (st->l2.debug)
printk(KERN_DEBUG "teihandler %d\n", pr);
switch (pr) {
case (MDL_ASSIGN):
data = (unsigned int) ibh;
BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 6);
if (!ibh)
return;
bp = DATAPTR(ibh);
bp += st->l2.uihsize;
bp[0] = 0xf;
bp[1] = data >> 8;
bp[2] = data & 0xff;
bp[3] = 0x1;
bp[4] = 0xff;
ibh->datasize = 8;
st->l3.l3l2(st, DL_UNIT_DATA, ibh);
break;
case (DL_UNIT_DATA):
bp = DATAPTR(ibh);
bp += 3;
if (bp[0] != 0xf)
break;
switch (bp[3]) {
case (2):
tces = (bp[1] << 8) | bp[2];
BufPoolRelease(ibh);
if (st->l3.debug)
printk(KERN_DEBUG "tei identity assigned for %d=%d\n", tces,
bp[4] >> 1);
if ((otsp = findces(st, tces)))
otsp->ma.teil2(otsp, MDL_ASSIGN,
(void *)(bp[4] >> 1));
break;
case (4):
if (st->l3.debug)
printk(KERN_DEBUG "checking identity for %d\n", bp[4] >> 1);
if (bp[4] >> 1 == 0x7f) {
BufPoolRelease(ibh);
ptr = *(st->l1.stlistp);
while (ptr) {
if ((ptr->l2.tei & 0x7f) != 0x7f) {
if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
break;
bp = DATAPTR(ibh);
bp += 3;
bp[0] = 0xf;
bp[1] = ptr->l2.ces >> 8;
bp[2] = ptr->l2.ces & 0xff;
bp[3] = 0x5;
bp[4] = (ptr->l2.tei << 1) | 1;
ibh->datasize = 8;
st->l3.l3l2(st, DL_UNIT_DATA, ibh);
}
ptr = ptr->next;
}
} else {
otsp = findtei(st, bp[4] >> 1);
BufPoolRelease(ibh);
if (!otsp)
break;
if (st->l3.debug)
printk(KERN_DEBUG "ces is %d\n", otsp->l2.ces);
if (BufPoolGet(&ibh, st->l1.smallpool, GFP_ATOMIC, (void *) st, 7))
break;
bp = DATAPTR(ibh);
bp += 3;
bp[0] = 0xf;
bp[1] = otsp->l2.ces >> 8;
bp[2] = otsp->l2.ces & 0xff;
bp[3] = 0x5;
bp[4] = (otsp->l2.tei << 1) | 1;
ibh->datasize = 8;
st->l3.l3l2(st, DL_UNIT_DATA, ibh);
}
break;
default:
BufPoolRelease(ibh);
if (st->l3.debug)
printk(KERN_DEBUG "tei message unknown %d ai %d\n", bp[3], bp[4] >> 1);
}
break;
default:
printk(KERN_WARNING "tei handler unknown primitive %d\n", pr);
break;
}
}
unsigned int
randomces(void)
{
int x = jiffies & 0xffff;
return (x);
}
static void
tei_man(struct PStack *sp, int i, void *v)
{
printk(KERN_DEBUG "tei_man\n");
}
static void
tei_l2tei(struct PStack *st, int pr, void *arg)
{
struct IsdnCardState *sp = st->l1.hardware;
tei_handler(sp->teistack, pr, arg);
}
void
setstack_tei(struct PStack *st)
{
st->l2.l2tei = tei_l2tei;
}
static void
init_tei(struct IsdnCardState *sp, int protocol)
{
struct PStack *st;
char tmp[128];
#define DIRTY_HACK_AGAINST_SIGSEGV
st = (struct PStack *) Smalloc(sizeof(struct PStack), GFP_KERNEL,
"struct PStack");
#ifdef DIRTY_HACK_AGAINST_SIGSEGV
sp->teistack = st; /* struct is not initialized yet */
sp->teistack->protocol = protocol; /* struct is not initialized yet */
#endif /* DIRTY_HACK_AGAINST_SIGSEGV */
setstack_HiSax(st, sp);
st->l2.extended = !0;
st->l2.laptype = LAPD;
st->l2.window = 1;
st->l2.orig = !0;
st->protocol = protocol;
/*
* the following is not necessary for tei mng. (broadcast only)
*/
st->l2.t200 = 500; /* 500 milliseconds */
st->l2.n200 = 4; /* try 4 times */
st->l2.sap = 63;
st->l2.tei = 127;
sprintf(tmp, "Card %d tei ", sp->cardnr);
setstack_isdnl2(st, tmp);
st->l2.debug = 0;
st->l3.debug = 0;
st->ma.manl2(st, MDL_NOTEIPROC, NULL);
st->l2.l2l3 = (void *) tei_handler;
st->l1.l1man = tei_man;
st->l2.l2man = tei_man;
st->l4.l2writewakeup = NULL;
HiSax_addlist(sp, st);
sp->teistack = st;
}
static void
release_tei(struct IsdnCardState *sp)
{
struct PStack *st = sp->teistack;
HiSax_rmlist(sp, st);
Sfree((void *) st);
}
void
TeiNew(void)
{
int i;
for (i = 0; i < nrcards; i++)
if (cards[i].sp)
init_tei(cards[i].sp, cards[i].protocol);
}
void
TeiFree(void)
{
int i;
for (i = 0; i < nrcards; i++)
if (cards[i].sp)
release_tei(cards[i].sp);
}

978
drivers/isdn/hisax/teles0.c Normal file
View File

@ -0,0 +1,978 @@
/* $Id$
*
* teles0.c low level stuff for Teles Memory IO isdn cards
* based on the teles driver from Jan den Ouden
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include "siemens.h"
#include "hisax.h"
#include "teles0.h"
#include "isdnl1.h"
#include <linux/kernel_stat.h>
extern const char *CardType[];
#define byteout(addr,val) outb_p(val,addr)
#define bytein(addr) inb_p(addr)
static inline byte
readisac(unsigned int adr, byte off)
{
return *(byte *) (adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off);
}
static inline void
writeisac(unsigned int adr, byte off, byte data)
{
*(byte *) (adr + 0x120 + ((off & 1) ? 0x1ff : 0) + off) = data;
}
static inline byte
readhscx(unsigned int adr, int hscx, byte off)
{
return *(byte *) (adr +(hscx? 0x1e0: 0x1a0) +
((off & 1) ? 0x1ff : 0) + off);
}
static inline void
writehscx(unsigned int adr, int hscx, byte off, byte data)
{
*(byte *) (adr +(hscx ? 0x1e0: 0x1a0) +
((off & 1) ? 0x1ff : 0) + off) = data;
}
static inline void
read_fifo_isac(unsigned int adr, byte * data, int size)
{
register int i;
register byte *ad = (byte *) (adr + 0x100);
for (i=0;i<size;i++)
data[i] = *ad;
}
static void
write_fifo_isac(unsigned int adr, byte * data, int size)
{
register int i;
register byte *ad = (byte *) (adr + 0x100);
for (i=0;i<size;i++)
*ad = data[i];
}
static inline void
read_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
{
register int i;
register byte *ad = (byte *) (adr +(hscx ? 0x1c0: 0x180));
for (i=0;i<size;i++)
data[i] = *ad;
}
static inline void
write_fifo_hscx(unsigned int adr, int hscx, byte * data, int size)
{
int i;
register byte *ad = (byte *) (adr +(hscx ? 0x1c0: 0x180));
for (i=0;i<size;i++)
*ad = data[i];
}
static inline void
waitforCEC(int adr, int hscx)
{
int to = 50;
while ((readhscx(adr, hscx, HSCX_STAR) & 0x04) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "Teles0: waitforCEC timeout\n");
}
static inline void
waitforXFW(int adr, int hscx)
{
int to = 50;
while ((!(readhscx(adr, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "Teles0: waitforXFW timeout\n");
}
static inline void
writehscxCMDR(int adr, int hscx, byte data)
{
long flags;
save_flags(flags);
cli();
waitforCEC(adr, hscx);
writehscx(adr, hscx, HSCX_CMDR, data);
restore_flags(flags);
}
/*
* fast interrupt here
*/
static void
hscxreport(struct IsdnCardState *sp, int hscx)
{
printk(KERN_DEBUG "HSCX %d\n", hscx);
printk(KERN_DEBUG "ISTA %x\n", readhscx(sp->membase, hscx, HSCX_ISTA));
printk(KERN_DEBUG "STAR %x\n", readhscx(sp->membase, hscx, HSCX_STAR));
printk(KERN_DEBUG "EXIR %x\n", readhscx(sp->membase, hscx, HSCX_EXIR));
}
void
teles0_report(struct IsdnCardState *sp)
{
printk(KERN_DEBUG "ISAC\n");
printk(KERN_DEBUG "ISTA %x\n", readisac(sp->membase, ISAC_ISTA));
printk(KERN_DEBUG "STAR %x\n", readisac(sp->membase, ISAC_STAR));
printk(KERN_DEBUG "EXIR %x\n", readisac(sp->membase, ISAC_EXIR));
hscxreport(sp, 0);
hscxreport(sp, 1);
}
/*
* HSCX stuff goes here
*/
static void
hscx_empty_fifo(struct HscxState *hsp, int count)
{
byte *ptr;
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh = hsp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_empty_fifo");
if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
HSCX_RBUF_BPPS)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "hscx_empty_fifo: incoming packet too large");
writehscxCMDR(sp->membase, hsp->hscx, 0x80);
return;
}
ptr = DATAPTR(ibh);
ptr += hsp->rcvptr;
hsp->rcvptr += count;
save_flags(flags);
cli();
read_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
writehscxCMDR(sp->membase, hsp->hscx, 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_empty_fifo %c cnt %d",
hsp->hscx?'B':'A',count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
hscx_fill_fifo(struct HscxState *hsp)
{
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh;
int more, count;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_fill_fifo");
ibh = hsp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - hsp->sendptr;
if (count <= 0)
return;
more = (hsp->mode == 1)?1:0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += hsp->sendptr;
hsp->sendptr += count;
waitforXFW(sp->membase, hsp->hscx);
save_flags(flags);
cli();
write_fifo_hscx(sp->membase, hsp->hscx, ptr, count);
writehscxCMDR(sp->membase, hsp->hscx, more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_fill_fifo %c cnt %d",
hsp->hscx?'B':'A', count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static inline void
hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
{
byte r;
struct HscxState *hsp = sp->hs + hscx;
int count, err;
char tmp[32];
if (!hsp->init)
return;
if (val & 0x80) { /* RME */
r = readhscx(sp->membase, hsp->hscx, HSCX_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!r & 0x80)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX invalid frame");
if ((r & 0x40) && hsp->mode)
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX RDO mode=%d",
hsp->mode);
debugl1(sp, tmp);
}
if (!r & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX CRC error");
if (hsp->rcvibh)
BufPoolRelease(hsp->rcvibh);
hsp->rcvibh = NULL;
writehscxCMDR(sp->membase, hsp->hscx, 0x80);
goto afterRME;
}
if (!hsp->rcvibh)
if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *) 1, 1)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RME out of buffers");
writehscxCMDR(sp->membase, hsp->hscx, 0x80);
goto afterRME;
} else
hsp->rcvptr = 0;
count = readhscx(sp->membase, hsp->hscx, HSCX_RBCL) & 0x1f;
if (count == 0)
count = 32;
hscx_empty_fifo(hsp, count);
hsp->rcvibh->datasize = hsp->rcvptr - 1;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!hsp->rcvibh) {
if (hsp->mode == 1)
err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
GFP_ATOMIC, (void *)1, 2);
else
err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *)1, 2);
if (err) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RPF out of buffers");
writehscxCMDR(sp->membase, hsp->hscx, 0x80);
goto afterRPF;
} else
hsp->rcvptr = 0;
}
hscx_empty_fifo(hsp, 32);
if (hsp->mode == 1) {
/* receive audio data */
hsp->rcvibh->datasize = hsp->rcvptr;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
}
afterRPF:
if (val & 0x10) { /* XPR */
if (hsp->xmtibh)
if (hsp->xmtibh->datasize > hsp->sendptr) {
hscx_fill_fifo(hsp);
goto afterXPR;
} else {
if (hsp->releasebuf)
BufPoolRelease(hsp->xmtibh);
hsp->sendptr = 0;
if (hsp->st->l4.l1writewakeup)
hsp->st->l4.l1writewakeup(hsp->st);
hsp->xmtibh = NULL;
}
if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
hsp->releasebuf = !0;
hscx_fill_fifo(hsp);
} else
hscx_sched_event(hsp, HSCX_XMTBUFREADY);
}
afterXPR:
}
/*
* ISAC stuff goes here
*/
static void
isac_empty_fifo(struct IsdnCardState *sp, int count)
{
byte *ptr;
struct BufHeader *ibh = sp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
debugl1(sp, "isac_empty_fifo");
if (sp->rcvptr >= 3072) {
if (sp->debug & L1_DEB_WARN) {
char tmp[40];
sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
debugl1(sp, tmp);
}
return;
}
ptr = DATAPTR(ibh);
ptr += sp->rcvptr;
sp->rcvptr += count;
save_flags(flags);
cli();
read_fifo_isac(sp->membase, ptr, count);
writeisac(sp->membase, ISAC_CMDR, 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_empty_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
isac_fill_fifo(struct IsdnCardState *sp)
{
struct BufHeader *ibh;
int count, more;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
debugl1(sp, "isac_fill_fifo");
ibh = sp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - sp->sendptr;
if (count <= 0)
return;
if (count >= 3072)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += sp->sendptr;
sp->sendptr += count;
save_flags(flags);
cli();
write_fifo_isac(sp->membase, ptr, count);
writeisac(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_fill_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
ph_command(struct IsdnCardState *sp, unsigned int command)
{
if (sp->debug & L1_DEB_ISAC) {
char tmp[32];
sprintf(tmp, "ph_command %d", command);
debugl1(sp, tmp);
}
writeisac(sp->membase, ISAC_CIX0, (command << 2) | 3);
}
static inline void
isac_interrupt(struct IsdnCardState *sp, byte val) {
byte exval;
unsigned int count;
char tmp[32];
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "ISAC interrupt %x", val);
debugl1(sp, tmp);
}
if (val & 0x80) { /* RME */
exval = readisac(sp->membase, ISAC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RDO");
if (!exval & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC CRC error");
if (sp->rcvibh)
BufPoolRelease(sp->rcvibh);
sp->rcvibh = NULL;
writeisac(sp->membase, ISAC_CMDR, 0x80);
goto afterRME;
}
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC,(void *) 1, 3)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writeisac(sp->membase, ISAC_CMDR, 0x80);
goto afterRME;
} else
sp->rcvptr = 0;
count = readisac(sp->membase, ISAC_RBCL) & 0x1f;
if (count == 0)
count = 32;
isac_empty_fifo(sp, count);
sp->rcvibh->datasize = sp->rcvptr;
BufQueueLink(&(sp->rq), sp->rcvibh);
sp->rcvibh = NULL;
isac_sched_event(sp, ISAC_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC, (void *) 1, 4)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writeisac(sp->membase, ISAC_CMDR, 0x80);
goto afterRPF;
} else
sp->rcvptr = 0;
isac_empty_fifo(sp, 32);
}
afterRPF:
if (val & 0x20) { /* RSC */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (sp->xmtibh)
if (sp->xmtibh->datasize > sp->sendptr) {
isac_fill_fifo(sp);
goto afterXPR;
} else {
if (sp->releasebuf)
BufPoolRelease(sp->xmtibh);
sp->xmtibh = NULL;
sp->sendptr = 0;
}
if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
sp->releasebuf = !0;
isac_fill_fifo(sp);
} else
isac_sched_event(sp, ISAC_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
sp->ph_state = (readisac(sp->membase, ISAC_CIX0) >> 2)
& 0xf;
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "l1state %d", sp->ph_state);
debugl1(sp, tmp);
}
isac_new_ph(sp);
}
if (val & 0x02) { /* SIN */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = readisac(sp->membase, ISAC_EXIR);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "ISAC EXIR %02x", exval);
debugl1(sp, tmp);
}
}
}
static inline void
hscx_int_main(struct IsdnCardState *sp, byte val) {
byte exval;
struct HscxState *hsp;
char tmp[32];
if (val & 0x01) {
hsp = sp->hs + 1;
exval = readhscx(sp->membase, 1, HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->membase, hsp->hscx, 0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0xf8) {
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B interrupt %x", val);
debugl1(sp, tmp);
}
hscx_interrupt(sp, val, 1);
}
if (val & 0x02) {
hsp = sp->hs;
exval = readhscx(sp->membase, 0, HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->membase, hsp->hscx,0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0x04) {
exval = readhscx(sp->membase, 0, HSCX_ISTA);
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A interrupt %x", exval);
debugl1(sp, tmp);
}
hscx_interrupt(sp, exval, 0);
}
}
static void
telesS0_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *sp;
byte val, stat=0;
sp = (struct IsdnCardState *) irq2dev_map[intno];
if (!sp) {
printk(KERN_WARNING "Teles0: Spurious interrupt!\n");
return;
}
val = readhscx(sp->membase, 1, HSCX_ISTA);
Start_HSCX:
if (val) {
hscx_int_main(sp,val);
stat |= 1;
}
val = readisac(sp->membase, ISAC_ISTA);
Start_ISAC:
if (val) {
isac_interrupt(sp,val);
stat |= 2;
}
val = readhscx(sp->membase, 1, HSCX_ISTA);
if (val) {
if (sp->debug & L1_DEB_HSCX)
debugl1(sp, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readisac(sp->membase, ISAC_ISTA);
if (val) {
if (sp->debug & L1_DEB_ISAC)
debugl1(sp, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (stat & 1) {
writehscx(sp->membase, 0, HSCX_MASK, 0xFF);
writehscx(sp->membase, 1, HSCX_MASK, 0xFF);
writehscx(sp->membase, 0, HSCX_MASK, 0x0);
writehscx(sp->membase, 1, HSCX_MASK, 0x0);
}
if (stat & 2) {
writeisac(sp->membase, ISAC_MASK, 0xFF);
writeisac(sp->membase, ISAC_MASK, 0x0);
}
}
static void
initisac(struct IsdnCardState *sp)
{
unsigned int adr=sp->membase;
/* 16.0 IOM 1 Mode */
writeisac(adr, ISAC_MASK, 0xff);
writeisac(adr, ISAC_ADF2, 0x0);
writeisac(adr, ISAC_SPCR, 0xa);
writeisac(adr, ISAC_ADF1, 0x2);
writeisac(adr, ISAC_STCR, 0x70);
writeisac(adr, ISAC_MODE, 0xc9);
writeisac(adr, ISAC_CMDR, 0x41);
writeisac(adr, ISAC_CIX0, (1 << 2) | 3);
writeisac(adr, ISAC_MASK, 0xff);
writeisac(adr, ISAC_MASK, 0x0);
}
static void
modehscx(struct HscxState *hs, int mode, int ichan)
{
struct IsdnCardState *sp = hs->sp;
int hscx = hs->hscx;
if (sp->debug & L1_DEB_HSCX) {
char tmp[40];
sprintf(tmp, "hscx %c mode %d ichan %d",
'A'+hscx, mode, ichan);
debugl1(sp, tmp);
}
hs->mode = mode;
writehscx(sp->membase, hscx, HSCX_CCR1, 0x85);
writehscx(sp->membase, hscx, HSCX_XAD1, 0xFF);
writehscx(sp->membase, hscx, HSCX_XAD2, 0xFF);
writehscx(sp->membase, hscx, HSCX_RAH2, 0xFF);
writehscx(sp->membase, hscx, HSCX_XBCH, 0x0);
/* Switch IOM 1 SSI */
if (hscx == 0)
ichan = 1 - ichan;
switch (mode) {
case (0):
writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
writehscx(sp->membase, hscx, HSCX_TSAX, 0xff);
writehscx(sp->membase, hscx, HSCX_TSAR, 0xff);
writehscx(sp->membase, hscx, HSCX_XCCR, 7);
writehscx(sp->membase, hscx, HSCX_RCCR, 7);
writehscx(sp->membase, hscx, HSCX_MODE, 0x84);
break;
case (1):
if (ichan == 0) {
writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
writehscx(sp->membase, hscx, HSCX_XCCR, 7);
writehscx(sp->membase, hscx, HSCX_RCCR, 7);
} else {
writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
writehscx(sp->membase, hscx, HSCX_XCCR, 7);
writehscx(sp->membase, hscx, HSCX_RCCR, 7);
}
writehscx(sp->membase, hscx, HSCX_MODE, 0xe4);
writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
break;
case (2):
if (ichan == 0) {
writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
writehscx(sp->membase, hscx, HSCX_TSAX, 0x7);
writehscx(sp->membase, hscx, HSCX_TSAR, 0x7);
writehscx(sp->membase, hscx, HSCX_XCCR, 7);
writehscx(sp->membase, hscx, HSCX_RCCR, 7);
} else {
writehscx(sp->membase, hscx, HSCX_CCR2, 0x30);
writehscx(sp->membase, hscx, HSCX_TSAX, 0x3);
writehscx(sp->membase, hscx, HSCX_TSAR, 0x3);
writehscx(sp->membase, hscx, HSCX_XCCR, 7);
writehscx(sp->membase, hscx, HSCX_RCCR, 7);
}
writehscx(sp->membase, hscx, HSCX_MODE, 0x8c);
writehscx(sp->membase, hscx, HSCX_CMDR, 0x41);
break;
}
writehscx(sp->membase, hscx, HSCX_ISTA, 0x00);
}
void release_io_teles0(struct IsdnCard *card) {
if (card->sp->cfg_reg)
release_region(card->sp->cfg_reg, 8);
}
static void
clear_pending_ints(struct IsdnCardState *sp)
{
int val;
char tmp[64];
val = readhscx(sp->membase, 1, HSCX_ISTA);
sprintf(tmp, "HSCX B ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readhscx(sp->membase, 1, HSCX_EXIR);
sprintf(tmp, "HSCX B EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x02) {
val = readhscx(sp->membase, 0, HSCX_EXIR);
sprintf(tmp, "HSCX A EXIR %x", val);
debugl1(sp, tmp);
}
val = readhscx(sp->membase, 0, HSCX_ISTA);
sprintf(tmp, "HSCX A ISTA %x", val);
debugl1(sp, tmp);
val = readhscx(sp->membase, 1, HSCX_STAR);
sprintf(tmp, "HSCX B STAR %x", val);
debugl1(sp, tmp);
val = readhscx(sp->membase, 0, HSCX_STAR);
sprintf(tmp, "HSCX A STAR %x", val);
debugl1(sp, tmp);
val = readisac(sp->membase, ISAC_STAR);
sprintf(tmp, "ISAC STAR %x", val);
debugl1(sp, tmp);
val = readisac(sp->membase, ISAC_MODE);
sprintf(tmp, "ISAC MODE %x", val);
debugl1(sp, tmp);
val = readisac(sp->membase, ISAC_ADF2);
sprintf(tmp, "ISAC ADF2 %x", val);
debugl1(sp, tmp);
val = readisac(sp->membase, ISAC_ISTA);
sprintf(tmp, "ISAC ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readisac(sp->membase, ISAC_EXIR);
sprintf(tmp, "ISAC EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x04) {
val = readisac(sp->membase, ISAC_CIR0);
sprintf(tmp, "ISAC CIR0 %x", val);
debugl1(sp, tmp);
}
writeisac(sp->membase, ISAC_MASK, 0);
writeisac(sp->membase, ISAC_CMDR, 0x41);
}
int
initteles0(struct IsdnCardState *sp)
{
int ret;
char tmp[40];
sp->counter = kstat.interrupts[sp->irq];
sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
debugl1(sp, tmp);
clear_pending_ints(sp);
ret = get_irq(sp->cardnr,&telesS0_interrupt);
if (ret) {
initisac(sp);
sp->modehscx(sp->hs, 0, 0);
sp->modehscx(sp->hs + 1, 0, 0);
sprintf(tmp, "IRQ %d count %d", sp->irq,
kstat.interrupts[sp->irq]);
debugl1(sp, tmp);
if (kstat.interrupts[sp->irq]==sp->counter) {
printk(KERN_WARNING
"Teles0: IRQ(%d) getting no interrupts during init\n",
sp->irq);
irq2dev_map[sp->irq] = NULL;
free_irq(sp->irq, NULL);
return(0);
}
}
return(ret);
}
int
setup_teles0(struct IsdnCard *card)
{
int timout;
byte cfval, val, verA, verB;
struct IsdnCardState *sp = card->sp;
if ((sp->typ != ISDN_CTYPE_16_0) && (sp->typ != ISDN_CTYPE_8_0))
return(0);
if (sp->typ == ISDN_CTYPE_16_0)
sp->cfg_reg = card->para[2];
else /* 8.0 */
sp->cfg_reg = 0;
if (card->para[1] < 0x10000) {
card->para[1] <<= 4;
printk(KERN_INFO
"Teles0: membase configured DOSish, assuming 0x%lx\n",
(unsigned long)card->para[1]);
}
sp->membase = card->para[1];
sp->irq = card->para[0];
if (sp->cfg_reg) {
if (check_region((sp->cfg_reg) ,8)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
sp->cfg_reg,
sp->cfg_reg + 8);
return (0);
} else {
request_region(sp->cfg_reg, 8, "teles cfg");
}
}
switch (sp->irq) {
case 2:
cfval = 0x00;
break;
case 3:
cfval = 0x02;
break;
case 4:
cfval = 0x04;
break;
case 5:
cfval = 0x06;
break;
case 10:
cfval = 0x08;
break;
case 11:
cfval = 0x0A;
break;
case 12:
cfval = 0x0C;
break;
case 15:
cfval = 0x0E;
break;
default:
cfval = 0x00;
break;
}
cfval |= ((card->para[1] >> 9) & 0xF0);
if (sp->cfg_reg) {
if ((val=bytein(sp->cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
sp->cfg_reg + 0, val);
release_region(sp->cfg_reg, 8);
return(0);
}
if ((val=bytein(sp->cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
sp->cfg_reg + 1, val);
release_region(sp->cfg_reg, 8);
return (0);
}
val = bytein(sp->cfg_reg + 2);/* 0x1e=without AB
* 0x1f=with AB
* 0x1c 16.3 ???
*/
if (val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles0: 16.0 Byte at %x is %x\n",
sp->cfg_reg + 2, val);
release_region(sp->cfg_reg, 8);
return (0);
}
cli();
timout = jiffies + (HZ / 10) + 1;
byteout(sp->cfg_reg + 4, cfval);
sti();
while (jiffies <= timout);
cli();
timout = jiffies + (HZ / 10) + 1;
byteout(sp->cfg_reg + 4, cfval | 1);
sti();
while (jiffies <= timout);
}
printk(KERN_NOTICE
"HiSax: %s found,irq:%d mem:%x cfg:%x\n",
CardType[sp->typ], sp->irq,
sp->membase,sp->cfg_reg);
verA=readhscx(sp->membase, 0,HSCX_VSTR) & 0xf;
verB=readhscx(sp->membase, 1,HSCX_VSTR) & 0xf;
printk(KERN_INFO "Teles0: HSCX version A: %s B: %s\n",
HscxVersion[verA], HscxVersion[verB]);
val = readisac(sp->membase, ISAC_RBCH);
printk(KERN_INFO "Teles0: ISAC version %d.%d\n",
(val>>6)&1, (val>>5)&1);
if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
printk(KERN_WARNING
"Teles0: wrong HSCX versions check IO/MEM addresses\n");
release_io_teles0(card);
return (0);
}
cli();
timout = jiffies + (HZ / 5) + 1;
*(byte *) (sp->membase + 0x80) = 0;
sti();
while (jiffies <= timout);
cli();
*(byte *) (sp->membase + 0x80) = 1;
timout = jiffies + (HZ / 5) + 1;
sti();
while (jiffies <= timout);
sp->modehscx = &modehscx;
sp->ph_command = &ph_command;
sp->hscx_fill_fifo = &hscx_fill_fifo;
sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}

View File

@ -0,0 +1,15 @@
/* $Id$
*
* teles0.h Header for Teles 16.0 8.0 & compatible
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
*
* $Log$
*
*/
extern void teles0_report(struct IsdnCardState *sp);
extern void release_io_teles0(struct IsdnCard *card);
extern int setup_teles0(struct IsdnCard *card);
extern int initteles0(struct IsdnCardState *sp);

989
drivers/isdn/hisax/teles3.c Normal file
View File

@ -0,0 +1,989 @@
/* $Id$
*
* teles3.c low level stuff for Teles 16.3 & PNP isdn cards
*
* based on the teles driver from Jan den Ouden
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
* Thanks to Jan den Ouden
* Fritz Elfert
* Beat Doebeli
*
* $Log$
*
*
*/
#define __NO_VERSION__
#include "siemens.h"
#include "hisax.h"
#include "teles3.h"
#include "isdnl1.h"
#include <linux/kernel_stat.h>
extern const char *CardType[];
#define byteout(addr,val) outb_p(val,addr)
#define bytein(addr) inb_p(addr)
static inline byte
readreg(unsigned int adr, byte off)
{
return (bytein(adr + off));
}
static inline void
writereg(unsigned int adr, byte off, byte data)
{
byteout(adr +off , data);
}
static inline void
read_fifo(unsigned int adr, byte * data, int size)
{
insb(adr +0x1e , data, size);
}
static void
write_fifo(unsigned int adr, byte * data, int size)
{
outsb(adr +0x1e , data, size);
}
static inline void
waitforCEC(int adr)
{
int to = 50;
while ((readreg(adr, HSCX_STAR) & 0x04) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "Teles3: waitforCEC timeout\n");
}
static inline void
waitforXFW(int adr)
{
int to = 50;
while ((!(readreg(adr, HSCX_STAR) & 0x44)==0x40) && to) {
udelay(1);
to--;
}
if (!to)
printk(KERN_WARNING "Teles3: waitforXFW timeout\n");
}
static inline void
writehscxCMDR(int adr, byte data)
{
long flags;
save_flags(flags);
cli();
waitforCEC(adr);
writereg(adr, HSCX_CMDR, data);
restore_flags(flags);
}
/*
* fast interrupt here
*/
static void
hscxreport(struct IsdnCardState *sp, int hscx)
{
printk(KERN_DEBUG "HSCX %d\n", hscx);
printk(KERN_DEBUG "ISTA %x\n", readreg(sp->hscx[hscx], HSCX_ISTA));
printk(KERN_DEBUG "STAR %x\n", readreg(sp->hscx[hscx], HSCX_STAR));
printk(KERN_DEBUG "EXIR %x\n", readreg(sp->hscx[hscx], HSCX_EXIR));
}
void
teles3_report(struct IsdnCardState *sp)
{
printk(KERN_DEBUG "ISAC\n");
printk(KERN_DEBUG "ISTA %x\n", readreg(sp->isac, ISAC_ISTA));
printk(KERN_DEBUG "STAR %x\n", readreg(sp->isac, ISAC_STAR));
printk(KERN_DEBUG "EXIR %x\n", readreg(sp->isac, ISAC_EXIR));
hscxreport(sp, 0);
hscxreport(sp, 1);
}
/*
* HSCX stuff goes here
*/
static void
hscx_empty_fifo(struct HscxState *hsp, int count)
{
byte *ptr;
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh = hsp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_empty_fifo");
if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
HSCX_RBUF_BPPS)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "hscx_empty_fifo: incoming packet too large");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
return;
}
ptr = DATAPTR(ibh);
ptr += hsp->rcvptr;
hsp->rcvptr += count;
save_flags(flags);
cli();
read_fifo(sp->hscx[hsp->hscx], ptr, count);
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_empty_fifo %c cnt %d",
hsp->hscx?'B':'A',count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
hscx_fill_fifo(struct HscxState *hsp)
{
struct IsdnCardState *sp = hsp->sp;
struct BufHeader *ibh;
int more, count;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_HSCX) && !(sp->debug & L1_DEB_HSCX_FIFO))
debugl1(sp, "hscx_fill_fifo");
ibh = hsp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - hsp->sendptr;
if (count <= 0)
return;
more = (hsp->mode == 1)?1:0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += hsp->sendptr;
hsp->sendptr += count;
waitforXFW(sp->hscx[hsp->hscx]);
save_flags(flags);
cli();
write_fifo(sp->hscx[hsp->hscx], ptr, count);
writehscxCMDR(sp->hscx[hsp->hscx], more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_HSCX_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"hscx_fill_fifo %c cnt %d",
hsp->hscx?'B':'A', count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static inline void
hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
{
byte r;
struct HscxState *hsp = sp->hs + hscx;
int count, err;
char tmp[32];
if (!hsp->init)
return;
if (val & 0x80) { /* RME */
r = readreg(sp->hscx[hsp->hscx], HSCX_RSTA);
if ((r & 0xf0) != 0xa0) {
if (!r & 0x80)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX invalid frame");
if ((r & 0x40) && hsp->mode)
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX RDO mode=%d",
hsp->mode);
debugl1(sp, tmp);
}
if (!r & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX CRC error");
if (hsp->rcvibh)
BufPoolRelease(hsp->rcvibh);
hsp->rcvibh = NULL;
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRME;
}
if (!hsp->rcvibh)
if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *) 1, 1)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RME out of buffers");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRME;
} else
hsp->rcvptr = 0;
count = readreg(sp->hscx[hsp->hscx], HSCX_RBCL) & 0x1f;
if (count == 0)
count = 32;
hscx_empty_fifo(hsp, count);
hsp->rcvibh->datasize = hsp->rcvptr - 1;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!hsp->rcvibh) {
if (hsp->mode == 1)
err=BufPoolGet(&hsp->rcvibh, &hsp->smallpool,
GFP_ATOMIC, (void *)1, 2);
else
err=BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
GFP_ATOMIC, (void *)1, 2);
if (err) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "HSCX RPF out of buffers");
writehscxCMDR(sp->hscx[hsp->hscx], 0x80);
goto afterRPF;
} else
hsp->rcvptr = 0;
}
hscx_empty_fifo(hsp, 32);
if (hsp->mode == 1) {
/* receive audio data */
hsp->rcvibh->datasize = hsp->rcvptr;
BufQueueLink(&hsp->rq, hsp->rcvibh);
hsp->rcvibh = NULL;
hscx_sched_event(hsp, HSCX_RCVBUFREADY);
}
}
afterRPF:
if (val & 0x10) { /* XPR */
if (hsp->xmtibh)
if (hsp->xmtibh->datasize > hsp->sendptr) {
hscx_fill_fifo(hsp);
goto afterXPR;
} else {
if (hsp->releasebuf)
BufPoolRelease(hsp->xmtibh);
hsp->sendptr = 0;
if (hsp->st->l4.l1writewakeup)
hsp->st->l4.l1writewakeup(hsp->st);
hsp->xmtibh = NULL;
}
if (!BufQueueUnlink(&hsp->xmtibh, &hsp->sq)) {
hsp->releasebuf = !0;
hscx_fill_fifo(hsp);
} else
hscx_sched_event(hsp, HSCX_XMTBUFREADY);
}
afterXPR:
}
/*
* ISAC stuff goes here
*/
static void
isac_empty_fifo(struct IsdnCardState *sp, int count)
{
byte *ptr;
struct BufHeader *ibh = sp->rcvibh;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
if (sp->debug & L1_DEB_ISAC)
debugl1(sp, "isac_empty_fifo");
if (sp->rcvptr >= 3072) {
if (sp->debug & L1_DEB_WARN) {
char tmp[40];
sprintf(tmp, "isac_empty_fifo rcvptr %d", sp->rcvptr);
debugl1(sp, tmp);
}
return;
}
ptr = DATAPTR(ibh);
ptr += sp->rcvptr;
sp->rcvptr += count;
save_flags(flags);
cli();
read_fifo(sp->isac, ptr, count);
writereg(sp->isac, ISAC_CMDR, 0x80);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_empty_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
isac_fill_fifo(struct IsdnCardState *sp)
{
struct BufHeader *ibh;
int count, more;
byte *ptr;
long flags;
if ((sp->debug & L1_DEB_ISAC) && !(sp->debug & L1_DEB_ISAC_FIFO))
debugl1(sp, "isac_fill_fifo");
ibh = sp->xmtibh;
if (!ibh)
return;
count = ibh->datasize - sp->sendptr;
if (count <= 0)
return;
if (count >= 3072)
return;
more = 0;
if (count > 32) {
more = !0;
count = 32;
}
ptr = DATAPTR(ibh);
ptr += sp->sendptr;
sp->sendptr += count;
save_flags(flags);
cli();
write_fifo(sp->isac, ptr, count);
writereg(sp->isac, ISAC_CMDR, more ? 0x8 : 0xa);
restore_flags(flags);
if (sp->debug & L1_DEB_ISAC_FIFO) {
char tmp[128];
char *t=tmp;
t += sprintf(t,"isac_fill_fifo cnt %d", count);
QuickHex(t,ptr,count);
debugl1(sp, tmp);
}
}
static void
ph_command(struct IsdnCardState *sp, unsigned int command)
{
if (sp->debug & L1_DEB_ISAC) {
char tmp[32];
sprintf(tmp, "ph_command %d", command);
debugl1(sp, tmp);
}
writereg(sp->isac, ISAC_CIX0, (command << 2) | 3);
}
static inline void
isac_interrupt(struct IsdnCardState *sp, byte val) {
byte exval;
unsigned int count;
char tmp[32];
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "ISAC interrupt %x", val);
debugl1(sp, tmp);
}
if (val & 0x80) { /* RME */
exval = readreg(sp->isac, ISAC_RSTA);
if ((exval & 0x70) != 0x20) {
if (exval & 0x40)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RDO");
if (!exval & 0x20)
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC CRC error");
if (sp->rcvibh)
BufPoolRelease(sp->rcvibh);
sp->rcvibh = NULL;
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRME;
}
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC,(void *) 1, 3)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRME;
} else
sp->rcvptr = 0;
count = readreg(sp->isac, ISAC_RBCL) & 0x1f;
if (count == 0)
count = 32;
isac_empty_fifo(sp, count);
sp->rcvibh->datasize = sp->rcvptr;
BufQueueLink(&(sp->rq), sp->rcvibh);
sp->rcvibh = NULL;
isac_sched_event(sp, ISAC_RCVBUFREADY);
}
afterRME:
if (val & 0x40) { /* RPF */
if (!sp->rcvibh)
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
GFP_ATOMIC, (void *) 1, 4)) {
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RME out of buffers!");
writereg(sp->isac, ISAC_CMDR, 0x80);
goto afterRPF;
} else
sp->rcvptr = 0;
isac_empty_fifo(sp, 32);
}
afterRPF:
if (val & 0x20) { /* RSC */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC RSC interrupt");
}
if (val & 0x10) { /* XPR */
if (sp->xmtibh)
if (sp->xmtibh->datasize > sp->sendptr) {
isac_fill_fifo(sp);
goto afterXPR;
} else {
if (sp->releasebuf)
BufPoolRelease(sp->xmtibh);
sp->xmtibh = NULL;
sp->sendptr = 0;
}
if (!BufQueueUnlink(&sp->xmtibh, &sp->sq)) {
sp->releasebuf = !0;
isac_fill_fifo(sp);
} else
isac_sched_event(sp, ISAC_XMTBUFREADY);
}
afterXPR:
if (val & 0x04) { /* CISQ */
sp->ph_state = (readreg(sp->isac, ISAC_CIX0) >> 2)
& 0xf;
if (sp->debug & L1_DEB_ISAC) {
sprintf(tmp, "l1state %d", sp->ph_state);
debugl1(sp, tmp);
}
isac_new_ph(sp);
}
if (val & 0x02) { /* SIN */
/* never */
if (sp->debug & L1_DEB_WARN)
debugl1(sp, "ISAC SIN interrupt");
}
if (val & 0x01) { /* EXI */
exval = readreg(sp->isac, ISAC_EXIR);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "ISAC EXIR %02x", exval);
debugl1(sp, tmp);
}
}
}
static inline void
hscx_int_main(struct IsdnCardState *sp, byte val) {
byte exval;
struct HscxState *hsp;
char tmp[32];
if (val & 0x01) {
hsp = sp->hs + 1;
exval = readreg(sp->hscx[1], HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->hscx[hsp->hscx], 0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX B EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0xf8) {
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX B interrupt %x", val);
debugl1(sp, tmp);
}
hscx_interrupt(sp, val, 1);
}
if (val & 0x02) {
hsp = sp->hs;
exval = readreg(sp->hscx[0], HSCX_EXIR);
if (exval == 0x40) {
if (hsp->mode == 1)
hscx_fill_fifo(hsp);
else {
/* Here we lost an TX interrupt, so
* restart transmitting the whole frame.
*/
hsp->sendptr = 0;
writehscxCMDR(sp->hscx[hsp->hscx],0x01);
if (sp->debug & L1_DEB_WARN) {
sprintf(tmp, "HSCX A EXIR %x Lost TX", exval);
debugl1(sp, tmp);
}
}
} else
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A EXIR %x", exval);
debugl1(sp, tmp);
}
}
if (val & 0x04) {
exval = readreg(sp->hscx[0], HSCX_ISTA);
if (sp->debug & L1_DEB_HSCX) {
sprintf(tmp, "HSCX A interrupt %x", exval);
debugl1(sp, tmp);
}
hscx_interrupt(sp, exval, 0);
}
}
static void
teles3_interrupt(int intno, void *dev_id, struct pt_regs *regs)
{
struct IsdnCardState *sp;
byte val, stat=0;
sp = (struct IsdnCardState *) irq2dev_map[intno];
if (!sp) {
printk(KERN_WARNING "Teles: Spurious interrupt!\n");
return;
}
val = readreg(sp->hscx[1], HSCX_ISTA);
Start_HSCX:
if (val) {
hscx_int_main(sp,val);
stat |= 1;
}
val = readreg(sp->isac, ISAC_ISTA);
Start_ISAC:
if (val) {
isac_interrupt(sp,val);
stat |= 2;
}
val = readreg(sp->hscx[1], HSCX_ISTA);
if (val) {
if (sp->debug & L1_DEB_HSCX)
debugl1(sp, "HSCX IntStat after IntRoutine");
goto Start_HSCX;
}
val = readreg(sp->isac, ISAC_ISTA);
if (val) {
if (sp->debug & L1_DEB_ISAC)
debugl1(sp, "ISAC IntStat after IntRoutine");
goto Start_ISAC;
}
if (stat & 1) {
writereg(sp->hscx[0], HSCX_MASK, 0xFF);
writereg(sp->hscx[1], HSCX_MASK, 0xFF);
writereg(sp->hscx[0], HSCX_MASK, 0x0);
writereg(sp->hscx[1], HSCX_MASK, 0x0);
}
if (stat & 2) {
writereg(sp->isac, ISAC_MASK, 0xFF);
writereg(sp->isac, ISAC_MASK, 0x0);
}
}
static void
initisac(struct IsdnCardState *sp)
{
unsigned int adr=sp->isac;
/* 16.3 IOM 2 Mode */
writereg(adr, ISAC_MASK, 0xff);
writereg(adr, ISAC_ADF2, 0x80);
writereg(adr, ISAC_SQXR, 0x2f);
writereg(adr, ISAC_SPCR, 0x0);
writereg(adr, ISAC_ADF1, 0x2);
writereg(adr, ISAC_STCR, 0x70);
writereg(adr, ISAC_MODE, 0xc9);
writereg(adr, ISAC_TIMR, 0x0);
writereg(adr, ISAC_ADF1, 0x0);
writereg(adr, ISAC_CMDR, 0x41);
writereg(adr, ISAC_CIX0, (1 << 2) | 3);
writereg(adr, ISAC_MASK, 0xff);
writereg(adr, ISAC_MASK, 0x0);
}
static void
modehscx(struct HscxState *hs, int mode, int ichan)
{
struct IsdnCardState *sp = hs->sp;
int hscx = hs->hscx;
if (sp->debug & L1_DEB_HSCX) {
char tmp[40];
sprintf(tmp, "hscx %c mode %d ichan %d",
'A'+hscx, mode, ichan);
debugl1(sp, tmp);
}
hs->mode = mode;
writereg(sp->hscx[hscx], HSCX_CCR1, 0x85);
writereg(sp->hscx[hscx], HSCX_XAD1, 0xFF);
writereg(sp->hscx[hscx], HSCX_XAD2, 0xFF);
writereg(sp->hscx[hscx], HSCX_RAH2, 0xFF);
writereg(sp->hscx[hscx], HSCX_XBCH, 0x0);
writereg(sp->hscx[hscx], HSCX_RLCR, 0x0);
switch (mode) {
case (0):
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0xff);
writereg(sp->hscx[hscx], HSCX_TSAR, 0xff);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
writereg(sp->hscx[hscx], HSCX_MODE, 0x84);
break;
case (1):
if (ichan == 0) {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
} else {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
}
writereg(sp->hscx[hscx], HSCX_MODE, 0xe4);
writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
break;
case (2):
if (ichan == 0) {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x2f);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x2f);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
} else {
writereg(sp->hscx[hscx], HSCX_CCR2, 0x30);
writereg(sp->hscx[hscx], HSCX_TSAX, 0x3);
writereg(sp->hscx[hscx], HSCX_TSAR, 0x3);
writereg(sp->hscx[hscx], HSCX_XCCR, 7);
writereg(sp->hscx[hscx], HSCX_RCCR, 7);
}
writereg(sp->hscx[hscx], HSCX_MODE, 0x8c);
writereg(sp->hscx[hscx], HSCX_CMDR, 0x41);
break;
}
writereg(sp->hscx[hscx], HSCX_ISTA, 0x00);
}
inline static void
release_ioregs(struct IsdnCard *card, int mask) {
if (mask & 1) release_region(card->sp->isac, 32);
if (mask & 2) release_region(card->sp->hscx[0], 32);
if (mask & 4) release_region(card->sp->hscx[1], 32);
}
void release_io_teles3(struct IsdnCard *card) {
if (card->sp->cfg_reg)
release_region(card->sp->cfg_reg, 8);
release_ioregs(card, 0x7);
}
static void
clear_pending_ints(struct IsdnCardState *sp)
{
int val;
char tmp[64];
val = readreg(sp->hscx[1], HSCX_ISTA);
sprintf(tmp, "HSCX B ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readreg(sp->hscx[1], HSCX_EXIR);
sprintf(tmp, "HSCX B EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x02) {
val = readreg(sp->hscx[0], HSCX_EXIR);
sprintf(tmp, "HSCX A EXIR %x", val);
debugl1(sp, tmp);
}
val = readreg(sp->hscx[0], HSCX_ISTA);
sprintf(tmp, "HSCX A ISTA %x", val);
debugl1(sp, tmp);
val = readreg(sp->hscx[1], HSCX_STAR);
sprintf(tmp, "HSCX B STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->hscx[0], HSCX_STAR);
sprintf(tmp, "HSCX A STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_STAR);
sprintf(tmp, "ISAC STAR %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_MODE);
sprintf(tmp, "ISAC MODE %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_ADF2);
sprintf(tmp, "ISAC ADF2 %x", val);
debugl1(sp, tmp);
val = readreg(sp->isac, ISAC_ISTA);
sprintf(tmp, "ISAC ISTA %x", val);
debugl1(sp, tmp);
if (val & 0x01) {
val = readreg(sp->isac, ISAC_EXIR);
sprintf(tmp, "ISAC EXIR %x", val);
debugl1(sp, tmp);
} else if (val & 0x04) {
val = readreg(sp->isac, ISAC_CIR0);
sprintf(tmp, "ISAC CIR0 %x", val);
debugl1(sp, tmp);
}
writereg(sp->isac, ISAC_MASK, 0);
writereg(sp->isac, ISAC_CMDR, 0x41);
}
int
initteles3(struct IsdnCardState *sp)
{
int ret;
char tmp[40];
sp->counter = kstat.interrupts[sp->irq];
sprintf(tmp, "IRQ %d count %d", sp->irq, sp->counter);
debugl1(sp, tmp);
clear_pending_ints(sp);
ret = get_irq(sp->cardnr,&teles3_interrupt);
if (ret) {
initisac(sp);
sp->modehscx(sp->hs, 0, 0);
sp->modehscx(sp->hs + 1, 0, 0);
sprintf(tmp, "IRQ %d count %d", sp->irq,
kstat.interrupts[sp->irq]);
debugl1(sp, tmp);
if (kstat.interrupts[sp->irq]==sp->counter) {
printk(KERN_WARNING
"Teles3: IRQ(%d) getting no interrupts during init\n",
sp->irq);
irq2dev_map[sp->irq] = NULL;
free_irq(sp->irq, NULL);
return(0);
}
}
return(ret);
}
int
setup_teles3(struct IsdnCard *card)
{
int timout;
byte cfval, val, verA, verB;
struct IsdnCardState *sp = card->sp;
if ((sp->typ != ISDN_CTYPE_16_3) && (sp->typ != ISDN_CTYPE_PNP))
return(0);
if (sp->typ == ISDN_CTYPE_16_3) {
sp->cfg_reg = card->para[1];
switch (sp->cfg_reg) {
case 0x180:
case 0x280:
case 0x380:
sp->cfg_reg |= 0xc00;
break;
}
sp->isac = sp->cfg_reg - 0x400;
sp->hscx[0] = sp->cfg_reg - 0xc00;
sp->hscx[1] = sp->cfg_reg - 0x800;
} else { /* PNP */
sp->cfg_reg = 0;
sp->isac = card->para[1];
sp->hscx[0] = card->para[2];
sp->hscx[1] = card->para[2] + 0x20;
}
sp->irq = card->para[0];
if (sp->cfg_reg) {
if (check_region((sp->cfg_reg) ,8)) {
printk(KERN_WARNING
"HiSax: %s config port %x-%x already in use\n",
CardType[card->typ],
sp->cfg_reg,
sp->cfg_reg + 8);
return (0);
} else {
request_region(sp->cfg_reg, 8, "teles3 cfg");
}
}
if (check_region((sp->isac) , 32)) {
printk(KERN_WARNING
"HiSax: %s isac ports %x-%x already in use\n",
CardType[sp->typ],
sp->isac,
sp->isac + 32);
if (sp->cfg_reg) {
release_region(sp->cfg_reg, 8);
}
return(0);
} else {
request_region(sp->isac, 32, "HiSax isac");
}
if (check_region((sp->hscx[0]) , 32)) {
printk(KERN_WARNING
"HiSax: %s hscx A ports %x-%x already in use\n",
CardType[sp->typ],
sp->hscx[0],
sp->hscx[0] + 32);
if (sp->cfg_reg) {
release_region(sp->cfg_reg, 8);
}
release_ioregs(card, 1);
return(0);
} else {
request_region(sp->hscx[0], 32, "HiSax hscx A");
}
if (check_region((sp->hscx[1]) , 32)) {
printk(KERN_WARNING
"HiSax: %s hscx B ports %x-%x already in use\n",
CardType[sp->typ],
sp->hscx[1],
sp->hscx[1] + 32);
if (sp->cfg_reg) {
release_region(sp->cfg_reg, 8);
}
release_ioregs(card, 3);
return(0);
} else {
request_region(sp->hscx[1], 32, "HiSax hscx B");
}
switch (sp->irq) {
case 2:
cfval = 0x00;
break;
case 3:
cfval = 0x02;
break;
case 4:
cfval = 0x04;
break;
case 5:
cfval = 0x06;
break;
case 10:
cfval = 0x08;
break;
case 11:
cfval = 0x0A;
break;
case 12:
cfval = 0x0C;
break;
case 15:
cfval = 0x0E;
break;
default:
cfval = 0x00;
break;
}
if (sp->cfg_reg) {
if ((val=bytein(sp->cfg_reg + 0)) != 0x51) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
sp->cfg_reg + 0, val);
release_io_teles3(card);
return(0);
}
if ((val=bytein(sp->cfg_reg + 1)) != 0x93) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
sp->cfg_reg + 1, val);
release_io_teles3(card);
return (0);
}
val = bytein(sp->cfg_reg + 2);/* 0x1e=without AB
* 0x1f=with AB
* 0x1c 16.3 ???
*/
if (val != 0x1c && val != 0x1e && val != 0x1f) {
printk(KERN_WARNING "Teles: 16.3 Byte at %x is %x\n",
sp->cfg_reg + 2, val);
release_io_teles3(card);
return (0);
}
cli();
timout = jiffies + (HZ / 10) + 1;
byteout(sp->cfg_reg + 4, cfval);
sti();
while (jiffies <= timout);
cli();
timout = jiffies + (HZ / 10) + 1;
byteout(sp->cfg_reg + 4, cfval | 1);
sti();
while (jiffies <= timout);
}
printk(KERN_NOTICE
"HiSax: %s found,irq:%d isac:%x cfg:%x\n",
CardType[sp->typ], sp->irq,
sp->isac,sp->cfg_reg);
printk(KERN_NOTICE
"HiSax: hscx A:%x hscx B:%x\n",
sp->hscx[0], sp->hscx[1]);
verA = readreg(sp->hscx[0],HSCX_VSTR) & 0xf;
verB = readreg(sp->hscx[1],HSCX_VSTR) & 0xf;
printk(KERN_INFO "Teles3: HSCX version A: %s B: %s\n",
HscxVersion[verA], HscxVersion[verB]);
val = readreg(sp->isac, ISAC_RBCH);
printk(KERN_INFO "Teles3: ISAC version %d.%d\n",
(val>>6)&1, (val>>5)&1);
if ((verA==0) | (verA==0xf) | (verB==0) | (verB==0xf)) {
printk(KERN_WARNING
"Teles3: wrong HSCX versions check IO address\n");
release_io_teles3(card);
return (0);
}
sp->modehscx = &modehscx;
sp->ph_command = &ph_command;
sp->hscx_fill_fifo = &hscx_fill_fifo;
sp->isac_fill_fifo = &isac_fill_fifo;
return (1);
}

View File

@ -0,0 +1,15 @@
/* $Id$
*
* teles3.h Header for Teles 16.3 PNP & compatible
*
* Author Karsten Keil (keil@temic-ech.spacenet.de)
*
*
* $Log$
*
*/
extern void teles3_report(struct IsdnCardState *sp);
extern void release_io_teles3(struct IsdnCard *card);
extern int setup_teles3(struct IsdnCard *card);
extern int initteles3(struct IsdnCardState *sp);