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.8 $ 12 * $Date: 1999/11/01 15:32:59 $ 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 */ 47extern DeviceDescr *devices[]; 48 49static DeviceDescr *deviceToUse = NULL; 50 51static struct Channel { 52 ChannelCallback callback; 53 void *callback_state; 54} channels[CI_NUM_CHANNELS]; 55 56static unsigned char HomeSeq; 57static unsigned char OppoSeq; 58 59/* 60 * Handler for DC_APPL packets 61 */ 62static DC_Appl_Handler dc_appl_handler = NULL; 63 64/* 65 * slots for registered asynchronous processing callback procedures 66 */ 67#define MAX_ASYNC_CALLBACKS 8 68static unsigned int num_async_callbacks = 0; 69static 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 */ 76static Packet *writeQueueRoot = NULL; 77static Packet *writeQueueSend = NULL; 78static Packet *resend_pkt = NULL; 79static 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 */ 87unsigned 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 */ 95unsigned int heartbeat_configured = TRUE; 96 97void 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 */ 135static 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 */ 165static 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 */ 188static 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 */ 221void 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 256Packet *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 268void Adp_SetLogEnable(int logEnableFlag) 269{ 270 DevSW_SetLogEnable(logEnableFlag); 271} 272 273void Adp_SetLogfile(const char *filename) 274{ 275 DevSW_SetLogfile(filename); 276} 277 278AdpErrs 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 327AdpErrs 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 353AdpErrs 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 365AdpErrs 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 393AdpErrs 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 441static 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 476AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) { 477 return ChannelWrite(chan, packet, async_block_on_write); 478} 479 480AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) { 481 return ChannelWrite(chan, packet, async_block_on_nothing); 482} 483 484static 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 499static 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 552static 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__) 560static 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 569static 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 587static 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 603static unsigned char tmp_ch; 604 605static 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 618static 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 */ 639static struct timeval time_now; 640static struct timeval time_lastalive; 641 642static 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 776static 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 813static 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 939static 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 959static 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 967void 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 */ 1021DC_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 */ 1038bool 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 */ 1054void 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