1
2/*
3 *
4 Copyright (c) Eicon Networks, 2002.
5 *
6 This source file is supplied for the use with
7 Eicon Networks range of DIVA Server Adapters.
8 *
9 Eicon File Revision :    2.1
10 *
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2, or (at your option)
14 any later version.
15 *
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY
18 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19 See the GNU General Public License for more details.
20 *
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 */
26#include "platform.h"
27#include "pc.h"
28#include "pr_pc.h"
29#include "di_defs.h"
30#include "di.h"
31#if !defined USE_EXTENDED_DEBUGS
32#include "dimaint.h"
33#else
34#define dprintf
35#endif
36#include "io.h"
37#include "dfifo.h"
38#define PR_RAM  ((struct pr_ram *)0)
39#define RAM ((struct dual *)0)
40/*------------------------------------------------------------------*/
41/* local function prototypes                                        */
42/*------------------------------------------------------------------*/
43void pr_out(ADAPTER *a);
44byte pr_dpc(ADAPTER *a);
45static byte pr_ready(ADAPTER *a);
46static byte isdn_rc(ADAPTER *, byte, byte, byte, word, dword, dword);
47static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
48/* -----------------------------------------------------------------
49   Functions used for the extended XDI Debug
50   macros
51   global convergence counter (used by all adapters)
52   Look by the implementation part of the functions
53   about the parameters.
54   If you change the dubugging parameters, then you should update
55   the aididbg.doc in the IDI doc's.
56   ----------------------------------------------------------------- */
57#if defined(XDI_USE_XLOG)
58#define XDI_A_NR(_x_) ((byte)(((ISDN_ADAPTER *)(_x_->io))->ANum))
59static void xdi_xlog(byte *msg, word code, int length);
60static byte xdi_xlog_sec = 0;
61#else
62#define XDI_A_NR(_x_) ((byte)0)
63#endif
64static void xdi_xlog_rc_event(byte Adapter,
65			      byte Id, byte Ch, byte Rc, byte cb, byte type);
66static void xdi_xlog_request(byte Adapter, byte Id,
67			     byte Ch, byte Req, byte type);
68static void xdi_xlog_ind(byte Adapter,
69			 byte Id,
70			 byte Ch,
71			 byte Ind,
72			 byte rnr_valid,
73			 byte rnr,
74			 byte type);
75/*------------------------------------------------------------------*/
76/* output function                                                  */
77/*------------------------------------------------------------------*/
78void pr_out(ADAPTER *a)
79{
80	byte e_no;
81	ENTITY *this = NULL;
82	BUFFERS *X;
83	word length;
84	word i;
85	word clength;
86	REQ *ReqOut;
87	byte more;
88	byte ReadyCount;
89	byte ReqCount;
90	byte Id;
91	dtrc(dprintf("pr_out"));
92	/* while a request is pending ...                           */
93	e_no = look_req(a);
94	if (!e_no)
95	{
96		dtrc(dprintf("no_req"));
97		return;
98	}
99	ReadyCount = pr_ready(a);
100	if (!ReadyCount)
101	{
102		dtrc(dprintf("not_ready"));
103		return;
104	}
105	ReqCount = 0;
106	while (e_no && ReadyCount) {
107		next_req(a);
108		this = entity_ptr(a, e_no);
109#ifdef USE_EXTENDED_DEBUGS
110		if (!this)
111		{
112			DBG_FTL(("XDI: [%02x] !A%d ==> NULL entity ptr - try to ignore",
113				 xdi_xlog_sec++, (int)((ISDN_ADAPTER *)a->io)->ANum))
114				e_no = look_req(a);
115			ReadyCount--;
116			continue;
117		}
118		{
119			DBG_TRC((">A%d Id=0x%x Req=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, this->Id, this->Req))
120				}
121#else
122		dbug(dprintf("out:Req=%x,Id=%x,Ch=%x", this->Req, this->Id, this->ReqCh));
123#endif
124		/* get address of next available request buffer             */
125		ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
126#if defined(DIVA_ISTREAM)
127		if (!(a->tx_stream[this->Id]   &&
128		      this->Req == N_DATA)) {
129#endif
130			/* now copy the data from the current data buffer into the  */
131			/* adapters request buffer                                  */
132			length = 0;
133			i = this->XCurrent;
134			X = PTR_X(a, this);
135			while (i < this->XNum && length < 270) {
136				clength = min((word)(270 - length), (word)(X[i].PLength-this->XOffset));
137				a->ram_out_buffer(a,
138						  &ReqOut->XBuffer.P[length],
139						  PTR_P(a, this, &X[i].P[this->XOffset]),
140						  clength);
141				length += clength;
142				this->XOffset += clength;
143				if (this->XOffset == X[i].PLength) {
144					this->XCurrent = (byte)++i;
145					this->XOffset = 0;
146				}
147			}
148#if defined(DIVA_ISTREAM)
149		} else { /* Use CMA extension in order to transfer data to the card */
150			i = this->XCurrent;
151			X = PTR_X(a, this);
152			while (i < this->XNum) {
153				diva_istream_write(a,
154						   this->Id,
155						   PTR_P(a, this, &X[i].P[0]),
156						   X[i].PLength,
157						   ((i + 1) == this->XNum),
158						   0, 0);
159				this->XCurrent = (byte)++i;
160			}
161			length = 0;
162		}
163#endif
164		a->ram_outw(a, &ReqOut->XBuffer.length, length);
165		a->ram_out(a, &ReqOut->ReqId, this->Id);
166		a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
167		/* if it's a specific request (no ASSIGN) ...                */
168		if (this->Id & 0x1f) {
169			/* if buffers are left in the list of data buffers do       */
170			/* do chaining (LL_MDATA, N_MDATA)                          */
171			this->More++;
172			if (i < this->XNum && this->MInd) {
173				xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->MInd,
174						 a->IdTypeTable[this->No]);
175				a->ram_out(a, &ReqOut->Req, this->MInd);
176				more = true;
177			}
178			else {
179				xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->Req,
180						 a->IdTypeTable[this->No]);
181				this->More |= XMOREF;
182				a->ram_out(a, &ReqOut->Req, this->Req);
183				more = false;
184				if (a->FlowControlIdTable[this->ReqCh] == this->Id)
185					a->FlowControlSkipTable[this->ReqCh] = true;
186				/*
187				  Note that remove request was sent to the card
188				*/
189				if (this->Req == REMOVE) {
190					a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_REMOVE_PENDING;
191				}
192			}
193			/* if we did chaining, this entity is put back into the     */
194			/* request queue                                            */
195			if (more) {
196				req_queue(a, this->No);
197			}
198		}
199		/* else it's a ASSIGN                                       */
200		else {
201			/* save the request code used for buffer chaining           */
202			this->MInd = 0;
203			if (this->Id == BLLC_ID) this->MInd = LL_MDATA;
204			if (this->Id == NL_ID ||
205			    this->Id == TASK_ID ||
206			    this->Id == MAN_ID
207				) this->MInd = N_MDATA;
208			/* send the ASSIGN                                          */
209			a->IdTypeTable[this->No] = this->Id;
210			xdi_xlog_request(XDI_A_NR(a), this->Id, this->ReqCh, this->Req, this->Id);
211			this->More |= XMOREF;
212			a->ram_out(a, &ReqOut->Req, this->Req);
213			/* save the reference of the ASSIGN                         */
214			assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
215		}
216		a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
217		ReadyCount--;
218		ReqCount++;
219		e_no = look_req(a);
220	}
221	/* send the filled request buffers to the ISDN adapter      */
222	a->ram_out(a, &PR_RAM->ReqInput,
223		   (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
224	/* if it is a 'unreturncoded' UREMOVE request, remove the  */
225	/* Id from our table after sending the request             */
226	if (this && (this->Req == UREMOVE) && this->Id) {
227		Id = this->Id;
228		e_no = a->IdTable[Id];
229		free_entity(a, e_no);
230		for (i = 0; i < 256; i++)
231		{
232			if (a->FlowControlIdTable[i] == Id)
233				a->FlowControlIdTable[i] = 0;
234		}
235		a->IdTable[Id] = 0;
236		this->Id = 0;
237	}
238}
239static byte pr_ready(ADAPTER *a)
240{
241	byte ReadyCount;
242	ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
243			    a->ram_in(a, &PR_RAM->ReqInput));
244	if (!ReadyCount) {
245		if (!a->ReadyInt) {
246			a->ram_inc(a, &PR_RAM->ReadyInt);
247			a->ReadyInt++;
248		}
249	}
250	return ReadyCount;
251}
252/*------------------------------------------------------------------*/
253/* isdn interrupt handler                                           */
254/*------------------------------------------------------------------*/
255byte pr_dpc(ADAPTER *a)
256{
257	byte Count;
258	RC *RcIn;
259	IND *IndIn;
260	byte c;
261	byte RNRId;
262	byte Rc;
263	byte Ind;
264	/* if return codes are available ...                        */
265	if ((Count = a->ram_in(a, &PR_RAM->RcOutput)) != 0) {
266		dtrc(dprintf("#Rc=%x", Count));
267		/* get the buffer address of the first return code          */
268		RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
269		/* for all return codes do ...                              */
270		while (Count--) {
271			if ((Rc = a->ram_in(a, &RcIn->Rc)) != 0) {
272				dword tmp[2];
273				/*
274				  Get extended information, associated with return code
275				*/
276				a->ram_in_buffer(a,
277						 &RcIn->Reserved2[0],
278						 (byte *)&tmp[0],
279						 8);
280				/* call return code handler, if it is not our return code   */
281				/* the handler returns 2                                    */
282				/* for all return codes we process, we clear the Rc field   */
283				isdn_rc(a,
284					Rc,
285					a->ram_in(a, &RcIn->RcId),
286					a->ram_in(a, &RcIn->RcCh),
287					a->ram_inw(a, &RcIn->Reference),
288					tmp[0],  /* type of extended information */
289					tmp[1]); /* extended information        */
290				a->ram_out(a, &RcIn->Rc, 0);
291			}
292			/* get buffer address of next return code                   */
293			RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
294		}
295		/* clear all return codes (no chaining!)                    */
296		a->ram_out(a, &PR_RAM->RcOutput, 0);
297		/* call output function                                     */
298		pr_out(a);
299	}
300	/* clear RNR flag                                           */
301	RNRId = 0;
302	/* if indications are available ...                         */
303	if ((Count = a->ram_in(a, &PR_RAM->IndOutput)) != 0) {
304		dtrc(dprintf("#Ind=%x", Count));
305		/* get the buffer address of the first indication           */
306		IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
307		/* for all indications do ...                               */
308		while (Count--) {
309			/* if the application marks an indication as RNR, all       */
310			/* indications from the same Id delivered in this interrupt */
311			/* are marked RNR                                           */
312			if (RNRId && RNRId == a->ram_in(a, &IndIn->IndId)) {
313				a->ram_out(a, &IndIn->Ind, 0);
314				a->ram_out(a, &IndIn->RNR, true);
315			}
316			else {
317				Ind = a->ram_in(a, &IndIn->Ind);
318				if (Ind) {
319					RNRId = 0;
320					/* call indication handler, a return value of 2 means chain */
321					/* a return value of 1 means RNR                            */
322					/* for all indications we process, we clear the Ind field   */
323					c = isdn_ind(a,
324						     Ind,
325						     a->ram_in(a, &IndIn->IndId),
326						     a->ram_in(a, &IndIn->IndCh),
327						     &IndIn->RBuffer,
328						     a->ram_in(a, &IndIn->MInd),
329						     a->ram_inw(a, &IndIn->MLength));
330					if (c == 1) {
331						dtrc(dprintf("RNR"));
332						a->ram_out(a, &IndIn->Ind, 0);
333						RNRId = a->ram_in(a, &IndIn->IndId);
334						a->ram_out(a, &IndIn->RNR, true);
335					}
336				}
337			}
338			/* get buffer address of next indication                    */
339			IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
340		}
341		a->ram_out(a, &PR_RAM->IndOutput, 0);
342	}
343	return false;
344}
345byte scom_test_int(ADAPTER *a)
346{
347	return a->ram_in(a, (void *)0x3fe);
348}
349void scom_clear_int(ADAPTER *a)
350{
351	a->ram_out(a, (void *)0x3fe, 0);
352}
353/*------------------------------------------------------------------*/
354/* return code handler                                              */
355/*------------------------------------------------------------------*/
356static byte isdn_rc(ADAPTER *a,
357		    byte Rc,
358		    byte Id,
359		    byte Ch,
360		    word Ref,
361		    dword extended_info_type,
362		    dword extended_info)
363{
364	ENTITY *this;
365	byte e_no;
366	word i;
367	int cancel_rc;
368#ifdef USE_EXTENDED_DEBUGS
369	{
370		DBG_TRC(("<A%d Id=0x%x Rc=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Rc))
371			}
372#else
373	dbug(dprintf("isdn_rc(Rc=%x,Id=%x,Ch=%x)", Rc, Id, Ch));
374#endif
375	/* check for ready interrupt                                */
376	if (Rc == READY_INT) {
377		xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 0, 0);
378		if (a->ReadyInt) {
379			a->ReadyInt--;
380			return 0;
381		}
382		return 2;
383	}
384	/* if we know this Id ...                                   */
385	e_no = a->IdTable[Id];
386	if (e_no) {
387		this = entity_ptr(a, e_no);
388		xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 0, a->IdTypeTable[this->No]);
389		this->RcCh = Ch;
390		/* if it is a return code to a REMOVE request, remove the   */
391		/* Id from our table                                        */
392		if ((a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_REMOVE_PENDING) &&
393		    (Rc == OK)) {
394			if (a->IdTypeTable[e_no] == NL_ID) {
395				if (a->RcExtensionSupported &&
396				    (extended_info_type != DIVA_RC_TYPE_REMOVE_COMPLETE)) {
397					dtrc(dprintf("XDI: N-REMOVE, A(%02x) Id:%02x, ignore RC=OK",
398						     XDI_A_NR(a), Id));
399					return (0);
400				}
401				if (extended_info_type == DIVA_RC_TYPE_REMOVE_COMPLETE)
402					a->RcExtensionSupported = true;
403			}
404			a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_REMOVE_PENDING;
405			a->misc_flags_table[e_no] &= ~DIVA_MISC_FLAGS_NO_RC_CANCELLING;
406			free_entity(a, e_no);
407			for (i = 0; i < 256; i++)
408			{
409				if (a->FlowControlIdTable[i] == Id)
410					a->FlowControlIdTable[i] = 0;
411			}
412			a->IdTable[Id] = 0;
413			this->Id = 0;
414			/* ---------------------------------------------------------------
415			   If we send N_DISC or N_DISK_ACK after we have received OK_FC
416			   then the card will respond with OK_FC and later with RC==OK.
417			   If we send N_REMOVE in this state we will receive only RC==OK
418			   This will create the state in that the XDI is waiting for the
419			   additional RC and does not delivery the RC to the client. This
420			   code corrects the counter of outstanding RC's in this case.
421			   --------------------------------------------------------------- */
422			if ((this->More & XMOREC) > 1) {
423				this->More &= ~XMOREC;
424				this->More |= 1;
425				dtrc(dprintf("XDI: correct MORE on REMOVE A(%02x) Id:%02x",
426					     XDI_A_NR(a), Id));
427			}
428		}
429		if (Rc == OK_FC) {
430			a->FlowControlIdTable[Ch] = Id;
431			a->FlowControlSkipTable[Ch] = false;
432			this->Rc = Rc;
433			this->More &= ~(XBUSY | XMOREC);
434			this->complete = 0xff;
435			xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
436			CALLBACK(a, this);
437			return 0;
438		}
439		/*
440		  New protocol code sends return codes that comes from release
441		  of flow control condition marked with DIVA_RC_TYPE_OK_FC extended
442		  information element type.
443		  If like return code arrives then application is able to process
444		  all return codes self and XDI should not cances return codes.
445		  This return code does not decrement XMOREC partial return code
446		  counter due to fact that it was no request for this return code,
447		  also XMOREC was not incremented.
448		*/
449		if (extended_info_type == DIVA_RC_TYPE_OK_FC) {
450			a->misc_flags_table[e_no] |= DIVA_MISC_FLAGS_NO_RC_CANCELLING;
451			this->Rc = Rc;
452			this->complete = 0xff;
453			xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
454			DBG_TRC(("XDI OK_FC A(%02x) Id:%02x Ch:%02x Rc:%02x",
455				 XDI_A_NR(a), Id, Ch, Rc))
456				CALLBACK(a, this);
457			return 0;
458		}
459		cancel_rc = !(a->misc_flags_table[e_no] & DIVA_MISC_FLAGS_NO_RC_CANCELLING);
460		if (cancel_rc && (a->FlowControlIdTable[Ch] == Id))
461		{
462			a->FlowControlIdTable[Ch] = 0;
463			if ((Rc != OK) || !a->FlowControlSkipTable[Ch])
464			{
465				this->Rc = Rc;
466				if (Ch == this->ReqCh)
467				{
468					this->More &= ~(XBUSY | XMOREC);
469					this->complete = 0xff;
470				}
471				xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
472				CALLBACK(a, this);
473			}
474			return 0;
475		}
476		if (this->More & XMOREC)
477			this->More--;
478		/* call the application callback function                   */
479		if (((!cancel_rc) || (this->More & XMOREF)) && !(this->More & XMOREC)) {
480			this->Rc = Rc;
481			this->More &= ~XBUSY;
482			this->complete = 0xff;
483			xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 1, a->IdTypeTable[this->No]);
484			CALLBACK(a, this);
485		}
486		return 0;
487	}
488	/* if it's an ASSIGN return code check if it's a return     */
489	/* code to an ASSIGN request from us                        */
490	if ((Rc & 0xf0) == ASSIGN_RC) {
491		e_no = get_assign(a, Ref);
492		if (e_no) {
493			this = entity_ptr(a, e_no);
494			this->Id = Id;
495			xdi_xlog_rc_event(XDI_A_NR(a), Id, Ch, Rc, 2, a->IdTypeTable[this->No]);
496			/* call the application callback function                   */
497			this->Rc = Rc;
498			this->More &= ~XBUSY;
499			this->complete = 0xff;
500#if defined(DIVA_ISTREAM) /* { */
501			if ((Rc == ASSIGN_OK) && a->ram_offset &&
502			    (a->IdTypeTable[this->No] == NL_ID) &&
503			    ((extended_info_type == DIVA_RC_TYPE_RX_DMA) ||
504			     (extended_info_type == DIVA_RC_TYPE_CMA_PTR)) &&
505			    extended_info) {
506				dword offset = (*(a->ram_offset)) (a);
507				dword tmp[2];
508				extended_info -= offset;
509#ifdef PLATFORM_GT_32BIT
510				a->ram_in_dw(a, (void *)ULongToPtr(extended_info), (dword *)&tmp[0], 2);
511#else
512				a->ram_in_dw(a, (void *)extended_info, (dword *)&tmp[0], 2);
513#endif
514				a->tx_stream[Id]  = tmp[0];
515				a->rx_stream[Id]  = tmp[1];
516				if (extended_info_type == DIVA_RC_TYPE_RX_DMA) {
517					DBG_TRC(("Id=0x%x RxDMA=%08x:%08x",
518						 Id, a->tx_stream[Id], a->rx_stream[Id]))
519						a->misc_flags_table[this->No] |= DIVA_MISC_FLAGS_RX_DMA;
520				} else {
521					DBG_TRC(("Id=0x%x CMA=%08x:%08x",
522						 Id, a->tx_stream[Id], a->rx_stream[Id]))
523						a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
524					a->rx_pos[Id]     = 0;
525					a->rx_stream[Id] -= offset;
526				}
527				a->tx_pos[Id]     = 0;
528				a->tx_stream[Id] -= offset;
529			} else {
530				a->tx_stream[Id] = 0;
531				a->rx_stream[Id] = 0;
532				a->misc_flags_table[this->No] &= ~DIVA_MISC_FLAGS_RX_DMA;
533			}
534#endif /* } */
535			CALLBACK(a, this);
536			if (Rc == ASSIGN_OK) {
537				a->IdTable[Id] = e_no;
538			}
539			else
540			{
541				free_entity(a, e_no);
542				for (i = 0; i < 256; i++)
543				{
544					if (a->FlowControlIdTable[i] == Id)
545						a->FlowControlIdTable[i] = 0;
546				}
547				a->IdTable[Id] = 0;
548				this->Id = 0;
549			}
550			return 1;
551		}
552	}
553	return 2;
554}
555/*------------------------------------------------------------------*/
556/* indication handler                                               */
557/*------------------------------------------------------------------*/
558static byte isdn_ind(ADAPTER *a,
559		     byte Ind,
560		     byte Id,
561		     byte Ch,
562		     PBUFFER *RBuffer,
563		     byte MInd,
564		     word MLength)
565{
566	ENTITY *this;
567	word clength;
568	word offset;
569	BUFFERS *R;
570	byte *cma = NULL;
571#ifdef USE_EXTENDED_DEBUGS
572	{
573		DBG_TRC(("<A%d Id=0x%x Ind=0x%x", ((ISDN_ADAPTER *)a->io)->ANum, Id, Ind))
574			}
575#else
576	dbug(dprintf("isdn_ind(Ind=%x,Id=%x,Ch=%x)", Ind, Id, Ch));
577#endif
578	if (a->IdTable[Id]) {
579		this = entity_ptr(a, a->IdTable[Id]);
580		this->IndCh = Ch;
581		xdi_xlog_ind(XDI_A_NR(a), Id, Ch, Ind,
582			     0/* rnr_valid */, 0 /* rnr */, a->IdTypeTable[this->No]);
583		/* if the Receive More flag is not yet set, this is the     */
584		/* first buffer of the packet                               */
585		if (this->RCurrent == 0xff) {
586			/* check for receive buffer chaining                        */
587			if (Ind == this->MInd) {
588				this->complete = 0;
589				this->Ind = MInd;
590			}
591			else {
592				this->complete = 1;
593				this->Ind = Ind;
594			}
595			/* call the application callback function for the receive   */
596			/* look ahead                                               */
597			this->RLength = MLength;
598#if defined(DIVA_ISTREAM)
599			if ((a->rx_stream[this->Id] ||
600			     (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA)) &&
601			    ((Ind == N_DATA) ||
602			     (a->protocol_capabilities & PROTCAP_CMA_ALLPR))) {
603				PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io;
604				if (a->misc_flags_table[this->No] & DIVA_MISC_FLAGS_RX_DMA) {
605#if defined(DIVA_IDI_RX_DMA)
606					dword d;
607					diva_get_dma_map_entry(\
608						(struct _diva_dma_map_entry *)IoAdapter->dma_map,
609						(int)a->rx_stream[this->Id], (void **)&cma, &d);
610#else
611					cma = &a->stream_buffer[0];
612					cma[0] = cma[1] = cma[2] = cma[3] = 0;
613#endif
614					this->RLength = MLength = (word)*(dword *)cma;
615					cma += 4;
616				} else {
617					int final = 0;
618					cma = &a->stream_buffer[0];
619					this->RLength = MLength = (word)diva_istream_read(a,
620											  Id,
621											  cma,
622											  sizeof(a->stream_buffer),
623											  &final, NULL, NULL);
624				}
625				IoAdapter->RBuffer.length = min(MLength, (word)270);
626				if (IoAdapter->RBuffer.length != MLength) {
627					this->complete = 0;
628				} else {
629					this->complete = 1;
630				}
631				memcpy(IoAdapter->RBuffer.P, cma, IoAdapter->RBuffer.length);
632				this->RBuffer = (DBUFFER *)&IoAdapter->RBuffer;
633			}
634#endif
635			if (!cma) {
636				a->ram_look_ahead(a, RBuffer, this);
637			}
638			this->RNum = 0;
639			CALLBACK(a, this);
640			/* map entity ptr, selector could be re-mapped by call to   */
641			/* IDI from within callback                                 */
642			this = entity_ptr(a, a->IdTable[Id]);
643			xdi_xlog_ind(XDI_A_NR(a), Id, Ch, Ind,
644				     1/* rnr_valid */, this->RNR/* rnr */, a->IdTypeTable[this->No]);
645			/* check for RNR                                            */
646			if (this->RNR == 1) {
647				this->RNR = 0;
648				return 1;
649			}
650			/* if no buffers are provided by the application, the       */
651			/* application want to copy the data itself including       */
652			/* N_MDATA/LL_MDATA chaining                                */
653			if (!this->RNR && !this->RNum) {
654				xdi_xlog_ind(XDI_A_NR(a), Id, Ch, Ind,
655					     2/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
656				return 0;
657			}
658			/* if there is no RNR, set the More flag                    */
659			this->RCurrent = 0;
660			this->ROffset = 0;
661		}
662		if (this->RNR == 2) {
663			if (Ind != this->MInd) {
664				this->RCurrent = 0xff;
665				this->RNR = 0;
666			}
667			return 0;
668		}
669		/* if we have received buffers from the application, copy   */
670		/* the data into these buffers                              */
671		offset = 0;
672		R = PTR_R(a, this);
673		do {
674			if (this->ROffset == R[this->RCurrent].PLength) {
675				this->ROffset = 0;
676				this->RCurrent++;
677			}
678			if (cma) {
679				clength = min(MLength, (word)(R[this->RCurrent].PLength-this->ROffset));
680			} else {
681				clength = min(a->ram_inw(a, &RBuffer->length)-offset,
682					      R[this->RCurrent].PLength-this->ROffset);
683			}
684			if (R[this->RCurrent].P) {
685				if (cma) {
686					memcpy(PTR_P(a, this, &R[this->RCurrent].P[this->ROffset]),
687					       &cma[offset],
688					       clength);
689				} else {
690					a->ram_in_buffer(a,
691							 &RBuffer->P[offset],
692							 PTR_P(a, this, &R[this->RCurrent].P[this->ROffset]),
693							 clength);
694				}
695			}
696			offset += clength;
697			this->ROffset += clength;
698			if (cma) {
699				if (offset >= MLength) {
700					break;
701				}
702				continue;
703			}
704		} while (offset < (a->ram_inw(a, &RBuffer->length)));
705		/* if it's the last buffer of the packet, call the          */
706		/* application callback function for the receive complete   */
707		/* call                                                     */
708		if (Ind != this->MInd) {
709			R[this->RCurrent].PLength = this->ROffset;
710			if (this->ROffset) this->RCurrent++;
711			this->RNum = this->RCurrent;
712			this->RCurrent = 0xff;
713			this->Ind = Ind;
714			this->complete = 2;
715			xdi_xlog_ind(XDI_A_NR(a), Id, Ch, Ind,
716				     3/* rnr_valid */, 0/* rnr */, a->IdTypeTable[this->No]);
717			CALLBACK(a, this);
718		}
719		return 0;
720	}
721	return 2;
722}
723#if defined(XDI_USE_XLOG)
724/* -----------------------------------------------------------
725   This function works in the same way as xlog on the
726   active board
727   ----------------------------------------------------------- */
728static void xdi_xlog(byte *msg, word code, int length) {
729	xdi_dbg_xlog("\x00\x02", msg, code, length);
730}
731#endif
732/* -----------------------------------------------------------
733   This function writes the information about the Return Code
734   processing in the trace buffer. Trace ID is 221.
735   INPUT:
736   Adapter - system unicue adapter number (0 ... 255)
737   Id      - Id of the entity that had sent this return code
738   Ch      - Channel of the entity that had sent this return code
739   Rc      - return code value
740   cb:       (0...2)
741   switch (cb) {
742   case 0: printf ("DELIVERY"); break;
743   case 1: printf ("CALLBACK"); break;
744   case 2: printf ("ASSIGN"); break;
745   }
746   DELIVERY - have entered isdn_rc with this RC
747   CALLBACK - about to make callback to the application
748   for this RC
749   ASSIGN   - about to make callback for RC that is result
750   of ASSIGN request. It is no DELIVERY message
751   before of this message
752   type   - the Id that was sent by the ASSIGN of this entity.
753   This should be global Id like NL_ID, DSIG_ID, MAN_ID.
754   An unknown Id will cause "?-" in the front of the request.
755   In this case the log.c is to be extended.
756   ----------------------------------------------------------- */
757static void xdi_xlog_rc_event(byte Adapter,
758			      byte Id, byte Ch, byte Rc, byte cb, byte type) {
759#if defined(XDI_USE_XLOG)
760	word LogInfo[4];
761	PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
762	PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
763	PUT_WORD(&LogInfo[2], ((word)Rc | (word)(type << 8)));
764	PUT_WORD(&LogInfo[3], cb);
765	xdi_xlog((byte *)&LogInfo[0], 221, sizeof(LogInfo));
766#endif
767}
768/* ------------------------------------------------------------------------
769   This function writes the information about the request processing
770   in the trace buffer. Trace ID is 220.
771   INPUT:
772   Adapter - system unicue adapter number (0 ... 255)
773   Id      - Id of the entity that had sent this request
774   Ch      - Channel of the entity that had sent this request
775   Req     - Code of the request
776   type    - the Id that was sent by the ASSIGN of this entity.
777   This should be global Id like NL_ID, DSIG_ID, MAN_ID.
778   An unknown Id will cause "?-" in the front of the request.
779   In this case the log.c is to be extended.
780   ------------------------------------------------------------------------ */
781static void xdi_xlog_request(byte Adapter, byte Id,
782			     byte Ch, byte Req, byte type) {
783#if defined(XDI_USE_XLOG)
784	word LogInfo[3];
785	PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
786	PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
787	PUT_WORD(&LogInfo[2], ((word)Req | (word)(type << 8)));
788	xdi_xlog((byte *)&LogInfo[0], 220, sizeof(LogInfo));
789#endif
790}
791/* ------------------------------------------------------------------------
792   This function writes the information about the indication processing
793   in the trace buffer. Trace ID is 222.
794   INPUT:
795   Adapter - system unicue adapter number (0 ... 255)
796   Id      - Id of the entity that had sent this indication
797   Ch      - Channel of the entity that had sent this indication
798   Ind     - Code of the indication
799   rnr_valid: (0 .. 3) supported
800   switch (rnr_valid) {
801   case 0: printf ("DELIVERY"); break;
802   case 1: printf ("RNR=%d", rnr);
803   case 2: printf ("RNum=0");
804   case 3: printf ("COMPLETE");
805   }
806   DELIVERY - indication entered isdn_rc function
807   RNR=...  - application had returned RNR=... after the
808   look ahead callback
809   RNum=0   - application had not returned any buffer to copy
810   this indication and will copy it self
811   COMPLETE - XDI had copied the data to the buffers provided
812   bu the application and is about to issue the
813   final callback
814   rnr:  Look case 1 of the rnr_valid
815   type: the Id that was sent by the ASSIGN of this entity. This should
816   be global Id like NL_ID, DSIG_ID, MAN_ID. An unknown Id will
817   cause "?-" in the front of the request. In this case the
818   log.c is to be extended.
819   ------------------------------------------------------------------------ */
820static void xdi_xlog_ind(byte Adapter,
821			 byte Id,
822			 byte Ch,
823			 byte Ind,
824			 byte rnr_valid,
825			 byte rnr,
826			 byte type) {
827#if defined(XDI_USE_XLOG)
828	word LogInfo[4];
829	PUT_WORD(&LogInfo[0], ((word)Adapter | (word)(xdi_xlog_sec++ << 8)));
830	PUT_WORD(&LogInfo[1], ((word)Id | (word)(Ch << 8)));
831	PUT_WORD(&LogInfo[2], ((word)Ind | (word)(type << 8)));
832	PUT_WORD(&LogInfo[3], ((word)rnr | (word)(rnr_valid << 8)));
833	xdi_xlog((byte *)&LogInfo[0], 222, sizeof(LogInfo));
834#endif
835}
836