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.8 $
12 *     $Date: 1999/11/01 15:32:59 $
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 */
47extern DeviceDescr *devices[];
48
49static DeviceDescr *deviceToUse = NULL;
50
51static struct Channel {
52    ChannelCallback callback;
53    void *callback_state;
54} channels[CI_NUM_CHANNELS];
55
56static unsigned char HomeSeq;
57static unsigned char OppoSeq;
58
59/*
60 * Handler for DC_APPL packets
61 */
62static DC_Appl_Handler dc_appl_handler = NULL;
63
64/*
65 * slots for registered asynchronous processing callback procedures
66 */
67#define MAX_ASYNC_CALLBACKS 8
68static unsigned int             num_async_callbacks = 0;
69static 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 */
76static Packet *writeQueueRoot = NULL;
77static Packet *writeQueueSend = NULL;
78static Packet *resend_pkt = NULL;
79static 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 */
87unsigned 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 */
95unsigned int heartbeat_configured = TRUE;
96
97void 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 */
135static 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 */
165static 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 */
188static 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 */
221void 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
256Packet *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
268void Adp_SetLogEnable(int logEnableFlag)
269{
270  DevSW_SetLogEnable(logEnableFlag);
271}
272
273void Adp_SetLogfile(const char *filename)
274{
275  DevSW_SetLogfile(filename);
276}
277
278AdpErrs 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
327AdpErrs 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
353AdpErrs 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
365AdpErrs 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
393AdpErrs 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
441static 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
476AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
477  return ChannelWrite(chan, packet, async_block_on_write);
478}
479
480AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
481  return ChannelWrite(chan, packet, async_block_on_nothing);
482}
483
484static 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
499static 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
552static 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__)
560static 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
569static 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
587static 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
603static unsigned char tmp_ch;
604
605static 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
618static 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 */
639static struct timeval time_now;
640static struct timeval time_lastalive;
641
642static 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
776static 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
813static 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
939static 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
959static 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
967void 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 */
1021DC_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 */
1038bool 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 */
1054void 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