u-isdn/cards/dumb/shell.c

1613 lines
39 KiB
C

#if defined(_ncp16_)
#define WIDE
#endif
#ifdef linux
#define SLOW_IO_BY_JUMPING
#if 0 /* def _ncp_ */
#define REALLY_SLOW_IO
#endif
#endif
#include "f_module.h"
#include "primitives.h"
#include "streams.h"
#include "isdn_12.h"
#include "smallq.h"
#include "isdn_limits.h"
#include "isdn_proto.h"
#include "stream.h"
#include "streamlib.h"
#include "kernel.h"
#ifdef SCO
#include <sys/immu.h>
#endif
#include <stddef.h>
#include "loader.h"
#ifdef linux
#include <asm/io.h>
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/malloc.h>
#define ByteOut(_where,_what) outb_p(_what,_where)
#define ByteIn(_where) inb_p(_where)
#endif
#if 1
#define CEC(x) do{int i;for(i=0;i<1000;i++) if(!(x)) break; } while(0);
#else
#define CEC(x) if(0)printf("c");
#endif
#define NEW_XMIT 0
#define r __rw.__r
#define w __rw.__w
#define ISAC_R_FIFO_SIZE 32
#define ISAC_W_FIFO_SIZE 32
#define HSCX_R_FIFO_SIZE 32
#define HSCX_W_FIFO_SIZE 32
#ifdef _teles3_
#define FIFO(x) Fifo
#else
#define FIFO(x) fifo[0] /* forget the address -- WARNING: side effects of x get lost */
#endif
#include "shell.h"
typedef struct _isac {
union {
struct {
volatile Byte fifo[ISAC_R_FIFO_SIZE];
/* 00 */ volatile Byte ISTA,STAR,MODE,TIMR;
/* 04 */ volatile Byte EXIR,RBCL,SAPR,RSTA;
/* 08 */ volatile Byte __f1,RHCR,RBCH,__f3;
/* 0C */ volatile Byte __f4[4];
/* 10 */ volatile Byte SPCR,CIR0,MOR0,CIR1;
/* 14 */ volatile Byte MOR1,C1R,C2R,B1CR;
/* 18 */ volatile Byte B2CR,ADF2,MOSR,SQRR;
/* 1C */ volatile Byte __f5,__f6,Fifo,__f7;
} __r;
struct {
volatile Byte fifo[ISAC_W_FIFO_SIZE];
/* 00 */ volatile Byte MASK,CMDR,MODE,TIMR;
/* 04 */ volatile Byte XAD1,XAD2,SAP1,SAP2;
/* 08 */ volatile Byte TEI1,TEI2,__f1,__f2;
/* 0C */ volatile Byte __f3[4];
/* 10 */ volatile Byte SPCR,CIX0,MOX0,CIX1;
/* 14 */ volatile Byte MOX1,C1R,C2R,STCR;
/* 18 */ volatile Byte ADF1,ADF2,MOCR,SQXR;
/* 1C */ volatile Byte __f5,__f6,Fifo,__f7;
} __w;
} __rw;
} *__isac;
#ifdef WIDE
typedef struct _hscx {
union {
struct {
volatile Byte fifo[HSCX_R_FIFO_SIZE];
/* 00 */ volatile Byte STAR,RSTA,MODE,TIMR;
/* 04 */ volatile Byte XAD1,XAD2,__f1,_f2;
/* 08 */ volatile Byte RAL1,RHCR,RBCL,RBCH;
/* 0C */ volatile Byte CCR0,CCR1,CCR2,CCR3;
/* 10 */ volatile Byte __f3,__f4,__f5,__f6;
/* 14 */ volatile Byte VSTR,__f7,PRE ,__f8;
/* 18 */ volatile Byte GISR,IPC ,ISR0,ISR1;
/* 1C */ volatile Byte PVR ,PIS ,Fifo,__f9; /* 0x1E is PCR, but ... */
} __r;
struct {
volatile Byte fifo[HSCX_W_FIFO_SIZE];
/* 00 */ volatile Byte CMDR,__f0,MODE,TIMR;
/* 04 */ volatile Byte XAD1,XAD2,RAH1,RAH2;
/* 08 */ volatile Byte RAL1,RAL2,XBCL,XBCH;
/* 0C */ volatile Byte CCR0,CCR1,CCR2,CCR3;
/* 10 */ volatile Byte TSAX,TSAR,XCCR,RCCR;
/* 14 */ volatile Byte BGR ,RLCR,PRE ,__f8;
/* 18 */ volatile Byte IVA ,IPC ,IMR0,IMR1;
/* 1C */ volatile Byte PVR ,PIM ,Fifo,__f9; /* 0x1E is PCR, but ... */
} __w;
} __rw;
} *__hscx;
#else
typedef struct _hscx {
union {
struct {
volatile Byte fifo[HSCX_R_FIFO_SIZE];
/* 00 */ volatile Byte ISTA,STAR,MODE,TIMR;
/* 04 */ volatile Byte EXIR,RBCL,_f1,RSTA;
/* 08 */ volatile Byte RAL1,RHCR,__f2,__f3;
/* 0C */ volatile Byte CCR2,RBCH,VSTR,CCR1;
/* 10 */ volatile Byte __f4,__f5,__f6,__f7;
/* 14 */ volatile Byte __f8,__f9,__fa,__fb;
/* 18 */ volatile Byte __fc,__fd,__fe,__ff;
/* 1C */ volatile Byte __fA,__fB,Fifo,__fC;
} __r;
struct {
volatile Byte fifo[HSCX_W_FIFO_SIZE];
/* 00 */ volatile Byte MASK,CMDR,MODE,TIMR;
/* 04 */ volatile Byte XAD1,XAD2,RAH1,RAH2;
/* 08 */ volatile Byte RAL1,RAL2,XBCL,BGR;
/* 0C */ volatile Byte CCR2,XBCH,RLCR,CCR1;
/* 10 */ volatile Byte TSAX,TSAR,XCCR,RCCR;
/* 14 */ volatile Byte __f8,__f9,__fa,__fb;
/* 18 */ volatile Byte __fc,__fd,__fe,__ff;
/* 1C */ volatile Byte __fA,__fB,Fifo,__fC;
} __w;
} __rw;
} *__hscx;
#endif
#define ByteInISAC(_dumb,_what) InISAC((_dumb),offsetof(struct _isac,r._what))
#define ByteOutISAC(_dumb,_what,_data) OutISAC((_dumb),offsetof(struct _isac,w._what), (_data))
#define ByteInHSCX(_dumb,_hcr,_what) InHSCX((_dumb),(_hcr),offsetof(struct _hscx,r._what))
#define ByteOutHSCX(_dumb,_hcr,_what,_data) OutHSCX((_dumb),(_hcr),offsetof(struct _hscx,w._what),(_data))
#ifdef linux
#define SetSPL(x) spl(1)
#else
#define SetSPL(x) spl((x))
#endif
#ifdef linux
#ifdef _avm_
#include "avm_io.c"
#endif
#ifdef _bsc_
#include "bsc_io.c"
#endif
#ifdef _ncp16_
#include "ncp16_io.c"
#endif
#ifdef _ncp_
#include "ncp_io.c"
#endif
#ifdef _teles_
#include "teles_io.c"
#endif
#ifdef _teles3_
#include "teles3_io.c"
#endif
#define DUMBTIME 300 /* poll: times per second */
void NAME(REALNAME,poll)(struct _dumb *dumb);
#else
void NAME(REALNAME,poll)(void *);
#endif
static struct _dumb *dumblist = NULL;
static void
toggle_off(struct _dumb * dumb)
{
int i;
ByteOutISAC(dumb,MASK,0xFF);
for(i=1;i <= dumb->numHSCX; i++) {
#ifdef WIDE
ByteOutHSCX(dumb,i,IMR0,0xFF);
ByteOutHSCX(dumb,i,IMR1,0xFF);
#else
ByteOutHSCX(dumb,i,MASK,0xFF);
#endif
}
}
static void
toggle_on(struct _dumb * dumb)
{
int i;
for(i=1;i <= dumb->numHSCX; i++) {
#ifdef WIDE
ByteOutHSCX(dumb,i,IMR0,0x00);
ByteOutHSCX(dumb,i,IMR1,0x00);
#else
ByteOutHSCX(dumb,i,MASK,0x00);
#endif
}
ByteOutISAC(dumb,MASK,0x00);
}
static void
fail_up(struct _dumb * dumb)
{
if(dumb->do_uptimer) {
dumb->do_uptimer = 0;
DEBUG(info) printf("CARD NOT UP, FAIL\n");
isdn2_new_state(&dumb->card,2);
}
}
static int
mode (struct _isdn1_card * card, short channel, char mode, char listen)
{
struct _dumb * dumb = (struct _dumb *) card;
unsigned long ms = SetSPL(dumb->ipl);
int err = 0;
char do_uptimer = dumb->do_uptimer;
static int modeloop = -1;
modeloop++;
switch(channel) {
case 0:
DEBUG(info) printf("%sISDN ISAC %s<%d>%s\n",KERN_INFO ,mode?(mode==1?"standby":"up"):"down",mode,listen?" listen":"");
if(dumb->do_uptimer) {
dumb->do_uptimer = 0;
#ifdef NEW_TIMEOUT
untimeout(dumb->uptimer);
#else
untimeout(fail_up,dumb);
#endif
}
if((dumb->chan[0].mode <= M_STANDBY) && (mode > M_STANDBY))
do_uptimer = 1;
else if(mode <= M_STANDBY)
do_uptimer = 0;
if(mode == M_ON)
mode = M_HDLC;
switch(mode) {
case M_OFF:
DEBUG(info) printk("%sISDN CIX1 0x3F\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x3F);
if(!modeloop) isdn2_new_state(&dumb->card,0);
dumb->chan[0].mode = mode;
break;
case M_STANDBY:
switch((ByteInISAC(dumb,CIR0)>>2)&0x0F) {
case 0x00:
case 0x0F:
DEBUG(info) printk("%sISDN CIX2 0x00\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x00);
break;
case 0x06:
DEBUG(info) printk("%sISDN CIX3 0x3F\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x07);
break;
case 0x0C:
case 0x0D:
DEBUG(info) printk("%sISDN noCIX2 CIR %02x\n",KERN_DEBUG,ByteInISAC(dumb,CIR0));
if(!modeloop) isdn2_new_state(&dumb->card,1);
do_uptimer = 0;
break;
default:
DEBUG(info) printk("%sISDN noCIX0 CIR %02x\n",KERN_DEBUG,ByteInISAC(dumb,CIR0));
break;
}
ByteOutISAC(dumb,MODE,0xC9);
ByteOutISAC(dumb,MASK,0x00);
dumb->chan[0].mode = mode;
dumb->chan[0].listen = 1;
break;
case M_HDLC:
ByteOutISAC(dumb,MODE,0xC9);
ByteOutISAC(dumb,MASK,0x00);
switch((ByteInISAC(dumb,CIR0)>>2)&0x0F) {
case 0x00:
case 0x0F:
if(dumb->chan[0].mode != M_HDLC) {
DEBUG(info) printk("%sISDN CIX4 0x3F\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x00);
}
break;
case 0x06:
if(dumb->chan[0].mode != M_HDLC) {
DEBUG(info) printk("%sISDN CIX5 0x3F\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x3F);
}
break;
case 0x07:
if(dumb->chan[0].mode != M_HDLC) {
DEBUG(info) printk("%sISDN CIX6 0x27\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x27);
}
break;
case 0x0C:
case 0x0D:
DEBUG(info) printk("%sISDN noCIX1 CIR %02x\n",KERN_DEBUG,ByteInISAC(dumb,CIR0));
if(!modeloop) isdn2_new_state(&dumb->card,1);
do_uptimer = 0;
break;
default:
DEBUG(info) printk("%sISDN CIX9 0x07\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x07);
break;
}
dumb->chan[0].mode = mode;
dumb->chan[0].listen = 0;
break;
}
if(mode == M_OFF) {
int j;
for(j=1;j <= dumb->numHSCX;j++)
HSCX_mode(dumb,j,M_OFF,0);
} else if (do_uptimer && !dumb->do_uptimer && !modeloop) {
#ifdef NEW_TIMEOUT
dumb->uptimer =
#endif
timeout((void *)fail_up,dumb,10*HZ);
dumb->do_uptimer = 1;
}
break;
default:
if(channel > 0 && channel <= dumb->numHSCX) {
DEBUG(info) printf("%sISDN HSCX%d %s<%d>%s\n",KERN_INFO ,channel,mode?"up":"down",mode,(listen&2)?"setup":((listen&1)?" listen":""));
if(listen & 2) {
err = HSCX_mode(dumb,channel,M_OFF,0);
} else {
if((mode > M_STANDBY) && (dumb->chan[channel].mode <= M_STANDBY)) {
modeloop--;
return -EAGAIN;
}
err = HSCX_mode(dumb,channel,(mode != M_ON) ? mode : dumb->chan[channel].mode,listen);
if (err < 0) {
printf("%sISDN err %d %d\n",KERN_WARNING ,channel, err);
splx(ms);
modeloop--;
return err;
}
dumb->chan[channel].nblk = 0;
dumb->chan[channel].maxblk = 10;
}
break;
} else {
printf("%sISDN badChan %d\n",KERN_WARNING ,channel);
splx(ms);
modeloop--;
return -EINVAL;
}
}
modeloop--;
NAME(REALNAME,poll)(dumb);
splx(ms);
return err;
}
static int
prot (struct _isdn1_card * card, short channel, mblk_t * mp, int flags)
{
struct _dumb * dumb = (struct _dumb *)card;
streamchar *origmp = mp->b_rptr;
ushort_t id;
int err = 0;
DEBUG(info)printf("%sDumbProt chan %d flags 0%o\n",KERN_DEBUG,channel,flags);
#define isspace(x) (((x)==' ') || ((x)=='\t'))
if(flags & CHP_MODLIST) {
if(!(flags & PUSH_AFTER)) {
streamchar *s1,*s2,sx;
s1 = mp->b_rptr;
while(s1 < mp->b_wptr && isspace(*s1))
s1++;
s2 = s1;
while(s2 < mp->b_wptr && !isspace(*s2))
s2++;
sx = *s2; *s2 = '\0';
if(!strcmp(s1,"trans"))
dumb->chan[channel].mode = M_TRANSPARENT;
else if(!strcmp(s1,"transalaw"))
dumb->chan[channel].mode = M_TRANS_ALAW;
else if(!strcmp(s1,"transv110"))
dumb->chan[channel].mode = M_TRANS_V110;
else if(!strcmp(s1,"transframe"))
dumb->chan[channel].mode = M_TRANS_HDLC;
else if(!strcmp(s1,"frame"))
dumb->chan[channel].mode = M_HDLC;
else if(!strcmp(s1,"framelow"))
dumb->chan[channel].mode = M_HDLC_7L;
else if(!strcmp(s1,"framehigh"))
dumb->chan[channel].mode = M_HDLC_7H;
else if(!strcmp(s1,"framezero"))
dumb->chan[channel].mode = M_HDLC_N0;
else if(!strcmp(s1,"frame16"))
dumb->chan[channel].mode = M_HDLC_16;
else {
mp->b_rptr = origmp;
return -ENOENT;
}
origmp = s2+1;
}
err = -ERESTART;
} else if(!(flags & ~CHP_FROMSTACK)) {
if ((err = m_getid (mp, &id)) != 0)
goto err;
switch (id) {
default:
err = -ERESTART;
break;
case PROTO_OFFSET:
{
long z;
if ((err = m_geti (mp, &z)) != 0)
goto err;
if (z < 0 || z >= 1024) {
err = -EINVAL;
goto err;
}
if(flags & CHP_FROMSTACK) /* down */
dumb->chan[channel].offset = z;
}
err = -ERESTART;
break;
}
} else
err = -ERESTART;
if(err == 0) {
freemsg(mp);
return 0;
}
err:
mp->b_rptr = origmp;
return ((err != -ERESTART) ? err : isdn2_chprot(card,channel,mp,flags));
}
/*
* Check if buffer space is available
*/
static int
candata (struct _isdn1_card * card, short channel)
{
struct _dumb * dumb = (struct _dumb *)card;
int ret = (dumb->chan[channel].q_out.nblocks < 4);
if(channel == 0) { DEBUG(isac) printf("%sCQ D %d...",KERN_DEBUG,ret); }
else { DEBUG(hscxout) printf("%sCQ %d %d...",KERN_DEBUG,channel,ret); }
return ret;
}
/*
* Enqueue the data.
*/
static int
data (struct _isdn1_card * card, short channel, mblk_t * data)
{
struct _dumb * dumb = (struct _dumb *)card;
if(channel == 0) { DEBUG(isac) printf("%sQ D %d...",KERN_DEBUG,msgdsize(data)); }
else { DEBUG(hscxout) printf("%sQ %d %d...",KERN_DEBUG,channel,msgdsize(data)); }
S_enqueue(&dumb->chan[channel].q_out, data);
NAME(REALNAME,poll)((struct _dumb *) card);
return 0;
}
/*
* Flush the send queue.
*/
static int
flush (struct _isdn1_card * card, short channel)
{
struct _dumb * dumb = (struct _dumb *)card;
S_flush(&dumb->chan[channel].q_out);
return 0;
}
static int
ISACpresent(struct _dumb *dumb)
{
unsigned char Bt;
if(((Bt = ByteInISAC(dumb,STAR)) & ~0x4F) != 0) {
printf("<STAR %02x> ",Bt);
return -ENXIO;
}
if(((Bt = ByteInISAC(dumb,EXIR)) & ~0x10) != 0) {
printf("<EXIR %02x> ",Bt);
return -ENXIO;
}
if(((Bt = ByteInISAC(dumb,RBCH)) & 0x8F) != 0x00) {
printf("<RBCH %02x> ",Bt);
return -ENXIO;
}
ByteOutISAC(dumb,MODE,0xD1);
if((Bt = ByteInISAC(dumb,MODE)) != 0xD1) {
printf("<MODE %02x> ",Bt);
return -ENXIO;
}
#if 0
if((Bt = ByteInISAC(dumb,RBCL)) != 0) {
printf("<RBCL %02x> ",Bt);
return -ENXIO;
}
#endif
ByteOutISAC(dumb,MODE,0xC1);
if((Bt = ByteInISAC(dumb,MODE)) != 0xC1) {
printf("<MODE %02x> ",Bt);
return -ENXIO;
}
return 1;
}
static void
InitHSCX(struct _dumb * dumb)
{
int i;
for (i=1; i <= dumb->numHSCX; i++)
InitHSCX_ (dumb,i);
}
static void
ISAC_kick(struct _dumb * dumb)
{
mblk_t *sendb;
uchar_t *sendp = NULL;
unsigned long ms = SetSPL(dumb->ipl);
DEBUG(isac) printf("%sK ",KERN_DEBUG );
if(dumb->chan[0].locked) {
DEBUG(isac) printf("lck ");
splx(ms);
return;
}
if(dumb->chan[0].mode < M_ON) {
if(0)DEBUG(isac) { printf("Flush Off\n"); }
S_flush(&dumb->chan[0].q_out);
if(dumb->chan[0].mode == M_OFF) {
if(dumb->chan[0].m_in != NULL) {
freemsg(dumb->chan[0].m_in);
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
}
}
if(dumb->chan[0].m_out != NULL) {
freemsg(dumb->chan[0].m_out);
dumb->chan[0].m_out = dumb->chan[0].m_out_run = NULL;
}
splx(ms);
return;
}
if ((ByteInISAC(dumb,STAR) & 0x40) == 0) { /* ! XFW */
DEBUG(isac) if(dumb->chan[0].q_out.nblocks+(dumb->chan[0].m_out_run != NULL))
printf("NRdy%d\n",dumb->chan[0].q_out.nblocks+(dumb->chan[0].m_out_run != NULL));
splx(ms);
return;
}
dumb->chan[0].locked = 1;
if(dumb->chan[0].m_out_run == NULL) {
sendb = dumb->chan[0].m_out = dumb->chan[0].m_out_run = S_dequeue(&dumb->chan[0].q_out);
if(sendb != NULL)
sendp = dumb->chan[0].m_out_run->b_rptr;
} else {
sendb = dumb->chan[0].m_out_run;
sendp = dumb->chan[0].p_out;
}
splx(ms);
if (sendb != NULL) {
short numb = 0;
DEBUG(isac) printf(".si");
do {
short thisb = (uchar_t *)sendb->b_wptr-sendp;
if(thisb > ISAC_W_FIFO_SIZE-numb) thisb = ISAC_W_FIFO_SIZE-numb;
for(;thisb > 0; thisb--) {
ByteOutISAC(dumb,FIFO(numb),*sendp);
numb++; sendp++;
}
while(sendp >= (uchar_t *)sendb->b_wptr) {
sendb = sendb->b_cont;
if(sendb != NULL)
sendp = (uchar_t *)sendb->b_rptr;
else
goto dEnd; /* shortcut */
}
} while((numb < ISAC_W_FIFO_SIZE) && (sendb != NULL));
if(sendb != NULL) {
ByteOutISAC(dumb,CMDR, 0x08); /* XTF */
DEBUG(isac)printf(",");
dumb->chan[0].m_out_run = sendb;
dumb->chan[0].p_out = sendp;
} else {
dEnd:
ByteOutISAC(dumb,CMDR, 0x0A); /* XTF|XME */
DEBUG(isac)printf(";");
freemsg(dumb->chan[0].m_out);
dumb->chan[0].m_out = dumb->chan[0].m_out_run = NULL;
if(dumb->chan[0].q_out.nblocks < 2)
isdn2_backenable(&dumb->card,0);
}
} else DEBUG(isac) printf("nothing");
dumb->chan[0].locked = 0;
DEBUG(isac) printf("\n");
}
#ifdef __GNUC__
/* inline */
#endif
static void
HSCX_kick(struct _dumb * dumb, u_char hscx)
{
mblk_t *sendb;
uchar_t *sendp = NULL;
hdlc_buf bufp = &dumb->chan[hscx];
unsigned long ms = SetSPL(dumb->ipl);
DEBUG(hscxout) printf("%sK.%d ",KERN_DEBUG ,hscx);
if(bufp->locked) {
DEBUG(hscxout) { printf("Lck\n"); }
splx(ms);
return;
}
if(bufp->listen) {
DEBUG(hscxout) { printf("Listen\n"); }
splx(ms);
return;
}
if(bufp->mode == M_OFF) {
DEBUG(hscxout) { if(bufp->q_out.nblocks > 0) printf("Flush Off\n"); }
S_flush(&bufp->q_out);
if(bufp->m_in != NULL) {
freemsg(bufp->m_in);
bufp->m_in = bufp->m_in_run = NULL;
}
if(bufp->m_out != NULL) {
freemsg(bufp->m_out);
bufp->m_out = bufp->m_out_run = NULL;
}
splx(ms);
return;
}
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
if ((ByteInHSCX(dumb,hscx,STAR) & 0x40) == 0) { /* ! XFW */
DEBUG(hscxout)printf("NR\n");
splx(ms);
return;
}
bufp->locked = 1;
splx(ms);
#if 0
do {
#endif
if(bufp->m_out_run == NULL) {
sendb = bufp->m_out = bufp->m_out_run = S_dequeue(&bufp->q_out);
if(sendb != NULL)
sendp = bufp->m_out_run->b_rptr;
} else {
sendb = bufp->m_out_run;
sendp = bufp->p_out;
}
if (sendb != NULL) {
short numb = 0;
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
#ifdef CONFIG_DEBUG_ISDN
if(sendp == NULL) {
DEBUG(hscxout)printf("\n");
printf("%sPNull! %p %p %p %p %p %d\n",KERN_WARNING ,sendb,sendp,bufp->m_out,bufp->m_out_run,bufp->p_out,numb);
goto exhopp;
}
#endif
DEBUG(hscxout) printf(".s");
do {
short thisb = (uchar_t *)sendb->b_wptr-sendp;
if(thisb > HSCX_W_FIFO_SIZE-numb) thisb = HSCX_W_FIFO_SIZE-numb;
DEBUG(hscxout) printf(">%d ",thisb);
for(;thisb > 0; thisb --) {
ByteOutHSCX(dumb,hscx,FIFO(numb),*sendp);
numb++; sendp++;
}
while(sendp >= (uchar_t *)sendb->b_wptr) {
sendb = sendb->b_cont;
DEBUG(hscxout)printf("=%p ",sendb);
if(sendb != NULL)
sendp = (uchar_t *)sendb->b_rptr;
else
goto bEnd; /* shortcut */
}
} while((numb < HSCX_W_FIFO_SIZE) && (sendb != NULL));
#if 1
if(
#ifdef WIDE
ByteInHSCX(dumb,hscx,ISR1)&0x10
#else
ByteInHSCX(dumb,hscx,EXIR)&0x40
#endif
) { /* XDU */
DEBUG(info) printf("%sUnderrun HSCX.%d\n",KERN_DEBUG ,hscx);
ByteOutHSCX(dumb,hscx,CMDR,0x01);
bufp->m_out_run = bufp->m_out;
bufp->p_out = bufp->m_out->b_rptr;
} else
#endif
if(sendb != NULL) {
ByteOutHSCX(dumb,hscx,CMDR, 0x08); /* XTF */
DEBUG(hscxout) printf(",");
bufp->m_out_run = sendb;
bufp->p_out = sendp;
} else {
bEnd:
if(bufp->mode >= M_HDLC)
ByteOutHSCX(dumb,hscx,CMDR, 0x0A); /* XTF|XME */
else
ByteOutHSCX(dumb,hscx,CMDR, 0x08); /* XTF */
DEBUG(hscxout) printf(";");
freemsg(bufp->m_out);
bufp->m_out = bufp->m_out_run = NULL;
if(bufp->q_out.nblocks < 2)
isdn2_backenable(&dumb->card,hscx);
}
} else {
short i;
switch(bufp->mode) {
default:
goto exhopp;
done:
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0x08); /* XTF */
DEBUG(hscxout) printf(",");
break;
case M_TRANS_HDLC:
for (i=0;i<HSCX_W_FIFO_SIZE; i++)
ByteOutHSCX(dumb,hscx,FIFO(i), 0x7E);
goto done;
case M_TRANS_ALAW:
for (i=0;i<HSCX_W_FIFO_SIZE; i++)
ByteOutHSCX(dumb,hscx,FIFO(i), 0x2A);
goto done;
case M_TRANS_V110:
for(i=0;i<=HSCX_W_FIFO_SIZE-10; i+=10) {
ByteOutHSCX(dumb,hscx,FIFO(i+0), 0x00);
ByteOutHSCX(dumb,hscx,FIFO(i+1), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+2), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+3), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+4), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+5), 0x01);
ByteOutHSCX(dumb,hscx,FIFO(i+6), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+7), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+8), 0xFF);
ByteOutHSCX(dumb,hscx,FIFO(i+9), 0xFF);
}
goto done;
}
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
}
#if 0
} while (ByteInHSCX(dumb,hscx,STAR) & 0x40); /* XFW */
#endif
DEBUG(hscxout) printf("\n");
exhopp:;
bufp->locked = 0;
}
#ifdef __GNUC__
/* inline */
#endif
static void
IRQ_HSCX_(struct _dumb * dumb, u_char hscx,
#ifdef WIDE
Byte isr0, Byte isr1
#else
Byte Reason, Byte hasEX
#endif
)
{
hdlc_buf bufp = &dumb->chan[hscx];
#ifdef WIDE
DEBUG(hscx) { printf("%s%c.%d %02x:%02x\n",KERN_DEBUG ,(dumb->polled<0)?'X':'I',hscx, isr0,isr1); }
#else
DEBUG(hscx) { printf("%s%c.%d %02x\n",KERN_DEBUG ,(dumb->polled<0)?'X':'I',hscx, Reason); }
if (hasEX)
#endif
{
#ifndef WIDE
Byte EXIR = ByteInHSCX(dumb,hscx,EXIR);
DEBUG(hscx) { printf(". %x", EXIR); }
#endif
if (
#ifdef WIDE
isr1 & 0x02
#else
EXIR & 0x80
#endif
) { /* XMR */
DEBUG(info) { printf("%sMsg Repeat HSCX.%d\n",KERN_DEBUG ,hscx); }
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
if (ByteInHSCX(dumb,hscx,STAR) & 0x40) { /* XFW */
#ifdef WIDE
isr1 |= 0x01; /* also set XPR */
#else
Reason |= 0x10; /* also set XPR bit */
#endif
} else {
ByteOutHSCX(dumb,hscx,CMDR, 0x01); /* XRES -- cause XPR */
}
/* Restart */
if((bufp->m_out_run = bufp->m_out) != NULL)
bufp->p_out = bufp->m_out->b_rptr;
}
if (
#ifdef WIDE
isr1 & 0x10
#else
EXIR & 0x40
#endif
) { /* XDU */
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
if (bufp->mode >= M_HDLC) {
DEBUG(info) {
printf("%sXmit Underrun HSCX.%d\n",KERN_DEBUG ,hscx); }
#if NEW_XMIT
ByteOutHSCX(dumb,hscx,CMDR, 0x01); /* XRES */
#ifdef WIDE
isr1 |= 0x01; /* set XPR */
#else
Reason |= 0x10; /* set XPR bit */
#endif
#else /* old */
if (ByteInHSCX(dumb,hscx,STAR) & 0x40) { /* XFW */
#ifdef WIDE
isr1 |= 0x01; /* set XPR */
#else
Reason |= 0x10; /* set XPR bit */
#endif
} else {
ByteOutHSCX(dumb,hscx,CMDR, 0x01); /* XRES -- cause XPR */
}
#endif
/* Restart */
if ((bufp->m_out_run = bufp->m_out) != NULL)
bufp->p_out = bufp->m_out->b_rptr;
} else {
#ifdef WIDE
isr1 |= 0x01; /* set XPR */
#else
Reason |= 0x10; /* set XPR bit */
#endif
}
}
#ifdef WIDE
DEBUG(hscx)if (isr0 & 0x08) { /* PLLA */
DEBUG(info) { printf("%sISDN .PLLA\n",KERN_WARNING ); }
}
DEBUG(hscx)if (isr0 & 0x20) { /* RSC */
DEBUG(info) { printf("%sISDN .RSC\n",KERN_WARNING ); }
}
DEBUG(hscx)if (isr0 & 0x10) { /* PCE */
DEBUG(info) { printf("%sISDN .PCE\n",KERN_WARNING ); }
}
DEBUG(hscx)if (isr0 & 0x40) { /* RFS */
DEBUG(info) { printf("%sISDN .RFS\n",KERN_WARNING ); }
}
#else
DEBUG(hscx)if (EXIR & 0x08) { /* CSC */
DEBUG(info) { printf("%sISDN .CSC\n",KERN_WARNING ); }
}
DEBUG(hscx)if (EXIR & 0x04) { /* RFS */
DEBUG(info) { printf("%sISDN .RFS\n",KERN_WARNING ); }
}
/* 0x02 and 0x01 are empty */
DEBUG(hscx)if (EXIR & 0x20) { /* PCE */
DEBUG(info) { printf("%sISDN .PCE\n",KERN_WARNING ); }
}
#endif
if (
#ifdef WIDE
isr0 & 0x02
#else
EXIR & 0x10
#endif
) { /* RFO */
DEBUG(info) { printf("%sRecv overflow HSCX.%d\n",KERN_DEBUG ,hscx); }
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
if(
#ifdef WIDE
isr0 & 0x81
#else
Reason & 0xC0
#endif
) { /* RME|RPF */
ByteOutHSCX(dumb,hscx,CMDR, 0xC0); /* RMC|RHR */
#ifdef WIDE
isr0 &=~ 0x81;
#else
Reason &=~ 0xC0;
#endif
} else
ByteOutHSCX(dumb,hscx,CMDR, 0x80); /* RMC */
if(bufp->m_in != NULL) {
freemsg(bufp->m_in);
bufp->m_in = bufp->m_in_run = NULL;
}
}
}
if (
#ifdef WIDE
isr0 & 0x80
#else
Reason & 0x80
#endif
) { /* RME */
Byte RSTA = ByteInHSCX(dumb,hscx,RSTA);
if ((RSTA & 0xF0) == 0xA0) {
uchar_t *recvp;
mblk_t *recvb;
short xblen = ((ByteInHSCX(dumb,hscx,RBCH) & 0x0F) << 8) + ByteInHSCX(dumb,hscx,RBCL);
short blen = ((xblen-1) & (HSCX_R_FIFO_SIZE-1));
if(0)DEBUG(hscx)printf(":%d ",xblen);
if(blen == 0) {
if((recvb = bufp->m_in_run) != NULL) {
mblk_t *msg = bufp->m_in;
bufp->m_in = bufp->m_in_run = NULL;
/* TODO: defer processing of incoming frames */
if(!isdn2_canrecv(&dumb->card,hscx))
freemsg(msg);
else if(isdn2_recv(&dumb->card,hscx,msg) != 0)
freemsg(msg);
}
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0x80); /* RMC */
} else {
if ((recvb = bufp->m_in_run) != NULL) {
if ((recvp = (uchar_t *)recvb->b_wptr) + blen > (uchar_t *)DATA_END(recvb))
recvb = NULL;
}
if (recvb == NULL) {
recvb = allocb(blen,BPRI_MED);
if(recvb != NULL) {
recvp = recvb->b_wptr;
if(bufp->m_in_run == NULL) {
bufp->m_in = recvb;
bufp->m_in_run = recvb;
} else {
linkb(bufp->m_in_run,recvb);
bufp->m_in_run = recvb;
}
}
}
if(recvb != NULL) {
mblk_t *msg = bufp->m_in;
bufp->m_in = bufp->m_in_run = NULL;
if(msg == NULL) {
printf(" :BufAllocErr%d:",hscx);
} else {
short i;
for(i=0;i < blen; i++)
*recvp++ = ByteInHSCX(dumb,hscx,FIFO(i));
recvb->b_wptr = recvp;
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0x80); /* RMC */
/* TODO: defer processing of incoming frames */
if(!isdn2_canrecv(&dumb->card,hscx))
freemsg(msg);
else if(isdn2_recv(&dumb->card,hscx,msg) != 0)
freemsg(msg);
}
} else {
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0xC0); /* RMC|RHR */
}
}
} else {
DEBUG(info) { printf("%sRecv abort (%02x) HSCX.%d\n",KERN_DEBUG , RSTA,hscx); }
if(bufp->m_in != NULL) {
freemsg(bufp->m_in);
bufp->m_in = bufp->m_in_run = NULL;
}
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0xC0); /* RMC|RHR */
}
} else if (
#ifdef WIDE
isr0 & 0x01
#else
Reason & 0x40
#endif
) { /* RPF */
uchar_t *recvp;
mblk_t *recvb;
if ((recvb = bufp->m_in_run) != NULL) {
if ((recvp = (uchar_t *)recvb->b_wptr) + HSCX_R_FIFO_SIZE > (uchar_t *)DATA_END(recvb))
recvb = NULL;
}
if(0)DEBUG(hscx)printf(":");
if (recvb == NULL) {
if(bufp->m_in_run == NULL) { /* first block */
recvb = allocb(HSCX_R_FIFO_SIZE*2+bufp->offset,BPRI_MED);
if(recvb != NULL) {
recvb->b_wptr += bufp->offset;
recvb->b_rptr += bufp->offset;
recvp = recvb->b_wptr;
bufp->m_in = bufp->m_in_run = recvb;
}
} else {
recvb = allocb(HSCX_R_FIFO_SIZE*4,BPRI_MED);
if(recvb != NULL) {
recvp = recvb->b_wptr;
linkb(bufp->m_in_run, recvb);
bufp->m_in_run = recvb;
}
}
}
if(recvb == NULL) {
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
if(bufp->mode >= M_HDLC) {
if(bufp->m_in != NULL) {
freemsg(bufp->m_in);
bufp->m_in = bufp->m_in_run = NULL;
}
ByteOutHSCX(dumb,hscx,CMDR, 0x40); /* RRESet */
} else {
ByteOutHSCX(dumb,hscx,CMDR, 0x80); /* RMC */
}
} else {
short i;
for (i=0; i < HSCX_R_FIFO_SIZE; i++)
*recvp++ = ByteInHSCX(dumb,hscx,FIFO(i));
recvb->b_wptr = recvp;
CEC(ByteInHSCX(dumb,hscx,STAR) & 0x04);
ByteOutHSCX(dumb,hscx,CMDR, 0x80); /* RMC */
if(bufp->mode < M_HDLC && ++bufp->nblk > bufp->maxblk) {
if(isdn2_canrecv(&dumb->card,hscx)) {
mblk_t *msg = bufp->m_in;
bufp->m_in = bufp->m_in_run = NULL;
if(isdn2_recv(&dumb->card,hscx,msg) != 0)
freemsg(msg);
bufp->nblk = 0;
} else if(bufp->nblk > 3*bufp->maxblk) {
mblk_t *msg = bufp->m_in;
bufp->m_in = bufp->m_in_run = NULL;
if(msg != NULL)
freemsg(msg);
bufp->nblk = 0;
}
}
}
}
#ifdef WIDE
DEBUG(hscx)if (isr1 & 0x08) { /* TIN */
DEBUG(info) { printf("%sISDN .TIN\n",KERN_WARNING ); }
}
DEBUG(hscx)if (isr1 & 0x20) { /* AOLP */
DEBUG(info) { printf("%sISDN .AOLP\n",KERN_WARNING ); }
}
#else
DEBUG(hscx)if (Reason & 0x20) { /* RSC */
DEBUG(info) { printf("%sISDN .RSC\n",KERN_WARNING ); }
}
DEBUG(hscx)if (Reason & 0x08) { /* TIN */
DEBUG(info) { printf("%sISDN .TIN\n",KERN_WARNING ); }
}
#endif
if ((
#ifdef WIDE
isr1 & 0x01
#else
Reason & 0x10
#endif
) || (ByteInHSCX(dumb,hscx,STAR) & 0x40)) { /* XPR */
HSCX_kick(dumb,hscx);
}
}
#ifdef __GNUC__
inline
#endif
static void DoCIR (struct _dumb * dumb, Byte CIR)
{
switch(CIR) {
case 0x0C:
case 0x0D:
DEBUG(info) printf(" up");
if(dumb->do_uptimer) {
dumb->do_uptimer = 0;
#ifdef NEW_TIMEOUT
untimeout(dumb->uptimer);
#else
untimeout(fail_up,dumb);
#endif
}
isdn2_new_state(&dumb->card,1);
break;
case 0x07:
if(dumb->chan[0].mode >= M_ON) {
DEBUG(info) printk("%sISDN CIX7 0x27\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x27);
}
/* FALL THRU */
case 0x04:
if((dumb->chan[0].mode >= M_ON) && !dumb->do_uptimer) {
#ifdef NEW_TIMEOUT
dumb->uptimer =
#endif
timeout((void *)fail_up,dumb,2*HZ);
dumb->do_uptimer = 1;
}
break;
case 0x00:
case 0x06:
case 0x0F:
if(dumb->chan[0].mode >= M_ON) {
DEBUG(info) printk("%sISDN CIX8 0x03\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x03);
}
if((CIR != 0x0F) && (dumb->chan[0].mode == M_OFF)) {
DEBUG(info) printk("%sISDN CIX9 0x3F\n",KERN_DEBUG );
ByteOutISAC(dumb,CIX0,0x3F);
}
isdn2_new_state(&dumb->card,0);
}
}
#ifdef __GNUC__
inline
#endif
static void
IRQ_ISAC(struct _dumb * dumb)
{
Byte Reason;
while((Reason = ByteInISAC(dumb,ISTA))) {
DEBUG(isac) { printf("%s%c %02x\n",KERN_DEBUG ,(dumb->polled<0)?'X':'I',Reason); }
if (Reason & 0x04) { /* CISQ */
Byte CIR = ByteInISAC(dumb,CIR0);
if (CIR & 0x80) { /* SQC */
DEBUG(info) { printf("%sISDN .SQC %x\n",KERN_WARNING ,ByteInISAC(dumb,SQRR)); }
}
if (CIR & 0x03) {
CIR = ((CIR >> 2) & 0x0F);
DEBUG(info) printf("%sISDN CIR %01x",KERN_DEBUG ,CIR);
if (dumb->polled >= 0)
DoCIR(dumb,CIR);
DEBUG(info) printf("\n");
#if 0
ByteOutISAC(dumb,CMDR,0x41);
Reason &=~ 0xC0;
#endif
}
}
if (Reason & 0x01) {
Byte EXIR = ByteInISAC(dumb,EXIR);
DEBUG(isac) { printf(". %x", EXIR); }
if (EXIR & 0x80) { /* XMR */
DEBUG(info) { printf("%sMsgRepeat ISAC\n",KERN_DEBUG ); }
CEC(ByteInISAC(dumb,STAR) & 0x04);
if (ByteInISAC(dumb,STAR) & 0x40) { /* XFW */
Reason |= 0x10; /* also set XPR bit */
} else {
ByteOutISAC(dumb,CMDR, 0x01); /* XRES -- cause XPR */
}
/* Restart */
if((dumb->chan[0].m_out_run = dumb->chan[0].m_out) != NULL)
dumb->chan[0].p_out = dumb->chan[0].m_out->b_rptr;
}
if (EXIR & 0x40) { /* XDU */
CEC(ByteInISAC(dumb,STAR) & 0x04);
if (dumb->chan[0].mode >= M_HDLC) {
DEBUG(info) { printf("%sXmit Underrun ISAC\n",KERN_DEBUG ); }
#if NEW_XMIT
ByteOutISAC(dumb,CMDR, 0x01); /* XRES */
Reason |= 0x10;
#else /* old */
if (ByteInISAC(dumb,STAR) & 0x40) { /* XFW */
Reason |= 0x10; /* set XPR bit */
} else {
ByteOutISAC(dumb,CMDR, 0x01); /* XRES -- cause XPR */
}
#endif
/* Restart */
if ((dumb->chan[0].m_out_run = dumb->chan[0].m_out) != NULL)
dumb->chan[0].p_out = dumb->chan[0].m_out->b_rptr;
} else {
Reason |= 0x10; /* set XPR bit */
}
}
DEBUG(isac)if (EXIR & 0x20) { /* PCE */
DEBUG(info) { printf("%sISDN .PCE\n",KERN_WARNING ); }
}
if (EXIR & 0x10) { /* RFO */
DEBUG(info) { printf("%sRecv overflow ISAC (%02x)\n",KERN_DEBUG , EXIR); }
CEC(ByteInISAC(dumb,STAR) & 0x04);
if(Reason & 0xC0) {
ByteOutISAC(dumb,CMDR, 0xC0); /* RMC|RHR */
Reason &=~ 0xC0;
} else
ByteOutISAC(dumb,CMDR, 0x80); /* RMC */
if(dumb->chan[0].m_in != NULL) {
freemsg(dumb->chan[0].m_in);
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
}
}
DEBUG(isac)if (EXIR & 0x08) { /* CSC */
DEBUG(info) { printf("%sISDN .CSC\n",KERN_WARNING ); }
}
DEBUG(isac)if (EXIR & 0x04) { /* RFS */
DEBUG(info) { printf("%sISDN .RFS\n",KERN_WARNING ); }
}
/* 0x02 and 0x01 are empty */
}
if (Reason & 0x80) { /* RME */
Byte RSTA = ByteInISAC(dumb,RSTA);
if ((RSTA & 0xF0) == 0xA0) {
uchar_t *recvp;
mblk_t *recvb;
short xblen;
short blen;
xblen = ByteInISAC(dumb,RBCL);
blen = (xblen & (ISAC_R_FIFO_SIZE-1));
xblen += (ByteInISAC(dumb,RBCH) & 0x0F) << 8;
#if 0 /* if this causes problems, TELL ME. */
if(blen == 1) {
DEBUG(isac) printf("%s.R-%d\n",KERN_DEBUG ,xblen);
if((recvb = dumb->chan[0].m_in_run) != NULL) {
mblk_t *msg = dumb->chan[0].m_in;
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
recvb->b_wptr --;
if(!isdn2_canrecv(&dumb->card,0))
freemsg(msg);
else if(isdn2_recv(&dumb->card,0,msg) != 0)
freemsg(msg);
}
} else
#endif
{
if(blen == 0)
blen = ISAC_R_FIFO_SIZE;
DEBUG(isac) printf("%s.R=%d",KERN_DEBUG ,xblen);
if ((recvb = dumb->chan[0].m_in_run) != NULL) {
DEBUG(isac)printf("a%d ",dsize(dumb->chan[0].m_in));
if ((recvp = (uchar_t *)recvb->b_wptr) + blen > (uchar_t *)DATA_END(recvb))
recvb = NULL;
}
if (recvb == NULL) {
recvb = allocb(ISAC_R_FIFO_SIZE,BPRI_MED);
if(recvb != NULL) {
recvp = recvb->b_wptr;
if(dumb->chan[0].m_in_run == NULL) {
dumb->chan[0].m_in = dumb->chan[0].m_in_run = recvb;
} else {
linkb(dumb->chan[0].m_in_run,recvb);
dumb->chan[0].m_in_run = recvb;
}
}
}
if(recvb != NULL) {
short i;
mblk_t *msg = dumb->chan[0].m_in;
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
DEBUG(isac) printf(">%p\n",recvp);
for(i=0;i < blen; i++)
*recvp++ = ByteInISAC(dumb,FIFO(i));
recvb->b_wptr = recvp;
CEC(ByteInISAC(dumb,STAR) & 0x04);
ByteOutISAC(dumb,CMDR, 0x80); /* RMC */
/* TODO: defer processing of incoming frames */
if(!isdn2_canrecv(&dumb->card,0))
freemsg(msg);
else if(isdn2_recv(&dumb->card,0,msg) != 0)
freemsg(msg);
} else {
CEC(ByteInISAC(dumb,STAR) & 0x04);
ByteOutISAC(dumb,CMDR, 0xC0); /* RMC|RHR */
DEBUG(isac) { printf(".NoBit ISAC\n"); }
}
}
} else {
DEBUG(info) { printf("%sRecv abort (%x)\n",KERN_DEBUG ,RSTA); }
if(dumb->chan[0].m_in != NULL) {
freemsg(dumb->chan[0].m_in);
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
}
CEC(ByteInISAC(dumb,STAR) & 0x04);
ByteOutISAC(dumb,CMDR, 0xC0); /* RMC|RHR */
}
} else if (Reason & 0x40) { /* RPF */
uchar_t *recvp;
mblk_t *recvb;
if ((recvb = dumb->chan[0].m_in_run) != NULL) {
if ((recvp = (uchar_t *)recvb->b_wptr) + ISAC_R_FIFO_SIZE > (uchar_t *)DATA_END(recvb))
recvb = NULL;
}
if (recvb == NULL) {
recvb = allocb(ISAC_R_FIFO_SIZE*2,BPRI_MED);
if(recvb != NULL) {
recvp = recvb->b_wptr;
if(dumb->chan[0].m_in_run == NULL) {
dumb->chan[0].m_in = dumb->chan[0].m_in_run = recvb;
} else {
linkb(dumb->chan[0].m_in_run,recvb);
dumb->chan[0].m_in_run = recvb;
}
}
}
if(recvb == NULL) {
CEC(ByteInISAC(dumb,STAR) & 0x04);
if(dumb->chan[0].mode >= M_HDLC) {
if(dumb->chan[0].m_in != NULL) {
freemsg(dumb->chan[0].m_in);
dumb->chan[0].m_in = dumb->chan[0].m_in_run = NULL;
}
ByteOutISAC(dumb,CMDR, 0x40); /* RRESet */
} else
ByteOutISAC(dumb,CMDR, 0x80); /* RMC */
} else {
short i;
DEBUG(isac) printf(">%p",recvp);
for(i=0;i < ISAC_R_FIFO_SIZE; i++)
*recvp++ = ByteInISAC(dumb,FIFO(i));
recvb->b_wptr = recvp;
CEC(ByteInISAC(dumb,STAR) & 0x04);
ByteOutISAC(dumb,CMDR, 0x80); /* RMC */
}
}
if (Reason & 0x20) { /* RSC */
DEBUG(info) { printf("%sISDN .RSC\n",KERN_WARNING ); }
}
if (Reason & 0x08) { /* TIN */
DEBUG(info) { printf("%sISDN .TIN\n",KERN_WARNING ); }
#if 0
ByteOutISAC(dumb,TIMR,0x11);
ByteOutISAC(dumb,CMDR,0x10); /* start timer */
#endif
}
if ((Reason & 0x10) || (ByteInISAC(dumb,STAR) & 0x40)) { /* XPR */
ISAC_kick(dumb);
}
}
}
#ifdef __GNUC__
inline
#endif
static void
IRQ_HSCX(struct _dumb * dumb)
{
int i;
for(i=1;i <= dumb->numHSCX; i += 2) {
#ifdef WIDE
Byte isr = ByteInHSCX(dumb,i,GISR);
if(isr & 0x0C) {
Byte isr0 = ByteInHSCX(dumb,i,ISR0);
Byte isr1 = ByteInHSCX(dumb,i,ISR1);
IRQ_HSCX_(dumb,i, isr0,isr1);
}
if(isr & 0x03) {
Byte isr0 = ByteInHSCX(dumb,i+1,ISR0);
Byte isr1 = ByteInHSCX(dumb,i+1,ISR1);
IRQ_HSCX_(dumb,i+1, isr0,isr1);
}
#else
Byte Reason = ByteInHSCX(dumb,i+1,ISTA);
if (Reason & 0x06)
IRQ_HSCX_(dumb,i, ByteInHSCX(dumb,i,ISTA), Reason & 0x02);
if (Reason & 0xF9)
IRQ_HSCX_(dumb,i+1, Reason, Reason & 0x01);
#endif
}
}
static void
intr(int irq, void *dev, struct pt_regs *regs)
{
struct _dumb *dumb = dev;
DEBUG(info)printf(" Pi%d ",dumb->polled);
if(!dumb->polled++) {
IRQ_HSCX(dumb);
IRQ_ISAC(dumb);
PostIRQ(dumb);
toggle_off(dumb);
dumb->polled--;
} else if(dumb->polled < 0)
dumb->polled--;
if(dumb->polled == 0) {
toggle_on(dumb);
}
DEBUG(info)printf(" -Pi%d ",dumb->polled);
}
void NAME(REALNAME,poll)(struct _dumb *dumb)
{
long s;
int j;
DEBUG(info)printf(" Pl%d ",dumb->polled);
s = splstr();
if(!dumb->polled++) {
splx(s);
IRQ_HSCX(dumb);
IRQ_ISAC(dumb);
if (dumb->chan[0].q_out.nblocks != 0)
ISAC_kick(dumb);
for(j=1;j <= dumb->numHSCX; j++) {
if (dumb->chan[j].q_out.nblocks != 0)
HSCX_kick(dumb,j);
}
splstr();
while(--dumb->polled) {
splx(s);
IRQ_HSCX(dumb);
IRQ_ISAC(dumb);
splstr();
}
toggle_off(dumb);
toggle_on(dumb);
} else
dumb->polled--;
splx(s);
DEBUG(info)printf(" -Pl%d ",dumb->polled);
}
#ifdef linux
static void dumbtimer(struct _dumb *dumb)
{
NAME(REALNAME,poll)(dumb);
#if 0
if(dumb->countme++ < 10) {
printf(" -(%d):%02x %02x %02x- ",dumb->info.irq,ByteInISAC(dumb,STAR),ByteInISAC(dumb,ISTA),ByteInISAC(dumb,CIR0));
}
#endif
#ifdef NEW_TIMEOUT
dumb->timer =
#endif
timeout((void *)dumbtimer,dumb,(dumb->info.irq == 0) ? HZ/DUMBTIME+1 : HZ/2);
}
#endif
int NAME(REALNAME,init)(struct cardinfo *inf)
{
int err;
struct _dumb *dumb;
dumb = kmalloc(sizeof(*dumb),GFP_KERNEL);
if(dumb == NULL) {
printf("???: No Memory\n");
return -ENOMEM;
}
bzero(dumb,sizeof(*dumb));
dumb->numHSCX = 1;
dumb->info = *inf;
dumb->infoptr = inf;
dumb->card.ctl = dumb;
dumb->card.modes = 0;
dumb->card.ch_mode = mode;
dumb->card.ch_prot = prot;
dumb->card.send = data;
dumb->card.flush = flush;
dumb->card.cansend = candata;
dumb->card.poll = NULL;
dumb->polled = -99;
printf("%sISDN: " STRING(REALNAME) " at mem 0x%lx io 0x%x irq %d: ",KERN_DEBUG, dumb->info.memaddr,dumb->info.ioaddr,dumb->info.irq);
if((err = Init(dumb)) < 0) {
printf("Card not initializable.\n");
kfree(dumb);
return err;
}
dumb->card.nr_chans = dumb->numHSCX;
InitHSCX(dumb);
InitISAC(dumb);
InitHSCX(dumb);
if((err = ISACpresent(dumb)) < 0) {
printf("Card not responding.\n");
kfree(dumb);
return err;
}
#ifdef linux
if((dumb->info.irq != 0) && request_irq(dumb->info.irq,intr,SA_SAMPLE_RANDOM|SA_INTERRUPT,STRING(REALNAME),dumb)) {
printf("IRQ not available.\n");
kfree(dumb);
return -EEXIST;
}
#endif
NAME(REALNAME,poll)(dumb);
if((err = isdn2_register(&dumb->card, dumb->info.ID)) != 0) {
printf("not installed (ISDN_2), err %d\n",err);
kfree(dumb);
return err;
}
dumb->polled = 0;
printf("installed at ");
if(dumb->info.memaddr != 0)
printf("mem 0x%lx ",dumb->info.memaddr);
if(dumb->info.ioaddr != 0)
printf("io 0x%x ",dumb->info.ioaddr);
if(dumb->info.irq != 0)
printf("irq %d.\n",dumb->info.irq);
else
printf("polled.\n");
dumb->next = dumblist;
dumblist = dumb;
#ifdef linux
dumbtimer(dumb);
#endif
MORE_USE;
return 0;
}
void
NAME(REALNAME,exit)(struct cardinfo *inf)
{
int j;
unsigned long ms = SetSPL(inf->ipl);
struct _dumb *dumb = NULL;
struct _dumb **ndumb = &dumblist;
while(*ndumb != NULL) {
if((*ndumb)->infoptr == inf) {
dumb = *ndumb;
*ndumb = dumb->next;
break;
}
ndumb = &((*ndumb)->next);
}
if(dumb == NULL) {
printf("%s??? No entry\n",KERN_DEBUG);
return;
}
#ifdef NEW_TIMEOUT
untimeout(dumb->timer);
#else
untimeout(dumbtimer,dumb);
#endif
ByteOutISAC(dumb,MASK,0xFF);
for(j=1; j<=dumb->numHSCX;j++) {
#ifdef WIDE
ByteOutHSCX(dumb,j,IMR0,0xFF);
ByteOutHSCX(dumb,j,IMR1,0xFF);
#else
ByteOutHSCX(dumb,j,MASK,0xFF);
#endif
}
if(dumb->info.irq > 0)
free_irq(dumb->info.irq,dumb);
isdn2_unregister(&dumb->card);
splx(ms);
kfree(dumb);
LESS_USE;
}
#ifdef MODULE
static int do_init_module(void)
{
return 0;
}
static int do_exit_module(void)
{
return 0;
}
#endif