diff options
Diffstat (limited to 'tools/firewire/nosy-dump.c')
-rw-r--r-- | tools/firewire/nosy-dump.c | 245 |
1 files changed, 132 insertions, 113 deletions
diff --git a/tools/firewire/nosy-dump.c b/tools/firewire/nosy-dump.c index 5d1e89233738..32c48556170b 100644 --- a/tools/firewire/nosy-dump.c +++ b/tools/firewire/nosy-dump.c | |||
@@ -487,138 +487,157 @@ static const struct packet_info packet_info[] = { | |||
487 | }; | 487 | }; |
488 | 488 | ||
489 | static int | 489 | static int |
490 | handle_packet(uint32_t *data, size_t length) | 490 | handle_request_packet(uint32_t *data, size_t length) |
491 | { | 491 | { |
492 | if (length == 0) { | 492 | struct link_packet *p = (struct link_packet *) data; |
493 | printf("bus reset\r\n"); | 493 | struct subaction *sa, *prev; |
494 | clear_pending_transaction_list(); | 494 | struct link_transaction *t; |
495 | } else if (length > sizeof(struct phy_packet)) { | ||
496 | struct link_packet *p = (struct link_packet *) data; | ||
497 | struct subaction *sa, *prev; | ||
498 | struct link_transaction *t; | ||
499 | 495 | ||
500 | switch (packet_info[p->common.tcode].type) { | 496 | t = link_transaction_lookup(p->common.source, p->common.destination, |
501 | case PACKET_REQUEST: | 497 | p->common.tlabel); |
502 | t = link_transaction_lookup(p->common.source, p->common.destination, | 498 | sa = subaction_create(data, length); |
503 | p->common.tlabel); | 499 | t->request = sa; |
504 | sa = subaction_create(data, length); | 500 | |
505 | t->request = sa; | 501 | if (!list_empty(&t->request_list)) { |
506 | 502 | prev = list_tail(&t->request_list, | |
507 | if (!list_empty(&t->request_list)) { | 503 | struct subaction, link); |
508 | prev = list_tail(&t->request_list, | 504 | |
509 | struct subaction, link); | 505 | if (!ACK_BUSY(prev->ack)) { |
510 | 506 | /* | |
511 | if (!ACK_BUSY(prev->ack)) { | 507 | * error, we should only see ack_busy_* before the |
512 | /* | 508 | * ack_pending/ack_complete -- this is an ack_pending |
513 | * error, we should only see ack_busy_* before the | 509 | * instead (ack_complete would have finished the |
514 | * ack_pending/ack_complete -- this is an ack_pending | 510 | * transaction). |
515 | * instead (ack_complete would have finished the | 511 | */ |
516 | * transaction). | 512 | } |
517 | */ | ||
518 | } | ||
519 | 513 | ||
520 | if (prev->packet.common.tcode != sa->packet.common.tcode || | 514 | if (prev->packet.common.tcode != sa->packet.common.tcode || |
521 | prev->packet.common.tlabel != sa->packet.common.tlabel) { | 515 | prev->packet.common.tlabel != sa->packet.common.tlabel) { |
522 | /* memcmp() ? */ | 516 | /* memcmp() ? */ |
523 | /* error, these should match for retries. */ | 517 | /* error, these should match for retries. */ |
524 | } | 518 | } |
525 | } | 519 | } |
526 | 520 | ||
527 | list_append(&t->request_list, &sa->link); | 521 | list_append(&t->request_list, &sa->link); |
528 | 522 | ||
529 | switch (sa->ack) { | 523 | switch (sa->ack) { |
530 | case ACK_COMPLETE: | 524 | case ACK_COMPLETE: |
531 | if (p->common.tcode != TCODE_WRITE_QUADLET && | 525 | if (p->common.tcode != TCODE_WRITE_QUADLET && |
532 | p->common.tcode != TCODE_WRITE_BLOCK) | 526 | p->common.tcode != TCODE_WRITE_BLOCK) |
533 | /* error, unified transactions only allowed for write */; | 527 | /* error, unified transactions only allowed for write */; |
534 | list_remove(&t->link); | 528 | list_remove(&t->link); |
535 | handle_transaction(t); | 529 | handle_transaction(t); |
536 | break; | 530 | break; |
537 | 531 | ||
538 | case ACK_NO_ACK: | 532 | case ACK_NO_ACK: |
539 | case ACK_DATA_ERROR: | 533 | case ACK_DATA_ERROR: |
540 | case ACK_TYPE_ERROR: | 534 | case ACK_TYPE_ERROR: |
541 | list_remove(&t->link); | 535 | list_remove(&t->link); |
542 | handle_transaction(t); | 536 | handle_transaction(t); |
543 | break; | 537 | break; |
538 | |||
539 | case ACK_PENDING: | ||
540 | /* request subaction phase over, wait for response. */ | ||
541 | break; | ||
542 | |||
543 | case ACK_BUSY_X: | ||
544 | case ACK_BUSY_A: | ||
545 | case ACK_BUSY_B: | ||
546 | /* ok, wait for retry. */ | ||
547 | /* check that retry protocol is respected. */ | ||
548 | break; | ||
549 | } | ||
544 | 550 | ||
545 | case ACK_PENDING: | 551 | return 1; |
546 | /* request subaction phase over, wait for response. */ | 552 | } |
547 | break; | ||
548 | 553 | ||
549 | case ACK_BUSY_X: | 554 | static int |
550 | case ACK_BUSY_A: | 555 | handle_response_packet(uint32_t *data, size_t length) |
551 | case ACK_BUSY_B: | 556 | { |
552 | /* ok, wait for retry. */ | 557 | struct link_packet *p = (struct link_packet *) data; |
553 | /* check that retry protocol is respected. */ | 558 | struct subaction *sa, *prev; |
554 | break; | 559 | struct link_transaction *t; |
555 | } | ||
556 | break; | ||
557 | 560 | ||
558 | case PACKET_RESPONSE: | 561 | t = link_transaction_lookup(p->common.destination, p->common.source, |
559 | t = link_transaction_lookup(p->common.destination, p->common.source, | 562 | p->common.tlabel); |
560 | p->common.tlabel); | 563 | if (list_empty(&t->request_list)) { |
561 | if (list_empty(&t->request_list)) { | 564 | /* unsolicited response */ |
562 | /* unsolicited response */ | 565 | } |
563 | } | ||
564 | 566 | ||
565 | sa = subaction_create(data, length); | 567 | sa = subaction_create(data, length); |
566 | t->response = sa; | 568 | t->response = sa; |
567 | 569 | ||
568 | if (!list_empty(&t->response_list)) { | 570 | if (!list_empty(&t->response_list)) { |
569 | prev = list_tail(&t->response_list, struct subaction, link); | 571 | prev = list_tail(&t->response_list, struct subaction, link); |
570 | 572 | ||
571 | if (!ACK_BUSY(prev->ack)) { | 573 | if (!ACK_BUSY(prev->ack)) { |
572 | /* | 574 | /* |
573 | * error, we should only see ack_busy_* before the | 575 | * error, we should only see ack_busy_* before the |
574 | * ack_pending/ack_complete | 576 | * ack_pending/ack_complete |
575 | */ | 577 | */ |
576 | } | 578 | } |
577 | 579 | ||
578 | if (prev->packet.common.tcode != sa->packet.common.tcode || | 580 | if (prev->packet.common.tcode != sa->packet.common.tcode || |
579 | prev->packet.common.tlabel != sa->packet.common.tlabel) { | 581 | prev->packet.common.tlabel != sa->packet.common.tlabel) { |
580 | /* use memcmp() instead? */ | 582 | /* use memcmp() instead? */ |
581 | /* error, these should match for retries. */ | 583 | /* error, these should match for retries. */ |
582 | } | 584 | } |
583 | } else { | 585 | } else { |
584 | prev = list_tail(&t->request_list, struct subaction, link); | 586 | prev = list_tail(&t->request_list, struct subaction, link); |
585 | if (prev->ack != ACK_PENDING) { | 587 | if (prev->ack != ACK_PENDING) { |
586 | /* | 588 | /* |
587 | * error, should not get response unless last request got | 589 | * error, should not get response unless last request got |
588 | * ack_pending. | 590 | * ack_pending. |
589 | */ | 591 | */ |
590 | } | 592 | } |
591 | 593 | ||
592 | if (packet_info[prev->packet.common.tcode].response_tcode != | 594 | if (packet_info[prev->packet.common.tcode].response_tcode != |
593 | sa->packet.common.tcode) { | 595 | sa->packet.common.tcode) { |
594 | /* error, tcode mismatch */ | 596 | /* error, tcode mismatch */ |
595 | } | 597 | } |
596 | } | 598 | } |
597 | 599 | ||
598 | list_append(&t->response_list, &sa->link); | 600 | list_append(&t->response_list, &sa->link); |
599 | 601 | ||
600 | switch (sa->ack) { | 602 | switch (sa->ack) { |
601 | case ACK_COMPLETE: | 603 | case ACK_COMPLETE: |
602 | case ACK_NO_ACK: | 604 | case ACK_NO_ACK: |
603 | case ACK_DATA_ERROR: | 605 | case ACK_DATA_ERROR: |
604 | case ACK_TYPE_ERROR: | 606 | case ACK_TYPE_ERROR: |
605 | list_remove(&t->link); | 607 | list_remove(&t->link); |
606 | handle_transaction(t); | 608 | handle_transaction(t); |
607 | /* transaction complete, remove t from pending list. */ | 609 | /* transaction complete, remove t from pending list. */ |
608 | break; | 610 | break; |
611 | |||
612 | case ACK_PENDING: | ||
613 | /* error for responses. */ | ||
614 | break; | ||
615 | |||
616 | case ACK_BUSY_X: | ||
617 | case ACK_BUSY_A: | ||
618 | case ACK_BUSY_B: | ||
619 | /* no problem, wait for next retry */ | ||
620 | break; | ||
621 | } | ||
609 | 622 | ||
610 | case ACK_PENDING: | 623 | return 1; |
611 | /* error for responses. */ | 624 | } |
612 | break; | ||
613 | 625 | ||
614 | case ACK_BUSY_X: | 626 | static int |
615 | case ACK_BUSY_A: | 627 | handle_packet(uint32_t *data, size_t length) |
616 | case ACK_BUSY_B: | 628 | { |
617 | /* no problem, wait for next retry */ | 629 | if (length == 0) { |
618 | break; | 630 | printf("bus reset\r\n"); |
619 | } | 631 | clear_pending_transaction_list(); |
632 | } else if (length > sizeof(struct phy_packet)) { | ||
633 | struct link_packet *p = (struct link_packet *) data; | ||
620 | 634 | ||
621 | break; | 635 | switch (packet_info[p->common.tcode].type) { |
636 | case PACKET_REQUEST: | ||
637 | return handle_request_packet(data, length); | ||
638 | |||
639 | case PACKET_RESPONSE: | ||
640 | return handle_response_packet(data, length); | ||
622 | 641 | ||
623 | case PACKET_OTHER: | 642 | case PACKET_OTHER: |
624 | case PACKET_RESERVED: | 643 | case PACKET_RESERVED: |