1 /*
2  * Core driver for Diva Server cards
3  * Implements the IDI interface
4  *
5  * Copyright (C) Eicon Technology Corporation, 2000.
6  *
7  * Eicon File Revision :    1.8
8  *
9  * This software may be used and distributed according to the terms
10  * of the GNU General Public License, incorporated herein by reference.
11  *
12  */
13 
14 #include "idi.h"
15 #include "adapter.h"
16 #include "pc.h"
17 #include "pr_pc.h"
18 #include "sys.h"
19 #include "uxio.h"
20 
21 /* IDI request functions */
22 
23 static void	request(card_t *card, ENTITY *e);
24 
req_0(ENTITY * e)25 static void req_0(ENTITY *e)	{ request(&DivasCards[ 0], e); }
req_1(ENTITY * e)26 static void req_1(ENTITY *e)	{ request(&DivasCards[ 1], e); }
req_2(ENTITY * e)27 static void req_2(ENTITY *e)	{ request(&DivasCards[ 2], e); }
req_3(ENTITY * e)28 static void req_3(ENTITY *e)	{ request(&DivasCards[ 3], e); }
req_4(ENTITY * e)29 static void req_4(ENTITY *e)	{ request(&DivasCards[ 4], e); }
req_5(ENTITY * e)30 static void req_5(ENTITY *e)	{ request(&DivasCards[ 5], e); }
req_6(ENTITY * e)31 static void req_6(ENTITY *e)	{ request(&DivasCards[ 6], e); }
req_7(ENTITY * e)32 static void req_7(ENTITY *e)	{ request(&DivasCards[ 7], e); }
req_8(ENTITY * e)33 static void req_8(ENTITY *e)	{ request(&DivasCards[ 8], e); }
req_9(ENTITY * e)34 static void req_9(ENTITY *e)	{ request(&DivasCards[ 9], e); }
req_10(ENTITY * e)35 static void req_10(ENTITY *e)	{ request(&DivasCards[10], e); }
req_11(ENTITY * e)36 static void req_11(ENTITY *e)	{ request(&DivasCards[11], e); }
req_12(ENTITY * e)37 static void req_12(ENTITY *e)	{ request(&DivasCards[12], e); }
req_13(ENTITY * e)38 static void req_13(ENTITY *e)	{ request(&DivasCards[13], e); }
req_14(ENTITY * e)39 static void req_14(ENTITY *e)	{ request(&DivasCards[14], e); }
req_15(ENTITY * e)40 static void req_15(ENTITY *e)	{ request(&DivasCards[15], e); }
41 
42 IDI_CALL DivasIdiRequest[16] =
43 {
44     &req_0,		&req_1,		&req_2,		&req_3,
45     &req_4,		&req_5,		&req_6,		&req_7,
46     &req_8,		&req_9,		&req_10,	&req_11,
47 	&req_12,	&req_13,	&req_14,	&req_15
48 };
49 
50 #define PR_RAM  ((struct pr_ram *)0)
51 #define RAM ((struct dual *)0)
52 
53 /*------------------------------------------------------------------*/
54 /* local function prototypes                                        */
55 /*------------------------------------------------------------------*/
56 
57 static byte isdn_rc(ADAPTER *, byte, byte, byte, word);
58 static byte isdn_ind(ADAPTER *, byte, byte, byte, PBUFFER *, byte, word);
59 
60 /*
61  * IDI related functions
62  */
63 
64 static
entity_ptr(ADAPTER * a,byte e_no)65 ENTITY	*entity_ptr(ADAPTER *a, byte e_no)
66 {
67 	card_t	*card;
68 
69 	card = a->io;
70 
71 	return card->e_tbl[e_no].e;
72 }
73 
74 static
CALLBACK(ADAPTER * a,ENTITY * e)75 void	CALLBACK(ADAPTER *a, ENTITY *e)
76 {
77 	card_t	*card = a->io;
78 
79 	if (card->log_types & DIVAS_LOG_IDI)
80 	{
81 		DivasLogIdi(card, e, FALSE);
82 	}
83 
84 	(*e->callback)(e);
85 }
86 
87 static
PTR_P(ADAPTER * a,ENTITY * e,void * P)88 void	*PTR_P(ADAPTER *a, ENTITY *e, void *P)
89 {
90 	return(P);
91 }
92 
93 static
PTR_R(ADAPTER * a,ENTITY * e)94 void	*PTR_R(ADAPTER *a, ENTITY *e)
95 {
96 	return((void*)e->R);
97 }
98 
99 static
PTR_X(ADAPTER * a,ENTITY * e)100 void	*PTR_X(ADAPTER *a, ENTITY *e)
101 {
102 	return((void*)e->X);
103 }
104 
105 static
free_entity(ADAPTER * a,byte e_no)106 void	free_entity(ADAPTER *a, byte e_no)
107 {
108 	card_t	*card;
109 	int		ipl;
110 
111 	card = a->io;
112 
113 	ipl = UxCardLock(card->hw);
114 
115 	card->e_tbl[e_no].e = NULL;
116 	card->e_count--;
117 
118 	UxCardUnlock(card->hw, ipl);
119 
120 	return;
121 }
122 
123 static
assign_queue(ADAPTER * a,byte e_no,word ref)124 void	assign_queue(ADAPTER * a, byte e_no, word ref)
125 {
126 	card_t	*card;
127 	int		ipl;
128 
129 	card = a->io;
130 
131 	ipl = UxCardLock(card->hw);
132 
133 	card->e_tbl[e_no].assign_ref = ref;
134 	card->e_tbl[e_no].next = card->assign;
135 	card->assign = e_no;
136 
137 	UxCardUnlock(card->hw, ipl);
138 
139 	return;
140 }
141 
142 static
get_assign(ADAPTER * a,word ref)143 byte	get_assign(ADAPTER *a, word ref)
144 {
145 	card_t	*card;
146 	byte	e_no;
147 	int		ipl;
148 
149 	card = a->io;
150 
151 	ipl = UxCardLock(card->hw);
152 
153 	e_no = (byte)card->assign;
154 	while (e_no)
155 	{
156 		if (card->e_tbl[e_no].assign_ref == ref)
157 		{
158 			break;
159 		}
160 		e_no = card->e_tbl[e_no].next;
161 	}
162 
163 	UxCardUnlock(card->hw, ipl);
164 
165 	return e_no;
166 }
167 
168 static
req_queue(ADAPTER * a,byte e_no)169 void	req_queue(ADAPTER * a, byte e_no)
170 {
171 	card_t	*card;
172 	int		ipl;
173 
174 	card = a->io;
175 
176 	ipl = UxCardLock(card->hw);
177 
178 	card->e_tbl[e_no].next = 0;
179 
180 	if (card->e_head)
181 	{
182 		card->e_tbl[card->e_tail].next = e_no;
183 		card->e_tail = e_no;
184 	}
185 	else
186 	{
187 		card->e_head = e_no;
188 		card->e_tail = e_no;
189 	}
190 
191 	UxCardUnlock(card->hw, ipl);
192 
193 	return;
194 }
195 
196 static
look_req(ADAPTER * a)197 byte	look_req(ADAPTER * a)
198 {
199 	card_t	*card;
200 
201 	card = a->io;
202 
203 	return(card->e_head);
204 }
205 
206 static
next_req(ADAPTER * a)207 void	next_req(ADAPTER * a)
208 {
209 	card_t	*card;
210 	int		ipl;
211 
212 
213 	card = a->io;
214 
215 	ipl = UxCardLock(card->hw);
216 
217 	card->e_head = card->e_tbl[card->e_head].next;
218 	if (!card->e_head)
219 	{
220 		card->e_tail = 0;
221 	}
222 
223 	UxCardUnlock(card->hw, ipl);
224 
225 	return;
226 }
227 
228 
229 /*
230  * IDI request function for active cards
231  */
232 static
request(card_t * card,ENTITY * e)233 void	request(card_t *card, ENTITY *e)
234 {
235 	word	*special_req;
236 	int		i;
237 	int		ipl;
238 
239 
240 	if (card->log_types & DIVAS_LOG_IDI)
241 	{
242 		DivasLogIdi(card, e, TRUE);
243 	}
244 
245 	if (!e->Req)
246 	{
247 		special_req = (word *) e;
248 
249 		switch (*special_req)
250 		{
251 		case REQ_REMOVE:
252 			return;
253 
254 		case REQ_NAME:
255 			for (i=0; i < DIM(card->cfg.name); i++)
256 			{
257 				((struct get_name_s *) e)->name[i] = card->cfg.name[i];
258 			}
259 			return;
260 
261 		case REQ_SERIAL:
262 		case REQ_XLOG:
263 			DPRINTF(("IDI: attempted REQ_SERIAL or REQ_XLOG"));
264 			return;
265 
266 		default:
267 			return;
268 		}
269 	}
270 
271 	ipl = UxCardLock(card->hw);
272 
273    	if (!(e->Id & 0x1f))
274 	{
275 		DPRINTF(("IDI: ASSIGN req"));
276 
277 		for (i = 1; i < card->e_max; i++)
278 		{
279 			if (!card->e_tbl[i].e)
280 			{
281 				break;
282 			}
283 		}
284 
285 		if (i == card->e_max)
286 		{
287 			DPRINTF(("IDI: request all ids in use (IDI req ignored)"));
288 			UxCardUnlock(card->hw, ipl);
289 			e->Rc = OUT_OF_RESOURCES;
290 			return;
291 		}
292 
293 		card->e_tbl[i].e = e;
294 		card->e_count++;
295 
296 		e->No = (byte) i;
297 		e->More = 0;
298 		e->RCurrent = 0xff;
299 	}
300 	else
301 	{
302 		i = e->No;
303 	}
304 
305     if (e->More & XBUSY)
306 	{
307 		DPRINTF(("IDI: request - entity is busy"));
308 		UxCardUnlock(card->hw, ipl);
309 		return;
310 	}
311 
312 	e->More |= XBUSY;
313 	e->More &= ~ XMOREF;
314 	e->XCurrent = 0;
315 	e->XOffset = 0;
316 
317 	card->e_tbl[i].next = 0;
318 
319 	if(card->e_head)
320 	{
321 		card->e_tbl[card->e_tail].next = i;
322 		card->e_tail = i;
323 	}
324 	else
325 	{
326 		card->e_head = i;
327 		card->e_tail = i;
328 	}
329 
330 	UxCardUnlock(card->hw, ipl);
331 
332 	DivasScheduleRequestDpc();
333 
334 	return;
335 }
336 
pr_ready(ADAPTER * a)337 static byte pr_ready(ADAPTER * a)
338 {
339   byte ReadyCount;
340 
341   ReadyCount = (byte)(a->ram_in(a, &PR_RAM->ReqOutput) -
342                       a->ram_in(a, &PR_RAM->ReqInput));
343 
344   if(!ReadyCount) {
345     if(!a->ReadyInt) {
346       a->ram_inc(a, &PR_RAM->ReadyInt);
347       a->ReadyInt++;
348     }
349   }
350   return ReadyCount;
351 }
352 
353 /*------------------------------------------------------------------*/
354 /* output function                                                  */
355 /*------------------------------------------------------------------*/
356 
DivasOut(ADAPTER * a)357 void DivasOut(ADAPTER * a)
358 {
359   byte e_no;
360   ENTITY  * this = NULL;
361   BUFFERS  *X;
362   word length;
363   word i;
364   word clength;
365   REQ * ReqOut;
366   byte more;
367   byte ReadyCount;
368   byte ReqCount;
369   byte Id;
370 
371         /* while a request is pending ...                           */
372   e_no = look_req(a);
373   if(!e_no)
374   {
375     return;
376   }
377 
378   ReadyCount = pr_ready(a);
379   if(!ReadyCount)
380   {
381     DPRINTF(("IDI: card not ready for next request"));
382     return;
383   }
384 
385   ReqCount = 0;
386   while(e_no && ReadyCount) {
387 
388     next_req(a);
389 
390     this = entity_ptr(a, e_no);
391 
392 #ifdef	USE_EXTENDED_DEBUGS
393 	if ( !this )
394 	{
395 		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
396 		DBG_FTL(("!A%d ==> NULL entity ptr - try to ignore", (int)io->ANum))
397 		e_no = look_req(a) ;
398 		ReadyCount-- ;
399 		continue ;
400 	}
401 	{
402 		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
403 		DPRINTF(("IDI: >A%d Id=0x%x Req=0x%x", io->ANum, this->Id, this->Req))
404 	}
405 #else
406     DPRINTF(("IDI: >REQ=%x,Id=%x,Ch=%x",this->Req,this->Id,this->ReqCh));
407 #endif
408 
409         /* get address of next available request buffer             */
410     ReqOut = (REQ *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextReq)];
411 
412         /* now copy the data from the current data buffer into the  */
413         /* adapters request buffer                                  */
414     length = 0;
415     i = this->XCurrent;
416     X = PTR_X(a,this);
417     while(i<this->XNum && length<270) {
418       clength = (word)(270-length);
419       if (clength > X[i].PLength-this->XOffset)
420 	      clength = X[i].PLength-this->XOffset;
421       a->ram_out_buffer(a,
422                         &ReqOut->XBuffer.P[length],
423                         PTR_P(a,this,&X[i].P[this->XOffset]),
424                         clength);
425 
426       length +=clength;
427       this->XOffset +=clength;
428       if(this->XOffset==X[i].PLength) {
429         this->XCurrent = (byte)++i;
430         this->XOffset = 0;
431       }
432     }
433 
434     a->ram_outw(a, &ReqOut->XBuffer.length, length);
435     a->ram_out(a, &ReqOut->ReqId, this->Id);
436     a->ram_out(a, &ReqOut->ReqCh, this->ReqCh);
437 
438         /* if its a specific request (no ASSIGN) ...                */
439 
440     if(this->Id &0x1f) {
441 
442         /* if buffers are left in the list of data buffers do       */
443         /* do chaining (LL_MDATA, N_MDATA)                          */
444 
445       this->More++;
446       if(i<this->XNum && this->MInd) {
447         a->ram_out(a, &ReqOut->Req, this->MInd);
448         more = TRUE;
449       }
450       else {
451         this->More |=XMOREF;
452         a->ram_out(a, &ReqOut->Req, this->Req);
453         more = FALSE;
454       }
455 
456         /* if we did chaining, this entity is put back into the     */
457         /* request queue                                            */
458 
459       if(more) {
460         req_queue(a,this->No);
461       }
462     }
463 
464         /* else it's a ASSIGN                                       */
465 
466     else {
467 
468         /* save the request code used for buffer chaining           */
469 
470       this->MInd = 0;
471       if (this->Id==BLLC_ID) this->MInd = LL_MDATA;
472       if (this->Id==NL_ID   ||
473           this->Id==TASK_ID ||
474           this->Id==MAN_ID
475         ) this->MInd = N_MDATA;
476 
477         /* send the ASSIGN                                          */
478 
479       this->More |=XMOREF;
480       a->ram_out(a, &ReqOut->Req, this->Req);
481 
482         /* save the reference of the ASSIGN                         */
483 
484       assign_queue(a, this->No, a->ram_inw(a, &ReqOut->Reference));
485     }
486     a->ram_outw(a, &PR_RAM->NextReq, a->ram_inw(a, &ReqOut->next));
487     ReadyCount--;
488     ReqCount++;
489 
490     e_no = look_req(a);
491   }
492 
493         /* send the filled request buffers to the ISDN adapter      */
494 
495   a->ram_out(a, &PR_RAM->ReqInput,
496              (byte)(a->ram_in(a, &PR_RAM->ReqInput) + ReqCount));
497 
498         /* if it is a 'unreturncoded' UREMOVE request, remove the  */
499         /* Id from our table after sending the request             */
500   if(this->Req==UREMOVE && this->Id) {
501     Id = this->Id;
502     e_no = a->IdTable[Id];
503     free_entity(a, e_no);
504     a->IdTable[Id] = 0;
505     this->Id = 0;
506   }
507 
508 }
509 
510 /*------------------------------------------------------------------*/
511 /* isdn interrupt handler                                           */
512 /*------------------------------------------------------------------*/
513 
DivasDpc(ADAPTER * a)514 byte DivasDpc(ADAPTER * a)
515 {
516   byte Count;
517   RC * RcIn;
518   IND * IndIn;
519   byte c;
520   byte RNRId;
521   byte Rc;
522   byte Ind;
523 
524         /* if return codes are available ...                        */
525   if((Count = a->ram_in(a, &PR_RAM->RcOutput))) {
526 
527     DPRINTF(("IDI: #Rc=%x",Count));
528 
529         /* get the buffer address of the first return code          */
530     RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextRc)];
531 
532         /* for all return codes do ...                              */
533     while(Count--) {
534 
535       if((Rc=a->ram_in(a, &RcIn->Rc))) {
536 
537         /* call return code handler, if it is not our return code   */
538         /* the handler returns 2                                    */
539         /* for all return codes we process, we clear the Rc field   */
540         isdn_rc(a,
541                 Rc,
542                 a->ram_in(a, &RcIn->RcId),
543                 a->ram_in(a, &RcIn->RcCh),
544                 a->ram_inw(a, &RcIn->Reference));
545 
546         a->ram_out(a, &RcIn->Rc, 0);
547       }
548 
549         /* get buffer address of next return code                   */
550       RcIn = (RC *)&PR_RAM->B[a->ram_inw(a, &RcIn->next)];
551     }
552 
553         /* clear all return codes (no chaining!)                    */
554     a->ram_out(a, &PR_RAM->RcOutput ,0);
555 
556         /* call output function                                     */
557     DivasOut(a);
558   }
559 
560         /* clear RNR flag                                           */
561   RNRId = 0;
562 
563         /* if indications are available ...                         */
564   if((Count = a->ram_in(a, &PR_RAM->IndOutput))) {
565 
566     DPRINTF(("IDI: #Ind=%x",Count));
567 
568         /* get the buffer address of the first indication           */
569     IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &PR_RAM->NextInd)];
570 
571         /* for all indications do ...                               */
572     while(Count--) {
573 
574         /* if the application marks an indication as RNR, all       */
575         /* indications from the same Id delivered in this interrupt */
576         /* are marked RNR                                           */
577       if(RNRId && RNRId==a->ram_in(a, &IndIn->IndId)) {
578         a->ram_out(a, &IndIn->Ind, 0);
579         a->ram_out(a, &IndIn->RNR, TRUE);
580       }
581       else {
582         Ind = a->ram_in(a, &IndIn->Ind);
583         if(Ind) {
584           RNRId = 0;
585 
586         /* call indication handler, a return value of 2 means chain */
587         /* a return value of 1 means RNR                            */
588         /* for all indications we process, we clear the Ind field   */
589           c = isdn_ind(a,
590                        Ind,
591                        a->ram_in(a, &IndIn->IndId),
592                        a->ram_in(a, &IndIn->IndCh),
593                        &IndIn->RBuffer,
594                        a->ram_in(a, &IndIn->MInd),
595                        a->ram_inw(a, &IndIn->MLength));
596 
597           if(c==1) {
598             DPRINTF(("IDI: RNR"));
599             a->ram_out(a, &IndIn->Ind, 0);
600             RNRId = a->ram_in(a, &IndIn->IndId);
601             a->ram_out(a, &IndIn->RNR, TRUE);
602           }
603         }
604       }
605 
606         /* get buffer address of next indication                    */
607       IndIn = (IND *)&PR_RAM->B[a->ram_inw(a, &IndIn->next)];
608     }
609 
610     a->ram_out(a, &PR_RAM->IndOutput, 0);
611   }
612   return FALSE;
613 }
614 
DivasTestInt(ADAPTER * a)615 byte DivasTestInt(ADAPTER * a)
616 {
617   return a->ram_in(a,(void *)0x3fe);
618 }
619 
DivasClearInt(ADAPTER * a)620 void DivasClearInt(ADAPTER * a)
621 {
622   a->ram_out(a,(void *)0x3fe,0);
623 }
624 
625 /*------------------------------------------------------------------*/
626 /* return code handler                                              */
627 /*------------------------------------------------------------------*/
628 
629 static
isdn_rc(ADAPTER * a,byte Rc,byte Id,byte Ch,word Ref)630 byte isdn_rc(ADAPTER * a,
631              byte Rc,
632              byte Id,
633              byte Ch,
634              word Ref)
635 {
636   ENTITY  * this;
637   byte e_no;
638 
639 #ifdef	USE_EXTENDED_DEBUGS
640 	{
641 		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
642 		DPRINTF(("IDI: <A%d Id=0x%x Rc=0x%x", io->ANum, Id, Rc))
643 	}
644 #else
645   DPRINTF(("IDI: <RC(Rc=%x,Id=%x,Ch=%x)",Rc,Id,Ch));
646 #endif
647 
648         /* check for ready interrupt                                */
649   if(Rc==READY_INT) {
650     if(a->ReadyInt) {
651       a->ReadyInt--;
652       return 0;
653     }
654     return 2;
655   }
656 
657         /* if we know this Id ...                                   */
658   e_no = a->IdTable[Id];
659   if(e_no) {
660 
661     this = entity_ptr(a,e_no);
662 
663     this->RcCh = Ch;
664 
665         /* if it is a return code to a REMOVE request, remove the   */
666         /* Id from our table                                        */
667     if(this->Req==REMOVE && Rc==OK) {
668       free_entity(a, e_no);
669       a->IdTable[Id] = 0;
670       this->Id = 0;
671 /**************************************************************/
672       if ((this->More & XMOREC) > 1) {
673         this->More &= ~XMOREC;
674 	this->More |= 1;
675 	DPRINTF(("isdn_rc, Id=%x, correct More on REMOVE", Id));
676       }
677     }
678 
679     if (Rc==OK_FC) {
680       this->Rc = Rc;
681       this->More = (this->More & (~XBUSY | XMOREC)) | 1;
682       this->complete = 0xFF;
683       CALLBACK(a, this);
684       return 0;
685     }
686     if(this->More &XMOREC)
687       this->More--;
688 
689         /* call the application callback function                   */
690     if(this->More &XMOREF && !(this->More &XMOREC)) {
691       this->Rc = Rc;
692       this->More &=~XBUSY;
693       this->complete=0xff;
694       CALLBACK(a, this);
695     }
696     return 0;
697   }
698 
699         /* if it's an ASSIGN return code check if it's a return     */
700         /* code to an ASSIGN request from us                        */
701   if((Rc &0xf0)==ASSIGN_RC) {
702 
703     e_no = get_assign(a, Ref);
704 
705     if(e_no) {
706 
707       this = entity_ptr(a,e_no);
708 
709       this->Id = Id;
710 
711         /* call the application callback function                   */
712       this->Rc = Rc;
713       this->More &=~XBUSY;
714       this->complete=0xff;
715       CALLBACK(a, this);
716 
717       if(Rc==ASSIGN_OK) {
718         a->IdTable[Id] = e_no;
719       }
720       else
721       {
722         free_entity(a, e_no);
723         a->IdTable[Id] = 0;
724         this->Id = 0;
725       }
726       return 1;
727     }
728   }
729   return 2;
730 }
731 
732 /*------------------------------------------------------------------*/
733 /* indication handler                                               */
734 /*------------------------------------------------------------------*/
735 
736 static
isdn_ind(ADAPTER * a,byte Ind,byte Id,byte Ch,PBUFFER * RBuffer,byte MInd,word MLength)737 byte isdn_ind(ADAPTER * a,
738               byte Ind,
739               byte Id,
740               byte Ch,
741               PBUFFER * RBuffer,
742               byte MInd,
743               word MLength)
744 {
745   ENTITY  * this;
746   word clength;
747   word offset;
748   BUFFERS  *R;
749 
750 #ifdef	USE_EXTENDED_DEBUGS
751 	{
752 		ISDN_ADAPTER *io = (ISDN_ADAPTER *)a->io ;
753 		DPRINTF(("IDI: <A%d Id=0x%x Ind=0x%x", io->ANum, Id, Ind))
754 	}
755 #else
756   DPRINTF(("IDI: <IND(Ind=%x,Id=%x,Ch=%x)",Ind,Id,Ch));
757 #endif
758 
759   if(a->IdTable[Id]) {
760 
761     this = entity_ptr(a,a->IdTable[Id]);
762 
763     this->IndCh = Ch;
764 
765         /* if the Receive More flag is not yet set, this is the     */
766         /* first buffer of the packet                               */
767     if(this->RCurrent==0xff) {
768 
769         /* check for receive buffer chaining                        */
770       if(Ind==this->MInd) {
771         this->complete = 0;
772         this->Ind = MInd;
773       }
774       else {
775         this->complete = 1;
776         this->Ind = Ind;
777       }
778 
779         /* call the application callback function for the receive   */
780         /* look ahead                                               */
781       this->RLength = MLength;
782 
783       a->ram_look_ahead(a, RBuffer, this);
784 
785       this->RNum = 0;
786       CALLBACK(a, this);
787 
788         /* map entity ptr, selector could be re-mapped by call to   */
789         /* IDI from within callback                                 */
790       this = entity_ptr(a,a->IdTable[Id]);
791 
792         /* check for RNR                                            */
793       if(this->RNR==1) {
794         this->RNR = 0;
795         return 1;
796       }
797 
798         /* if no buffers are provided by the application, the       */
799         /* application want to copy the data itself including       */
800         /* N_MDATA/LL_MDATA chaining                                */
801       if(!this->RNR && !this->RNum) {
802         return 0;
803       }
804 
805         /* if there is no RNR, set the More flag                    */
806       this->RCurrent = 0;
807       this->ROffset = 0;
808     }
809 
810     if(this->RNR==2) {
811       if(Ind!=this->MInd) {
812         this->RCurrent = 0xff;
813         this->RNR = 0;
814       }
815       return 0;
816     }
817         /* if we have received buffers from the application, copy   */
818         /* the data into these buffers                              */
819     offset = 0;
820     R = PTR_R(a,this);
821     do {
822       if(this->ROffset==R[this->RCurrent].PLength) {
823         this->ROffset = 0;
824         this->RCurrent++;
825       }
826       clength = a->ram_inw(a, &RBuffer->length)-offset;
827       if (clength > R[this->RCurrent].PLength-this->ROffset)
828 	      clength = R[this->RCurrent].PLength-this->ROffset;
829       if(R[this->RCurrent].P) {
830         a->ram_in_buffer(a,
831                          &RBuffer->P[offset],
832                          PTR_P(a,this,&R[this->RCurrent].P[this->ROffset]),
833                          clength);
834       }
835       offset +=clength;
836       this->ROffset +=clength;
837     } while(offset<(a->ram_inw(a, &RBuffer->length)));
838 
839         /* if it's the last buffer of the packet, call the          */
840         /* application callback function for the receive complete   */
841         /* call                                                     */
842     if(Ind!=this->MInd) {
843       R[this->RCurrent].PLength = this->ROffset;
844       if(this->ROffset) this->RCurrent++;
845       this->RNum = this->RCurrent;
846       this->RCurrent = 0xff;
847       this->Ind = Ind;
848       this->complete = 2;
849       CALLBACK(a, this);
850     }
851     return 0;
852   }
853   return 2;
854 }
855