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