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");
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 AdpErrs
Adp_OpenDevice(const char *name
, const char *arg
,
269 unsigned int heartbeat_on
)
276 printf("Adp_OpenDevice(%s, %s)\n", name
, arg
? arg
: "<NULL>");
279 heartbeat_configured
= heartbeat_on
;
280 if (deviceToUse
!= NULL
)
281 return adp_device_already_open
;
283 for (i
= 0; (deviceToUse
= devices
[i
]) != NULL
; ++i
)
284 if (DevSW_Match(deviceToUse
, name
, arg
) == adp_ok
)
287 if (deviceToUse
== NULL
)
288 return adp_device_not_found
;
291 * we seem to have found a suitable device driver, so try to open it
293 if ((retc
= DevSW_Open(deviceToUse
, name
, arg
, DC_DBUG
)) != adp_ok
)
295 /* we don't have a device to use */
301 * there is no explicit open on channels any more, so
302 * initialise state for all channels.
304 for (chan
= 0; chan
< CI_NUM_CHANNELS
; ++chan
)
306 struct Channel
*ch
= channels
+ chan
;
308 ch
->callback
= DummyCallback
;
309 ch
->callback_state
= NULL
;
317 AdpErrs
Adp_CloseDevice(void)
322 printf("Adp_CloseDevice\n");
325 if (deviceToUse
== NULL
)
326 return adp_device_not_open
;
328 heartbeat_enabled
= FALSE
;
330 retc
= DevSW_Close(deviceToUse
, DC_DBUG
);
333 * we have to clear deviceToUse, even when the lower layers
334 * faulted the close, otherwise the condition will never clear
337 WARN("DevSW_Close faulted the call");
343 AdpErrs
Adp_Ioctl(int opcode
, void *args
)
346 printf("Adp_Ioctl\n");
349 if (deviceToUse
== NULL
)
350 return adp_device_not_open
;
352 return DevSW_Ioctl(deviceToUse
, opcode
, args
);
355 AdpErrs
Adp_ChannelRegisterRead(const ChannelID chan
,
356 const ChannelCallback cbfunc
,
360 printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan
, cbfunc
, cbstate
);
363 if (deviceToUse
== NULL
)
364 return adp_device_not_open
;
366 if (invalidChannelID(chan
))
367 return adp_bad_channel_id
;
371 channels
[chan
].callback
= DummyCallback
;
372 channels
[chan
].callback_state
= NULL
;
376 channels
[chan
].callback
= cbfunc
;
377 channels
[chan
].callback_state
= cbstate
;
383 AdpErrs
Adp_ChannelRead(const ChannelID chan
, Packet
**packet
)
388 printf("Adp_ChannelRead(%d, %x)\n", chan
, *packet
);
391 if (deviceToUse
== NULL
)
392 return adp_device_not_open
;
394 if (invalidChannelID(chan
))
395 return adp_bad_channel_id
;
398 * if a callback has already been registered for this
399 * channel, then we do not allow this blocking read.
401 ch
= channels
+ chan
;
402 if (ch
->callback
!= DummyCallback
)
403 return adp_callback_already_registered
;
406 * OK, use our own callback to wait for a packet to arrive
409 ch
->callback
= BlockingCallback
;
410 ch
->callback_state
= packet
;
414 * keep polling until a packet appears for this channel
416 while (((volatile Packet
*)(*packet
)) == NULL
)
418 * this call will block until a packet is read on any channel
420 Adp_AsynchronousProcessing(async_block_on_read
);
423 * OK, the packet has arrived: clear the callback
425 ch
->callback
= DummyCallback
;
426 ch
->callback_state
= NULL
;
431 static AdpErrs
ChannelWrite(
432 const ChannelID chan
, Packet
*packet
, AsyncMode mode
)
438 printf( "Adp_ChannelWrite(%d, %x)\n", chan
, packet
);
441 if (deviceToUse
== NULL
)
442 return adp_device_not_open
;
444 if (invalidChannelID(chan
))
445 return adp_bad_channel_id
;
448 * fill in the channels header at the start of this buffer
450 ch
= channels
+ chan
;
451 cptr
= packet
->pk_buffer
;
454 packet
->pk_length
+= CHAN_HEADER_SIZE
;
457 * OK, add this packet to the write queue, and try to flush it out
460 Adp_addToQueue(&writeQueueSend
, packet
);
461 Adp_AsynchronousProcessing(mode
);
466 AdpErrs
Adp_ChannelWrite(const ChannelID chan
, Packet
*packet
) {
467 return ChannelWrite(chan
, packet
, async_block_on_write
);
470 AdpErrs
Adp_ChannelWriteAsync(const ChannelID chan
, Packet
*packet
) {
471 return ChannelWrite(chan
, packet
, async_block_on_nothing
);
474 static AdpErrs
send_resend_msg(DeviceID devid
) {
477 * Send a resend message, usually in response to a bad packet or
478 * a resend request */
480 packet
= DevSW_AllocatePacket(CF_DATA_BYTE_POS
);
481 packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] = CI_PRIVATE
;
482 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
] = HomeSeq
;
483 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
] = OppoSeq
;
484 packet
->pk_buffer
[CF_FLAGS_BYTE_POS
] = CF_RELIABLE
| CF_RESEND
;
485 packet
->pk_length
= CF_DATA_BYTE_POS
;
486 return DevSW_Write(deviceToUse
, packet
, devid
);
489 static AdpErrs
check_seq(unsigned char msg_home
, unsigned char msg_oppo
) {
494 * check if we have got an ack for anything and if so remove it from the
497 if (msg_home
== (unsigned char)(OppoSeq
+1)) {
499 * arrived in sequence can increment our opposing seq number and remove
500 * the relevant packet from our queue
501 * check that the packet we're going to remove really is the right one
503 tmp_pkt
= writeQueueRoot
;
504 while ((tmp_pkt
->pk_next
!= NULL
) &&
505 (tmp_pkt
->pk_next
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
]
507 tmp_pkt
= tmp_pkt
->pk_next
;
510 if (tmp_pkt
->pk_next
== NULL
) {
512 printf("trying to remove a non existant packet\n");
514 return adp_bad_packet
;
517 Packet
*tmp
= tmp_pkt
->pk_next
;
519 printf("removing a packet from the root queue\n");
521 tmp_pkt
->pk_next
= tmp_pkt
->pk_next
->pk_next
;
522 /* remove the appropriate packet */
523 DevSW_FreePacket(tmp
);
527 else if (msg_home
< (unsigned char) (OppoSeq
+1)){
528 /* already received this message */
530 printf("sequence numbers low\n");
534 else { /* we've missed something */
536 printf("sequence numbers high\n");
542 static unsigned long tv_diff(const struct timeval
*time_now
,
543 const struct timeval
*time_was
)
545 return ( ((time_now
->tv_sec
* 1000000) + time_now
->tv_usec
)
546 - ((time_was
->tv_sec
* 1000000) + time_was
->tv_usec
) );
549 #if !defined(__unix) && !defined(__CYGWIN__)
550 static void gettimeofday( struct timeval
*time_now
, void *dummy
)
554 time_now
->tv_sec
= t
/CLOCKS_PER_SEC
;
555 time_now
->tv_usec
= (t
%CLOCKS_PER_SEC
)*(1000000/CLOCKS_PER_SEC
);
559 static AdpErrs
pacemaker(void)
563 packet
= DevSW_AllocatePacket(CF_DATA_BYTE_POS
);
564 if (packet
== NULL
) {
565 printf("ERROR: could not allocate a packet in pacemaker()\n");
566 return adp_malloc_failure
;
568 packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] = CI_PRIVATE
;
569 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
] = HomeSeq
;
570 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
] = OppoSeq
;
571 packet
->pk_buffer
[CF_FLAGS_BYTE_POS
] = CF_RELIABLE
| CF_HEARTBEAT
;
572 packet
->pk_length
= CF_DATA_BYTE_POS
;
573 return DevSW_Write(deviceToUse
, packet
, DC_DBUG
);
576 #ifdef FAKE_BAD_LINE_RX
577 static AdpErrs
fake_bad_line_rx( const Packet
*const packet
, AdpErrs adp_err
)
579 static unsigned int bl_num
= 0;
581 if ( (packet
!= NULL
)
583 && ((bl_num
% FAKE_BAD_LINE_RX
) == 0))
585 printf("DEBUG: faking a bad packet\n");
586 return adp_bad_packet
;
590 #endif /* def FAKE_BAD_LINE_RX */
592 #ifdef FAKE_BAD_LINE_TX
593 static unsigned char tmp_ch
;
595 static void fake_bad_line_tx( void )
597 static unsigned int bl_num
= 0;
599 /* give the thing a chance to boot then try corrupting stuff */
600 if ( (bl_num
++ >= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) == 0))
602 printf("DEBUG: faking a bad packet for tx\n");
603 tmp_ch
= writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
];
604 writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
] = 77;
608 static void unfake_bad_line_tx( void )
610 static unsigned int bl_num
= 0;
613 * must reset the packet so that its not corrupted when we
616 if ( (bl_num
>= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) != 0))
618 writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
] = tmp_ch
;
621 #endif /* def FAKE_BAD_LINE_TX */
624 * NOTE: we are assuming that a resolution of microseconds will
625 * be good enough for the purporses of the heartbeat. If this proves
626 * not to be the case then we may need a rethink, possibly using
629 static struct timeval time_now
;
630 static struct timeval time_lastalive
;
632 static void async_process_dbug_read( const AsyncMode mode
,
633 bool *const finished
)
636 unsigned int msg_home
, msg_oppo
;
639 adp_err
= DevSW_Read(deviceToUse
, DC_DBUG
, &packet
,
640 mode
== async_block_on_read
);
642 #ifdef FAKE_BAD_LINE_RX
643 adp_err
= fake_bad_line_rx( packet
, adp_err
);
646 if (adp_err
== adp_bad_packet
) {
647 /* We got a bad packet, ask for a resend, send a resend message */
649 printf("received a bad packet\n");
651 send_resend_msg(DC_DBUG
);
653 else if (packet
!= NULL
)
655 /* update the heartbeat clock */
656 gettimeofday(&time_lastalive
, NULL
);
659 * we got a live one here - were we waiting for it?
661 if (mode
== async_block_on_read
)
666 if (packet
->pk_length
< CF_DATA_BYTE_POS
) {
667 /* we've got a packet with no header information! */
668 printf("ERROR: packet with no transport header\n");
669 send_resend_msg(DC_DBUG
);
676 * TODO: Check to see if its acknowledgeing anything, remove
677 * those packets it is from the queue. If its a retrans add the
678 * packets to the queue
680 msg_home
= packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
];
681 msg_oppo
= packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
];
683 printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
685 for (c
=0;c
<packet
->pk_length
;c
++)
686 printf("%02.2x", packet
->pk_buffer
[c
]);
689 /* now was it a resend request? */
690 if ((packet
->pk_buffer
[CF_FLAGS_BYTE_POS
])
692 /* we've been asked for a resend so we had better resend */
694 * I don't think we can use a resend as acknowledgement for
695 * anything so lets not do this for the moment
696 * check_seq(msg_home, msg_oppo);
699 printf("received a resend request\n");
701 if (HomeSeq
!= msg_oppo
) {
703 /* need to resend from msg_oppo +1 upwards */
704 DevSW_FreePacket(packet
);
706 /* find the correct packet to resend from */
707 packet
= writeQueueRoot
;
708 while (((packet
->pk_next
) != NULL
) && !found
) {
709 if ((packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
])
714 packet
= packet
->pk_next
;
717 panic("trying to resend non-existent packets\n");
720 else if (OppoSeq
!= msg_home
) {
722 * send a resend request telling the target where we think
725 DevSW_FreePacket(packet
);
726 send_resend_msg(DC_DBUG
);
730 /* not a resend request, lets check the sequence numbers */
732 if ((packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] != CI_HBOOT
) &&
733 (packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] != CI_TBOOT
)) {
734 adp_err
= check_seq(msg_home
, msg_oppo
);
735 if (adp_err
== adp_seq_low
) {
736 /* we have already received this packet so discard */
737 DevSW_FreePacket(packet
);
739 else if (adp_err
== adp_seq_high
) {
741 * we must have missed a packet somewhere, discard this
742 * packet and tell the target where we are
744 DevSW_FreePacket(packet
);
745 send_resend_msg(DC_DBUG
);
749 * now pass the packet to whoever is waiting for it
751 FireCallback(packet
);
754 FireCallback(packet
);
759 * now pass the packet to whoever is waiting for it
761 FireCallback(packet
);
766 static void async_process_appl_read(void)
771 /* see if there is anything for the DC_APPL channel */
772 adp_err
= DevSW_Read(deviceToUse
, DC_APPL
, &packet
, FALSE
);
774 if (adp_err
== adp_ok
&& packet
!= NULL
)
776 /* got an application packet on a shared device */
779 printf("GOT DC_APPL PACKET: len %d\nData: ", packet
->pk_length
);
782 for ( c
= 0; c
< packet
->pk_length
; ++c
)
783 printf( "%02X ", packet
->pk_buffer
[c
] );
788 if (dc_appl_handler
!= NULL
)
790 dc_appl_handler( deviceToUse
, packet
);
794 /* for now, just free it!! */
796 printf("no handler - dropping DC_APPL packet\n");
798 DevSW_FreePacket( packet
);
803 static void async_process_write( const AsyncMode mode
,
804 bool *const finished
)
809 static unsigned int num_written
= 0;
813 * NOTE: here we rely in the fact that any packet in the writeQueueSend
814 * section of the queue will need its sequence number setting up while
815 * and packet in the writeQueueRoot section will have its sequence
816 * numbers set up from when it was first sent so we can easily look
817 * up the packet numbers when(if) we want to resend the packet.
821 if (writeQueueSend
!=NULL
)
822 printf("written 0x%x\n",num_written
+= writeQueueSend
->pk_length
);
825 * give the switcher a chance to complete any partial writes
827 if (DevSW_FlushPendingWrite(deviceToUse
) == adp_write_busy
)
829 /* no point trying a new write */
834 * now see whether there is anything to write
840 printf("resending hseq 0x%x oseq 0x%x\n",
841 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
],
842 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
]);
845 else if (writeQueueSend
!= NULL
) {
847 /* set up the sequence number on the packet */
848 packet
= writeQueueSend
;
850 (writeQueueSend
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
])
852 (writeQueueSend
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
])
854 (writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
])
857 printf("sending packet with hseq 0x%x oseq 0x%x\n",
858 writeQueueSend
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
],
859 writeQueueSend
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
]);
864 if (packet
!= NULL
) {
867 #ifdef FAKE_BAD_LINE_TX
871 dev_err
= DevSW_Write(deviceToUse
, packet
, DC_DBUG
);
872 if (dev_err
== adp_ok
) {
875 /* check to see if we've recovered yet */
876 if ((packet
->pk_next
) == NULL
){
878 printf("we have recovered\n");
883 resend_pkt
= resend_pkt
->pk_next
;
888 * move the packet we just sent from the send queue to the root
890 Packet
*tmp_pkt
, *tmp
;
892 # ifdef FAKE_BAD_LINE_TX
893 unfake_bad_line_tx();
896 tmp_pkt
= writeQueueSend
;
897 writeQueueSend
= writeQueueSend
->pk_next
;
898 tmp_pkt
->pk_next
= NULL
;
899 if (writeQueueRoot
== NULL
)
900 writeQueueRoot
= tmp_pkt
;
902 tmp
= writeQueueRoot
;
903 while (tmp
->pk_next
!= NULL
) {
906 tmp
->pk_next
= tmp_pkt
;
909 #else /* not RETRANS */
911 * switcher has taken the write, so remove it from the
912 * queue, and free its resources
914 DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend
));
915 #endif /* if RETRANS ... else ... */
917 if (mode
== async_block_on_write
)
918 *finished
= DevSW_WriteFinished(deviceToUse
);
920 } /* endif write ok */
922 else /* packet == NULL */
924 if (mode
== async_block_on_write
)
925 *finished
= DevSW_WriteFinished(deviceToUse
);
929 static void async_process_heartbeat( void )
931 /* check to see whether we need to send a heartbeat */
932 gettimeofday(&time_now
, NULL
);
934 if (tv_diff(&time_now
, &time_lastalive
) >= HEARTRATE
)
937 * if we've not booted then don't do send a heartrate the link
938 * must be reliable enough for us to boot without any clever stuff,
939 * if we can't do this then theres little chance of the link staying
940 * together even with the resends etc
942 if (heartbeat_enabled
) {
943 gettimeofday(&time_lastalive
, NULL
);
949 static void async_process_callbacks( void )
951 /* call any registered asynchronous callbacks */
953 for ( i
= 0; i
< num_async_callbacks
; ++i
)
954 async_callbacks
[i
]( deviceToUse
, &time_now
);
957 void Adp_AsynchronousProcessing(const AsyncMode mode
)
959 bool finished
= FALSE
;
961 unsigned int wc
= 0, dc
= 0, ac
= 0, hc
= 0;
962 # define INC_COUNT(x) ((x)++)
964 # define INC_COUNT(x)
967 if ((time_lastalive
.tv_sec
== 0) && (time_lastalive
.tv_usec
== 0)) {
968 /* first time through, needs initing */
969 gettimeofday(&time_lastalive
, NULL
);
975 async_process_write( mode
, &finished
);
978 if ( ! finished
&& mode
!= async_block_on_write
)
980 async_process_dbug_read( mode
, &finished
);
984 if ( ! finished
&& mode
!= async_block_on_write
)
986 async_process_appl_read();
992 if (heartbeat_configured
)
993 async_process_heartbeat();
994 async_process_callbacks();
998 } while (!finished
&& mode
!= async_block_on_nothing
);
1001 if ( mode
!= async_block_on_nothing
)
1002 printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1003 mode
== async_block_on_write
? "blk_write" : "blk_read",
1009 * install a handler for DC_APPL packets (can be NULL), returning old one.
1011 DC_Appl_Handler
Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler
)
1013 DC_Appl_Handler old_handler
= dc_appl_handler
;
1016 printf( "Installing DC_APPL handler %x (old %x)\n", handler
, old_handler
);
1019 dc_appl_handler
= handler
;
1025 * add an asynchronous processing callback to the list
1026 * TRUE == okay, FALSE == no more async processing slots
1028 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc
)
1030 if ( num_async_callbacks
< MAX_ASYNC_CALLBACKS
&& callback_proc
!= NULL
)
1032 async_callbacks
[num_async_callbacks
] = callback_proc
;
1033 ++num_async_callbacks
;
1042 * delay for a given period (in microseconds)
1044 void Adp_delay(unsigned int period
)
1049 printf("delaying for %d microseconds\n", period
);
1051 tv
.tv_sec
= (period
/ 1000000);
1052 tv
.tv_usec
= (period
% 1000000);
1054 (void)select(0, NULL
, NULL
, NULL
, &tv
);
1057 /* EOF hostchan.c */