Initial revision
This commit is contained in:
parent
fc5476a55d
commit
31d2853652
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
|
@ -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';
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
|
@ -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);
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
|
@ -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);
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
Loading…
Reference in New Issue