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