|  |  | 
|  | /* | 
|  | * | 
|  | 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) { | 
|  | clength = min((word)(270-length),(word)(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; | 
|  | } | 
|  | } | 
|  | #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); | 
|  | more = true; | 
|  | } | 
|  | 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); | 
|  | more = false; | 
|  | if (a->FlowControlIdTable[this->ReqCh] == this->Id) | 
|  | a->FlowControlSkipTable[this->ReqCh] = true; | 
|  | /* | 
|  | 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 information */ | 
|  | 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); | 
|  | 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) { | 
|  | dtrc(dprintf("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 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                                              */ | 
|  | /*------------------------------------------------------------------*/ | 
|  | static 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) | 
|  | a->RcExtensionSupported = true; | 
|  | } | 
|  | 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; | 
|  | a->FlowControlSkipTable[Ch] = false; | 
|  | 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                                               */ | 
|  | /*------------------------------------------------------------------*/ | 
|  | 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; | 
|  | 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); | 
|  | } | 
|  | IoAdapter->RBuffer.length = min(MLength, (word)270); | 
|  | 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) { | 
|  | clength = min(MLength, (word)(R[this->RCurrent].PLength-this->ROffset)); | 
|  | } else { | 
|  | clength = min(a->ram_inw(a, &RBuffer->length)-offset, | 
|  | 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 | 
|  | } |