1898 lines
52 KiB
C
1898 lines
52 KiB
C
/* $Id$
|
|
*
|
|
* card.c low level stuff for the Teles S0 isdn card
|
|
*
|
|
* Author Jan den Ouden
|
|
*
|
|
* Beat Doebeli log all D channel traffic
|
|
*
|
|
* $Log$
|
|
* Revision 1.15 1996/09/29 19:41:56 fritz
|
|
* Bugfix: ignore unknown frames.
|
|
*
|
|
* Revision 1.14 1996/09/23 01:53:49 fritz
|
|
* Bugfix: discard unknown frames (non-EDSS1 and non-1TR6).
|
|
*
|
|
* Revision 1.13 1996/07/18 11:21:24 jdenoud
|
|
* Use small buffers for incoming audio data
|
|
*
|
|
* Revision 1.12 1996/06/24 17:16:52 fritz
|
|
* Added check for misconfigured membase.
|
|
*
|
|
* Revision 1.11 1996/06/14 03:30:37 fritz
|
|
* Added recovery from EXIR 40 interrupt.
|
|
* Some cleanup.
|
|
*
|
|
* Revision 1.10 1996/06/11 14:57:20 hipp
|
|
* minor changes to ensure, that SKBs are sent in the right order
|
|
*
|
|
* Revision 1.9 1996/06/06 14:42:09 fritz
|
|
* Bugfix: forgot hsp-> in last change.
|
|
*
|
|
* Revision 1.7 1996/05/31 01:02:21 fritz
|
|
* Cosmetic changes.
|
|
*
|
|
* Revision 1.6 1996/05/26 14:58:10 fritz
|
|
* Bugfix: Did not show port correctly, when no card found.
|
|
*
|
|
* Revision 1.5 1996/05/17 03:45:02 fritz
|
|
* Made error messages more clearly.
|
|
* Bugfix: Only 31 bytes of 32-byte audio frames
|
|
* have been transfered to upper layers.
|
|
*
|
|
* Revision 1.4 1996/05/06 10:17:57 fritz
|
|
* Added voice-send stuff
|
|
* (Not reporting EXIR when in voice-mode, since it's normal).
|
|
*
|
|
* Revision 1.3 1996/04/30 22:02:40 isdn4dev
|
|
* Bugfixes for 16.3
|
|
* -improved IO allocation
|
|
* -fix second B channel problem
|
|
* -correct ph_command patch
|
|
*
|
|
* Revision 1.2 1996/04/30 10:00:59 fritz
|
|
* Bugfix: Added ph_command(8) for 16.3.
|
|
* Bugfix: Ports did not get registered correctly
|
|
* when using a 16.3.
|
|
* Started voice support.
|
|
* Some experimental changes of waitforXFW().
|
|
*
|
|
* Revision 1.1 1996/04/13 10:22:42 fritz
|
|
* Initial revision
|
|
*
|
|
*
|
|
*/
|
|
|
|
#define __NO_VERSION__
|
|
#include "teles.h"
|
|
#include "proto.h"
|
|
|
|
#define INCLUDE_INLINE_FUNCS
|
|
#include <linux/tqueue.h>
|
|
#include <linux/interrupt.h>
|
|
|
|
#undef DCHAN_VERBOSE
|
|
|
|
extern void tei_handler(struct PStack *st, byte pr,
|
|
struct BufHeader *ibh);
|
|
extern struct IsdnCard cards[];
|
|
extern int nrcards;
|
|
|
|
#define byteout(addr,val) outb_p(val,addr)
|
|
#define bytein(addr) inb_p(addr)
|
|
|
|
static inline byte
|
|
readisac_0(byte * cardm, byte offset)
|
|
{
|
|
return readb(cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
|
|
}
|
|
|
|
static inline byte
|
|
readisac_3(int iobase, byte offset)
|
|
{
|
|
return (bytein(iobase - 0x420 + offset));
|
|
}
|
|
|
|
#define READISAC(mbase,ibase,ofs) \
|
|
((mbase)?readisac_0(mbase,ofs):readisac_3(ibase,ofs))
|
|
|
|
static inline void
|
|
writeisac_0(byte * cardm, byte offset, byte value)
|
|
{
|
|
writeb(value, cardm + 0x100 + ((offset & 1) ? 0x1ff : 0) + offset);
|
|
}
|
|
|
|
static inline void
|
|
writeisac_3(int iobase, byte offset, byte value)
|
|
{
|
|
byteout(iobase - 0x420 + offset, value);
|
|
}
|
|
|
|
#define WRITEISAC(mbase,ibase,ofs,val) \
|
|
((mbase)?writeisac_0(mbase,ofs,val):writeisac_3(ibase,ofs,val))
|
|
|
|
static inline void
|
|
readisac_s(int iobase, byte offset, byte * dest, int count)
|
|
{
|
|
insb(iobase - 0x420 + offset, dest, count);
|
|
}
|
|
|
|
static inline void
|
|
writeisac_s(int iobase, byte offset, byte * src, int count)
|
|
{
|
|
outsb(iobase - 0x420 + offset, src, count);
|
|
}
|
|
|
|
static inline byte
|
|
readhscx_0(byte * base, byte hscx, byte offset)
|
|
{
|
|
return readb(base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
|
|
((hscx & 1) ? 0x40 : 0) + offset);
|
|
}
|
|
|
|
static inline byte
|
|
readhscx_3(int iobase, byte hscx, byte offset)
|
|
{
|
|
return (bytein(iobase - (hscx ? 0x820 : 0xc20) + offset));
|
|
}
|
|
|
|
#define READHSCX(mbase,ibase,hscx,ofs) \
|
|
((mbase)?readhscx_0(mbase,hscx,ofs):readhscx_3(ibase,hscx,ofs))
|
|
|
|
static inline void
|
|
writehscx_0(byte * base, byte hscx, byte offset, byte data)
|
|
{
|
|
writeb(data, base + 0x180 + ((offset & 1) ? 0x1FF : 0) +
|
|
((hscx & 1) ? 0x40 : 0) + offset);
|
|
}
|
|
|
|
static inline void
|
|
writehscx_3(int iobase, byte hscx, byte offset, byte data)
|
|
{
|
|
byteout(iobase - (hscx ? 0x820 : 0xc20) + offset, data);
|
|
}
|
|
|
|
static inline void
|
|
readhscx_s(int iobase, byte hscx, byte offset, byte * dest, int count)
|
|
{
|
|
insb(iobase - (hscx ? 0x820 : 0xc20) + offset, dest, count);
|
|
}
|
|
|
|
static inline void
|
|
writehscx_s(int iobase, byte hscx, byte offset, byte * src, int count)
|
|
{
|
|
outsb(iobase - (hscx ? 0x820 : 0xc20) + offset, src, count);
|
|
}
|
|
|
|
#define ISAC_MASK 0x20
|
|
#define ISAC_ISTA 0x20
|
|
#define ISAC_STAR 0x21
|
|
#define ISAC_CMDR 0x21
|
|
#define ISAC_EXIR 0x24
|
|
|
|
#define ISAC_RBCH 0x2a
|
|
|
|
#define ISAC_ADF2 0x39
|
|
#define ISAC_SPCR 0x30
|
|
#define ISAC_ADF1 0x38
|
|
#define ISAC_CIX0 0x31
|
|
#define ISAC_STCR 0x37
|
|
#define ISAC_MODE 0x22
|
|
#define ISAC_RSTA 0x27
|
|
#define ISAC_RBCL 0x25
|
|
#define ISAC_TIMR 0x23
|
|
#define ISAC_SQXR 0x3b
|
|
|
|
#define HSCX_ISTA 0x20
|
|
#define HSCX_CCR1 0x2f
|
|
#define HSCX_CCR2 0x2c
|
|
#define HSCX_TSAR 0x31
|
|
#define HSCX_TSAX 0x30
|
|
#define HSCX_XCCR 0x32
|
|
#define HSCX_RCCR 0x33
|
|
#define HSCX_MODE 0x22
|
|
#define HSCX_CMDR 0x21
|
|
#define HSCX_EXIR 0x24
|
|
#define HSCX_XAD1 0x24
|
|
#define HSCX_XAD2 0x25
|
|
#define HSCX_RAH2 0x27
|
|
#define HSCX_RSTA 0x27
|
|
#define HSCX_TIMR 0x23
|
|
#define HSCX_STAR 0x21
|
|
#define HSCX_RBCL 0x25
|
|
#define HSCX_XBCH 0x2d
|
|
#define HSCX_VSTR 0x2e
|
|
#define HSCX_RLCR 0x2e
|
|
#define HSCX_MASK 0x20
|
|
|
|
static inline void
|
|
waitforCEC_0(byte * base, byte hscx)
|
|
{
|
|
long to = 10;
|
|
|
|
while ((readhscx_0(base, hscx, HSCX_STAR) & 0x04) && to) {
|
|
udelay(5);
|
|
to--;
|
|
}
|
|
if (!to)
|
|
printk(KERN_WARNING "waitforCEC timeout\n");
|
|
}
|
|
|
|
static inline void
|
|
waitforCEC_3(int iobase, byte hscx)
|
|
{
|
|
long to = 10;
|
|
|
|
while ((readhscx_3(iobase, hscx, HSCX_STAR) & 0x04) && to) {
|
|
udelay(5);
|
|
to--;
|
|
}
|
|
if (!to)
|
|
printk(KERN_WARNING "waitforCEC timeout\n");
|
|
}
|
|
|
|
static inline void
|
|
waitforXFW_0(byte * base, byte hscx)
|
|
{
|
|
long to = 20;
|
|
|
|
while ((!(readhscx_0(base, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
|
|
udelay(5);
|
|
to--;
|
|
}
|
|
if (!to)
|
|
printk(KERN_WARNING "waitforXFW timeout\n");
|
|
}
|
|
|
|
static inline void
|
|
waitforXFW_3(int iobase, byte hscx)
|
|
{
|
|
long to = 20;
|
|
|
|
while ((!(readhscx_3(iobase, hscx, HSCX_STAR) & 0x44)==0x40) && to) {
|
|
udelay(5);
|
|
to--;
|
|
}
|
|
if (!to)
|
|
printk(KERN_WARNING "waitforXFW timeout\n");
|
|
}
|
|
|
|
static inline void
|
|
writehscxCMDR_0(byte * base, byte hscx, byte data)
|
|
{
|
|
long flags;
|
|
|
|
save_flags(flags);
|
|
cli();
|
|
waitforCEC_0(base, hscx);
|
|
writehscx_0(base, hscx, HSCX_CMDR, data);
|
|
restore_flags(flags);
|
|
}
|
|
|
|
static inline void
|
|
writehscxCMDR_3(int iobase, byte hscx, byte data)
|
|
{
|
|
long flags;
|
|
|
|
save_flags(flags);
|
|
cli();
|
|
waitforCEC_3(iobase, hscx);
|
|
writehscx_3(iobase, hscx, HSCX_CMDR, data);
|
|
restore_flags(flags);
|
|
}
|
|
|
|
#define WRITEHSCX_CMDR(mbase,ibase,hscx,data) \
|
|
((mbase)?writehscxCMDR_0(mbase,hscx,data):writehscxCMDR_3(ibase,hscx,data))
|
|
|
|
/*
|
|
* fast interrupt here
|
|
*/
|
|
|
|
#define ISAC_RCVBUFREADY 0
|
|
#define ISAC_XMTBUFREADY 1
|
|
#define ISAC_PHCHANGE 2
|
|
|
|
#define HSCX_RCVBUFREADY 0
|
|
#define HSCX_XMTBUFREADY 1
|
|
|
|
void
|
|
teles_hscxreport(struct IsdnCardState *sp, int hscx)
|
|
{
|
|
printk(KERN_DEBUG "HSCX %d\n", hscx);
|
|
if (sp->membase) {
|
|
printk(KERN_DEBUG " ISTA %x\n", readhscx_0(sp->membase,
|
|
hscx, HSCX_ISTA));
|
|
printk(KERN_DEBUG " STAR %x\n", readhscx_0(sp->membase,
|
|
hscx, HSCX_STAR));
|
|
printk(KERN_DEBUG " EXIR %x\n", readhscx_0(sp->membase,
|
|
hscx, HSCX_EXIR));
|
|
} else {
|
|
printk(KERN_DEBUG " ISTA %x\n", readhscx_3(sp->iobase,
|
|
hscx, HSCX_ISTA));
|
|
printk(KERN_DEBUG " STAR %x\n", readhscx_3(sp->iobase,
|
|
hscx, HSCX_STAR));
|
|
printk(KERN_DEBUG " EXIR %x\n", readhscx_3(sp->iobase,
|
|
hscx, HSCX_EXIR));
|
|
}
|
|
}
|
|
|
|
void
|
|
teles_report(struct IsdnCardState *sp)
|
|
{
|
|
printk(KERN_DEBUG "ISAC\n");
|
|
if (sp->membase) {
|
|
printk(KERN_DEBUG " ISTA %x\n", readisac_0(sp->membase,
|
|
ISAC_ISTA));
|
|
printk(KERN_DEBUG " STAR %x\n", readisac_0(sp->membase,
|
|
ISAC_STAR));
|
|
printk(KERN_DEBUG " EXIR %x\n", readisac_0(sp->membase,
|
|
ISAC_EXIR));
|
|
} else {
|
|
printk(KERN_DEBUG " ISTA %x\n", readisac_3(sp->iobase,
|
|
ISAC_ISTA));
|
|
printk(KERN_DEBUG " STAR %x\n", readisac_3(sp->iobase,
|
|
ISAC_STAR));
|
|
printk(KERN_DEBUG " EXIR %x\n", readisac_3(sp->iobase,
|
|
ISAC_EXIR));
|
|
}
|
|
teles_hscxreport(sp, 0);
|
|
teles_hscxreport(sp, 1);
|
|
}
|
|
|
|
/*
|
|
* HSCX stuff goes here
|
|
*/
|
|
|
|
static 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);
|
|
}
|
|
|
|
static void
|
|
hscx_empty_fifo(struct HscxState *hsp, int count)
|
|
{
|
|
byte *ptr;
|
|
struct BufHeader *ibh = hsp->rcvibh;
|
|
|
|
if (hsp->sp->debug)
|
|
printk(KERN_DEBUG "hscx_empty_fifo\n");
|
|
|
|
if (hsp->rcvptr + count > BUFFER_SIZE(HSCX_RBUF_ORDER,
|
|
HSCX_RBUF_BPPS)) {
|
|
printk(KERN_WARNING
|
|
"hscx_empty_fifo: incoming packet too large\n");
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx, 0x80);
|
|
return;
|
|
}
|
|
ptr = DATAPTR(ibh);
|
|
ptr += hsp->rcvptr;
|
|
|
|
hsp->rcvptr += count;
|
|
if (hsp->membase) {
|
|
while (count--)
|
|
*ptr++ = readhscx_0(hsp->membase, hsp->hscx, 0x0);
|
|
writehscxCMDR_0(hsp->membase, hsp->hscx, 0x80);
|
|
} else {
|
|
readhscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
|
|
writehscxCMDR_3(hsp->iobase, hsp->hscx, 0x80);
|
|
}
|
|
}
|
|
|
|
static void
|
|
hscx_fill_fifo(struct HscxState *hsp)
|
|
{
|
|
struct BufHeader *ibh;
|
|
int more, count;
|
|
byte *ptr;
|
|
|
|
if (hsp->sp->debug)
|
|
printk(KERN_DEBUG "hscx_fill_fifo\n");
|
|
|
|
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;
|
|
|
|
#ifdef BCHAN_VERBOSE
|
|
{
|
|
int i;
|
|
printk(KERN_DEBUG "hscx_fill_fifo ");
|
|
for (i = 0; i < count; i++)
|
|
printk(" %2x", ptr[i]);
|
|
printk("\n");
|
|
}
|
|
#endif
|
|
if (hsp->membase) {
|
|
waitforXFW_0(hsp->membase, hsp->hscx);
|
|
while (count--)
|
|
writehscx_0(hsp->membase, hsp->hscx, 0x0, *ptr++);
|
|
writehscxCMDR_0(hsp->membase, hsp->hscx, more ? 0x8 : 0xa);
|
|
} else {
|
|
waitforXFW_3(hsp->iobase, hsp->hscx);
|
|
writehscx_s(hsp->iobase, hsp->hscx, 0x3e, ptr, count);
|
|
writehscxCMDR_3(hsp->iobase, hsp->hscx, more ? 0x8 : 0xa);
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
hscx_interrupt(struct IsdnCardState *sp, byte val, byte hscx)
|
|
{
|
|
byte r;
|
|
struct HscxState *hsp = sp->hs + hscx;
|
|
int count, err;
|
|
|
|
if (!hsp->init)
|
|
return;
|
|
|
|
if (val & 0x80) { /* RME */
|
|
|
|
r = READHSCX(hsp->membase, sp->iobase, hsp->hscx, HSCX_RSTA);
|
|
if ((r & 0xf0) != 0xa0) {
|
|
if (!r & 0x80)
|
|
printk(KERN_WARNING
|
|
"Teles: HSCX invalid frame\n");
|
|
if ((r & 0x40) && hsp->mode)
|
|
printk(KERN_WARNING "Teles: HSCX RDO mode=%d\n",hsp->mode);
|
|
if (!r & 0x20)
|
|
printk(KERN_WARNING "Teles: HSCX CRC error\n");
|
|
if (hsp->rcvibh)
|
|
BufPoolRelease(hsp->rcvibh);
|
|
hsp->rcvibh = NULL;
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase, hsp->hscx,
|
|
0x80);
|
|
goto afterRME;
|
|
}
|
|
if (!hsp->rcvibh)
|
|
if (BufPoolGet(&hsp->rcvibh, &hsp->rbufpool,
|
|
GFP_ATOMIC, (void *) 1, 1)) {
|
|
printk(KERN_WARNING
|
|
"HSCX RME out of buffers at %ld\n",
|
|
jiffies);
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
|
|
hsp->hscx, 0x80);
|
|
goto afterRME;
|
|
} else
|
|
hsp->rcvptr = 0;
|
|
|
|
count = READHSCX(hsp->membase, sp->iobase, 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) {
|
|
printk(KERN_WARNING
|
|
"HSCX RPF out of buffers at %ld\n",
|
|
jiffies);
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
|
|
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_sched_event(struct IsdnCardState *sp, int event)
|
|
{
|
|
sp->event |= 1 << event;
|
|
queue_task_irq_off(&sp->tqueue, &tq_immediate);
|
|
mark_bh(IMMEDIATE_BH);
|
|
}
|
|
|
|
static void
|
|
empty_fifo(struct IsdnCardState *sp, int count)
|
|
{
|
|
byte *ptr;
|
|
struct BufHeader *ibh = sp->rcvibh;
|
|
|
|
if (sp->debug)
|
|
printk(KERN_DEBUG "empty_fifo\n");
|
|
|
|
if (sp->rcvptr >= 3072) {
|
|
printk(KERN_WARNING "empty_fifo rcvptr %d\n", sp->rcvptr);
|
|
return;
|
|
}
|
|
ptr = DATAPTR(ibh);
|
|
ptr += sp->rcvptr;
|
|
sp->rcvptr += count;
|
|
|
|
if (sp->membase) {
|
|
#ifdef DCHAN_VERBOSE
|
|
printk(KERN_DEBUG "empty_fifo ");
|
|
while (count--) {
|
|
*ptr = readisac_0(sp->membase, 0x0);
|
|
printk("%2x ", *ptr);
|
|
ptr++;
|
|
}
|
|
printk("\n");
|
|
#else
|
|
while (count--)
|
|
*ptr++ = readisac_0(sp->membase, 0x0);
|
|
#endif
|
|
writeisac_0(sp->membase, ISAC_CMDR, 0x80);
|
|
} else {
|
|
#ifdef DCHAN_VERBOSE
|
|
int i;
|
|
printk(KERN_DEBUG "empty_fifo ");
|
|
readisac_s(sp->iobase, 0x3e, ptr, count);
|
|
for (i = 0; i < count; i++)
|
|
printk("%2x ", ptr[i]);
|
|
printk("\n");
|
|
#else
|
|
readisac_s(sp->iobase, 0x3e, ptr, count);
|
|
#endif
|
|
writeisac_3(sp->iobase, ISAC_CMDR, 0x80);
|
|
}
|
|
}
|
|
|
|
static void
|
|
fill_fifo(struct IsdnCardState *sp)
|
|
{
|
|
struct BufHeader *ibh;
|
|
int count, more;
|
|
byte *ptr;
|
|
|
|
if (sp->debug)
|
|
printk(KERN_DEBUG "fill_fifo\n");
|
|
|
|
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;
|
|
|
|
if (sp->membase) {
|
|
#ifdef DCHAN_VERBOSE
|
|
printk(KERN_DEBUG "fill_fifo ");
|
|
while (count--) {
|
|
writeisac_0(sp->membase, 0x0, *ptr);
|
|
printk("%2x ", *ptr);
|
|
ptr++;
|
|
}
|
|
printk("\n");
|
|
#else
|
|
while (count--)
|
|
writeisac_0(sp->membase, 0x0, *ptr++);
|
|
#endif
|
|
writeisac_0(sp->membase, ISAC_CMDR, more ? 0x8 : 0xa);
|
|
} else {
|
|
#ifdef DCHAN_VERBOSE
|
|
int i;
|
|
writeisac_s(sp->iobase, 0x3e, ptr, count);
|
|
printk(KERN_DEBUG "fill_fifo ");
|
|
for (i = 0; i < count; i++)
|
|
printk("%2x ", ptr[i]);
|
|
printk("\n");
|
|
#else
|
|
writeisac_s(sp->iobase, 0x3e, ptr, count);
|
|
#endif
|
|
writeisac_3(sp->iobase, ISAC_CMDR, more ? 0x8 : 0xa);
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
}
|
|
|
|
static void
|
|
ph_command(struct IsdnCardState *sp, unsigned int command)
|
|
{
|
|
printk(KERN_DEBUG "ph_command %d\n", command);
|
|
WRITEISAC(sp->membase, sp->iobase, ISAC_CIX0, (command << 2) | 3);
|
|
}
|
|
|
|
static void
|
|
isac_new_ph(struct IsdnCardState *sp)
|
|
{
|
|
int enq;
|
|
|
|
enq = act_wanted(sp);
|
|
|
|
switch (sp->ph_state) {
|
|
case (0):
|
|
case (6):
|
|
if (enq)
|
|
ph_command(sp, 0);
|
|
else
|
|
ph_command(sp, 15);
|
|
break;
|
|
case (7):
|
|
if (enq)
|
|
ph_command(sp, 9);
|
|
break;
|
|
case (12):
|
|
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)
|
|
fill_fifo(sp);
|
|
break;
|
|
case (13):
|
|
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)
|
|
fill_fifo(sp);
|
|
break;
|
|
case (4):
|
|
case (8):
|
|
break;
|
|
default:
|
|
sp->ph_active = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
teles_interrupt(int intno, void *dev_id, struct pt_regs *regs)
|
|
{
|
|
byte val, r, exval;
|
|
struct IsdnCardState *sp;
|
|
unsigned int count;
|
|
struct HscxState *hsp;
|
|
|
|
sp = (struct IsdnCardState *) irq2dev_map[intno];
|
|
|
|
if (!sp) {
|
|
printk(KERN_WARNING "Teles: Spurious interrupt!\n");
|
|
return;
|
|
}
|
|
val = READHSCX(sp->membase, sp->iobase, 1, HSCX_ISTA);
|
|
|
|
if (val & 0x01) {
|
|
hsp = sp->hs + 1;
|
|
exval = READHSCX(sp->membase, sp->iobase, 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;
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
|
|
hsp->hscx, 0x01);
|
|
printk(KERN_DEBUG "HSCX B EXIR %x\n", exval);
|
|
}
|
|
} else
|
|
printk(KERN_WARNING "HSCX B EXIR %x\n", exval);
|
|
}
|
|
if (val & 0xf8) {
|
|
if (sp->debug)
|
|
printk(KERN_DEBUG "HSCX B interrupt %x\n", val);
|
|
hscx_interrupt(sp, val, 1);
|
|
}
|
|
if (val & 0x02) {
|
|
hsp = sp->hs;
|
|
exval = READHSCX(sp->membase, sp->iobase, 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;
|
|
WRITEHSCX_CMDR(hsp->membase, hsp->iobase,
|
|
hsp->hscx, 0x01);
|
|
printk(KERN_DEBUG "HSCX A EXIR %x\n", exval);
|
|
}
|
|
} else
|
|
printk(KERN_WARNING "HSCX A EXIR %x\n", exval);
|
|
}
|
|
if (val & 0x04) {
|
|
val = READHSCX(sp->membase, sp->iobase, 0, HSCX_ISTA);
|
|
if (sp->debug)
|
|
printk(KERN_DEBUG "HSCX A interrupt %x\n",
|
|
val);
|
|
hscx_interrupt(sp, val, 0);
|
|
}
|
|
|
|
val = READISAC(sp->membase, sp->iobase, ISAC_ISTA);
|
|
|
|
if (sp->debug)
|
|
printk(KERN_DEBUG "ISAC interrupt %x\n", val);
|
|
|
|
if (val & 0x80) { /* RME */
|
|
|
|
r = READISAC(sp->membase, sp->iobase, ISAC_RSTA);
|
|
if ((r & 0x70) != 0x20) {
|
|
if (r & 0x40)
|
|
printk(KERN_WARNING "Teles: ISAC RDO\n");
|
|
if (!r & 0x20)
|
|
printk(KERN_WARNING "Teles: ISAC CRC error\n");
|
|
if (sp->rcvibh)
|
|
BufPoolRelease(sp->rcvibh);
|
|
sp->rcvibh = NULL;
|
|
WRITEISAC(sp->membase, sp->iobase, ISAC_CMDR, 0x80);
|
|
goto afterRME;
|
|
}
|
|
if (!sp->rcvibh)
|
|
if (BufPoolGet(&(sp->rcvibh), &(sp->rbufpool),
|
|
GFP_ATOMIC,
|
|
(void *) 1, 3)) {
|
|
printk(KERN_WARNING
|
|
"ISAC RME out of buffers!\n");
|
|
WRITEISAC(sp->membase, sp->iobase,
|
|
ISAC_CMDR, 0x80);
|
|
goto afterRME;
|
|
} else
|
|
sp->rcvptr = 0;
|
|
|
|
count = READISAC(sp->membase, sp->iobase, ISAC_RBCL) & 0x1f;
|
|
if (count == 0)
|
|
count = 32;
|
|
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)) {
|
|
printk(KERN_WARNING
|
|
"ISAC RME out of buffers!\n");
|
|
WRITEISAC(sp->membase, sp->iobase,
|
|
ISAC_CMDR, 0x80);
|
|
goto afterRPF;
|
|
} else
|
|
sp->rcvptr = 0;
|
|
empty_fifo(sp, 32);
|
|
}
|
|
afterRPF:
|
|
if (val & 0x20) {
|
|
}
|
|
if (val & 0x10) { /* XPR */
|
|
if (sp->xmtibh)
|
|
if (sp->xmtibh->datasize > sp->sendptr) {
|
|
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;
|
|
fill_fifo(sp);
|
|
} else
|
|
isac_sched_event(sp, ISAC_XMTBUFREADY);
|
|
}
|
|
afterXPR:
|
|
if (val & 0x04) { /* CISQ */
|
|
sp->ph_state = (READISAC(sp->membase, sp->iobase, ISAC_CIX0)
|
|
>> 2) & 0xf;
|
|
printk(KERN_DEBUG "l1state %d\n", sp->ph_state);
|
|
isac_new_ph(sp);
|
|
}
|
|
if (sp->membase) {
|
|
writeisac_0(sp->membase, ISAC_MASK, 0xFF);
|
|
writehscx_0(sp->membase, 0, HSCX_MASK, 0xFF);
|
|
writehscx_0(sp->membase, 1, HSCX_MASK, 0xFF);
|
|
writeisac_0(sp->membase, ISAC_MASK, 0x0);
|
|
writehscx_0(sp->membase, 0, HSCX_MASK, 0x0);
|
|
writehscx_0(sp->membase, 1, HSCX_MASK, 0x0);
|
|
} else {
|
|
writeisac_3(sp->iobase, ISAC_MASK, 0xFF);
|
|
writehscx_3(sp->iobase, 0, HSCX_MASK, 0xFF);
|
|
writehscx_3(sp->iobase, 1, HSCX_MASK, 0xFF);
|
|
writeisac_3(sp->iobase, ISAC_MASK, 0x0);
|
|
writehscx_3(sp->iobase, 0, HSCX_MASK, 0x0);
|
|
writehscx_3(sp->iobase, 1, HSCX_MASK, 0x0);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* soft interrupt
|
|
*/
|
|
|
|
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 && sp->dlogflag && (!(ptr[0] >> 2)))
|
|
dlogframe(sp, ptr + 3, ibh->datasize - 3,
|
|
"Q.931 frame network->user broadcast");
|
|
|
|
if (broadc) {
|
|
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 "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);
|
|
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
|
|
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))
|
|
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
|
|
*/
|
|
|
|
static void
|
|
restart_ph(struct IsdnCardState *sp)
|
|
{
|
|
switch (sp->ph_active) {
|
|
case (0):
|
|
if (sp->ph_state == 6)
|
|
ph_command(sp, 0);
|
|
else
|
|
ph_command(sp, 1);
|
|
sp->ph_active = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
initisac(byte * cardmem, int iobase)
|
|
{
|
|
if (cardmem) {
|
|
writeisac_0(cardmem, ISAC_MASK, 0xff);
|
|
writeisac_0(cardmem, ISAC_ADF2, 0x0);
|
|
writeisac_0(cardmem, ISAC_SPCR, 0xa);
|
|
writeisac_0(cardmem, ISAC_ADF1, 0x2);
|
|
writeisac_0(cardmem, ISAC_STCR, 0x70);
|
|
writeisac_0(cardmem, ISAC_MODE, 0xc9);
|
|
writeisac_0(cardmem, ISAC_CMDR, 0x41);
|
|
writeisac_0(cardmem, ISAC_CIX0, (1 << 2) | 3);
|
|
} else {
|
|
writeisac_3(iobase, ISAC_MASK, 0xff);
|
|
writeisac_3(iobase, ISAC_ADF2, 0x80);
|
|
writeisac_3(iobase, ISAC_SQXR, 0x2f);
|
|
writeisac_3(iobase, ISAC_SPCR, 0x00);
|
|
writeisac_3(iobase, ISAC_ADF1, 0x02);
|
|
writeisac_3(iobase, ISAC_STCR, 0x70);
|
|
writeisac_3(iobase, ISAC_MODE, 0xc9);
|
|
writeisac_3(iobase, ISAC_TIMR, 0x00);
|
|
writeisac_3(iobase, ISAC_ADF1, 0x00);
|
|
writeisac_3(iobase, ISAC_CMDR, 0x41);
|
|
writeisac_3(iobase, ISAC_CIX0, (1 << 2) | 3);
|
|
}
|
|
}
|
|
|
|
static int
|
|
checkcard(int cardnr)
|
|
{
|
|
int timout;
|
|
byte cfval, val;
|
|
struct IsdnCard *card = cards + cardnr;
|
|
|
|
if (card->membase)
|
|
if ((unsigned long)card->membase < 0x10000) {
|
|
(unsigned long)card->membase <<= 4;
|
|
printk(KERN_INFO
|
|
"Teles membase configured DOSish, assuming 0x%lx\n",
|
|
(unsigned long)card->membase);
|
|
}
|
|
if (!card->iobase) {
|
|
if (card->membase) {
|
|
printk(KERN_NOTICE
|
|
"Teles 8 assumed, mem: %lx irq: %d proto: %s\n",
|
|
(long) card->membase, card->interrupt,
|
|
(card->protocol == ISDN_PTYPE_1TR6) ?
|
|
"1TR6" : "EDSS1");
|
|
printk(KERN_INFO "HSCX version A:%x B:%x\n",
|
|
readhscx_0(card->membase, 0, HSCX_VSTR) & 0xf,
|
|
readhscx_0(card->membase, 1, HSCX_VSTR) & 0xf);
|
|
}
|
|
} else {
|
|
switch (card->iobase) {
|
|
case 0x180:
|
|
case 0x280:
|
|
case 0x380:
|
|
card->iobase |= 0xc00;
|
|
break;
|
|
}
|
|
if (card->membase) { /* 16.0 */
|
|
if (check_region(card->iobase, 8)) {
|
|
printk(KERN_WARNING
|
|
"teles: ports %x-%x already in use\n",
|
|
card->iobase,
|
|
card->iobase + 8 );
|
|
return -1;
|
|
}
|
|
} else { /* 16.3 */
|
|
if (check_region(card->iobase, 16)) {
|
|
printk(KERN_WARNING
|
|
"teles: 16.3 ports %x-%x already in use\n",
|
|
card->iobase,
|
|
card->iobase + 16 );
|
|
return -1;
|
|
}
|
|
if (check_region((card->iobase - 0xc00) , 32)) {
|
|
printk(KERN_WARNING
|
|
"teles: 16.3 ports %x-%x already in use\n",
|
|
card->iobase - 0xc00,
|
|
card->iobase - 0xc00 + 32);
|
|
return -1;
|
|
}
|
|
if (check_region((card->iobase - 0x800) , 32)) {
|
|
printk(KERN_WARNING
|
|
"teles: 16.3 ports %x-%x already in use\n",
|
|
card->iobase - 0x800,
|
|
card->iobase - 0x800 + 32);
|
|
return -1;
|
|
}
|
|
if (check_region((card->iobase - 0x400) , 32)) {
|
|
printk(KERN_WARNING
|
|
"teles: 16.3 ports %x-%x already in use\n",
|
|
card->iobase - 0x400,
|
|
card->iobase - 0x400 + 32);
|
|
return -1;
|
|
}
|
|
}
|
|
switch (card->interrupt) {
|
|
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 (card->membase) {
|
|
cfval |= (((unsigned int) card->membase >> 9) & 0xF0);
|
|
}
|
|
if (bytein(card->iobase + 0) != 0x51) {
|
|
printk(KERN_INFO "XXX Byte at %x is %x\n",
|
|
card->iobase + 0,
|
|
bytein(card->iobase + 0));
|
|
return -2;
|
|
}
|
|
if (bytein(card->iobase + 1) != 0x93) {
|
|
printk(KERN_INFO "XXX Byte at %x is %x\n",
|
|
card->iobase + 1,
|
|
bytein(card->iobase + 1));
|
|
return -2;
|
|
}
|
|
val = bytein(card->iobase + 2); /* 0x1e=without AB
|
|
* 0x1f=with AB
|
|
* 0x1c 16.3 ???
|
|
*/
|
|
if (val != 0x1c && val != 0x1e && val != 0x1f) {
|
|
printk(KERN_INFO "XXX Byte at %x is %x\n",
|
|
card->iobase + 2,
|
|
bytein(card->iobase + 2));
|
|
return -2;
|
|
}
|
|
if (card->membase) { /* 16.0 */
|
|
request_region(card->iobase, 8, "teles 16.0");
|
|
} else {
|
|
request_region(card->iobase, 16, "teles 16.3");
|
|
request_region(card->iobase - 0xC00, 32, "teles HSCX0");
|
|
request_region(card->iobase - 0x800, 32, "teles HSCX1");
|
|
request_region(card->iobase - 0x400, 32, "teles ISAC");
|
|
}
|
|
cli();
|
|
timout = jiffies + (HZ / 10) + 1;
|
|
byteout(card->iobase + 4, cfval);
|
|
sti();
|
|
while (jiffies <= timout);
|
|
|
|
cli();
|
|
timout = jiffies + (HZ / 10) + 1;
|
|
byteout(card->iobase + 4, cfval | 1);
|
|
sti();
|
|
while (jiffies <= timout);
|
|
|
|
if (card->membase)
|
|
printk(KERN_NOTICE
|
|
"Teles 16.0 found, io: %x mem: %lx irq: %d proto: %s\n",
|
|
card->iobase, (long) card->membase,
|
|
card->interrupt,
|
|
(card->protocol == ISDN_PTYPE_1TR6) ?
|
|
"1TR6" : "EDSS1");
|
|
else
|
|
printk(KERN_NOTICE
|
|
"Teles 16.3 found, io: %x irq: %d proto: %s\n",
|
|
card->iobase, card->interrupt,
|
|
(card->protocol == ISDN_PTYPE_1TR6) ?
|
|
"1TR6" : "EDSS1");
|
|
printk(KERN_INFO "HSCX version A:%x B:%x\n",
|
|
READHSCX(card->membase, card->iobase, 0,
|
|
HSCX_VSTR) & 0xf,
|
|
READHSCX(card->membase, card->iobase, 1,
|
|
HSCX_VSTR) & 0xf);
|
|
|
|
}
|
|
if (card->membase) {
|
|
cli();
|
|
timout = jiffies + (HZ / 5) + 1;
|
|
writeb(0, card->membase + 0x80);
|
|
sti();
|
|
while (jiffies <= timout);
|
|
|
|
cli();
|
|
writeb(1, card->membase + 0x80);
|
|
timout = jiffies + (HZ / 5) + 1;
|
|
sti();
|
|
while (jiffies <= timout);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
void
|
|
modehscx(struct HscxState *hs, int mode,
|
|
int ichan)
|
|
{
|
|
struct IsdnCardState *sp = hs->sp;
|
|
int hscx = hs->hscx;
|
|
|
|
printk(KERN_DEBUG "modehscx hscx %d mode %d ichan %d\n",
|
|
hscx, mode, ichan);
|
|
|
|
hs->mode = mode;
|
|
if (sp->membase) {
|
|
/* What's that ??? KKeil */
|
|
if (hscx == 0)
|
|
ichan = 1 - ichan; /* raar maar waar... */
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR1, 0x85);
|
|
writehscx_0(sp->membase, hscx, HSCX_XAD1, 0xFF);
|
|
writehscx_0(sp->membase, hscx, HSCX_XAD2, 0xFF);
|
|
writehscx_0(sp->membase, hscx, HSCX_RAH2, 0xFF);
|
|
writehscx_0(sp->membase, hscx, HSCX_XBCH, 0x0);
|
|
|
|
switch (mode) {
|
|
case (0):
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAX, 0xff);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAR, 0xff);
|
|
writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_MODE, 0x84);
|
|
break;
|
|
case (1):
|
|
if (ichan == 0) {
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
|
|
writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
|
|
} else {
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
|
|
writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
|
|
}
|
|
writehscx_0(sp->membase, hscx, HSCX_MODE, 0xe4);
|
|
writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
|
|
break;
|
|
case (2):
|
|
if (ichan == 0) {
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x7);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x7);
|
|
writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
|
|
} else {
|
|
writehscx_0(sp->membase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAX, 0x3);
|
|
writehscx_0(sp->membase, hscx, HSCX_TSAR, 0x3);
|
|
writehscx_0(sp->membase, hscx, HSCX_XCCR, 7);
|
|
writehscx_0(sp->membase, hscx, HSCX_RCCR, 7);
|
|
}
|
|
writehscx_0(sp->membase, hscx, HSCX_MODE, 0x8c);
|
|
writehscx_0(sp->membase, hscx, HSCX_CMDR, 0x41);
|
|
break;
|
|
}
|
|
writehscx_0(sp->membase, hscx, HSCX_ISTA, 0x00);
|
|
} else {
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR1, 0x85);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XAD1, 0xFF);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XAD2, 0xFF);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RAH2, 0xFF);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XBCH, 0x00);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RLCR, 0x00);
|
|
|
|
switch (mode) {
|
|
case (0):
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0xff);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0xff);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x84);
|
|
break;
|
|
case (1):
|
|
if (ichan == 0) {
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
|
|
} else {
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
|
|
}
|
|
writehscx_3(sp->iobase, hscx, HSCX_MODE, 0xe4);
|
|
writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
|
|
break;
|
|
case (2):
|
|
if (ichan == 0) {
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x2f);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x2f);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
|
|
} else {
|
|
writehscx_3(sp->iobase, hscx, HSCX_CCR2, 0x30);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAX, 0x3);
|
|
writehscx_3(sp->iobase, hscx, HSCX_TSAR, 0x3);
|
|
writehscx_3(sp->iobase, hscx, HSCX_XCCR, 7);
|
|
writehscx_3(sp->iobase, hscx, HSCX_RCCR, 7);
|
|
}
|
|
writehscx_3(sp->iobase, hscx, HSCX_MODE, 0x8c);
|
|
writehscx_3(sp->iobase, hscx, HSCX_CMDR, 0x41);
|
|
break;
|
|
}
|
|
writehscx_3(sp->iobase, hscx, HSCX_ISTA, 0x00);
|
|
}
|
|
}
|
|
|
|
void
|
|
teles_addlist(struct IsdnCardState *sp,
|
|
struct PStack *st)
|
|
{
|
|
st->next = sp->stlist;
|
|
sp->stlist = st;
|
|
}
|
|
|
|
void
|
|
teles_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
|
|
teles_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;
|
|
fill_fifo(sp);
|
|
}
|
|
break;
|
|
case (PH_DATA_PULLED):
|
|
if (sp->xmtibh) {
|
|
printk(KERN_DEBUG "teles_l2l1: this shouldn't happen\n");
|
|
break;
|
|
}
|
|
sp->xmtibh = ibh;
|
|
sp->sendptr = 0;
|
|
sp->releasebuf = 0;
|
|
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
|
|
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
|
|
teles_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
|
|
teles_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_teles(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->teistack->protocol;
|
|
|
|
setstack_tei(st);
|
|
|
|
st->l1.stlistp = &(sp->stlist);
|
|
st->l1.act_state = 0;
|
|
st->l2.l2l1 = teles_l2l1;
|
|
st->l2.l2l1discardq = teles_l2l1discardq;
|
|
st->ma.manl1 = teles_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->membase = sp->membase;
|
|
hsp->iobase = sp->iobase;
|
|
|
|
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
|
|
}
|
|
|
|
void
|
|
initcard(int cardnr)
|
|
{
|
|
struct IsdnCardState *sp;
|
|
struct IsdnCard *card = cards + cardnr;
|
|
|
|
sp = (struct IsdnCardState *)
|
|
Smalloc(sizeof(struct IsdnCardState), GFP_KERNEL,
|
|
"struct IsdnCardState");
|
|
|
|
sp->membase = card->membase;
|
|
sp->iobase = card->iobase;
|
|
sp->cardnr = cardnr;
|
|
|
|
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->dlogspace = Smalloc(4096, GFP_KERNEL, "dlogspace");
|
|
|
|
initisac(card->membase, card->iobase);
|
|
|
|
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 = 0;
|
|
|
|
sp->releasebuf = 0;
|
|
#ifdef DEBUG_MAGIC
|
|
sp->magic = 301271;
|
|
#endif
|
|
|
|
cards[sp->cardnr].sp = sp;
|
|
|
|
init_hscxstate(sp, 0);
|
|
init_hscxstate(sp, 1);
|
|
|
|
modehscx(sp->hs, 0, 0);
|
|
modehscx(sp->hs + 1, 0, 0);
|
|
|
|
WRITEISAC(sp->membase, sp->iobase, ISAC_MASK, 0x0);
|
|
}
|
|
|
|
static int
|
|
get_irq(int cardnr)
|
|
{
|
|
struct IsdnCard *card = cards + cardnr;
|
|
long flags;
|
|
|
|
save_flags(flags);
|
|
cli();
|
|
if (request_irq(card->interrupt, &teles_interrupt,
|
|
SA_INTERRUPT, "teles", NULL)) {
|
|
printk(KERN_WARNING "Teles couldn't get interrupt %d\n",
|
|
card->interrupt);
|
|
restore_flags(flags);
|
|
return (!0);
|
|
}
|
|
irq2dev_map[card->interrupt] = (void *) card->sp;
|
|
restore_flags(flags);
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
release_irq(int cardnr)
|
|
{
|
|
struct IsdnCard *card = cards + cardnr;
|
|
|
|
irq2dev_map[card->interrupt] = NULL;
|
|
free_irq(card->interrupt, NULL);
|
|
}
|
|
|
|
void
|
|
close_hscxstate(struct HscxState *hs)
|
|
{
|
|
modehscx(hs, 0, 0);
|
|
hs->inuse = 0;
|
|
|
|
if (hs->init) {
|
|
BufPoolFree(&hs->smallpool);
|
|
BufPoolFree(&hs->rbufpool);
|
|
BufPoolFree(&hs->sbufpool);
|
|
}
|
|
hs->init = 0;
|
|
}
|
|
|
|
void
|
|
closecard(int cardnr)
|
|
{
|
|
struct IsdnCardState *sp = cards[cardnr].sp;
|
|
|
|
cards[cardnr].sp = NULL;
|
|
|
|
Sfree(sp->dlogspace);
|
|
|
|
BufPoolFree(&sp->smallpool);
|
|
BufPoolFree(&sp->rbufpool);
|
|
BufPoolFree(&sp->sbufpool);
|
|
|
|
close_hscxstate(sp->hs + 1);
|
|
close_hscxstate(sp->hs);
|
|
|
|
if (cards[cardnr].iobase)
|
|
if (cards[cardnr].membase) { /* 16.0 */
|
|
release_region(cards[cardnr].iobase, 8);
|
|
} else {
|
|
release_region(cards[cardnr].iobase, 16);
|
|
release_region(cards[cardnr].iobase - 0xC00, 32);
|
|
release_region(cards[cardnr].iobase - 0x800, 32);
|
|
release_region(cards[cardnr].iobase - 0x400, 32);
|
|
}
|
|
|
|
Sfree((void *) sp);
|
|
}
|
|
|
|
void
|
|
teles_shiftcards(int idx)
|
|
{
|
|
int i;
|
|
|
|
for (i = idx; i < 15; i++)
|
|
memcpy(&cards[i],&cards[i+1],sizeof(cards[i]));
|
|
}
|
|
|
|
int
|
|
teles_inithardware(void)
|
|
{
|
|
int foundcards = 0;
|
|
int i = 0;
|
|
|
|
while (i < nrcards) {
|
|
if (!cards[i].protocol)
|
|
break;
|
|
switch (checkcard(i)) {
|
|
case (0):
|
|
initcard(i);
|
|
if (get_irq(i)) {
|
|
closecard(i);
|
|
teles_shiftcards(i);
|
|
} else {
|
|
foundcards++;
|
|
i++;
|
|
}
|
|
break;
|
|
case (-1):
|
|
teles_shiftcards(i);
|
|
break;
|
|
case (-2):
|
|
release_region(cards[i].iobase, 8);
|
|
printk(KERN_WARNING "NO Teles card found at 0x%x!\n", cards[i].iobase);
|
|
teles_shiftcards(i);
|
|
break;
|
|
}
|
|
}
|
|
return foundcards;
|
|
}
|
|
|
|
void
|
|
teles_closehardware(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nrcards; i++)
|
|
if (cards[i].sp) {
|
|
release_irq(i);
|
|
closecard(i);
|
|
}
|
|
}
|
|
|
|
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;
|
|
hscx_fill_fifo(hsp);
|
|
}
|
|
break;
|
|
case (PH_DATA_PULLED):
|
|
if (hsp->xmtibh) {
|
|
printk(KERN_DEBUG "hscx_l2l1: this shouldn't happen\n");
|
|
break;
|
|
}
|
|
hsp->xmtibh = ibh;
|
|
hsp->sendptr = 0;
|
|
hsp->releasebuf = 0;
|
|
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;
|
|
modehscx(hsp, st->l1.hscxmode, st->l1.hscxchannel);
|
|
st->l1.l1man(st, PH_ACTIVATE, NULL);
|
|
break;
|
|
case (PH_DEACTIVATE):
|
|
if (!hsp->xmtibh)
|
|
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
|
|
teles_reportcard(int cardnr)
|
|
{
|
|
printk(KERN_DEBUG "teles_reportcard\n");
|
|
}
|