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 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 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 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 void Adp_SetLogEnable(int logEnableFlag) 269 { 270 DevSW_SetLogEnable(logEnableFlag); 271 } 272 273 void Adp_SetLogfile(const char *filename) 274 { 275 DevSW_SetLogfile(filename); 276 } 277 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 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 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 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 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 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 476 AdpErrs Adp_ChannelWrite(const ChannelID chan, Packet *packet) { 477 return ChannelWrite(chan, packet, async_block_on_write); 478 } 479 480 AdpErrs Adp_ChannelWriteAsync(const ChannelID chan, Packet *packet) { 481 return ChannelWrite(chan, packet, async_block_on_nothing); 482 } 483 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 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 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__) 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 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 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 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 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 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 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 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 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 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 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 */ 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 */ 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 */ 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