]> Git Repo - binutils.git/blob - gdb/rdi-share/hostchan.c
Applied patches from [email protected] to implement the Angel remote
[binutils.git] / gdb / rdi-share / hostchan.c
1 /* 
2  * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3  * 
4  * This software may be freely used, copied, modified, and distributed
5  * provided that the above copyright notice is preserved in all copies of the
6  * software.
7  */
8
9 /* -*-C-*-
10  *
11  * $Revision$
12  *     $Date$
13  *
14  *
15  * hostchan.c - Semi Synchronous Host side channel interface for Angel.
16  */
17
18 #include <stdio.h>
19
20 #if defined(__unix) || defined(__CYGWIN32__)
21 #  include <sys/time.h>
22 #  ifdef sun
23       int gettimeofday(struct timeval *tp, struct timezone *tzp);
24 #  endif
25 #else
26 #  include "winsock.h"
27 #  include "time.h"
28 #endif
29 #include "hsys.h"
30 #include "host.h"
31 #include "logging.h"
32 #include "chandefs.h"
33 #include "chanpriv.h"
34 #include "devclnt.h"
35 #include "buffers.h"
36 #include "drivers.h"
37 #include "adperr.h"
38 #include "devsw.h"
39 #include "hostchan.h"
40
41 #ifndef UNUSED
42 #define UNUSED(x) (x = x)  /* Silence compiler warnings for unused arguments */
43 #endif
44
45 #define HEARTRATE 5000000
46
47 /*
48  * list of available drivers, declared in drivers.c
49  */
50 extern DeviceDescr *devices[];
51
52 static DeviceDescr *deviceToUse = NULL;
53
54 static struct Channel {
55     ChannelCallback callback;
56     void *callback_state;
57 } channels[CI_NUM_CHANNELS];
58
59 static unsigned char HomeSeq;
60 static unsigned char OppoSeq;
61
62 /*
63  * Handler for DC_APPL packets
64  */
65 static DC_Appl_Handler dc_appl_handler = NULL;
66
67 /*
68  * slots for registered asynchronous processing callback procedures
69  */
70 #define MAX_ASYNC_CALLBACKS 8
71 static unsigned int             num_async_callbacks = 0;
72 static Adp_Async_Callback       async_callbacks[MAX_ASYNC_CALLBACKS];
73
74 /*
75  * writeQueueRoot is the queue of write requests pending acknowledgement
76  * writeQueueSend is the queue of pending write requests which will
77  * be a subset of the list writeQueueRoot
78  */
79 static Packet *writeQueueRoot = NULL;
80 static Packet *writeQueueSend = NULL;
81 static Packet *resend_pkt = NULL;
82 static int resending = FALSE;
83
84 /* heartbeat_enabled is a flag used to indicate whether the heartbeat is
85  * currently turned on, heartbeat_enabled will be false in situations
86  * where even though a heartbeat is being used it is problematical or
87  * dis-advantageous to have it turned on, for instance during the 
88  * initial stages of boot up
89  */
90 unsigned int heartbeat_enabled = FALSE;
91 /* heartbeat_configured is set up by the device driver to indicate whether
92  * the heartbeat is being used during this debug session.  In contrast to
93  * heartbeat_enabled it must not be changed during a session.  The logic for
94  * deciding whether to send a heartbeat is: Is heartbeat_configured for this
95  * session? if and only if it is then if heartbeat[is currently]_enabled and
96  * we are due to send a pulse then send it 
97  */
98 unsigned int heartbeat_configured = TRUE;
99
100 void Adp_initSeq( void ) {
101   Packet *tmp_pkt = writeQueueSend;
102
103   HomeSeq = 0;
104   OppoSeq = 0;
105   if ( writeQueueSend != NULL) {
106     while (writeQueueSend->pk_next !=NULL) {
107       tmp_pkt = writeQueueSend;
108       writeQueueSend = tmp_pkt->pk_next;
109       DevSW_FreePacket(tmp_pkt);
110     }
111   }
112   tmp_pkt = writeQueueRoot;
113   if ( writeQueueRoot == NULL)
114     return;
115
116   while (writeQueueRoot->pk_next !=NULL) {
117     tmp_pkt = writeQueueRoot;
118     writeQueueRoot = tmp_pkt->pk_next;
119     DevSW_FreePacket(tmp_pkt);
120   }
121   return;
122 }
123
124 /**********************************************************************/
125
126 /*
127  *  Function: DummyCallback
128  *   Purpose: Default callback routine to handle unexpected input
129  *              on a channel
130  *
131  *    Params:
132  *       Input: packet  The received packet
133  *
134  *              state   Contains nothing of significance
135  *
136  *   Returns: Nothing
137  */
138 static void DummyCallback(Packet *packet, void *state)
139 {
140     ChannelID chan;
141     const char fmt[] = "Unexpected read on channel %u, length %d\n";
142     char fmtbuf[sizeof(fmt) + 24];
143
144     UNUSED(state);
145
146     chan = *(packet->pk_buffer);
147     sprintf(fmtbuf, fmt, chan, packet->pk_length);
148     printf(fmtbuf);
149
150     /*
151      * junk this packet
152      */
153     DevSW_FreePacket(packet);
154 }
155
156 /*
157  *  Function: BlockingCallback
158  *   Purpose: Callback routine used to implement a blocking read call
159  *
160  *    Params:
161  *       Input: packet  The received packet.
162  *
163  *      Output: state   Address of higher level's pointer to the received
164  *                      packet.
165  *
166  *   Returns: Nothing
167  */
168 static void BlockingCallback(Packet *packet, void *state)
169 {
170     /*
171      * Pass the packet back to the caller which requested a packet
172      * from this channel.  This also flags the completion of the I/O
173      * request to the blocking read call.
174      */
175     *((Packet **)state) = packet;
176 }
177
178 /*
179  *  Function: FireCallback
180  *   Purpose: Pass received packet along to the callback routine for
181  *              the appropriate channel
182  *
183  *    Params:
184  *       Input: packet  The received packet.
185  *
186  *   Returns: Nothing
187  *
188  * Post-conditions: The Target-to-Host sequence number for the channel
189  *                      will have been incremented.
190  */
191 static void FireCallback(Packet *packet)
192 {
193     ChannelID chan;
194     struct Channel *ch;
195
196     /*
197      * is this a sensible channel number?
198      */
199     chan = *(packet->pk_buffer);
200     if (invalidChannelID(chan))
201     {
202         printf("ERROR: invalid ChannelID received from target\n");
203
204         /*
205          * free the packet's resources, 'cause no-one else will
206          */
207         DevSW_FreePacket(packet);
208         return;
209     }
210
211     /*
212      * looks OK - increment sequence number, and pass packet to callback
213      */
214     ch = channels + chan;
215     (ch->callback)(packet, ch->callback_state);
216 }
217
218 /**********************************************************************/
219
220 /*
221  * These are the externally visible functions.  They are documented
222  * in hostchan.h
223  */
224 void Adp_addToQueue(Packet **head, Packet *newpkt)
225 {
226     /*
227      * this is a bit of a hack
228      */
229     Packet *pk;
230
231     /*
232      * make sure that the hack we are about to use will work as expected
233      */
234     ASSERT(&(((Packet *)0)->pk_next) == 0, "bad struct Packet layout");
235
236 #if DEBUG && 0
237     printf("Adp_addToQueue(%p, %p)\n", head, newpkt);
238 #endif
239
240     /*
241      * here's the hack - it relies upon the next
242      * pointer being at the start of Packet.
243      */
244     pk = (Packet *)(head);
245
246     /*
247      * skip to the end of the queue
248      */
249     while (pk->pk_next != NULL)
250         pk = pk->pk_next;
251
252     /*
253      * now add the new element
254      */
255     newpkt->pk_next = NULL;
256     pk->pk_next = newpkt;
257 }
258
259 Packet *Adp_removeFromQueue(Packet **head)
260 {
261     struct Packet *pk;
262
263     pk = *head;
264
265     if (pk != NULL)
266         *head = pk->pk_next;
267
268     return pk;
269 }
270
271 AdpErrs Adp_OpenDevice(const char *name, const char *arg,
272                        unsigned int heartbeat_on)
273 {
274     int i;
275     AdpErrs retc;
276     ChannelID chan;
277
278 #ifdef DEBUG
279     printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : "<NULL>");
280 #endif
281
282     heartbeat_configured = heartbeat_on;
283     if (deviceToUse != NULL)
284         return adp_device_already_open;
285
286     for (i = 0; (deviceToUse = devices[i]) != NULL; ++i)
287         if (DevSW_Match(deviceToUse, name, arg) == adp_ok)
288             break;
289
290     if (deviceToUse == NULL)
291         return adp_device_not_found;
292
293     /*
294      * we seem to have found a suitable device driver, so try to open it
295      */
296     if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok)
297     {
298         /* we don't have a device to use */
299         deviceToUse = NULL;
300         return retc;
301     }
302
303     /*
304      * there is no explicit open on channels any more, so
305      * initialise state for all channels.
306      */
307     for (chan = 0; chan < CI_NUM_CHANNELS; ++chan)
308     {
309         struct Channel *ch = channels + chan;
310
311         ch->callback = DummyCallback;
312         ch->callback_state = NULL;
313         OppoSeq = 0;
314         HomeSeq = 0;
315     }
316
317     return adp_ok;
318 }
319
320 AdpErrs Adp_CloseDevice(void)
321 {
322     AdpErrs retc;
323
324 #ifdef DEBUG
325     printf("Adp_CloseDevice\n");
326 #endif
327
328     if (deviceToUse == NULL)
329         return adp_device_not_open;
330
331     heartbeat_enabled = FALSE;
332
333     retc = DevSW_Close(deviceToUse, DC_DBUG);
334
335     /*
336      * we have to clear deviceToUse, even when the lower layers
337      * faulted the close, otherwise the condition will never clear
338      */
339     if (retc != adp_ok)
340         WARN("DevSW_Close faulted the call");
341
342     deviceToUse = NULL;
343     return retc;
344 }
345
346 AdpErrs Adp_Ioctl(int opcode, void *args)
347 {
348 #ifdef DEBUG
349     printf("Adp_Ioctl\n");
350 #endif
351
352     if (deviceToUse == NULL)
353         return adp_device_not_open;
354
355     return DevSW_Ioctl(deviceToUse, opcode, args);
356 }
357
358 AdpErrs Adp_ChannelRegisterRead(const ChannelID chan,
359                                 const ChannelCallback cbfunc,
360                                 void *cbstate)
361 {
362 #ifdef DEBUG
363     printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate);
364 #endif
365
366     if (deviceToUse == NULL)
367         return adp_device_not_open;
368
369     if (invalidChannelID(chan))
370         return adp_bad_channel_id;
371
372     if (cbfunc == NULL)
373     {
374         channels[chan].callback = DummyCallback;
375         channels[chan].callback_state = NULL;
376     }
377     else
378     {
379         channels[chan].callback = cbfunc;
380         channels[chan].callback_state = cbstate;
381     }
382
383     return adp_ok;
384 }
385
386 AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet)
387 {
388     struct Channel *ch;
389
390 #ifdef DEBUG
391     printf("Adp_ChannelRead(%d, %x)\n", chan, *packet);
392 #endif
393
394     if (deviceToUse == NULL)
395         return adp_device_not_open;
396
397     if (invalidChannelID(chan))
398         return adp_bad_channel_id;
399
400     /*
401      * if a callback has already been registered for this
402      * channel, then we do not allow this blocking read.
403      */
404     ch = channels + chan;
405     if (ch->callback != DummyCallback)
406         return adp_callback_already_registered;
407
408     /*
409      * OK, use our own callback to wait for a packet to arrive
410      * on this channel
411      */
412     ch->callback = BlockingCallback;
413     ch->callback_state = packet;
414     *packet = NULL;
415
416     /*
417      * keep polling until a packet appears for this channel
418      */
419     while (((volatile Packet *)(*packet)) == NULL)
420         /*
421          * this call will block until a packet is read on any channel
422          */
423         Adp_AsynchronousProcessing(async_block_on_read);
424
425     /*
426      * OK, the packet has arrived: clear the callback
427      */
428     ch->callback = DummyCallback;
429     ch->callback_state = NULL;
430
431     return adp_ok;
432 }
433
434 static AdpErrs ChannelWrite(
435     const ChannelID chan, Packet *packet, AsyncMode mode)
436 {
437     struct Channel *ch;
438     unsigned char *cptr;
439
440 #ifdef DEBUG
441     printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet );
442 #endif
443
444     if (deviceToUse == NULL)
445         return adp_device_not_open;
446
447     if (invalidChannelID(chan))
448         return adp_bad_channel_id;
449
450     /*
451      * fill in the channels header at the start of this buffer
452      */
453     ch = channels + chan;
454     cptr = packet->pk_buffer;
455     *cptr++ = chan;
456     *cptr = 0;
457     packet->pk_length += CHAN_HEADER_SIZE;
458
459     /*
460      * OK, add this packet to the write queue, and try to flush it out
461      */
462
463     Adp_addToQueue(&writeQueueSend, packet);
464     Adp_AsynchronousProcessing(mode);
465
466     return adp_ok;
467 }
468
469 AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
470   return ChannelWrite(chan, packet, async_block_on_write);
471 }
472
473 AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
474   return ChannelWrite(chan, packet, async_block_on_nothing);
475 }
476
477 static AdpErrs send_resend_msg(DeviceID devid) {
478
479   /*
480    * Send a resend message, usually in response to a bad packet or
481    * a resend request */
482   Packet * packet;
483   packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
484   packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
485   packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
486   packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
487   packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND;
488   packet->pk_length = CF_DATA_BYTE_POS;
489   return DevSW_Write(deviceToUse, packet, devid);
490 }
491
492 static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) {
493   Packet *tmp_pkt;
494
495   UNUSED(msg_oppo);
496   /* 
497    * check if we have got an ack for anything and if so remove it from the
498    * queue
499    */
500   if (msg_home == (unsigned char)(OppoSeq+1)) {
501     /*
502      * arrived in sequence can increment our opposing seq number and remove
503      * the relevant packet from our queue
504      * check that the packet we're going to remove really is the right one
505      */
506     tmp_pkt = writeQueueRoot;
507     while ((tmp_pkt->pk_next != NULL) &&
508            (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS]
509             != OppoSeq)){
510       tmp_pkt = tmp_pkt->pk_next;
511     }
512     OppoSeq++;
513     if (tmp_pkt->pk_next == NULL) {
514 #ifdef DEBUG
515       printf("trying to remove a non existant packet\n");
516 #endif
517       return adp_bad_packet;
518     }
519     else {
520       Packet *tmp = tmp_pkt->pk_next;
521 #ifdef RET_DEBUG
522       printf("removing a packet from the root queue\n");
523 #endif
524       tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next;
525       /* remove the appropriate packet */
526       DevSW_FreePacket(tmp);
527     return adp_ok;
528     }
529   }
530   else if (msg_home < (unsigned char) (OppoSeq+1)){
531     /* already received this message */
532 #ifdef RET_DEBUG
533     printf("sequence numbers low\n");
534 #endif   
535     return adp_seq_low;
536   }
537   else {  /* we've missed something */
538 #ifdef RET_DEBUG
539     printf("sequence numbers high\n");
540 #endif   
541     return adp_seq_high;
542   }
543 }
544
545 static unsigned long tv_diff(const struct timeval *time_now, 
546                              const struct timeval *time_was)
547 {
548     return (  ((time_now->tv_sec * 1000000) + time_now->tv_usec)
549             - ((time_was->tv_sec * 1000000) + time_was->tv_usec) );
550 }
551
552 #if !defined(__unix) && !defined(__CYGWIN32__)
553 static void gettimeofday( struct timeval *time_now, void *dummy )
554 {
555     time_t t = clock();
556     UNUSED(dummy);
557     time_now->tv_sec = t/CLOCKS_PER_SEC;
558     time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC);
559 }
560 #endif
561
562 static AdpErrs pacemaker(void)
563 {
564   Packet *packet;
565
566   packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
567   if (packet == NULL) {
568     printf("ERROR: could not allocate a packet in pacemaker()\n");
569     return adp_malloc_failure;
570   }
571   packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
572   packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
573   packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
574   packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT;
575   packet->pk_length = CF_DATA_BYTE_POS;
576   return DevSW_Write(deviceToUse, packet, DC_DBUG);
577 }  
578
579 #ifdef FAKE_BAD_LINE_RX
580 static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err )
581 {
582     static unsigned int bl_num = 0;
583
584     if (     (packet != NULL)
585           && (bl_num++ >= 20 )
586           && ((bl_num % FAKE_BAD_LINE_RX) == 0))
587     {
588         printf("DEBUG: faking a bad packet\n");
589         return adp_bad_packet;
590     }
591     return adp_err;
592 }
593 #endif /* def FAKE_BAD_LINE_RX */
594
595 #ifdef FAKE_BAD_LINE_TX
596 static unsigned char tmp_ch;
597
598 static void fake_bad_line_tx( void )
599 {
600     static unsigned int bl_num = 0;
601
602     /* give the thing a chance to boot then try corrupting stuff */
603     if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0)) 
604     {
605         printf("DEBUG: faking a bad packet for tx\n");
606         tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS];
607         writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77;
608     }
609 }
610
611 static void unfake_bad_line_tx( void )
612 {
613     static unsigned int bl_num = 0;
614
615     /*
616      * must reset the packet so that its not corrupted when we
617      *  resend it 
618      */   
619     if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0))
620     {
621         writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch;
622     }
623 }
624 #endif /* def FAKE_BAD_LINE_TX */
625
626 /*
627  * NOTE: we are assuming that a resolution of microseconds will
628  * be good enough for the purporses of the heartbeat.  If this proves
629  * not to be the case then we may need a rethink, possibly using
630  * [get,set]itimer
631  */
632 static struct timeval time_now;
633 static struct timeval time_lastalive;
634
635 static void async_process_dbug_read( const AsyncMode mode,
636                                      bool *const finished  )
637 {
638     Packet *packet;
639     unsigned int msg_home, msg_oppo;
640     AdpErrs adp_err;
641
642     adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet,
643                          mode == async_block_on_read    );
644
645 #ifdef FAKE_BAD_LINE_RX
646     adp_err = fake_bad_line_rx( packet, adp_err );
647 #endif
648
649     if (adp_err == adp_bad_packet) {
650         /* We got a bad packet, ask for a resend, send a resend message */
651 #ifdef DEBUG
652         printf("received a bad packet\n");
653 #endif
654         send_resend_msg(DC_DBUG);
655     }
656     else if (packet != NULL)
657     {
658         /* update the heartbeat clock */
659         gettimeofday(&time_lastalive, NULL);
660
661             /*
662              * we got a live one here - were we waiting for it?
663              */
664         if (mode == async_block_on_read)
665            /* not any more */
666            *finished = TRUE;
667 #ifdef RETRANS
668
669         if (packet->pk_length < CF_DATA_BYTE_POS) {
670             /* we've got a packet with no header information! */
671             printf("ERROR: packet with no transport header\n");
672             send_resend_msg(DC_DBUG);
673         }
674         else {
675 #ifdef RET_DEBUG
676             unsigned int c;
677 #endif
678             /*
679              * TODO: Check to see if its acknowledgeing anything, remove
680              * those packets it is from the queue.  If its a retrans add the
681              * packets to the queue
682              */
683             msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS];
684             msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS];
685 #ifdef RET_DEBUG
686             printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
687                    msg_home, msg_oppo);
688             for (c=0;c<packet->pk_length;c++)
689                printf("%02.2x", packet->pk_buffer[c]);
690             printf("\n");
691 #endif
692             /* now was it a resend request? */
693             if ((packet->pk_buffer[CF_FLAGS_BYTE_POS]) 
694                 & CF_RESEND) {
695                 /* we've been asked for a resend so we had better resend */
696                 /*
697                  * I don't think we can use a resend as acknowledgement for
698                  * anything so lets not do this for the moment
699                  * check_seq(msg_home, msg_oppo);
700                  */
701 #ifdef RET_DEBUG
702                 printf("received a resend request\n");
703 #endif
704                 if (HomeSeq != msg_oppo) {
705                     int found = FALSE;
706                     /* need to resend from msg_oppo +1 upwards */
707                     DevSW_FreePacket(packet);
708                     resending = TRUE;
709                     /* find the correct packet to resend from */
710                     packet = writeQueueRoot;
711                     while (((packet->pk_next) != NULL) && !found) {
712                         if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
713                             != msg_oppo+1) {
714                             resend_pkt = packet;
715                             found = TRUE;
716                         }
717                         packet = packet->pk_next;
718                     }
719                     if (!found) {
720                         panic("trying to resend non-existent packets\n");
721                     }
722                 }
723                 else if (OppoSeq != msg_home) {
724                     /* 
725                      * send a resend request telling the target where we think
726                      * the world is at 
727                      */
728                     DevSW_FreePacket(packet);
729                     send_resend_msg(DC_DBUG);
730                 }
731             }
732             else {
733                 /* not a resend request, lets check the sequence numbers */
734                 
735                 if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) &&
736                     (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) {
737                     adp_err = check_seq(msg_home, msg_oppo);
738                     if (adp_err == adp_seq_low) {
739                         /* we have already received this packet so discard */
740                         DevSW_FreePacket(packet);
741                     }
742                     else if (adp_err == adp_seq_high) {
743                         /*
744                          * we must have missed a packet somewhere, discard this 
745                          * packet and tell the target where we are
746                          */
747                         DevSW_FreePacket(packet);
748                         send_resend_msg(DC_DBUG);
749                     }
750                     else
751                        /*
752                         * now pass the packet to whoever is waiting for it
753                         */
754                        FireCallback(packet);
755                 }
756                 else
757                    FireCallback(packet);
758             }
759         }
760 #else
761         /*
762              * now pass the packet to whoever is waiting for it
763              */
764         FireCallback(packet);
765 #endif
766     }
767 }
768
769 static void async_process_appl_read(void)
770 {
771     Packet *packet;
772     AdpErrs adp_err;
773
774     /* see if there is anything for the DC_APPL channel */
775     adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE);
776
777     if (adp_err == adp_ok && packet != NULL)
778     {
779         /* got an application packet on a shared device */
780
781 #ifdef DEBUG
782         printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length);
783         {
784             unsigned int c;
785             for ( c = 0; c < packet->pk_length; ++c )
786                printf( "%02X ", packet->pk_buffer[c] );
787         }
788         printf("\n");
789 #endif
790
791         if (dc_appl_handler != NULL)
792         {
793             dc_appl_handler( deviceToUse, packet );
794         }
795         else
796         {
797             /* for now, just free it!! */
798 #ifdef DEBUG
799             printf("no handler - dropping DC_APPL packet\n");
800 #endif
801             DevSW_FreePacket( packet );
802         }
803     }
804 }
805
806 static void async_process_write( const AsyncMode mode,
807                                  bool *const finished  )
808 {
809     Packet *packet;
810
811 #ifdef DEBUG
812     static unsigned int num_written = 0;
813 #endif
814
815     /*
816      * NOTE: here we rely in the fact that any packet in the writeQueueSend
817      * section of the queue will need its sequence number setting up while
818      * and packet in the writeQueueRoot section will have its sequence
819      * numbers set up from when it was first sent so we can easily look
820      * up the packet numbers when(if) we want to resend the packet.
821      */
822
823 #ifdef DEBUG
824     if (writeQueueSend!=NULL)
825        printf("written 0x%x\n",num_written += writeQueueSend->pk_length);
826 #endif
827     /*
828      * give the switcher a chance to complete any partial writes
829      */
830     if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy)
831     {
832         /* no point trying a new write */
833         return;
834     }
835       
836     /*
837      * now see whether there is anything to write
838      */
839     packet = NULL;
840     if (resending) {
841         packet = resend_pkt;
842 #ifdef RET_DEBUG
843         printf("resending hseq 0x%x oseq 0x%x\n", 
844                packet->pk_buffer[CF_HOME_SEQ_BYTE_POS],
845                packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
846 #endif
847     }
848     else if (writeQueueSend != NULL) {
849 #ifdef RETRANS
850         /* set up the sequence number on the packet */
851         packet = writeQueueSend;
852         HomeSeq++;
853         (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
854             = OppoSeq;
855         (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS])
856             = HomeSeq;
857         (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS])
858             = CF_RELIABLE;
859 # ifdef RET_DEBUG
860         printf("sending packet with hseq 0x%x oseq 0x%x\n",
861                writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS],
862                writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
863 # endif
864 #endif /* RETRANS */
865     }
866
867     if (packet != NULL) {
868         AdpErrs dev_err;
869
870 #ifdef FAKE_BAD_LINE_TX
871         fake_bad_line_tx();
872 #endif
873
874         dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG);
875         if (dev_err == adp_ok) {
876 #ifdef RETRANS
877             if (resending) {
878                 /* check to see if we've recovered yet */
879                 if ((packet->pk_next) == NULL){
880 # ifdef RET_DEBUG
881                     printf("we have recovered\n");
882 # endif
883                     resending = FALSE;
884                 }
885                 else {
886                     resend_pkt = resend_pkt->pk_next;
887                 }
888             }
889             else {
890                 /* 
891                  * move the packet we just sent from the send queue to the root
892                  */
893                 Packet *tmp_pkt, *tmp;
894
895 # ifdef FAKE_BAD_LINE_TX
896                 unfake_bad_line_tx();
897 # endif
898
899                 tmp_pkt = writeQueueSend;
900                 writeQueueSend = writeQueueSend->pk_next;
901                 tmp_pkt->pk_next = NULL;
902                 if (writeQueueRoot == NULL)
903                    writeQueueRoot = tmp_pkt;
904                 else {
905                     tmp = writeQueueRoot;
906                     while (tmp->pk_next != NULL) {
907                         tmp = tmp->pk_next;
908                     }
909                     tmp->pk_next = tmp_pkt;
910                 }
911             }
912 #else  /* not RETRANS */
913             /*
914              * switcher has taken the write, so remove it from the
915              * queue, and free its resources
916              */
917             DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend));
918 #endif /* if RETRANS ... else ... */
919
920             if (mode == async_block_on_write)
921                *finished = DevSW_WriteFinished(deviceToUse);
922
923         } /* endif write ok */
924     }
925     else /* packet == NULL */
926     {
927         if (mode == async_block_on_write)
928            *finished = DevSW_WriteFinished(deviceToUse);
929     }
930 }
931
932 static void async_process_heartbeat( void )
933 {
934     /* check to see whether we need to send a heartbeat */
935     gettimeofday(&time_now, NULL);
936
937     if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE)
938     {
939         /*
940          * if we've not booted then don't do send a heartrate the link
941          * must be reliable enough for us to boot without any clever stuff,
942          * if we can't do this then theres little chance of the link staying
943          * together even with the resends etc
944          */
945         if (heartbeat_enabled) {
946             gettimeofday(&time_lastalive, NULL);
947             pacemaker();
948         }
949     }
950 }
951
952 static void async_process_callbacks( void )
953 {
954     /* call any registered asynchronous callbacks */
955     unsigned int i;
956     for ( i = 0; i < num_async_callbacks; ++i )
957        async_callbacks[i]( deviceToUse, &time_now );
958 }
959
960 void Adp_AsynchronousProcessing(const AsyncMode mode)
961 {
962     bool finished = FALSE;
963 #ifdef DEBUG
964     unsigned int wc = 0, dc = 0, ac = 0, hc = 0;
965 # define INC_COUNT(x) ((x)++)
966 #else
967 # define INC_COUNT(x)
968 #endif
969
970     if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) {
971       /* first time through, needs initing */
972       gettimeofday(&time_lastalive, NULL);
973     }
974
975     /* main loop */
976     do
977     {
978         async_process_write( mode, &finished );
979         INC_COUNT(wc);
980
981         if ( ! finished && mode != async_block_on_write )
982         {
983             async_process_dbug_read( mode, &finished );
984             INC_COUNT(dc);
985         }
986
987         if ( ! finished && mode != async_block_on_write )
988         {
989            async_process_appl_read();
990            INC_COUNT(ac);
991         }
992
993         if ( ! finished )
994         {
995           if (heartbeat_configured)
996             async_process_heartbeat();
997           async_process_callbacks();
998           INC_COUNT(hc);
999         }
1000
1001     } while (!finished && mode != async_block_on_nothing);
1002
1003 #ifdef DEBUG
1004     if ( mode != async_block_on_nothing )
1005        printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1006                mode == async_block_on_write ? "blk_write" : "blk_read",
1007                wc, dc, ac, hc );
1008 #endif
1009 }
1010
1011 /*
1012  * install a handler for DC_APPL packets (can be NULL), returning old one.
1013  */
1014 DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)
1015 {
1016     DC_Appl_Handler old_handler = dc_appl_handler;
1017
1018 #ifdef DEBUG
1019     printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler );
1020 #endif
1021
1022     dc_appl_handler = handler;
1023     return old_handler;
1024 }
1025
1026
1027 /*
1028  * add an asynchronous processing callback to the list
1029  * TRUE == okay, FALSE == no more async processing slots
1030  */
1031 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc )
1032 {
1033     if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL )
1034     {
1035         async_callbacks[num_async_callbacks] = callback_proc;
1036         ++num_async_callbacks;
1037         return TRUE;
1038     }
1039     else
1040        return FALSE;
1041 }
1042
1043
1044 /*
1045  * delay for a given period (in microseconds)
1046  */
1047 void Adp_delay(unsigned int period)
1048 {
1049     struct timeval tv;
1050
1051 #ifdef DEBUG
1052     printf("delaying for %d microseconds\n", period);
1053 #endif
1054     tv.tv_sec = (period / 1000000);
1055     tv.tv_usec = (period % 1000000);
1056
1057     (void)select(0, NULL, NULL, NULL, &tv);
1058 }
1059
1060 /* EOF hostchan.c */
This page took 0.081398 seconds and 4 git commands to generate.