2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
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
15 * hostchan.c - Semi Synchronous Host side channel interface for Angel.
20 #ifdef HAVE_SYS_TIME_H
21 # include <sys/time.h>
39 #define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */
42 #define HEARTRATE 5000000
45 * list of available drivers, declared in drivers.c
47 extern DeviceDescr
*devices
[];
49 static DeviceDescr
*deviceToUse
= NULL
;
51 static struct Channel
{
52 ChannelCallback callback
;
54 } channels
[CI_NUM_CHANNELS
];
56 static unsigned char HomeSeq
;
57 static unsigned char OppoSeq
;
60 * Handler for DC_APPL packets
62 static DC_Appl_Handler dc_appl_handler
= NULL
;
65 * slots for registered asynchronous processing callback procedures
67 #define MAX_ASYNC_CALLBACKS 8
68 static unsigned int num_async_callbacks
= 0;
69 static Adp_Async_Callback async_callbacks
[MAX_ASYNC_CALLBACKS
];
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
76 static Packet
*writeQueueRoot
= NULL
;
77 static Packet
*writeQueueSend
= NULL
;
78 static Packet
*resend_pkt
= NULL
;
79 static int resending
= FALSE
;
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
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
95 unsigned int heartbeat_configured
= TRUE
;
97 void Adp_initSeq( void ) {
98 Packet
*tmp_pkt
= writeQueueSend
;
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
);
109 tmp_pkt
= writeQueueRoot
;
110 if ( writeQueueRoot
== NULL
)
113 while (writeQueueRoot
->pk_next
!=NULL
) {
114 tmp_pkt
= writeQueueRoot
;
115 writeQueueRoot
= tmp_pkt
->pk_next
;
116 DevSW_FreePacket(tmp_pkt
);
121 /**********************************************************************/
124 * Function: DummyCallback
125 * Purpose: Default callback routine to handle unexpected input
129 * Input: packet The received packet
131 * state Contains nothing of significance
135 static void DummyCallback(Packet
*packet
, void *state
)
138 const char fmt
[] = "Unexpected read on channel %u, length %d\n";
139 char fmtbuf
[sizeof(fmt
) + 24];
143 chan
= *(packet
->pk_buffer
);
144 sprintf(fmtbuf
, fmt
, chan
, packet
->pk_length
);
150 DevSW_FreePacket(packet
);
154 * Function: BlockingCallback
155 * Purpose: Callback routine used to implement a blocking read call
158 * Input: packet The received packet.
160 * Output: state Address of higher level's pointer to the received
165 static void BlockingCallback(Packet
*packet
, void *state
)
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.
172 *((Packet
**)state
) = packet
;
176 * Function: FireCallback
177 * Purpose: Pass received packet along to the callback routine for
178 * the appropriate channel
181 * Input: packet The received packet.
185 * Post-conditions: The Target-to-Host sequence number for the channel
186 * will have been incremented.
188 static void FireCallback(Packet
*packet
)
194 * is this a sensible channel number?
196 chan
= *(packet
->pk_buffer
);
197 if (invalidChannelID(chan
))
199 printf("ERROR: invalid ChannelID received from target\n");
202 * free the packet's resources, 'cause no-one else will
204 DevSW_FreePacket(packet
);
209 * looks OK - increment sequence number, and pass packet to callback
211 ch
= channels
+ chan
;
212 (ch
->callback
)(packet
, ch
->callback_state
);
215 /**********************************************************************/
218 * These are the externally visible functions. They are documented
221 void Adp_addToQueue(Packet
**head
, Packet
*newpkt
)
224 * this is a bit of a hack
229 * make sure that the hack we are about to use will work as expected
231 ASSERT(&(((Packet
*)0)->pk_next
) == 0, "bad struct Packet layout");
233 #if defined(DEBUG) && 0
234 printf("Adp_addToQueue(%p, %p)\n", head
, newpkt
);
238 * here's the hack - it relies upon the next
239 * pointer being at the start of Packet.
241 pk
= (Packet
*)(head
);
244 * skip to the end of the queue
246 while (pk
->pk_next
!= NULL
)
250 * now add the new element
252 newpkt
->pk_next
= NULL
;
253 pk
->pk_next
= newpkt
;
256 Packet
*Adp_removeFromQueue(Packet
**head
)
268 void Adp_SetLogEnable(int logEnableFlag
)
270 DevSW_SetLogEnable(logEnableFlag
);
273 void Adp_SetLogfile(const char *filename
)
275 DevSW_SetLogfile(filename
);
278 AdpErrs
Adp_OpenDevice(const char *name
, const char *arg
,
279 unsigned int heartbeat_on
)
286 printf("Adp_OpenDevice(%s, %s)\n", name
, arg
? arg
: "<NULL>");
289 heartbeat_configured
= heartbeat_on
;
290 if (deviceToUse
!= NULL
)
291 return adp_device_already_open
;
293 for (i
= 0; (deviceToUse
= devices
[i
]) != NULL
; ++i
)
294 if (DevSW_Match(deviceToUse
, name
, arg
) == adp_ok
)
297 if (deviceToUse
== NULL
)
298 return adp_device_not_found
;
301 * we seem to have found a suitable device driver, so try to open it
303 if ((retc
= DevSW_Open(deviceToUse
, name
, arg
, DC_DBUG
)) != adp_ok
)
305 /* we don't have a device to use */
311 * there is no explicit open on channels any more, so
312 * initialise state for all channels.
314 for (chan
= 0; chan
< CI_NUM_CHANNELS
; ++chan
)
316 struct Channel
*ch
= channels
+ chan
;
318 ch
->callback
= DummyCallback
;
319 ch
->callback_state
= NULL
;
327 AdpErrs
Adp_CloseDevice(void)
332 printf("Adp_CloseDevice\n");
335 if (deviceToUse
== NULL
)
336 return adp_device_not_open
;
338 heartbeat_enabled
= FALSE
;
340 retc
= DevSW_Close(deviceToUse
, DC_DBUG
);
343 * we have to clear deviceToUse, even when the lower layers
344 * faulted the close, otherwise the condition will never clear
347 WARN("DevSW_Close faulted the call");
353 AdpErrs
Adp_Ioctl(int opcode
, void *args
)
356 printf("Adp_Ioctl\n");
359 if (deviceToUse
== NULL
)
360 return adp_device_not_open
;
362 return DevSW_Ioctl(deviceToUse
, opcode
, args
);
365 AdpErrs
Adp_ChannelRegisterRead(const ChannelID chan
,
366 const ChannelCallback cbfunc
,
370 printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan
, cbfunc
, cbstate
);
373 if (deviceToUse
== NULL
)
374 return adp_device_not_open
;
376 if (invalidChannelID(chan
))
377 return adp_bad_channel_id
;
381 channels
[chan
].callback
= DummyCallback
;
382 channels
[chan
].callback_state
= NULL
;
386 channels
[chan
].callback
= cbfunc
;
387 channels
[chan
].callback_state
= cbstate
;
393 AdpErrs
Adp_ChannelRead(const ChannelID chan
, Packet
**packet
)
398 printf("Adp_ChannelRead(%d, %x)\n", chan
, *packet
);
401 if (deviceToUse
== NULL
)
402 return adp_device_not_open
;
404 if (invalidChannelID(chan
))
405 return adp_bad_channel_id
;
408 * if a callback has already been registered for this
409 * channel, then we do not allow this blocking read.
411 ch
= channels
+ chan
;
412 if (ch
->callback
!= DummyCallback
)
413 return adp_callback_already_registered
;
416 * OK, use our own callback to wait for a packet to arrive
419 ch
->callback
= BlockingCallback
;
420 ch
->callback_state
= packet
;
424 * keep polling until a packet appears for this channel
426 while (((volatile Packet
*)(*packet
)) == NULL
)
428 * this call will block until a packet is read on any channel
430 Adp_AsynchronousProcessing(async_block_on_read
);
433 * OK, the packet has arrived: clear the callback
435 ch
->callback
= DummyCallback
;
436 ch
->callback_state
= NULL
;
441 static AdpErrs
ChannelWrite(
442 const ChannelID chan
, Packet
*packet
, AsyncMode mode
)
448 printf( "Adp_ChannelWrite(%d, %x)\n", chan
, packet
);
451 if (deviceToUse
== NULL
)
452 return adp_device_not_open
;
454 if (invalidChannelID(chan
))
455 return adp_bad_channel_id
;
458 * fill in the channels header at the start of this buffer
460 ch
= channels
+ chan
;
461 cptr
= packet
->pk_buffer
;
464 packet
->pk_length
+= CHAN_HEADER_SIZE
;
467 * OK, add this packet to the write queue, and try to flush it out
470 Adp_addToQueue(&writeQueueSend
, packet
);
471 Adp_AsynchronousProcessing(mode
);
476 AdpErrs
Adp_ChannelWrite(const ChannelID chan
, Packet
*packet
) {
477 return ChannelWrite(chan
, packet
, async_block_on_write
);
480 AdpErrs
Adp_ChannelWriteAsync(const ChannelID chan
, Packet
*packet
) {
481 return ChannelWrite(chan
, packet
, async_block_on_nothing
);
484 static AdpErrs
send_resend_msg(DeviceID devid
) {
487 * Send a resend message, usually in response to a bad packet or
488 * a resend request */
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
);
499 static AdpErrs
check_seq(unsigned char msg_home
, unsigned char msg_oppo
) {
504 * check if we have got an ack for anything and if so remove it from the
507 if (msg_home
== (unsigned char)(OppoSeq
+1)) {
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
513 tmp_pkt
= writeQueueRoot
;
514 while ((tmp_pkt
->pk_next
!= NULL
) &&
515 (tmp_pkt
->pk_next
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
]
517 tmp_pkt
= tmp_pkt
->pk_next
;
520 if (tmp_pkt
->pk_next
== NULL
) {
522 printf("trying to remove a non existant packet\n");
524 return adp_bad_packet
;
527 Packet
*tmp
= tmp_pkt
->pk_next
;
529 printf("removing a packet from the root queue\n");
531 tmp_pkt
->pk_next
= tmp_pkt
->pk_next
->pk_next
;
532 /* remove the appropriate packet */
533 DevSW_FreePacket(tmp
);
537 else if (msg_home
< (unsigned char) (OppoSeq
+1)){
538 /* already received this message */
540 printf("sequence numbers low\n");
544 else { /* we've missed something */
546 printf("sequence numbers high\n");
552 static unsigned long tv_diff(const struct timeval
*time_now
,
553 const struct timeval
*time_was
)
555 return ( ((time_now
->tv_sec
* 1000000) + time_now
->tv_usec
)
556 - ((time_was
->tv_sec
* 1000000) + time_was
->tv_usec
) );
559 #if !defined(__unix) && !defined(__CYGWIN32__)
560 static void gettimeofday( struct timeval
*time_now
, void *dummy
)
564 time_now
->tv_sec
= t
/CLOCKS_PER_SEC
;
565 time_now
->tv_usec
= (t
%CLOCKS_PER_SEC
)*(1000000/CLOCKS_PER_SEC
);
569 static AdpErrs
pacemaker(void)
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
;
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
);
586 #ifdef FAKE_BAD_LINE_RX
587 static AdpErrs
fake_bad_line_rx( const Packet
*const packet
, AdpErrs adp_err
)
589 static unsigned int bl_num
= 0;
591 if ( (packet
!= NULL
)
593 && ((bl_num
% FAKE_BAD_LINE_RX
) == 0))
595 printf("DEBUG: faking a bad packet\n");
596 return adp_bad_packet
;
600 #endif /* def FAKE_BAD_LINE_RX */
602 #ifdef FAKE_BAD_LINE_TX
603 static unsigned char tmp_ch
;
605 static void fake_bad_line_tx( void )
607 static unsigned int bl_num
= 0;
609 /* give the thing a chance to boot then try corrupting stuff */
610 if ( (bl_num
++ >= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) == 0))
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;
618 static void unfake_bad_line_tx( void )
620 static unsigned int bl_num
= 0;
623 * must reset the packet so that its not corrupted when we
626 if ( (bl_num
>= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) != 0))
628 writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
] = tmp_ch
;
631 #endif /* def FAKE_BAD_LINE_TX */
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
639 static struct timeval time_now
;
640 static struct timeval time_lastalive
;
642 static void async_process_dbug_read( const AsyncMode mode
,
643 bool *const finished
)
646 unsigned int msg_home
, msg_oppo
;
649 adp_err
= DevSW_Read(deviceToUse
, DC_DBUG
, &packet
,
650 mode
== async_block_on_read
);
652 #ifdef FAKE_BAD_LINE_RX
653 adp_err
= fake_bad_line_rx( packet
, adp_err
);
656 if (adp_err
== adp_bad_packet
) {
657 /* We got a bad packet, ask for a resend, send a resend message */
659 printf("received a bad packet\n");
661 send_resend_msg(DC_DBUG
);
663 else if (packet
!= NULL
)
665 /* update the heartbeat clock */
666 gettimeofday(&time_lastalive
, NULL
);
669 * we got a live one here - were we waiting for it?
671 if (mode
== async_block_on_read
)
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
);
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
690 msg_home
= packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
];
691 msg_oppo
= packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
];
693 printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
695 for (c
=0;c
<packet
->pk_length
;c
++)
696 printf("%02.2x", packet
->pk_buffer
[c
]);
699 /* now was it a resend request? */
700 if ((packet
->pk_buffer
[CF_FLAGS_BYTE_POS
])
702 /* we've been asked for a resend so we had better resend */
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);
709 printf("received a resend request\n");
711 if (HomeSeq
!= msg_oppo
) {
713 /* need to resend from msg_oppo +1 upwards */
714 DevSW_FreePacket(packet
);
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
])
724 packet
= packet
->pk_next
;
727 panic("trying to resend non-existent packets\n");
730 else if (OppoSeq
!= msg_home
) {
732 * send a resend request telling the target where we think
735 DevSW_FreePacket(packet
);
736 send_resend_msg(DC_DBUG
);
740 /* not a resend request, lets check the sequence numbers */
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
);
749 else if (adp_err
== adp_seq_high
) {
751 * we must have missed a packet somewhere, discard this
752 * packet and tell the target where we are
754 DevSW_FreePacket(packet
);
755 send_resend_msg(DC_DBUG
);
759 * now pass the packet to whoever is waiting for it
761 FireCallback(packet
);
764 FireCallback(packet
);
769 * now pass the packet to whoever is waiting for it
771 FireCallback(packet
);
776 static void async_process_appl_read(void)
781 /* see if there is anything for the DC_APPL channel */
782 adp_err
= DevSW_Read(deviceToUse
, DC_APPL
, &packet
, FALSE
);
784 if (adp_err
== adp_ok
&& packet
!= NULL
)
786 /* got an application packet on a shared device */
789 printf("GOT DC_APPL PACKET: len %d\nData: ", packet
->pk_length
);
792 for ( c
= 0; c
< packet
->pk_length
; ++c
)
793 printf( "%02X ", packet
->pk_buffer
[c
] );
798 if (dc_appl_handler
!= NULL
)
800 dc_appl_handler( deviceToUse
, packet
);
804 /* for now, just free it!! */
806 printf("no handler - dropping DC_APPL packet\n");
808 DevSW_FreePacket( packet
);
813 static void async_process_write( const AsyncMode mode
,
814 bool *const finished
)
819 static unsigned int num_written
= 0;
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.
831 if (writeQueueSend
!=NULL
)
832 printf("written 0x%x\n",num_written
+= writeQueueSend
->pk_length
);
835 * give the switcher a chance to complete any partial writes
837 if (DevSW_FlushPendingWrite(deviceToUse
) == adp_write_busy
)
839 /* no point trying a new write */
844 * now see whether there is anything to write
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
]);
855 else if (writeQueueSend
!= NULL
) {
857 /* set up the sequence number on the packet */
858 packet
= writeQueueSend
;
860 (writeQueueSend
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
])
862 (writeQueueSend
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
])
864 (writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
])
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
]);
874 if (packet
!= NULL
) {
877 #ifdef FAKE_BAD_LINE_TX
881 dev_err
= DevSW_Write(deviceToUse
, packet
, DC_DBUG
);
882 if (dev_err
== adp_ok
) {
885 /* check to see if we've recovered yet */
886 if ((packet
->pk_next
) == NULL
){
888 printf("we have recovered\n");
893 resend_pkt
= resend_pkt
->pk_next
;
898 * move the packet we just sent from the send queue to the root
900 Packet
*tmp_pkt
, *tmp
;
902 # ifdef FAKE_BAD_LINE_TX
903 unfake_bad_line_tx();
906 tmp_pkt
= writeQueueSend
;
907 writeQueueSend
= writeQueueSend
->pk_next
;
908 tmp_pkt
->pk_next
= NULL
;
909 if (writeQueueRoot
== NULL
)
910 writeQueueRoot
= tmp_pkt
;
912 tmp
= writeQueueRoot
;
913 while (tmp
->pk_next
!= NULL
) {
916 tmp
->pk_next
= tmp_pkt
;
919 #else /* not RETRANS */
921 * switcher has taken the write, so remove it from the
922 * queue, and free its resources
924 DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend
));
925 #endif /* if RETRANS ... else ... */
927 if (mode
== async_block_on_write
)
928 *finished
= DevSW_WriteFinished(deviceToUse
);
930 } /* endif write ok */
932 else /* packet == NULL */
934 if (mode
== async_block_on_write
)
935 *finished
= DevSW_WriteFinished(deviceToUse
);
939 static void async_process_heartbeat( void )
941 /* check to see whether we need to send a heartbeat */
942 gettimeofday(&time_now
, NULL
);
944 if (tv_diff(&time_now
, &time_lastalive
) >= HEARTRATE
)
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
952 if (heartbeat_enabled
) {
953 gettimeofday(&time_lastalive
, NULL
);
959 static void async_process_callbacks( void )
961 /* call any registered asynchronous callbacks */
963 for ( i
= 0; i
< num_async_callbacks
; ++i
)
964 async_callbacks
[i
]( deviceToUse
, &time_now
);
967 void Adp_AsynchronousProcessing(const AsyncMode mode
)
969 bool finished
= FALSE
;
971 unsigned int wc
= 0, dc
= 0, ac
= 0, hc
= 0;
972 # define INC_COUNT(x) ((x)++)
974 # define INC_COUNT(x)
977 if ((time_lastalive
.tv_sec
== 0) && (time_lastalive
.tv_usec
== 0)) {
978 /* first time through, needs initing */
979 gettimeofday(&time_lastalive
, NULL
);
985 async_process_write( mode
, &finished
);
988 if ( ! finished
&& mode
!= async_block_on_write
)
990 async_process_dbug_read( mode
, &finished
);
994 if ( ! finished
&& mode
!= async_block_on_write
)
996 async_process_appl_read();
1002 if (heartbeat_configured
)
1003 async_process_heartbeat();
1004 async_process_callbacks();
1008 } while (!finished
&& mode
!= async_block_on_nothing
);
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",
1019 * install a handler for DC_APPL packets (can be NULL), returning old one.
1021 DC_Appl_Handler
Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler
)
1023 DC_Appl_Handler old_handler
= dc_appl_handler
;
1026 printf( "Installing DC_APPL handler %x (old %x)\n", handler
, old_handler
);
1029 dc_appl_handler
= handler
;
1035 * add an asynchronous processing callback to the list
1036 * TRUE == okay, FALSE == no more async processing slots
1038 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc
)
1040 if ( num_async_callbacks
< MAX_ASYNC_CALLBACKS
&& callback_proc
!= NULL
)
1042 async_callbacks
[num_async_callbacks
] = callback_proc
;
1043 ++num_async_callbacks
;
1052 * delay for a given period (in microseconds)
1054 void Adp_delay(unsigned int period
)
1059 printf("delaying for %d microseconds\n", period
);
1061 tv
.tv_sec
= (period
/ 1000000);
1062 tv
.tv_usec
= (period
% 1000000);
1064 (void)select(0, NULL
, NULL
, NULL
, &tv
);
1067 /* EOF hostchan.c */