2005-04-16 18:20:36 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
Copyright (c) Eicon Networks, 2002.
|
|
|
|
*
|
|
|
|
This source file is supplied for the use with
|
|
|
|
Eicon Networks range of DIVA Server Adapters.
|
|
|
|
*
|
|
|
|
Eicon File Revision : 2.1
|
|
|
|
*
|
|
|
|
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.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
#include "platform.h"
|
|
|
|
#include "pc.h"
|
|
|
|
#include "pr_pc.h"
|
|
|
|
#include "di_defs.h"
|
|
|
|
#include "di.h"
|
|
|
|
#if !defined USE_EXTENDED_DEBUGS
|
|
|
|
#include "dimaint.h"
|
|
|
|
#else
|
|
|
|
#define dprintf
|
|
|
|
#endif
|
|
|
|
#include "io.h"
|
|
|
|
#include "dfifo.h"
|
|
|
|
#define PR_RAM ((struct pr_ram *)0)
|
|
|
|
#define RAM ((struct dual *)0)
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* local function prototypes */
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void pr_out(ADAPTER * a);
|
|
|
|
byte pr_dpc(ADAPTER * a);
|
|
|
|
static byte pr_ready(ADAPTER * a);
|
|
|
|
static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword);
|
|
|
|
static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
|
|
|
|
/* -----------------------------------------------------------------
|
|
|
|
Functions used for the extended XDI Debug
|
|
|
|
macros
|
|
|
|
global convergence counter (used by all adapters)
|
|
|
|
Look by the implementation part of the functions
|
|
|
|
about the parameters.
|
|
|
|
If you change the dubugging parameters, then you should update
|
|
|
|
the aididbg.doc in the IDI doc's.
|
|
|
|
----------------------------------------------------------------- */
|
|
|
|
#if defined(XDI_USE_XLOG)
|
|
|
|
#define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum))
|
|
|
|
static void xdi_xlog (byte *msg, word code, int length);
|
|
|
|
static byte xdi_xlog_sec = 0;
|
|
|
|
#else
|
|
|
|
#define XDI_A_NR(_x_) ((byte)0)
|
|
|
|
#endif
|
|
|
|
static void xdi_xlog_rc_event (byte Adapter,
|
|
|
|
byte Id, byte Ch, byte Rc, byte cb, byte type);
|
|
|
|
static void xdi_xlog_request (byte Adapter, byte Id,
|
|
|
|
byte Ch, byte Req, byte type);
|
|
|
|
static void xdi_xlog_ind (byte Adapter,
|
|
|
|
byte Id,
|
|
|
|
byte Ch,
|
|
|
|
byte Ind,
|
|
|
|
byte rnr_valid,
|
|
|
|
byte rnr,
|
|
|
|
byte type);
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* output function */
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
void pr_out(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;
|
|
|
|
dtrc(dprintf("pr_out"));
|
|
|
|
/* while a request is pending ... */
|
|
|
|
e_no = look_req(a);
|
|
|
|
if(!e_no)
|
|
|
|
{
|
|
|
|
dtrc(dprintf("no_req"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ReadyCount = pr_ready(a);
|
|
|
|
if(!ReadyCount)
|
|
|
|
{
|
|
|
|
dtrc(dprintf("not_ready"));
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
ReqCount = 0;
|
|
|
|
while(e_no && ReadyCount) {
|
|
|
|
next_req(a);
|
|
|
|
this = entity_ptr(a, e_no);
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
|
|
if ( !this )
|
|
|
|
{
|
|
|
|
DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
|
|
|
|
xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum))
|
|
|
|
e_no = look_req(a) ;
|
|
|
|
ReadyCount-- ;
|
|
|
|
continue ;
|
|
|
|
}
|
|
|
|
{
|
|
|
|
DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req))
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
dbug(dprintf("out: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)];
|
|
|
|
#if defined(DIVA_ISTREAM)
|
|
|
|
if (!(a->tx_stream[this->Id] &&
|
|
|
|
this->Req == N_DATA)) {
|
|
|
|
#endif
|
|
|
|
/* 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) {
|
2006-12-08 05:39:32 -05:00
|
|
|
clength = min((word)(270-length),(word)(X[i].PLength-this->XOffset));
|
2005-04-16 18:20:36 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#if defined(DIVA_ISTREAM)
|
|
|
|
} else { /* Use CMA extension in order to transfer data to the card */
|
|
|
|
i = this->XCurrent;
|
|
|
|
X = PTR_X(a,this);
|
|
|
|
while (i < this->XNum) {
|
|
|
|
diva_istream_write (a,
|
|
|
|
this->Id,
|
|
|
|
PTR_P(a,this,&X[i].P[0]),
|
|
|
|
X[i].PLength,
|
|
|
|
((i+1) == this->XNum),
|
|
|
|
0, 0);
|
|
|
|
this->XCurrent = (byte)++i;
|
|
|
|
}
|
|
|
|
length = 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
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 it's 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) {
|
|
|
|
xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
|
|
|
|
a->IdTypeTable[this->No]);
|
|
|
|
a->ram_out(a, &ReqOut->Req, this->MInd);
|
2007-02-12 03:53:24 -05:00
|
|
|
more = true;
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
xdi_xlog_request (XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
|
|
|
|
a->IdTypeTable[this->No]);
|
|
|
|
this->More |=XMOREF;
|
|
|
|
a->ram_out(a, &ReqOut->Req, this->Req);
|
2007-02-12 03:53:24 -05:00
|
|
|
more = false;
|
2005-04-16 18:20:36 -04:00
|
|
|
if (a->FlowControlIdTable[this->ReqCh] == this->Id)
|
2007-02-12 03:53:24 -05:00
|
|
|
a->FlowControlSkipTable[this->ReqCh] = true;
|
2005-04-16 18:20:36 -04:00
|
|
|
/*
|
|
|
|
Note that remove request was sent to the card
|
|
|
|
*/
|
|
|
|
if (this->Req == REMOVE) {
|
|
|
|
a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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 */
|
|
|
|
a->IdTypeTable[this->No] = this->Id;
|
|
|
|
xdi_xlog_request (XDI_A_NR(a),this->Id,this->ReqCh,this->Req, this->Id);
|
|
|
|
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 && (this->Req==UREMOVE) && this->Id) {
|
|
|
|
Id = this->Id;
|
|
|
|
e_no = a->IdTable[Id];
|
|
|
|
free_entity(a, e_no);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
if (a->FlowControlIdTable[i] == Id)
|
|
|
|
a->FlowControlIdTable[i] = 0;
|
|
|
|
}
|
|
|
|
a->IdTable[Id] = 0;
|
|
|
|
this->Id = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* isdn interrupt handler */
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
byte pr_dpc(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)) != 0) {
|
|
|
|
dtrc(dprintf("#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)) != 0) {
|
|
|
|
dword tmp[2];
|
|
|
|
/*
|
|
|
|
Get extended information, associated with return code
|
|
|
|
*/
|
|
|
|
a->ram_in_buffer(a,
|
|
|
|
&RcIn->Reserved2[0],
|
|
|
|
(byte*)&tmp[0],
|
|
|
|
8);
|
|
|
|
/* 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),
|
|
|
|
tmp[0], /* type of extended informtion */
|
|
|
|
tmp[1]); /* extended information */
|
|
|
|
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 */
|
|
|
|
pr_out(a);
|
|
|
|
}
|
|
|
|
/* clear RNR flag */
|
|
|
|
RNRId = 0;
|
|
|
|
/* if indications are available ... */
|
|
|
|
if((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) {
|
|
|
|
dtrc(dprintf("#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);
|
2007-02-12 03:53:24 -05:00
|
|
|
a->ram_out(a, &IndIn->RNR, true);
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
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) {
|
|
|
|
dtrc(dprintf("RNR"));
|
|
|
|
a->ram_out(a, &IndIn->Ind, 0);
|
|
|
|
RNRId = a->ram_in(a, &IndIn->IndId);
|
2007-02-12 03:53:24 -05:00
|
|
|
a->ram_out(a, &IndIn->RNR, true);
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* 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);
|
|
|
|
}
|
2007-02-12 03:53:24 -05:00
|
|
|
return false;
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
byte scom_test_int(ADAPTER * a)
|
|
|
|
{
|
|
|
|
return a->ram_in(a,(void *)0x3fe);
|
|
|
|
}
|
|
|
|
void scom_clear_int(ADAPTER * a)
|
|
|
|
{
|
|
|
|
a->ram_out(a,(void *)0x3fe,0);
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* return code handler */
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
byte isdn_rc(ADAPTER * a,
|
|
|
|
byte Rc,
|
|
|
|
byte Id,
|
|
|
|
byte Ch,
|
|
|
|
word Ref,
|
|
|
|
dword extended_info_type,
|
|
|
|
dword extended_info)
|
|
|
|
{
|
|
|
|
ENTITY * this;
|
|
|
|
byte e_no;
|
|
|
|
word i;
|
|
|
|
int cancel_rc;
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
|
|
{
|
|
|
|
DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc))
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
|
|
|
|
#endif
|
|
|
|
/* check for ready interrupt */
|
|
|
|
if(Rc==READY_INT) {
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, 0);
|
|
|
|
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);
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
|
|
|
|
this->RcCh = Ch;
|
|
|
|
/* if it is a return code to a REMOVE request, remove the */
|
|
|
|
/* Id from our table */
|
|
|
|
if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
|
|
|
|
(Rc==OK)) {
|
|
|
|
if (a->IdTypeTable[e_no] == NL_ID) {
|
|
|
|
if (a->RcExtensionSupported &&
|
|
|
|
(extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
|
|
|
|
dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
|
|
|
|
XDI_A_NR(a),Id));
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
|
2007-02-12 03:53:24 -05:00
|
|
|
a->RcExtensionSupported = true;
|
2005-04-16 18:20:36 -04:00
|
|
|
}
|
|
|
|
a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
|
|
|
|
a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
|
|
|
|
free_entity(a, e_no);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
if (a->FlowControlIdTable[i] == Id)
|
|
|
|
a->FlowControlIdTable[i] = 0;
|
|
|
|
}
|
|
|
|
a->IdTable[Id] = 0;
|
|
|
|
this->Id = 0;
|
|
|
|
/* ---------------------------------------------------------------
|
|
|
|
If we send N_DISC or N_DISK_ACK after we have received OK_FC
|
|
|
|
then the card will respond with OK_FC and later with RC==OK.
|
|
|
|
If we send N_REMOVE in this state we will receive only RC==OK
|
|
|
|
This will create the state in that the XDI is waiting for the
|
|
|
|
additional RC and does not delivery the RC to the client. This
|
|
|
|
code corrects the counter of outstanding RC's in this case.
|
|
|
|
--------------------------------------------------------------- */
|
|
|
|
if ((this->More & XMOREC) > 1) {
|
|
|
|
this->More &= ~XMOREC;
|
|
|
|
this->More |= 1;
|
|
|
|
dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
|
|
|
|
XDI_A_NR(a),Id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (Rc==OK_FC) {
|
|
|
|
a->FlowControlIdTable[Ch] = Id;
|
2007-02-12 03:53:24 -05:00
|
|
|
a->FlowControlSkipTable[Ch] = false;
|
2005-04-16 18:20:36 -04:00
|
|
|
this->Rc = Rc;
|
|
|
|
this->More &= ~(XBUSY | XMOREC);
|
|
|
|
this->complete=0xff;
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
|
|
|
|
CALLBACK(a, this);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
New protocol code sends return codes that comes from release
|
|
|
|
of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
|
|
|
|
information element type.
|
|
|
|
If like return code arrives then application is able to process
|
|
|
|
all return codes self and XDI should not cances return codes.
|
|
|
|
This return code does not decrement XMOREC partial return code
|
|
|
|
counter due to fact that it was no request for this return code,
|
|
|
|
also XMOREC was not incremented.
|
|
|
|
*/
|
|
|
|
if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
|
|
|
|
a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
|
|
|
|
this->Rc = Rc;
|
|
|
|
this->complete=0xff;
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
|
|
|
|
DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
|
|
|
|
XDI_A_NR(a), Id, Ch, Rc))
|
|
|
|
CALLBACK(a, this);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
|
|
|
|
if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
|
|
|
|
{
|
|
|
|
a->FlowControlIdTable[Ch] = 0;
|
|
|
|
if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
|
|
|
|
{
|
|
|
|
this->Rc = Rc;
|
|
|
|
if (Ch == this->ReqCh)
|
|
|
|
{
|
|
|
|
this->More &=~(XBUSY | XMOREC);
|
|
|
|
this->complete=0xff;
|
|
|
|
}
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
|
|
|
|
CALLBACK(a, this);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (this->More &XMOREC)
|
|
|
|
this->More--;
|
|
|
|
/* call the application callback function */
|
|
|
|
if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
|
|
|
|
this->Rc = Rc;
|
|
|
|
this->More &=~XBUSY;
|
|
|
|
this->complete=0xff;
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
|
|
|
|
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;
|
|
|
|
xdi_xlog_rc_event (XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
|
|
|
|
/* call the application callback function */
|
|
|
|
this->Rc = Rc;
|
|
|
|
this->More &=~XBUSY;
|
|
|
|
this->complete=0xff;
|
|
|
|
#if defined(DIVA_ISTREAM) /* { */
|
|
|
|
if ((Rc == ASSIGN_OK) && a->ram_offset &&
|
|
|
|
(a->IdTypeTable[this->No] == NL_ID) &&
|
|
|
|
((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
|
|
|
|
(extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
|
|
|
|
extended_info) {
|
|
|
|
dword offset = (*(a->ram_offset)) (a);
|
|
|
|
dword tmp[2];
|
|
|
|
extended_info -= offset;
|
|
|
|
#ifdef PLATFORM_GT_32BIT
|
|
|
|
a->ram_in_dw(a, (void*)ULongToPtr(extended_info), (dword*)&tmp[0], 2);
|
|
|
|
#else
|
|
|
|
a->ram_in_dw(a, (void*)extended_info, (dword*)&tmp[0], 2);
|
|
|
|
#endif
|
|
|
|
a->tx_stream[Id] = tmp[0];
|
|
|
|
a->rx_stream[Id] = tmp[1];
|
|
|
|
if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
|
|
|
|
DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
|
|
|
|
Id, a->tx_stream[Id], a->rx_stream[Id]))
|
|
|
|
a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
|
|
|
|
} else {
|
|
|
|
DBG_TRC(("Id=0x%x CMA=%08x:%08x",
|
|
|
|
Id, a->tx_stream[Id], a->rx_stream[Id]))
|
|
|
|
a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
|
|
|
|
a->rx_pos[Id] = 0;
|
|
|
|
a->rx_stream[Id] -= offset;
|
|
|
|
}
|
|
|
|
a->tx_pos[Id] = 0;
|
|
|
|
a->tx_stream[Id] -= offset;
|
|
|
|
} else {
|
|
|
|
a->tx_stream[Id] = 0;
|
|
|
|
a->rx_stream[Id] = 0;
|
|
|
|
a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
|
|
|
|
}
|
|
|
|
#endif /* } */
|
|
|
|
CALLBACK(a, this);
|
|
|
|
if(Rc==ASSIGN_OK) {
|
|
|
|
a->IdTable[Id] = e_no;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
free_entity(a, e_no);
|
|
|
|
for (i = 0; i < 256; i++)
|
|
|
|
{
|
|
|
|
if (a->FlowControlIdTable[i] == Id)
|
|
|
|
a->FlowControlIdTable[i] = 0;
|
|
|
|
}
|
|
|
|
a->IdTable[Id] = 0;
|
|
|
|
this->Id = 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
/* indication handler */
|
|
|
|
/*------------------------------------------------------------------*/
|
|
|
|
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;
|
|
|
|
byte* cma = NULL;
|
|
|
|
#ifdef USE_EXTENDED_DEBUGS
|
|
|
|
{
|
|
|
|
DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind))
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
dbug(dprintf("isdn_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;
|
|
|
|
xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
|
|
|
|
0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
|
|
|
|
/* 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;
|
|
|
|
#if defined(DIVA_ISTREAM)
|
|
|
|
if ((a->rx_stream[this->Id] ||
|
|
|
|
(a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
|
|
|
|
((Ind == N_DATA) ||
|
|
|
|
(a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
|
|
|
|
PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ;
|
|
|
|
if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
|
|
|
|
#if defined(DIVA_IDI_RX_DMA)
|
|
|
|
dword d;
|
|
|
|
diva_get_dma_map_entry (\
|
|
|
|
(struct _diva_dma_map_entry*)IoAdapter->dma_map,
|
|
|
|
(int)a->rx_stream[this->Id], (void**)&cma, &d);
|
|
|
|
#else
|
|
|
|
cma = &a->stream_buffer[0];
|
|
|
|
cma[0] = cma[1] = cma[2] = cma[3] = 0;
|
|
|
|
#endif
|
|
|
|
this->RLength = MLength = (word)*(dword*)cma;
|
|
|
|
cma += 4;
|
|
|
|
} else {
|
|
|
|
int final = 0;
|
|
|
|
cma = &a->stream_buffer[0];
|
|
|
|
this->RLength = MLength = (word)diva_istream_read (a,
|
|
|
|
Id,
|
|
|
|
cma,
|
|
|
|
sizeof(a->stream_buffer),
|
|
|
|
&final, NULL, NULL);
|
|
|
|
}
|
2006-12-08 05:39:32 -05:00
|
|
|
IoAdapter->RBuffer.length = min(MLength, (word)270);
|
2005-04-16 18:20:36 -04:00
|
|
|
if (IoAdapter->RBuffer.length != MLength) {
|
|
|
|
this->complete = 0;
|
|
|
|
} else {
|
|
|
|
this->complete = 1;
|
|
|
|
}
|
|
|
|
memcpy (IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length) ;
|
|
|
|
this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!cma) {
|
|
|
|
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]);
|
|
|
|
xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
|
|
|
|
1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
|
|
|
|
/* 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) {
|
|
|
|
xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
|
|
|
|
2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
|
|
|
|
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++;
|
|
|
|
}
|
|
|
|
if (cma) {
|
2006-12-08 05:39:32 -05:00
|
|
|
clength = min(MLength, (word)(R[this->RCurrent].PLength-this->ROffset));
|
2005-04-16 18:20:36 -04:00
|
|
|
} else {
|
2006-12-08 05:39:32 -05:00
|
|
|
clength = min(a->ram_inw(a, &RBuffer->length)-offset,
|
2005-04-16 18:20:36 -04:00
|
|
|
R[this->RCurrent].PLength-this->ROffset);
|
|
|
|
}
|
|
|
|
if(R[this->RCurrent].P) {
|
|
|
|
if (cma) {
|
|
|
|
memcpy (PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
|
|
|
|
&cma[offset],
|
|
|
|
clength);
|
|
|
|
} else {
|
|
|
|
a->ram_in_buffer(a,
|
|
|
|
&RBuffer->P[offset],
|
|
|
|
PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
|
|
|
|
clength);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
offset +=clength;
|
|
|
|
this->ROffset +=clength;
|
|
|
|
if (cma) {
|
|
|
|
if (offset >= MLength) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} 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;
|
|
|
|
xdi_xlog_ind (XDI_A_NR(a), Id, Ch, Ind,
|
|
|
|
3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
|
|
|
|
CALLBACK(a, this);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
#if defined(XDI_USE_XLOG)
|
|
|
|
/* -----------------------------------------------------------
|
|
|
|
This function works in the same way as xlog on the
|
|
|
|
active board
|
|
|
|
----------------------------------------------------------- */
|
|
|
|
static void xdi_xlog (byte *msg, word code, int length) {
|
|
|
|
xdi_dbg_xlog ("\x00\x02", msg, code, length);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* -----------------------------------------------------------
|
|
|
|
This function writes the information about the Return Code
|
|
|
|
processing in the trace buffer. Trace ID is 221.
|
|
|
|
INPUT:
|
|
|
|
Adapter - system unicue adapter number (0 ... 255)
|
|
|
|
Id - Id of the entity that had sent this return code
|
|
|
|
Ch - Channel of the entity that had sent this return code
|
|
|
|
Rc - return code value
|
|
|
|
cb: (0...2)
|
|
|
|
switch (cb) {
|
|
|
|
case 0: printf ("DELIVERY"); break;
|
|
|
|
case 1: printf ("CALLBACK"); break;
|
|
|
|
case 2: printf ("ASSIGN"); break;
|
|
|
|
}
|
|
|
|
DELIVERY - have entered isdn_rc with this RC
|
|
|
|
CALLBACK - about to make callback to the application
|
|
|
|
for this RC
|
|
|
|
ASSIGN - about to make callback for RC that is result
|
|
|
|
of ASSIGN request. It is no DELIVERY message
|
|
|
|
before of this message
|
|
|
|
type - the Id that was sent by the ASSIGN of this entity.
|
|
|
|
This should be global Id like NL_ID, DSIG_ID, MAN_ID.
|
|
|
|
An unknown Id will cause "?-" in the front of the request.
|
|
|
|
In this case the log.c is to be extended.
|
|
|
|
----------------------------------------------------------- */
|
|
|
|
static void xdi_xlog_rc_event (byte Adapter,
|
|
|
|
byte Id, byte Ch, byte Rc, byte cb, byte type) {
|
|
|
|
#if defined(XDI_USE_XLOG)
|
|
|
|
word LogInfo[4];
|
|
|
|
PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
|
|
|
|
PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
|
|
|
|
PUT_WORD(&LogInfo[2], ((word)Rc | (word)(type << 8)));
|
|
|
|
PUT_WORD(&LogInfo[3], cb);
|
|
|
|
xdi_xlog ((byte*)&LogInfo[0], 221, sizeof(LogInfo));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
This function writes the information about the request processing
|
|
|
|
in the trace buffer. Trace ID is 220.
|
|
|
|
INPUT:
|
|
|
|
Adapter - system unicue adapter number (0 ... 255)
|
|
|
|
Id - Id of the entity that had sent this request
|
|
|
|
Ch - Channel of the entity that had sent this request
|
|
|
|
Req - Code of the request
|
|
|
|
type - the Id that was sent by the ASSIGN of this entity.
|
|
|
|
This should be global Id like NL_ID, DSIG_ID, MAN_ID.
|
|
|
|
An unknown Id will cause "?-" in the front of the request.
|
|
|
|
In this case the log.c is to be extended.
|
|
|
|
------------------------------------------------------------------------ */
|
|
|
|
static void xdi_xlog_request (byte Adapter, byte Id,
|
|
|
|
byte Ch, byte Req, byte type) {
|
|
|
|
#if defined(XDI_USE_XLOG)
|
|
|
|
word LogInfo[3];
|
|
|
|
PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
|
|
|
|
PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
|
|
|
|
PUT_WORD(&LogInfo[2], ((word)Req | (word)(type << 8)));
|
|
|
|
xdi_xlog ((byte*)&LogInfo[0], 220, sizeof(LogInfo));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
/* ------------------------------------------------------------------------
|
|
|
|
This function writes the information about the indication processing
|
|
|
|
in the trace buffer. Trace ID is 222.
|
|
|
|
INPUT:
|
|
|
|
Adapter - system unicue adapter number (0 ... 255)
|
|
|
|
Id - Id of the entity that had sent this indication
|
|
|
|
Ch - Channel of the entity that had sent this indication
|
|
|
|
Ind - Code of the indication
|
|
|
|
rnr_valid: (0 .. 3) supported
|
|
|
|
switch (rnr_valid) {
|
|
|
|
case 0: printf ("DELIVERY"); break;
|
|
|
|
case 1: printf ("RNR=%d", rnr);
|
|
|
|
case 2: printf ("RNum=0");
|
|
|
|
case 3: printf ("COMPLETE");
|
|
|
|
}
|
|
|
|
DELIVERY - indication entered isdn_rc function
|
|
|
|
RNR=... - application had returned RNR=... after the
|
|
|
|
look ahead callback
|
|
|
|
RNum=0 - aplication had not returned any buffer to copy
|
|
|
|
this indication and will copy it self
|
|
|
|
COMPLETE - XDI had copied the data to the buffers provided
|
|
|
|
bu the application and is about to issue the
|
|
|
|
final callback
|
|
|
|
rnr: Look case 1 of the rnr_valid
|
|
|
|
type: the Id that was sent by the ASSIGN of this entity. This should
|
|
|
|
be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will
|
|
|
|
cause "?-" in the front of the request. In this case the
|
|
|
|
log.c is to be extended.
|
|
|
|
------------------------------------------------------------------------ */
|
|
|
|
static void xdi_xlog_ind (byte Adapter,
|
|
|
|
byte Id,
|
|
|
|
byte Ch,
|
|
|
|
byte Ind,
|
|
|
|
byte rnr_valid,
|
|
|
|
byte rnr,
|
|
|
|
byte type) {
|
|
|
|
#if defined(XDI_USE_XLOG)
|
|
|
|
word LogInfo[4];
|
|
|
|
PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
|
|
|
|
PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
|
|
|
|
PUT_WORD(&LogInfo[2], ((word)Ind | (word)(type << 8)));
|
|
|
|
PUT_WORD(&LogInfo[3], ((word)rnr | (word)(rnr_valid << 8)));
|
|
|
|
xdi_xlog ((byte*)&LogInfo[0], 222, sizeof(LogInfo));
|
|
|
|
#endif
|
|
|
|
}
|