1 /*
2 * Copyright (C) 1995 Advanced RISC Machines Limited. All rights reserved.
3 *
4 * This software may be freely used, copied, modified, and distributed
5 * provided that the above copyright notice is preserved in all copies of the
6 * software.
7 */
8
9 /* -*-C-*-
10 *
11 * $Revision: 1.3 $
12 * $Date: 2004/12/27 14:00:54 $
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
Adp_initSeq(void)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 */
DummyCallback(Packet * packet,void * state)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 */
BlockingCallback(Packet * packet,void * state)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 */
FireCallback(Packet * packet)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 */
Adp_addToQueue(Packet ** head,Packet * newpkt)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 defined(DEBUG) && 0
234 printf("Adp_addToQueue(%p, %p)\n", head, newpkt);
235 #endif
236
237 /*
238 * here's the hack - it relies upon the next
239 * pointer being at the start of Packet.
240 */
241 pk = (Packet *)(head);
242
243 /*
244 * skip to the end of the queue
245 */
246 while (pk->pk_next != NULL)
247 pk = pk->pk_next;
248
249 /*
250 * now add the new element
251 */
252 newpkt->pk_next = NULL;
253 pk->pk_next = newpkt;
254 }
255
Adp_removeFromQueue(Packet ** head)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
Adp_SetLogEnable(int logEnableFlag)268 void Adp_SetLogEnable(int logEnableFlag)
269 {
270 DevSW_SetLogEnable(logEnableFlag);
271 }
272
Adp_SetLogfile(const char * filename)273 void Adp_SetLogfile(const char *filename)
274 {
275 DevSW_SetLogfile(filename);
276 }
277
Adp_OpenDevice(const char * name,const char * arg,unsigned int heartbeat_on)278 AdpErrs Adp_OpenDevice(const char *name, const char *arg,
279 unsigned int heartbeat_on)
280 {
281 int i;
282 AdpErrs retc;
283 ChannelID chan;
284
285 #ifdef DEBUG
286 printf("Adp_OpenDevice(%s, %s)\n", name, arg ? arg : "<NULL>");
287 #endif
288
289 heartbeat_configured = heartbeat_on;
290 if (deviceToUse != NULL)
291 return adp_device_already_open;
292
293 for (i = 0; (deviceToUse = devices[i]) != NULL; ++i)
294 if (DevSW_Match(deviceToUse, name, arg) == adp_ok)
295 break;
296
297 if (deviceToUse == NULL)
298 return adp_device_not_found;
299
300 /*
301 * we seem to have found a suitable device driver, so try to open it
302 */
303 if ((retc = DevSW_Open(deviceToUse, name, arg, DC_DBUG)) != adp_ok)
304 {
305 /* we don't have a device to use */
306 deviceToUse = NULL;
307 return retc;
308 }
309
310 /*
311 * there is no explicit open on channels any more, so
312 * initialise state for all channels.
313 */
314 for (chan = 0; chan < CI_NUM_CHANNELS; ++chan)
315 {
316 struct Channel *ch = channels + chan;
317
318 ch->callback = DummyCallback;
319 ch->callback_state = NULL;
320 OppoSeq = 0;
321 HomeSeq = 0;
322 }
323
324 return adp_ok;
325 }
326
Adp_CloseDevice(void)327 AdpErrs Adp_CloseDevice(void)
328 {
329 AdpErrs retc;
330
331 #ifdef DEBUG
332 printf("Adp_CloseDevice\n");
333 #endif
334
335 if (deviceToUse == NULL)
336 return adp_device_not_open;
337
338 heartbeat_enabled = FALSE;
339
340 retc = DevSW_Close(deviceToUse, DC_DBUG);
341
342 /*
343 * we have to clear deviceToUse, even when the lower layers
344 * faulted the close, otherwise the condition will never clear
345 */
346 if (retc != adp_ok)
347 WARN("DevSW_Close faulted the call");
348
349 deviceToUse = NULL;
350 return retc;
351 }
352
Adp_Ioctl(int opcode,void * args)353 AdpErrs Adp_Ioctl(int opcode, void *args)
354 {
355 #ifdef DEBUG
356 printf("Adp_Ioctl\n");
357 #endif
358
359 if (deviceToUse == NULL)
360 return adp_device_not_open;
361
362 return DevSW_Ioctl(deviceToUse, opcode, args);
363 }
364
Adp_ChannelRegisterRead(const ChannelID chan,const ChannelCallback cbfunc,void * cbstate)365 AdpErrs Adp_ChannelRegisterRead(const ChannelID chan,
366 const ChannelCallback cbfunc,
367 void *cbstate)
368 {
369 #ifdef DEBUG
370 printf("Adp_ChannelRegisterRead(%d, %p, %x)\n", chan, cbfunc, cbstate);
371 #endif
372
373 if (deviceToUse == NULL)
374 return adp_device_not_open;
375
376 if (invalidChannelID(chan))
377 return adp_bad_channel_id;
378
379 if (cbfunc == NULL)
380 {
381 channels[chan].callback = DummyCallback;
382 channels[chan].callback_state = NULL;
383 }
384 else
385 {
386 channels[chan].callback = cbfunc;
387 channels[chan].callback_state = cbstate;
388 }
389
390 return adp_ok;
391 }
392
Adp_ChannelRead(const ChannelID chan,Packet ** packet)393 AdpErrs Adp_ChannelRead(const ChannelID chan, Packet **packet)
394 {
395 struct Channel *ch;
396
397 #ifdef DEBUG
398 printf("Adp_ChannelRead(%d, %x)\n", chan, *packet);
399 #endif
400
401 if (deviceToUse == NULL)
402 return adp_device_not_open;
403
404 if (invalidChannelID(chan))
405 return adp_bad_channel_id;
406
407 /*
408 * if a callback has already been registered for this
409 * channel, then we do not allow this blocking read.
410 */
411 ch = channels + chan;
412 if (ch->callback != DummyCallback)
413 return adp_callback_already_registered;
414
415 /*
416 * OK, use our own callback to wait for a packet to arrive
417 * on this channel
418 */
419 ch->callback = BlockingCallback;
420 ch->callback_state = packet;
421 *packet = NULL;
422
423 /*
424 * keep polling until a packet appears for this channel
425 */
426 while (((volatile Packet *)(*packet)) == NULL)
427 /*
428 * this call will block until a packet is read on any channel
429 */
430 Adp_AsynchronousProcessing(async_block_on_read);
431
432 /*
433 * OK, the packet has arrived: clear the callback
434 */
435 ch->callback = DummyCallback;
436 ch->callback_state = NULL;
437
438 return adp_ok;
439 }
440
ChannelWrite(const ChannelID chan,Packet * packet,AsyncMode mode)441 static AdpErrs ChannelWrite(
442 const ChannelID chan, Packet *packet, AsyncMode mode)
443 {
444 struct Channel *ch;
445 unsigned char *cptr;
446
447 #ifdef DEBUG
448 printf( "Adp_ChannelWrite(%d, %x)\n", chan, packet );
449 #endif
450
451 if (deviceToUse == NULL)
452 return adp_device_not_open;
453
454 if (invalidChannelID(chan))
455 return adp_bad_channel_id;
456
457 /*
458 * fill in the channels header at the start of this buffer
459 */
460 ch = channels + chan;
461 cptr = packet->pk_buffer;
462 *cptr++ = chan;
463 *cptr = 0;
464 packet->pk_length += CHAN_HEADER_SIZE;
465
466 /*
467 * OK, add this packet to the write queue, and try to flush it out
468 */
469
470 Adp_addToQueue(&writeQueueSend, packet);
471 Adp_AsynchronousProcessing(mode);
472
473 return adp_ok;
474 }
475
Adp_ChannelWrite(const ChannelID chan,Packet * packet)476 AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) {
477 return ChannelWrite(chan, packet, async_block_on_write);
478 }
479
Adp_ChannelWriteAsync(const ChannelID chan,Packet * packet)480 AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) {
481 return ChannelWrite(chan, packet, async_block_on_nothing);
482 }
483
send_resend_msg(DeviceID devid)484 static AdpErrs send_resend_msg(DeviceID devid) {
485
486 /*
487 * Send a resend message, usually in response to a bad packet or
488 * a resend request */
489 Packet * packet;
490 packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
491 packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
492 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
493 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
494 packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_RESEND;
495 packet->pk_length = CF_DATA_BYTE_POS;
496 return DevSW_Write(deviceToUse, packet, devid);
497 }
498
check_seq(unsigned char msg_home,unsigned char msg_oppo)499 static AdpErrs check_seq(unsigned char msg_home, unsigned char msg_oppo) {
500 Packet *tmp_pkt;
501
502 UNUSED(msg_oppo);
503 /*
504 * check if we have got an ack for anything and if so remove it from the
505 * queue
506 */
507 if (msg_home == (unsigned char)(OppoSeq+1)) {
508 /*
509 * arrived in sequence can increment our opposing seq number and remove
510 * the relevant packet from our queue
511 * check that the packet we're going to remove really is the right one
512 */
513 tmp_pkt = writeQueueRoot;
514 while ((tmp_pkt->pk_next != NULL) &&
515 (tmp_pkt->pk_next->pk_buffer[CF_HOME_SEQ_BYTE_POS]
516 != OppoSeq)){
517 tmp_pkt = tmp_pkt->pk_next;
518 }
519 OppoSeq++;
520 if (tmp_pkt->pk_next == NULL) {
521 #ifdef DEBUG
522 printf("trying to remove a non existant packet\n");
523 #endif
524 return adp_bad_packet;
525 }
526 else {
527 Packet *tmp = tmp_pkt->pk_next;
528 #ifdef RET_DEBUG
529 printf("removing a packet from the root queue\n");
530 #endif
531 tmp_pkt->pk_next = tmp_pkt->pk_next->pk_next;
532 /* remove the appropriate packet */
533 DevSW_FreePacket(tmp);
534 return adp_ok;
535 }
536 }
537 else if (msg_home < (unsigned char) (OppoSeq+1)){
538 /* already received this message */
539 #ifdef RET_DEBUG
540 printf("sequence numbers low\n");
541 #endif
542 return adp_seq_low;
543 }
544 else { /* we've missed something */
545 #ifdef RET_DEBUG
546 printf("sequence numbers high\n");
547 #endif
548 return adp_seq_high;
549 }
550 }
551
tv_diff(const struct timeval * time_now,const struct timeval * time_was)552 static unsigned long tv_diff(const struct timeval *time_now,
553 const struct timeval *time_was)
554 {
555 return ( ((time_now->tv_sec * 1000000) + time_now->tv_usec)
556 - ((time_was->tv_sec * 1000000) + time_was->tv_usec) );
557 }
558
559 #if !defined(__unix) && !defined(__CYGWIN__)
gettimeofday(struct timeval * time_now,void * dummy)560 static void gettimeofday( struct timeval *time_now, void *dummy )
561 {
562 time_t t = clock();
563 UNUSED(dummy);
564 time_now->tv_sec = t/CLOCKS_PER_SEC;
565 time_now->tv_usec = (t%CLOCKS_PER_SEC)*(1000000/CLOCKS_PER_SEC);
566 }
567 #endif
568
pacemaker(void)569 static AdpErrs pacemaker(void)
570 {
571 Packet *packet;
572
573 packet = DevSW_AllocatePacket(CF_DATA_BYTE_POS);
574 if (packet == NULL) {
575 printf("ERROR: could not allocate a packet in pacemaker()\n");
576 return adp_malloc_failure;
577 }
578 packet->pk_buffer[CF_CHANNEL_BYTE_POS] = CI_PRIVATE;
579 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS] = HomeSeq;
580 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS] = OppoSeq;
581 packet->pk_buffer[CF_FLAGS_BYTE_POS] = CF_RELIABLE | CF_HEARTBEAT;
582 packet->pk_length = CF_DATA_BYTE_POS;
583 return DevSW_Write(deviceToUse, packet, DC_DBUG);
584 }
585
586 #ifdef FAKE_BAD_LINE_RX
fake_bad_line_rx(const Packet * const packet,AdpErrs adp_err)587 static AdpErrs fake_bad_line_rx( const Packet *const packet, AdpErrs adp_err )
588 {
589 static unsigned int bl_num = 0;
590
591 if ( (packet != NULL)
592 && (bl_num++ >= 20 )
593 && ((bl_num % FAKE_BAD_LINE_RX) == 0))
594 {
595 printf("DEBUG: faking a bad packet\n");
596 return adp_bad_packet;
597 }
598 return adp_err;
599 }
600 #endif /* def FAKE_BAD_LINE_RX */
601
602 #ifdef FAKE_BAD_LINE_TX
603 static unsigned char tmp_ch;
604
fake_bad_line_tx(void)605 static void fake_bad_line_tx( void )
606 {
607 static unsigned int bl_num = 0;
608
609 /* give the thing a chance to boot then try corrupting stuff */
610 if ( (bl_num++ >= 20) && ((bl_num % FAKE_BAD_LINE_TX) == 0))
611 {
612 printf("DEBUG: faking a bad packet for tx\n");
613 tmp_ch = writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS];
614 writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = 77;
615 }
616 }
617
unfake_bad_line_tx(void)618 static void unfake_bad_line_tx( void )
619 {
620 static unsigned int bl_num = 0;
621
622 /*
623 * must reset the packet so that its not corrupted when we
624 * resend it
625 */
626 if ( (bl_num >= 20) && ((bl_num % FAKE_BAD_LINE_TX) != 0))
627 {
628 writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS] = tmp_ch;
629 }
630 }
631 #endif /* def FAKE_BAD_LINE_TX */
632
633 /*
634 * NOTE: we are assuming that a resolution of microseconds will
635 * be good enough for the purporses of the heartbeat. If this proves
636 * not to be the case then we may need a rethink, possibly using
637 * [get,set]itimer
638 */
639 static struct timeval time_now;
640 static struct timeval time_lastalive;
641
async_process_dbug_read(const AsyncMode mode,bool * const finished)642 static void async_process_dbug_read( const AsyncMode mode,
643 bool *const finished )
644 {
645 Packet *packet;
646 unsigned int msg_home, msg_oppo;
647 AdpErrs adp_err;
648
649 adp_err = DevSW_Read(deviceToUse, DC_DBUG, &packet,
650 mode == async_block_on_read );
651
652 #ifdef FAKE_BAD_LINE_RX
653 adp_err = fake_bad_line_rx( packet, adp_err );
654 #endif
655
656 if (adp_err == adp_bad_packet) {
657 /* We got a bad packet, ask for a resend, send a resend message */
658 #ifdef DEBUG
659 printf("received a bad packet\n");
660 #endif
661 send_resend_msg(DC_DBUG);
662 }
663 else if (packet != NULL)
664 {
665 /* update the heartbeat clock */
666 gettimeofday(&time_lastalive, NULL);
667
668 /*
669 * we got a live one here - were we waiting for it?
670 */
671 if (mode == async_block_on_read)
672 /* not any more */
673 *finished = TRUE;
674 #ifdef RETRANS
675
676 if (packet->pk_length < CF_DATA_BYTE_POS) {
677 /* we've got a packet with no header information! */
678 printf("ERROR: packet with no transport header\n");
679 send_resend_msg(DC_DBUG);
680 }
681 else {
682 #ifdef RET_DEBUG
683 unsigned int c;
684 #endif
685 /*
686 * TODO: Check to see if its acknowledgeing anything, remove
687 * those packets it is from the queue. If its a retrans add the
688 * packets to the queue
689 */
690 msg_home = packet->pk_buffer[CF_HOME_SEQ_BYTE_POS];
691 msg_oppo = packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS];
692 #ifdef RET_DEBUG
693 printf("msg seq numbers are hseq 0x%x oseq 0x%x\n",
694 msg_home, msg_oppo);
695 for (c=0;c<packet->pk_length;c++)
696 printf("%02.2x", packet->pk_buffer[c]);
697 printf("\n");
698 #endif
699 /* now was it a resend request? */
700 if ((packet->pk_buffer[CF_FLAGS_BYTE_POS])
701 & CF_RESEND) {
702 /* we've been asked for a resend so we had better resend */
703 /*
704 * I don't think we can use a resend as acknowledgement for
705 * anything so lets not do this for the moment
706 * check_seq(msg_home, msg_oppo);
707 */
708 #ifdef RET_DEBUG
709 printf("received a resend request\n");
710 #endif
711 if (HomeSeq != msg_oppo) {
712 int found = FALSE;
713 /* need to resend from msg_oppo +1 upwards */
714 DevSW_FreePacket(packet);
715 resending = TRUE;
716 /* find the correct packet to resend from */
717 packet = writeQueueRoot;
718 while (((packet->pk_next) != NULL) && !found) {
719 if ((packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
720 != msg_oppo+1) {
721 resend_pkt = packet;
722 found = TRUE;
723 }
724 packet = packet->pk_next;
725 }
726 if (!found) {
727 panic("trying to resend non-existent packets\n");
728 }
729 }
730 else if (OppoSeq != msg_home) {
731 /*
732 * send a resend request telling the target where we think
733 * the world is at
734 */
735 DevSW_FreePacket(packet);
736 send_resend_msg(DC_DBUG);
737 }
738 }
739 else {
740 /* not a resend request, lets check the sequence numbers */
741
742 if ((packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_HBOOT) &&
743 (packet->pk_buffer[CF_CHANNEL_BYTE_POS] != CI_TBOOT)) {
744 adp_err = check_seq(msg_home, msg_oppo);
745 if (adp_err == adp_seq_low) {
746 /* we have already received this packet so discard */
747 DevSW_FreePacket(packet);
748 }
749 else if (adp_err == adp_seq_high) {
750 /*
751 * we must have missed a packet somewhere, discard this
752 * packet and tell the target where we are
753 */
754 DevSW_FreePacket(packet);
755 send_resend_msg(DC_DBUG);
756 }
757 else
758 /*
759 * now pass the packet to whoever is waiting for it
760 */
761 FireCallback(packet);
762 }
763 else
764 FireCallback(packet);
765 }
766 }
767 #else
768 /*
769 * now pass the packet to whoever is waiting for it
770 */
771 FireCallback(packet);
772 #endif
773 }
774 }
775
async_process_appl_read(void)776 static void async_process_appl_read(void)
777 {
778 Packet *packet;
779 AdpErrs adp_err;
780
781 /* see if there is anything for the DC_APPL channel */
782 adp_err = DevSW_Read(deviceToUse, DC_APPL, &packet, FALSE);
783
784 if (adp_err == adp_ok && packet != NULL)
785 {
786 /* got an application packet on a shared device */
787
788 #ifdef DEBUG
789 printf("GOT DC_APPL PACKET: len %d\nData: ", packet->pk_length);
790 {
791 unsigned int c;
792 for ( c = 0; c < packet->pk_length; ++c )
793 printf( "%02X ", packet->pk_buffer[c] );
794 }
795 printf("\n");
796 #endif
797
798 if (dc_appl_handler != NULL)
799 {
800 dc_appl_handler( deviceToUse, packet );
801 }
802 else
803 {
804 /* for now, just free it!! */
805 #ifdef DEBUG
806 printf("no handler - dropping DC_APPL packet\n");
807 #endif
808 DevSW_FreePacket( packet );
809 }
810 }
811 }
812
async_process_write(const AsyncMode mode,bool * const finished)813 static void async_process_write( const AsyncMode mode,
814 bool *const finished )
815 {
816 Packet *packet;
817
818 #ifdef DEBUG
819 static unsigned int num_written = 0;
820 #endif
821
822 /*
823 * NOTE: here we rely in the fact that any packet in the writeQueueSend
824 * section of the queue will need its sequence number setting up while
825 * and packet in the writeQueueRoot section will have its sequence
826 * numbers set up from when it was first sent so we can easily look
827 * up the packet numbers when(if) we want to resend the packet.
828 */
829
830 #ifdef DEBUG
831 if (writeQueueSend!=NULL)
832 printf("written 0x%x\n",num_written += writeQueueSend->pk_length);
833 #endif
834 /*
835 * give the switcher a chance to complete any partial writes
836 */
837 if (DevSW_FlushPendingWrite(deviceToUse) == adp_write_busy)
838 {
839 /* no point trying a new write */
840 return;
841 }
842
843 /*
844 * now see whether there is anything to write
845 */
846 packet = NULL;
847 if (resending) {
848 packet = resend_pkt;
849 #ifdef RET_DEBUG
850 printf("resending hseq 0x%x oseq 0x%x\n",
851 packet->pk_buffer[CF_HOME_SEQ_BYTE_POS],
852 packet->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
853 #endif
854 }
855 else if (writeQueueSend != NULL) {
856 #ifdef RETRANS
857 /* set up the sequence number on the packet */
858 packet = writeQueueSend;
859 HomeSeq++;
860 (writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS])
861 = OppoSeq;
862 (writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS])
863 = HomeSeq;
864 (writeQueueSend->pk_buffer[CF_FLAGS_BYTE_POS])
865 = CF_RELIABLE;
866 # ifdef RET_DEBUG
867 printf("sending packet with hseq 0x%x oseq 0x%x\n",
868 writeQueueSend->pk_buffer[CF_HOME_SEQ_BYTE_POS],
869 writeQueueSend->pk_buffer[CF_OPPO_SEQ_BYTE_POS]);
870 # endif
871 #endif /* RETRANS */
872 }
873
874 if (packet != NULL) {
875 AdpErrs dev_err;
876
877 #ifdef FAKE_BAD_LINE_TX
878 fake_bad_line_tx();
879 #endif
880
881 dev_err = DevSW_Write(deviceToUse, packet, DC_DBUG);
882 if (dev_err == adp_ok) {
883 #ifdef RETRANS
884 if (resending) {
885 /* check to see if we've recovered yet */
886 if ((packet->pk_next) == NULL){
887 # ifdef RET_DEBUG
888 printf("we have recovered\n");
889 # endif
890 resending = FALSE;
891 }
892 else {
893 resend_pkt = resend_pkt->pk_next;
894 }
895 }
896 else {
897 /*
898 * move the packet we just sent from the send queue to the root
899 */
900 Packet *tmp_pkt, *tmp;
901
902 # ifdef FAKE_BAD_LINE_TX
903 unfake_bad_line_tx();
904 # endif
905
906 tmp_pkt = writeQueueSend;
907 writeQueueSend = writeQueueSend->pk_next;
908 tmp_pkt->pk_next = NULL;
909 if (writeQueueRoot == NULL)
910 writeQueueRoot = tmp_pkt;
911 else {
912 tmp = writeQueueRoot;
913 while (tmp->pk_next != NULL) {
914 tmp = tmp->pk_next;
915 }
916 tmp->pk_next = tmp_pkt;
917 }
918 }
919 #else /* not RETRANS */
920 /*
921 * switcher has taken the write, so remove it from the
922 * queue, and free its resources
923 */
924 DevSW_FreePacket(Adp_removeFromQueue(&writeQueueSend));
925 #endif /* if RETRANS ... else ... */
926
927 if (mode == async_block_on_write)
928 *finished = DevSW_WriteFinished(deviceToUse);
929
930 } /* endif write ok */
931 }
932 else /* packet == NULL */
933 {
934 if (mode == async_block_on_write)
935 *finished = DevSW_WriteFinished(deviceToUse);
936 }
937 }
938
async_process_heartbeat(void)939 static void async_process_heartbeat( void )
940 {
941 /* check to see whether we need to send a heartbeat */
942 gettimeofday(&time_now, NULL);
943
944 if (tv_diff(&time_now, &time_lastalive) >= HEARTRATE)
945 {
946 /*
947 * if we've not booted then don't do send a heartrate the link
948 * must be reliable enough for us to boot without any clever stuff,
949 * if we can't do this then theres little chance of the link staying
950 * together even with the resends etc
951 */
952 if (heartbeat_enabled) {
953 gettimeofday(&time_lastalive, NULL);
954 pacemaker();
955 }
956 }
957 }
958
async_process_callbacks(void)959 static void async_process_callbacks( void )
960 {
961 /* call any registered asynchronous callbacks */
962 unsigned int i;
963 for ( i = 0; i < num_async_callbacks; ++i )
964 async_callbacks[i]( deviceToUse, &time_now );
965 }
966
Adp_AsynchronousProcessing(const AsyncMode mode)967 void Adp_AsynchronousProcessing(const AsyncMode mode)
968 {
969 bool finished = FALSE;
970 #ifdef DEBUG
971 unsigned int wc = 0, dc = 0, ac = 0, hc = 0;
972 # define INC_COUNT(x) ((x)++)
973 #else
974 # define INC_COUNT(x)
975 #endif
976
977 if ((time_lastalive.tv_sec == 0) && (time_lastalive.tv_usec == 0)) {
978 /* first time through, needs initing */
979 gettimeofday(&time_lastalive, NULL);
980 }
981
982 /* main loop */
983 do
984 {
985 async_process_write( mode, &finished );
986 INC_COUNT(wc);
987
988 if ( ! finished && mode != async_block_on_write )
989 {
990 async_process_dbug_read( mode, &finished );
991 INC_COUNT(dc);
992 }
993
994 if ( ! finished && mode != async_block_on_write )
995 {
996 async_process_appl_read();
997 INC_COUNT(ac);
998 }
999
1000 if ( ! finished )
1001 {
1002 if (heartbeat_configured)
1003 async_process_heartbeat();
1004 async_process_callbacks();
1005 INC_COUNT(hc);
1006 }
1007
1008 } while (!finished && mode != async_block_on_nothing);
1009
1010 #ifdef DEBUG
1011 if ( mode != async_block_on_nothing )
1012 printf( "Async: %s - w %d, d %d, a %d, h %d\n",
1013 mode == async_block_on_write ? "blk_write" : "blk_read",
1014 wc, dc, ac, hc );
1015 #endif
1016 }
1017
1018 /*
1019 * install a handler for DC_APPL packets (can be NULL), returning old one.
1020 */
Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)1021 DC_Appl_Handler Adp_Install_DC_Appl_Handler(const DC_Appl_Handler handler)
1022 {
1023 DC_Appl_Handler old_handler = dc_appl_handler;
1024
1025 #ifdef DEBUG
1026 printf( "Installing DC_APPL handler %x (old %x)\n", handler, old_handler );
1027 #endif
1028
1029 dc_appl_handler = handler;
1030 return old_handler;
1031 }
1032
1033
1034 /*
1035 * add an asynchronous processing callback to the list
1036 * TRUE == okay, FALSE == no more async processing slots
1037 */
Adp_Install_Async_Callback(const Adp_Async_Callback callback_proc)1038 bool Adp_Install_Async_Callback( const Adp_Async_Callback callback_proc )
1039 {
1040 if ( num_async_callbacks < MAX_ASYNC_CALLBACKS && callback_proc != NULL )
1041 {
1042 async_callbacks[num_async_callbacks] = callback_proc;
1043 ++num_async_callbacks;
1044 return TRUE;
1045 }
1046 else
1047 return FALSE;
1048 }
1049
1050
1051 /*
1052 * delay for a given period (in microseconds)
1053 */
Adp_delay(unsigned int period)1054 void Adp_delay(unsigned int period)
1055 {
1056 struct timeval tv;
1057
1058 #ifdef DEBUG
1059 printf("delaying for %d microseconds\n", period);
1060 #endif
1061 tv.tv_sec = (period / 1000000);
1062 tv.tv_usec = (period % 1000000);
1063
1064 (void)select(0, NULL, NULL, NULL, &tv);
1065 }
1066
1067 /* EOF hostchan.c */
1068