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 #if defined(__unix) || defined(__CYGWIN32__)
21 # include <sys/time.h>
23 int gettimeofday(struct timeval
*tp
, struct timezone
*tzp
);
42 #define UNUSED(x) (x = x) /* Silence compiler warnings for unused arguments */
45 #define HEARTRATE 5000000
48 * list of available drivers, declared in drivers.c
50 extern DeviceDescr
*devices
[];
52 static DeviceDescr
*deviceToUse
= NULL
;
54 static struct Channel
{
55 ChannelCallback callback
;
57 } channels
[CI_NUM_CHANNELS
];
59 static unsigned char HomeSeq
;
60 static unsigned char OppoSeq
;
63 * Handler for DC_APPL packets
65 static DC_Appl_Handler dc_appl_handler
= NULL
;
68 * slots for registered asynchronous processing callback procedures
70 #define MAX_ASYNC_CALLBACKS 8
71 static unsigned int num_async_callbacks
= 0;
72 static Adp_Async_Callback async_callbacks
[MAX_ASYNC_CALLBACKS
];
75 * writeQueueRoot is the queue of write requests pending acknowledgement
76 * writeQueueSend is the queue of pending write requests which will
77 * be a subset of the list writeQueueRoot
79 static Packet
*writeQueueRoot
= NULL
;
80 static Packet
*writeQueueSend
= NULL
;
81 static Packet
*resend_pkt
= NULL
;
82 static int resending
= FALSE
;
84 /* heartbeat_enabled is a flag used to indicate whether the heartbeat is
85 * currently turned on, heartbeat_enabled will be false in situations
86 * where even though a heartbeat is being used it is problematical or
87 * dis-advantageous to have it turned on, for instance during the
88 * initial stages of boot up
90 unsigned int heartbeat_enabled
= FALSE
;
91 /* heartbeat_configured is set up by the device driver to indicate whether
92 * the heartbeat is being used during this debug session. In contrast to
93 * heartbeat_enabled it must not be changed during a session. The logic for
94 * deciding whether to send a heartbeat is: Is heartbeat_configured for this
95 * session? if and only if it is then if heartbeat[is currently]_enabled and
96 * we are due to send a pulse then send it
98 unsigned int heartbeat_configured
= TRUE
;
100 void Adp_initSeq( void ) {
101 Packet
*tmp_pkt
= writeQueueSend
;
105 if ( writeQueueSend
!= NULL
) {
106 while (writeQueueSend
->pk_next
!=NULL
) {
107 tmp_pkt
= writeQueueSend
;
108 writeQueueSend
= tmp_pkt
->pk_next
;
109 DevSW_FreePacket(tmp_pkt
);
112 tmp_pkt
= writeQueueRoot
;
113 if ( writeQueueRoot
== NULL
)
116 while (writeQueueRoot
->pk_next
!=NULL
) {
117 tmp_pkt
= writeQueueRoot
;
118 writeQueueRoot
= tmp_pkt
->pk_next
;
119 DevSW_FreePacket(tmp_pkt
);
124 /**********************************************************************/
127 * Function: DummyCallback
128 * Purpose: Default callback routine to handle unexpected input
132 * Input: packet The received packet
134 * state Contains nothing of significance
138 static void DummyCallback(Packet
*packet
, void *state
)
141 const char fmt
[] = "Unexpected read on channel %u, length %d\n";
142 char fmtbuf
[sizeof(fmt
) + 24];
146 chan
= *(packet
->pk_buffer
);
147 sprintf(fmtbuf
, fmt
, chan
, packet
->pk_length
);
153 DevSW_FreePacket(packet
);
157 * Function: BlockingCallback
158 * Purpose: Callback routine used to implement a blocking read call
161 * Input: packet The received packet.
163 * Output: state Address of higher level's pointer to the received
168 static void BlockingCallback(Packet
*packet
, void *state
)
171 * Pass the packet back to the caller which requested a packet
172 * from this channel. This also flags the completion of the I/O
173 * request to the blocking read call.
175 *((Packet
**)state
) = packet
;
179 * Function: FireCallback
180 * Purpose: Pass received packet along to the callback routine for
181 * the appropriate channel
184 * Input: packet The received packet.
188 * Post-conditions: The Target-to-Host sequence number for the channel
189 * will have been incremented.
191 static void FireCallback(Packet
*packet
)
197 * is this a sensible channel number?
199 chan
= *(packet
->pk_buffer
);
200 if (invalidChannelID(chan
))
202 printf("ERROR: invalid ChannelID received from target\n");
205 * free the packet's resources, 'cause no-one else will
207 DevSW_FreePacket(packet
);
212 * looks OK - increment sequence number, and pass packet to callback
214 ch
= channels
+ chan
;
215 (ch
->callback
)(packet
, ch
->callback_state
);
218 /**********************************************************************/
221 * These are the externally visible functions. They are documented
224 void Adp_addToQueue(Packet
**head
, Packet
*newpkt
)
227 * this is a bit of a hack
232 * make sure that the hack we are about to use will work as expected
234 ASSERT(&(((Packet
*)0)->pk_next
) == 0, "bad struct Packet layout");
237 printf("Adp_addToQueue(%p, %p)\n", head
, newpkt
);
241 * here's the hack - it relies upon the next
242 * pointer being at the start of Packet.
244 pk
= (Packet
*)(head
);
247 * skip to the end of the queue
249 while (pk
->pk_next
!= NULL
)
253 * now add the new element
255 newpkt
->pk_next
= NULL
;
256 pk
->pk_next
= newpkt
;
259 Packet
*Adp_removeFromQueue(Packet
**head
)
271 AdpErrs
Adp_OpenDevice(const char *name
, const char *arg
,
272 unsigned int heartbeat_on
)
279 printf("Adp_OpenDevice(%s, %s)\n", name
, arg
? arg
: "<NULL>");
282 heartbeat_configured
= heartbeat_on
;
283 if (deviceToUse
!= NULL
)
284 return adp_device_already_open
;
286 for (i
= 0; (deviceToUse
= devices
[i
]) != NULL
; ++i
)
287 if (DevSW_Match(deviceToUse
, name
, arg
) == adp_ok
)
290 if (deviceToUse
== NULL
)
291 return adp_device_not_found
;
294 * we seem to have found a suitable device driver, so try to open it
296 if ((retc
= DevSW_Open(deviceToUse
, name
, arg
, DC_DBUG
)) != adp_ok
)
298 /* we don't have a device to use */
304 * there is no explicit open on channels any more, so
305 * initialise state for all channels.
307 for (chan
= 0; chan
< CI_NUM_CHANNELS
; ++chan
)
309 struct Channel
*ch
= channels
+ chan
;
311 ch
->callback
= DummyCallback
;
312 ch
->callback_state
= NULL
;
320 AdpErrs
Adp_CloseDevice(void)
325 printf("Adp_CloseDevice\n");
328 if (deviceToUse
== NULL
)
329 return adp_device_not_open
;
331 heartbeat_enabled
= FALSE
;
333 retc
= DevSW_Close(deviceToUse
, DC_DBUG
);
336 * we have to clear deviceToUse, even when the lower layers
337 * faulted the close, otherwise the condition will never clear
340 WARN("DevSW_Close faulted the call");
346 AdpErrs
Adp_Ioctl(int opcode
, void *args
)
349 printf("Adp_Ioctl\n");
352 if (deviceToUse
== NULL
)
353 return adp_device_not_open
;
355 return DevSW_Ioctl(deviceToUse
, opcode
, args
);
358 AdpErrs
Adp_ChannelRegisterRead(const ChannelID chan
,
359 const ChannelCallback cbfunc
,
363 printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan
, cbfunc
, cbstate
);
366 if (deviceToUse
== NULL
)
367 return adp_device_not_open
;
369 if (invalidChannelID(chan
))
370 return adp_bad_channel_id
;
374 channels
[chan
].callback
= DummyCallback
;
375 channels
[chan
].callback_state
= NULL
;
379 channels
[chan
].callback
= cbfunc
;
380 channels
[chan
].callback_state
= cbstate
;
386 AdpErrs
Adp_ChannelRead(const ChannelID chan
, Packet
**packet
)
391 printf("Adp_ChannelRead(%d, %x)\n", chan
, *packet
);
394 if (deviceToUse
== NULL
)
395 return adp_device_not_open
;
397 if (invalidChannelID(chan
))
398 return adp_bad_channel_id
;
401 * if a callback has already been registered for this
402 * channel, then we do not allow this blocking read.
404 ch
= channels
+ chan
;
405 if (ch
->callback
!= DummyCallback
)
406 return adp_callback_already_registered
;
409 * OK, use our own callback to wait for a packet to arrive
412 ch
->callback
= BlockingCallback
;
413 ch
->callback_state
= packet
;
417 * keep polling until a packet appears for this channel
419 while (((volatile Packet
*)(*packet
)) == NULL
)
421 * this call will block until a packet is read on any channel
423 Adp_AsynchronousProcessing(async_block_on_read
);
426 * OK, the packet has arrived: clear the callback
428 ch
->callback
= DummyCallback
;
429 ch
->callback_state
= NULL
;
434 static AdpErrs
ChannelWrite(
435 const ChannelID chan
, Packet
*packet
, AsyncMode mode
)
441 printf( "Adp_ChannelWrite(%d, %x)\n", chan
, packet
);
444 if (deviceToUse
== NULL
)
445 return adp_device_not_open
;
447 if (invalidChannelID(chan
))
448 return adp_bad_channel_id
;
451 * fill in the channels header at the start of this buffer
453 ch
= channels
+ chan
;
454 cptr
= packet
->pk_buffer
;
457 packet
->pk_length
+= CHAN_HEADER_SIZE
;
460 * OK, add this packet to the write queue, and try to flush it out
463 Adp_addToQueue(&writeQueueSend
, packet
);
464 Adp_AsynchronousProcessing(mode
);
469 AdpErrs
Adp_ChannelWrite(const ChannelID chan
, Packet
*packet
) {
470 return ChannelWrite(chan
, packet
, async_block_on_write
);
473 AdpErrs
Adp_ChannelWriteAsync(const ChannelID chan
, Packet
*packet
) {
474 return ChannelWrite(chan
, packet
, async_block_on_nothing
);
477 static AdpErrs
send_resend_msg(DeviceID devid
) {
480 * Send a resend message, usually in response to a bad packet or
481 * a resend request */
483 packet
= DevSW_AllocatePacket(CF_DATA_BYTE_POS
);
484 packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] = CI_PRIVATE
;
485 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
] = HomeSeq
;
486 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
] = OppoSeq
;
487 packet
->pk_buffer
[CF_FLAGS_BYTE_POS
] = CF_RELIABLE
| CF_RESEND
;
488 packet
->pk_length
= CF_DATA_BYTE_POS
;
489 return DevSW_Write(deviceToUse
, packet
, devid
);
492 static AdpErrs
check_seq(unsigned char msg_home
, unsigned char msg_oppo
) {
497 * check if we have got an ack for anything and if so remove it from the
500 if (msg_home
== (unsigned char)(OppoSeq
+1)) {
502 * arrived in sequence can increment our opposing seq number and remove
503 * the relevant packet from our queue
504 * check that the packet we're going to remove really is the right one
506 tmp_pkt
= writeQueueRoot
;
507 while ((tmp_pkt
->pk_next
!= NULL
) &&
508 (tmp_pkt
->pk_next
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
]
510 tmp_pkt
= tmp_pkt
->pk_next
;
513 if (tmp_pkt
->pk_next
== NULL
) {
515 printf("trying to remove a non existant packet\n");
517 return adp_bad_packet
;
520 Packet
*tmp
= tmp_pkt
->pk_next
;
522 printf("removing a packet from the root queue\n");
524 tmp_pkt
->pk_next
= tmp_pkt
->pk_next
->pk_next
;
525 /* remove the appropriate packet */
526 DevSW_FreePacket(tmp
);
530 else if (msg_home
< (unsigned char) (OppoSeq
+1)){
531 /* already received this message */
533 printf("sequence numbers low\n");
537 else { /* we've missed something */
539 printf("sequence numbers high\n");
545 static unsigned long tv_diff(const struct timeval
*time_now
,
546 const struct timeval
*time_was
)
548 return ( ((time_now
->tv_sec
* 1000000) + time_now
->tv_usec
)
549 - ((time_was
->tv_sec
* 1000000) + time_was
->tv_usec
) );
552 #if !defined(__unix) && !defined(__CYGWIN32__)
553 static void gettimeofday( struct timeval
*time_now
, void *dummy
)
557 time_now
->tv_sec
= t
/CLOCKS_PER_SEC
;
558 time_now
->tv_usec
= (t
%CLOCKS_PER_SEC
)*(1000000/CLOCKS_PER_SEC
);
562 static AdpErrs
pacemaker(void)
566 packet
= DevSW_AllocatePacket(CF_DATA_BYTE_POS
);
567 if (packet
== NULL
) {
568 printf("ERROR: could not allocate a packet in pacemaker()\n");
569 return adp_malloc_failure
;
571 packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] = CI_PRIVATE
;
572 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
] = HomeSeq
;
573 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
] = OppoSeq
;
574 packet
->pk_buffer
[CF_FLAGS_BYTE_POS
] = CF_RELIABLE
| CF_HEARTBEAT
;
575 packet
->pk_length
= CF_DATA_BYTE_POS
;
576 return DevSW_Write(deviceToUse
, packet
, DC_DBUG
);
579 #ifdef FAKE_BAD_LINE_RX
580 static AdpErrs
fake_bad_line_rx( const Packet
*const packet
, AdpErrs adp_err
)
582 static unsigned int bl_num
= 0;
584 if ( (packet
!= NULL
)
586 && ((bl_num
% FAKE_BAD_LINE_RX
) == 0))
588 printf("DEBUG: faking a bad packet\n");
589 return adp_bad_packet
;
593 #endif /* def FAKE_BAD_LINE_RX */
595 #ifdef FAKE_BAD_LINE_TX
596 static unsigned char tmp_ch
;
598 static void fake_bad_line_tx( void )
600 static unsigned int bl_num
= 0;
602 /* give the thing a chance to boot then try corrupting stuff */
603 if ( (bl_num
++ >= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) == 0))
605 printf("DEBUG: faking a bad packet for tx\n");
606 tmp_ch
= writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
];
607 writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
] = 77;
611 static void unfake_bad_line_tx( void )
613 static unsigned int bl_num
= 0;
616 * must reset the packet so that its not corrupted when we
619 if ( (bl_num
>= 20) && ((bl_num
% FAKE_BAD_LINE_TX
) != 0))
621 writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
] = tmp_ch
;
624 #endif /* def FAKE_BAD_LINE_TX */
627 * NOTE: we are assuming that a resolution of microseconds will
628 * be good enough for the purporses of the heartbeat. If this proves
629 * not to be the case then we may need a rethink, possibly using
632 static struct timeval time_now
;
633 static struct timeval time_lastalive
;
635 static void async_process_dbug_read( const AsyncMode mode
,
636 bool *const finished
)
639 unsigned int msg_home
, msg_oppo
;
642 adp_err
= DevSW_Read(deviceToUse
, DC_DBUG
, &packet
,
643 mode
== async_block_on_read
);
645 #ifdef FAKE_BAD_LINE_RX
646 adp_err
= fake_bad_line_rx( packet
, adp_err
);
649 if (adp_err
== adp_bad_packet
) {
650 /* We got a bad packet, ask for a resend, send a resend message */
652 printf("received a bad packet\n");
654 send_resend_msg(DC_DBUG
);
656 else if (packet
!= NULL
)
658 /* update the heartbeat clock */
659 gettimeofday(&time_lastalive
, NULL
);
662 * we got a live one here - were we waiting for it?
664 if (mode
== async_block_on_read
)
669 if (packet
->pk_length
< CF_DATA_BYTE_POS
) {
670 /* we've got a packet with no header information! */
671 printf("ERROR: packet with no transport header\n");
672 send_resend_msg(DC_DBUG
);
679 * TODO: Check to see if its acknowledgeing anything, remove
680 * those packets it is from the queue. If its a retrans add the
681 * packets to the queue
683 msg_home
= packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
];
684 msg_oppo
= packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
];
686 printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
688 for (c
=0;c
<packet
->pk_length
;c
++)
689 printf("%02.2x", packet
->pk_buffer
[c
]);
692 /* now was it a resend request? */
693 if ((packet
->pk_buffer
[CF_FLAGS_BYTE_POS
])
695 /* we've been asked for a resend so we had better resend */
697 * I don't think we can use a resend as acknowledgement for
698 * anything so lets not do this for the moment
699 * check_seq(msg_home, msg_oppo);
702 printf("received a resend request\n");
704 if (HomeSeq
!= msg_oppo
) {
706 /* need to resend from msg_oppo +1 upwards */
707 DevSW_FreePacket(packet
);
709 /* find the correct packet to resend from */
710 packet
= writeQueueRoot
;
711 while (((packet
->pk_next
) != NULL
) && !found
) {
712 if ((packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
])
717 packet
= packet
->pk_next
;
720 panic("trying to resend non-existent packets\n");
723 else if (OppoSeq
!= msg_home
) {
725 * send a resend request telling the target where we think
728 DevSW_FreePacket(packet
);
729 send_resend_msg(DC_DBUG
);
733 /* not a resend request, lets check the sequence numbers */
735 if ((packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] != CI_HBOOT
) &&
736 (packet
->pk_buffer
[CF_CHANNEL_BYTE_POS
] != CI_TBOOT
)) {
737 adp_err
= check_seq(msg_home
, msg_oppo
);
738 if (adp_err
== adp_seq_low
) {
739 /* we have already received this packet so discard */
740 DevSW_FreePacket(packet
);
742 else if (adp_err
== adp_seq_high
) {
744 * we must have missed a packet somewhere, discard this
745 * packet and tell the target where we are
747 DevSW_FreePacket(packet
);
748 send_resend_msg(DC_DBUG
);
752 * now pass the packet to whoever is waiting for it
754 FireCallback(packet
);
757 FireCallback(packet
);
762 * now pass the packet to whoever is waiting for it
764 FireCallback(packet
);
769 static void async_process_appl_read(void)
774 /* see if there is anything for the DC_APPL channel */
775 adp_err
= DevSW_Read(deviceToUse
, DC_APPL
, &packet
, FALSE
);
777 if (adp_err
== adp_ok
&& packet
!= NULL
)
779 /* got an application packet on a shared device */
782 printf("GOT DC_APPL PACKET: len %d\nData: ", packet
->pk_length
);
785 for ( c
= 0; c
< packet
->pk_length
; ++c
)
786 printf( "%02X ", packet
->pk_buffer
[c
] );
791 if (dc_appl_handler
!= NULL
)
793 dc_appl_handler( deviceToUse
, packet
);
797 /* for now, just free it!! */
799 printf("no handler - dropping DC_APPL packet\n");
801 DevSW_FreePacket( packet
);
806 static void async_process_write( const AsyncMode mode
,
807 bool *const finished
)
812 static unsigned int num_written
= 0;
816 * NOTE: here we rely in the fact that any packet in the writeQueueSend
817 * section of the queue will need its sequence number setting up while
818 * and packet in the writeQueueRoot section will have its sequence
819 * numbers set up from when it was first sent so we can easily look
820 * up the packet numbers when(if) we want to resend the packet.
824 if (writeQueueSend
!=NULL
)
825 printf("written 0x%x\n",num_written
+= writeQueueSend
->pk_length
);
828 * give the switcher a chance to complete any partial writes
830 if (DevSW_FlushPendingWrite(deviceToUse
) == adp_write_busy
)
832 /* no point trying a new write */
837 * now see whether there is anything to write
843 printf("resending hseq 0x%x oseq 0x%x\n",
844 packet
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
],
845 packet
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
]);
848 else if (writeQueueSend
!= NULL
) {
850 /* set up the sequence number on the packet */
851 packet
= writeQueueSend
;
853 (writeQueueSend
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
])
855 (writeQueueSend
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
])
857 (writeQueueSend
->pk_buffer
[CF_FLAGS_BYTE_POS
])
860 printf("sending packet with hseq 0x%x oseq 0x%x\n",
861 writeQueueSend
->pk_buffer
[CF_HOME_SEQ_BYTE_POS
],
862 writeQueueSend
->pk_buffer
[CF_OPPO_SEQ_BYTE_POS
]);
867 if (packet
!= NULL
) {
870 #ifdef FAKE_BAD_LINE_TX
874 dev_err
= DevSW_Write(deviceToUse
, packet
, DC_DBUG
);
875 if (dev_err
== adp_ok
) {
878 /* check to see if we've recovered yet */
879 if ((packet
->pk_next
) == NULL
){
881 printf("we have recovered\n");
886 resend_pkt
= resend_pkt
->pk_next
;
891 * move the packet we just sent from the send queue to the root
893 Packet
*tmp_pkt
, *tmp
;
895 # ifdef FAKE_BAD_LINE_TX
896 unfake_bad_line_tx();
899 tmp_pkt
= writeQueueSend
;
900 writeQueueSend
= writeQueueSend
->pk_next
;
901 tmp_pkt
->pk_next
= NULL
;
902 if (writeQueueRoot
== NULL
)
903 writeQueueRoot
= tmp_pkt
;
905 tmp
= writeQueueRoot
;
906 while (tmp
->pk_next
!= NULL
) {
909 tmp
->pk_next
= tmp_pkt
;
912 #else /* not RETRANS */
914 * switcher has taken the write, so remove it from the
915 * queue, and free its resources
917 DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend
));
918 #endif /* if RETRANS ... else ... */
920 if (mode
== async_block_on_write
)
921 *finished
= DevSW_WriteFinished(deviceToUse
);
923 } /* endif write ok */
925 else /* packet == NULL */
927 if (mode
== async_block_on_write
)
928 *finished
= DevSW_WriteFinished(deviceToUse
);
932 static void async_process_heartbeat( void )
934 /* check to see whether we need to send a heartbeat */
935 gettimeofday(&time_now
, NULL
);
937 if (tv_diff(&time_now
, &time_lastalive
) >= HEARTRATE
)
940 * if we've not booted then don't do send a heartrate the link
941 * must be reliable enough for us to boot without any clever stuff,
942 * if we can't do this then theres little chance of the link staying
943 * together even with the resends etc
945 if (heartbeat_enabled
) {
946 gettimeofday(&time_lastalive
, NULL
);
952 static void async_process_callbacks( void )
954 /* call any registered asynchronous callbacks */
956 for ( i
= 0; i
< num_async_callbacks
; ++i
)
957 async_callbacks
[i
]( deviceToUse
, &time_now
);
960 void Adp_AsynchronousProcessing(const AsyncMode mode
)
962 bool finished
= FALSE
;
964 unsigned int wc
= 0, dc
= 0, ac
= 0, hc
= 0;
965 # define INC_COUNT(x) ((x)++)
967 # define INC_COUNT(x)
970 if ((time_lastalive
.tv_sec
== 0) && (time_lastalive
.tv_usec
== 0)) {
971 /* first time through, needs initing */
972 gettimeofday(&time_lastalive
, NULL
);
978 async_process_write( mode
, &finished
);
981 if ( ! finished
&& mode
!= async_block_on_write
)
983 async_process_dbug_read( mode
, &finished
);
987 if ( ! finished
&& mode
!= async_block_on_write
)
989 async_process_appl_read();
995 if (heartbeat_configured
)
996 async_process_heartbeat();
997 async_process_callbacks();
1001 } while (!finished
&& mode
!= async_block_on_nothing
);
1004 if ( mode
!= async_block_on_nothing
)
1005 printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1006 mode
== async_block_on_write
? "blk_write" : "blk_read",
1012 * install a handler for DC_APPL packets (can be NULL), returning old one.
1014 DC_Appl_Handler
Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler
)
1016 DC_Appl_Handler old_handler
= dc_appl_handler
;
1019 printf( "Installing DC_APPL handler %x (old %x)\n", handler
, old_handler
);
1022 dc_appl_handler
= handler
;
1028 * add an asynchronous processing callback to the list
1029 * TRUE == okay, FALSE == no more async processing slots
1031 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc
)
1033 if ( num_async_callbacks
< MAX_ASYNC_CALLBACKS
&& callback_proc
!= NULL
)
1035 async_callbacks
[num_async_callbacks
] = callback_proc
;
1036 ++num_async_callbacks
;
1045 * delay for a given period (in microseconds)
1047 void Adp_delay(unsigned int period
)
1052 printf("delaying for %d microseconds\n", period
);
1054 tv
.tv_sec
= (period
/ 1000000);
1055 tv
.tv_usec
= (period
% 1000000);
1057 (void)select(0, NULL
, NULL
, NULL
, &tv
);
1060 /* EOF hostchan.c */