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