871 lines
20 KiB
C
871 lines
20 KiB
C
|
|
/*
|
|
*
|
|
* Copyright (C) Eicon Technology Corporation, 2000.
|
|
*
|
|
* Eicon File Revision : 1.8
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
* See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
* Core driver for Diva Server cards
|
|
* Implements the IDI interface
|
|
*/
|
|
|
|
#include "idi.h"
|
|
#include "adapter.h"
|
|
#include "pc.h"
|
|
#include "pr_pc.h"
|
|
#include "sys.h"
|
|
#include "uxio.h"
|
|
|
|
/* IDI request functions */
|
|
|
|
static void request(card_t *card, ENTITY *e);
|
|
|
|
static void req_0(ENTITY *e) { request(&DivasCards[ 0], e); }
|
|
static void req_1(ENTITY *e) { request(&DivasCards[ 1], e); }
|
|
static void req_2(ENTITY *e) { request(&DivasCards[ 2], e); }
|
|
static void req_3(ENTITY *e) { request(&DivasCards[ 3], e); }
|
|
static void req_4(ENTITY *e) { request(&DivasCards[ 4], e); }
|
|
static void req_5(ENTITY *e) { request(&DivasCards[ 5], e); }
|
|
static void req_6(ENTITY *e) { request(&DivasCards[ 6], e); }
|
|
static void req_7(ENTITY *e) { request(&DivasCards[ 7], e); }
|
|
static void req_8(ENTITY *e) { request(&DivasCards[ 8], e); }
|
|
static void req_9(ENTITY *e) { request(&DivasCards[ 9], e); }
|
|
static void req_10(ENTITY *e) { request(&DivasCards[10], e); }
|
|
static void req_11(ENTITY *e) { request(&DivasCards[11], e); }
|
|
static void req_12(ENTITY *e) { request(&DivasCards[12], e); }
|
|
static void req_13(ENTITY *e) { request(&DivasCards[13], e); }
|
|
static void req_14(ENTITY *e) { request(&DivasCards[14], e); }
|
|
static void req_15(ENTITY *e) { request(&DivasCards[15], e); }
|
|
|
|
IDI_CALL DivasIdiRequest[16] =
|
|
{
|
|
&req_0, &req_1, &req_2, &req_3,
|
|
&req_4, &req_5, &req_6, &req_7,
|
|
&req_8, &req_9, &req_10, &req_11,
|
|
&req_12, &req_13, &req_14, &req_15
|
|
};
|
|
|
|
#define PR_RAM ((struct pr_ram *)0)
|
|
#define RAM ((struct dual *)0)
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* local function prototypes */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
static byte isdn_rc(ADAPTER *, byte, byte, byte, word);
|
|
static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
|
|
|
|
/*
|
|
* IDI related functions
|
|
*/
|
|
|
|
static
|
|
ENTITY *entity_ptr(ADAPTER *a, byte e_no)
|
|
{
|
|
card_t *card;
|
|
|
|
card = a->io;
|
|
|
|
return card->e_tbl[e_no].e;
|
|
}
|
|
|
|
static
|
|
void CALLBACK(ADAPTER *a, ENTITY *e)
|
|
{
|
|
card_t *card = a->io;
|
|
|
|
if (card->log_types & DIVAS_LOG_IDI)
|
|
{
|
|
DivasLogIdi(card, e, FALSE);
|
|
}
|
|
|
|
(*e->callback)(e);
|
|
}
|
|
|
|
static
|
|
void *PTR_P(ADAPTER *a, ENTITY *e, void *P)
|
|
{
|
|
return(P);
|
|
}
|
|
|
|
static
|
|
void *PTR_R(ADAPTER *a, ENTITY *e)
|
|
{
|
|
return((void*)e->R);
|
|
}
|
|
|
|
static
|
|
void *PTR_X(ADAPTER *a, ENTITY *e)
|
|
{
|
|
return((void*)e->X);
|
|
}
|
|
|
|
static
|
|
void free_entity(ADAPTER *a, byte e_no)
|
|
{
|
|
card_t *card;
|
|
int ipl;
|
|
|
|
card = a->io;
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
card->e_tbl[e_no].e = NULL;
|
|
card->e_count--;
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
void assign_queue(ADAPTER * a, byte e_no, word ref)
|
|
{
|
|
card_t *card;
|
|
int ipl;
|
|
|
|
card = a->io;
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
card->e_tbl[e_no].assign_ref = ref;
|
|
card->e_tbl[e_no].next = card->assign;
|
|
card->assign = e_no;
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
byte get_assign(ADAPTER *a, word ref)
|
|
{
|
|
card_t *card;
|
|
byte e_no;
|
|
int ipl;
|
|
|
|
card = a->io;
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
e_no = (byte)card->assign;
|
|
while (e_no)
|
|
{
|
|
if (card->e_tbl[e_no].assign_ref == ref)
|
|
{
|
|
break;
|
|
}
|
|
e_no = card->e_tbl[e_no].next;
|
|
}
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
return e_no;
|
|
}
|
|
|
|
static
|
|
void req_queue(ADAPTER * a, byte e_no)
|
|
{
|
|
card_t *card;
|
|
int ipl;
|
|
|
|
card = a->io;
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
card->e_tbl[e_no].next = 0;
|
|
|
|
if (card->e_head)
|
|
{
|
|
card->e_tbl[card->e_tail].next = e_no;
|
|
card->e_tail = e_no;
|
|
}
|
|
else
|
|
{
|
|
card->e_head = e_no;
|
|
card->e_tail = e_no;
|
|
}
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
return;
|
|
}
|
|
|
|
static
|
|
byte look_req(ADAPTER * a)
|
|
{
|
|
card_t *card;
|
|
|
|
card = a->io;
|
|
|
|
return(card->e_head);
|
|
}
|
|
|
|
static
|
|
void next_req(ADAPTER * a)
|
|
{
|
|
card_t *card;
|
|
int ipl;
|
|
|
|
|
|
card = a->io;
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
card->e_head = card->e_tbl[card->e_head].next;
|
|
if (!card->e_head)
|
|
{
|
|
card->e_tail = 0;
|
|
}
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
* IDI request function for active cards
|
|
*/
|
|
static
|
|
void request(card_t *card, ENTITY *e)
|
|
{
|
|
word *special_req;
|
|
int i;
|
|
int ipl;
|
|
|
|
|
|
if (card->log_types & DIVAS_LOG_IDI)
|
|
{
|
|
DivasLogIdi(card, e, TRUE);
|
|
}
|
|
|
|
if (!e->Req)
|
|
{
|
|
special_req = (word *) e;
|
|
|
|
switch (*special_req)
|
|
{
|
|
case REQ_REMOVE:
|
|
return;
|
|
|
|
case REQ_NAME:
|
|
for (i=0; i < DIM(card->cfg.name); i++)
|
|
{
|
|
((struct get_name_s *) e)->name[i] = card->cfg.name[i];
|
|
}
|
|
return;
|
|
|
|
case REQ_SERIAL:
|
|
case REQ_XLOG:
|
|
DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG"));
|
|
return;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|
|
ipl = UxCardLock(card->hw);
|
|
|
|
if (!(e->Id & 0x1f))
|
|
{
|
|
DPRINTF(("IDI: ASSIGN req"));
|
|
|
|
for (i = 1; i < card->e_max; i++)
|
|
{
|
|
if (!card->e_tbl[i].e)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == card->e_max)
|
|
{
|
|
DPRINTF(("IDI: request all ids in use (IDI req ignored)"));
|
|
UxCardUnlock(card->hw, ipl);
|
|
e->Rc = OUT_OF_RESOURCES;
|
|
return;
|
|
}
|
|
|
|
card->e_tbl[i].e = e;
|
|
card->e_count++;
|
|
|
|
e->No = (byte) i;
|
|
e->More = 0;
|
|
e->RCurrent = 0xff;
|
|
}
|
|
else
|
|
{
|
|
i = e->No;
|
|
}
|
|
|
|
if (e->More & XBUSY)
|
|
{
|
|
DPRINTF(("IDI: request - entity is busy"));
|
|
UxCardUnlock(card->hw, ipl);
|
|
return;
|
|
}
|
|
|
|
e->More |= XBUSY;
|
|
e->More &= ~ XMOREF;
|
|
e->XCurrent = 0;
|
|
e->XOffset = 0;
|
|
|
|
card->e_tbl[i].next = 0;
|
|
|
|
if(card->e_head)
|
|
{
|
|
card->e_tbl[card->e_tail].next = i;
|
|
card->e_tail = i;
|
|
}
|
|
else
|
|
{
|
|
card->e_head = i;
|
|
card->e_tail = i;
|
|
}
|
|
|
|
UxCardUnlock(card->hw, ipl);
|
|
|
|
DivasScheduleRequestDpc();
|
|
|
|
return;
|
|
}
|
|
|
|
static byte pr_ready(ADAPTER * a)
|
|
{
|
|
byte ReadyCount;
|
|
|
|
ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
|
|
a->ram_in(a, &PR_RAM->ReqInput));
|
|
|
|
if(!ReadyCount) {
|
|
if(!a->ReadyInt) {
|
|
a->ram_inc(a, &PR_RAM->ReadyInt);
|
|
a->ReadyInt++;
|
|
}
|
|
}
|
|
return ReadyCount;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* output function */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void DivasOut(ADAPTER * a)
|
|
{
|
|
byte e_no;
|
|
ENTITY * this = NULL;
|
|
BUFFERS *X;
|
|
word length;
|
|
word i;
|
|
word clength;
|
|
REQ * ReqOut;
|
|
byte more;
|
|
byte ReadyCount;
|
|
byte ReqCount;
|
|
byte Id;
|
|
|
|
/* while a request is pending ... */
|
|
e_no = look_req(a);
|
|
if(!e_no)
|
|
{
|
|
return;
|
|
}
|
|
|
|
ReadyCount = pr_ready(a);
|
|
if(!ReadyCount)
|
|
{
|
|
DPRINTF(("IDI: card not ready for next request"));
|
|
return;
|
|
}
|
|
|
|
ReqCount = 0;
|
|
while(e_no && ReadyCount) {
|
|
|
|
next_req(a);
|
|
|
|
this = entity_ptr(a, e_no);
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
if ( !this )
|
|
{
|
|
ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
|
|
DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
|
|
e_no = look_req(a) ;
|
|
ReadyCount-- ;
|
|
continue ;
|
|
}
|
|
{
|
|
ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
|
|
DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
|
|
}
|
|
#else
|
|
DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
|
|
#endif
|
|
|
|
/* get address of next available request buffer */
|
|
ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
|
|
|
|
/* now copy the data from the current data buffer into the */
|
|
/* adapters request buffer */
|
|
length = 0;
|
|
i = this->XCurrent;
|
|
X = PTR_X(a,this);
|
|
while(i<this->XNum && length<270) {
|
|
clength = (word)(270-length);
|
|
if (clength > X[i].PLength-this->XOffset)
|
|
clength = X[i].PLength-this->XOffset;
|
|
a->ram_out_buffer(a,
|
|
&ReqOut->XBuffer.P[length],
|
|
PTR_P(a,this,&X[i].P[this->XOffset]),
|
|
clength);
|
|
|
|
length +=clength;
|
|
this->XOffset +=clength;
|
|
if(this->XOffset==X[i].PLength) {
|
|
this->XCurrent = (byte)++i;
|
|
this->XOffset = 0;
|
|
}
|
|
}
|
|
|
|
a->ram_outw(a, &ReqOut->XBuffer.length, length);
|
|
a->ram_out(a, &ReqOut->ReqId, this->Id);
|
|
a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
|
|
|
|
/* if its a specific request (no ASSIGN) ... */
|
|
|
|
if(this->Id &0x1f) {
|
|
|
|
/* if buffers are left in the list of data buffers do */
|
|
/* do chaining (LL_MDATA, N_MDATA) */
|
|
|
|
this->More++;
|
|
if(i<this->XNum && this->MInd) {
|
|
a->ram_out(a, &ReqOut->Req, this->MInd);
|
|
more = TRUE;
|
|
}
|
|
else {
|
|
this->More |=XMOREF;
|
|
a->ram_out(a, &ReqOut->Req, this->Req);
|
|
more = FALSE;
|
|
}
|
|
|
|
/* if we did chaining, this entity is put back into the */
|
|
/* request queue */
|
|
|
|
if(more) {
|
|
req_queue(a,this->No);
|
|
}
|
|
}
|
|
|
|
/* else it's a ASSIGN */
|
|
|
|
else {
|
|
|
|
/* save the request code used for buffer chaining */
|
|
|
|
this->MInd = 0;
|
|
if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
|
|
if (this->Id==NL_ID ||
|
|
this->Id==TASK_ID ||
|
|
this->Id==MAN_ID
|
|
) this->MInd = N_MDATA;
|
|
|
|
/* send the ASSIGN */
|
|
|
|
this->More |=XMOREF;
|
|
a->ram_out(a, &ReqOut->Req, this->Req);
|
|
|
|
/* save the reference of the ASSIGN */
|
|
|
|
assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
|
|
}
|
|
a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
|
|
ReadyCount--;
|
|
ReqCount++;
|
|
|
|
e_no = look_req(a);
|
|
}
|
|
|
|
/* send the filled request buffers to the ISDN adapter */
|
|
|
|
a->ram_out(a, &PR_RAM->ReqInput,
|
|
(byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
|
|
|
|
/* if it is a 'unreturncoded' UREMOVE request, remove the */
|
|
/* Id from our table after sending the request */
|
|
if(this->Req==UREMOVE && this->Id) {
|
|
Id = this->Id;
|
|
e_no = a->IdTable[Id];
|
|
free_entity(a, e_no);
|
|
a->IdTable[Id] = 0;
|
|
this->Id = 0;
|
|
}
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* isdn interrupt handler */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
byte DivasDpc(ADAPTER * a)
|
|
{
|
|
byte Count;
|
|
RC * RcIn;
|
|
IND * IndIn;
|
|
byte c;
|
|
byte RNRId;
|
|
byte Rc;
|
|
byte Ind;
|
|
|
|
/* if return codes are available ... */
|
|
if((Count = a->ram_in(a, &PR_RAM->RcOutput))) {
|
|
|
|
DPRINTF(("IDI: #Rc=%x",Count));
|
|
|
|
/* get the buffer address of the first return code */
|
|
RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
|
|
|
|
/* for all return codes do ... */
|
|
while(Count--) {
|
|
|
|
if((Rc=a->ram_in(a, &RcIn->Rc))) {
|
|
|
|
/* call return code handler, if it is not our return code */
|
|
/* the handler returns 2 */
|
|
/* for all return codes we process, we clear the Rc field */
|
|
isdn_rc(a,
|
|
Rc,
|
|
a->ram_in(a, &RcIn->RcId),
|
|
a->ram_in(a, &RcIn->RcCh),
|
|
a->ram_inw(a, &RcIn->Reference));
|
|
|
|
a->ram_out(a, &RcIn->Rc, 0);
|
|
}
|
|
|
|
/* get buffer address of next return code */
|
|
RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
|
|
}
|
|
|
|
/* clear all return codes (no chaining!) */
|
|
a->ram_out(a, &PR_RAM->RcOutput ,0);
|
|
|
|
/* call output function */
|
|
DivasOut(a);
|
|
}
|
|
|
|
/* clear RNR flag */
|
|
RNRId = 0;
|
|
|
|
/* if indications are available ... */
|
|
if((Count = a->ram_in(a, &PR_RAM->IndOutput))) {
|
|
|
|
DPRINTF(("IDI: #Ind=%x",Count));
|
|
|
|
/* get the buffer address of the first indication */
|
|
IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
|
|
|
|
/* for all indications do ... */
|
|
while(Count--) {
|
|
|
|
/* if the application marks an indication as RNR, all */
|
|
/* indications from the same Id delivered in this interrupt */
|
|
/* are marked RNR */
|
|
if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
|
|
a->ram_out(a, &IndIn->Ind, 0);
|
|
a->ram_out(a, &IndIn->RNR, TRUE);
|
|
}
|
|
else {
|
|
Ind = a->ram_in(a, &IndIn->Ind);
|
|
if(Ind) {
|
|
RNRId = 0;
|
|
|
|
/* call indication handler, a return value of 2 means chain */
|
|
/* a return value of 1 means RNR */
|
|
/* for all indications we process, we clear the Ind field */
|
|
c = isdn_ind(a,
|
|
Ind,
|
|
a->ram_in(a, &IndIn->IndId),
|
|
a->ram_in(a, &IndIn->IndCh),
|
|
&IndIn->RBuffer,
|
|
a->ram_in(a, &IndIn->MInd),
|
|
a->ram_inw(a, &IndIn->MLength));
|
|
|
|
if(c==1) {
|
|
DPRINTF(("IDI: RNR"));
|
|
a->ram_out(a, &IndIn->Ind, 0);
|
|
RNRId = a->ram_in(a, &IndIn->IndId);
|
|
a->ram_out(a, &IndIn->RNR, TRUE);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* get buffer address of next indication */
|
|
IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
|
|
}
|
|
|
|
a->ram_out(a, &PR_RAM->IndOutput, 0);
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
byte DivasTestInt(ADAPTER * a)
|
|
{
|
|
return a->ram_in(a,(void *)0x3fe);
|
|
}
|
|
|
|
void DivasClearInt(ADAPTER * a)
|
|
{
|
|
a->ram_out(a,(void *)0x3fe,0);
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* return code handler */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
static
|
|
byte isdn_rc(ADAPTER * a,
|
|
byte Rc,
|
|
byte Id,
|
|
byte Ch,
|
|
word Ref)
|
|
{
|
|
ENTITY * this;
|
|
byte e_no;
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
{
|
|
ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
|
|
DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
|
|
}
|
|
#else
|
|
DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
|
|
#endif
|
|
|
|
/* check for ready interrupt */
|
|
if(Rc==READY_INT) {
|
|
if(a->ReadyInt) {
|
|
a->ReadyInt--;
|
|
return 0;
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
/* if we know this Id ... */
|
|
e_no = a->IdTable[Id];
|
|
if(e_no) {
|
|
|
|
this = entity_ptr(a,e_no);
|
|
|
|
this->RcCh = Ch;
|
|
|
|
/* if it is a return code to a REMOVE request, remove the */
|
|
/* Id from our table */
|
|
if(this->Req==REMOVE && Rc==OK) {
|
|
free_entity(a, e_no);
|
|
a->IdTable[Id] = 0;
|
|
this->Id = 0;
|
|
/**************************************************************/
|
|
if ((this->More & XMOREC) > 1) {
|
|
this->More &= ~XMOREC;
|
|
this->More |= 1;
|
|
DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
|
|
}
|
|
}
|
|
|
|
if (Rc==OK_FC) {
|
|
this->Rc = Rc;
|
|
this->More = (this->More & (~XBUSY | XMOREC)) | 1;
|
|
this->complete = 0xFF;
|
|
CALLBACK(a, this);
|
|
return 0;
|
|
}
|
|
if(this->More &XMOREC)
|
|
this->More--;
|
|
|
|
/* call the application callback function */
|
|
if(this->More &XMOREF && !(this->More &XMOREC)) {
|
|
this->Rc = Rc;
|
|
this->More &=~XBUSY;
|
|
this->complete=0xff;
|
|
CALLBACK(a, this);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* if it's an ASSIGN return code check if it's a return */
|
|
/* code to an ASSIGN request from us */
|
|
if((Rc &0xf0)==ASSIGN_RC) {
|
|
|
|
e_no = get_assign(a, Ref);
|
|
|
|
if(e_no) {
|
|
|
|
this = entity_ptr(a,e_no);
|
|
|
|
this->Id = Id;
|
|
|
|
/* call the application callback function */
|
|
this->Rc = Rc;
|
|
this->More &=~XBUSY;
|
|
this->complete=0xff;
|
|
CALLBACK(a, this);
|
|
|
|
if(Rc==ASSIGN_OK) {
|
|
a->IdTable[Id] = e_no;
|
|
}
|
|
else
|
|
{
|
|
free_entity(a, e_no);
|
|
a->IdTable[Id] = 0;
|
|
this->Id = 0;
|
|
}
|
|
return 1;
|
|
}
|
|
}
|
|
return 2;
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
/* indication handler */
|
|
/*------------------------------------------------------------------*/
|
|
|
|
static
|
|
byte isdn_ind(ADAPTER * a,
|
|
byte Ind,
|
|
byte Id,
|
|
byte Ch,
|
|
PBUFFER * RBuffer,
|
|
byte MInd,
|
|
word MLength)
|
|
{
|
|
ENTITY * this;
|
|
word clength;
|
|
word offset;
|
|
BUFFERS *R;
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
{
|
|
ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
|
|
DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
|
|
}
|
|
#else
|
|
DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
|
|
#endif
|
|
|
|
if(a->IdTable[Id]) {
|
|
|
|
this = entity_ptr(a,a->IdTable[Id]);
|
|
|
|
this->IndCh = Ch;
|
|
|
|
/* if the Receive More flag is not yet set, this is the */
|
|
/* first buffer of the packet */
|
|
if(this->RCurrent==0xff) {
|
|
|
|
/* check for receive buffer chaining */
|
|
if(Ind==this->MInd) {
|
|
this->complete = 0;
|
|
this->Ind = MInd;
|
|
}
|
|
else {
|
|
this->complete = 1;
|
|
this->Ind = Ind;
|
|
}
|
|
|
|
/* call the application callback function for the receive */
|
|
/* look ahead */
|
|
this->RLength = MLength;
|
|
|
|
a->ram_look_ahead(a, RBuffer, this);
|
|
|
|
this->RNum = 0;
|
|
CALLBACK(a, this);
|
|
|
|
/* map entity ptr, selector could be re-mapped by call to */
|
|
/* IDI from within callback */
|
|
this = entity_ptr(a,a->IdTable[Id]);
|
|
|
|
/* check for RNR */
|
|
if(this->RNR==1) {
|
|
this->RNR = 0;
|
|
return 1;
|
|
}
|
|
|
|
/* if no buffers are provided by the application, the */
|
|
/* application want to copy the data itself including */
|
|
/* N_MDATA/LL_MDATA chaining */
|
|
if(!this->RNR && !this->RNum) {
|
|
return 0;
|
|
}
|
|
|
|
/* if there is no RNR, set the More flag */
|
|
this->RCurrent = 0;
|
|
this->ROffset = 0;
|
|
}
|
|
|
|
if(this->RNR==2) {
|
|
if(Ind!=this->MInd) {
|
|
this->RCurrent = 0xff;
|
|
this->RNR = 0;
|
|
}
|
|
return 0;
|
|
}
|
|
/* if we have received buffers from the application, copy */
|
|
/* the data into these buffers */
|
|
offset = 0;
|
|
R = PTR_R(a,this);
|
|
do {
|
|
if(this->ROffset==R[this->RCurrent].PLength) {
|
|
this->ROffset = 0;
|
|
this->RCurrent++;
|
|
}
|
|
clength = a->ram_inw(a, &RBuffer->length)-offset;
|
|
if (clength > R[this->RCurrent].PLength-this->ROffset)
|
|
clength = R[this->RCurrent].PLength-this->ROffset;
|
|
if(R[this->RCurrent].P) {
|
|
a->ram_in_buffer(a,
|
|
&RBuffer->P[offset],
|
|
PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
|
|
clength);
|
|
}
|
|
offset +=clength;
|
|
this->ROffset +=clength;
|
|
} while(offset<(a->ram_inw(a, &RBuffer->length)));
|
|
|
|
/* if it's the last buffer of the packet, call the */
|
|
/* application callback function for the receive complete */
|
|
/* call */
|
|
if(Ind!=this->MInd) {
|
|
R[this->RCurrent].PLength = this->ROffset;
|
|
if(this->ROffset) this->RCurrent++;
|
|
this->RNum = this->RCurrent;
|
|
this->RCurrent = 0xff;
|
|
this->Ind = Ind;
|
|
this->complete = 2;
|
|
CALLBACK(a, this);
|
|
}
|
|
return 0;
|
|
}
|
|
return 2;
|
|
}
|