root/tools/firewire/nosy-dump.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sigint_handler
  2. subaction_create
  3. subaction_destroy
  4. link_transaction_lookup
  5. link_transaction_destroy
  6. handle_transaction
  7. clear_pending_transaction_list
  8. handle_request_packet
  9. handle_response_packet
  10. handle_packet
  11. get_bits
  12. dump_data
  13. decode_link_packet
  14. print_packet
  15. print_stats
  16. reset_input_mode
  17. set_input_mode
  18. main

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
   4  * Copyright (C) 2002-2006 Kristian Høgsberg
   5  */
   6 
   7 #include <byteswap.h>
   8 #include <endian.h>
   9 #include <fcntl.h>
  10 #include <linux/firewire-constants.h>
  11 #include <poll.h>
  12 #include <popt.h>
  13 #include <signal.h>
  14 #include <stdio.h>
  15 #include <stdlib.h>
  16 #include <string.h>
  17 #include <sys/ioctl.h>
  18 #include <sys/time.h>
  19 #include <termios.h>
  20 #include <unistd.h>
  21 
  22 #include "list.h"
  23 #include "nosy-dump.h"
  24 #include "nosy-user.h"
  25 
  26 enum {
  27         PACKET_FIELD_DETAIL             = 0x01,
  28         PACKET_FIELD_DATA_LENGTH        = 0x02,
  29         /* Marks the fields we print in transaction view. */
  30         PACKET_FIELD_TRANSACTION        = 0x04,
  31 };
  32 
  33 static void print_packet(uint32_t *data, size_t length);
  34 static void decode_link_packet(struct link_packet *packet, size_t length,
  35                                int include_flags, int exclude_flags);
  36 static int run = 1;
  37 sig_t sys_sigint_handler;
  38 
  39 static char *option_nosy_device = "/dev/nosy";
  40 static char *option_view = "packet";
  41 static char *option_output;
  42 static char *option_input;
  43 static int option_hex;
  44 static int option_iso;
  45 static int option_cycle_start;
  46 static int option_version;
  47 static int option_verbose;
  48 
  49 enum {
  50         VIEW_TRANSACTION,
  51         VIEW_PACKET,
  52         VIEW_STATS,
  53 };
  54 
  55 static const struct poptOption options[] = {
  56         {
  57                 .longName       = "device",
  58                 .shortName      = 'd',
  59                 .argInfo        = POPT_ARG_STRING,
  60                 .arg            = &option_nosy_device,
  61                 .descrip        = "Path to nosy device.",
  62                 .argDescrip     = "DEVICE"
  63         },
  64         {
  65                 .longName       = "view",
  66                 .argInfo        = POPT_ARG_STRING,
  67                 .arg            = &option_view,
  68                 .descrip        = "Specify view of bus traffic: packet, transaction or stats.",
  69                 .argDescrip     = "VIEW"
  70         },
  71         {
  72                 .longName       = "hex",
  73                 .shortName      = 'x',
  74                 .argInfo        = POPT_ARG_NONE,
  75                 .arg            = &option_hex,
  76                 .descrip        = "Print each packet in hex.",
  77         },
  78         {
  79                 .longName       = "iso",
  80                 .argInfo        = POPT_ARG_NONE,
  81                 .arg            = &option_iso,
  82                 .descrip        = "Print iso packets.",
  83         },
  84         {
  85                 .longName       = "cycle-start",
  86                 .argInfo        = POPT_ARG_NONE,
  87                 .arg            = &option_cycle_start,
  88                 .descrip        = "Print cycle start packets.",
  89         },
  90         {
  91                 .longName       = "verbose",
  92                 .shortName      = 'v',
  93                 .argInfo        = POPT_ARG_NONE,
  94                 .arg            = &option_verbose,
  95                 .descrip        = "Verbose packet view.",
  96         },
  97         {
  98                 .longName       = "output",
  99                 .shortName      = 'o',
 100                 .argInfo        = POPT_ARG_STRING,
 101                 .arg            = &option_output,
 102                 .descrip        = "Log to output file.",
 103                 .argDescrip     = "FILENAME"
 104         },
 105         {
 106                 .longName       = "input",
 107                 .shortName      = 'i',
 108                 .argInfo        = POPT_ARG_STRING,
 109                 .arg            = &option_input,
 110                 .descrip        = "Decode log from file.",
 111                 .argDescrip     = "FILENAME"
 112         },
 113         {
 114                 .longName       = "version",
 115                 .argInfo        = POPT_ARG_NONE,
 116                 .arg            = &option_version,
 117                 .descrip        = "Specify print version info.",
 118         },
 119         POPT_AUTOHELP
 120         POPT_TABLEEND
 121 };
 122 
 123 /* Allow all ^C except the first to interrupt the program in the usual way. */
 124 static void
 125 sigint_handler(int signal_num)
 126 {
 127         if (run == 1) {
 128                 run = 0;
 129                 signal(SIGINT, SIG_DFL);
 130         }
 131 }
 132 
 133 static struct subaction *
 134 subaction_create(uint32_t *data, size_t length)
 135 {
 136         struct subaction *sa;
 137 
 138         /* we put the ack in the subaction struct for easy access. */
 139         sa = malloc(sizeof *sa - sizeof sa->packet + length);
 140         if (!sa)
 141                 exit(EXIT_FAILURE);
 142         sa->ack = data[length / 4 - 1];
 143         sa->length = length;
 144         memcpy(&sa->packet, data, length);
 145 
 146         return sa;
 147 }
 148 
 149 static void
 150 subaction_destroy(struct subaction *sa)
 151 {
 152         free(sa);
 153 }
 154 
 155 static struct list pending_transaction_list = {
 156         &pending_transaction_list, &pending_transaction_list
 157 };
 158 
 159 static struct link_transaction *
 160 link_transaction_lookup(int request_node, int response_node, int tlabel)
 161 {
 162         struct link_transaction *t;
 163 
 164         list_for_each_entry(t, &pending_transaction_list, link) {
 165                 if (t->request_node == request_node &&
 166                     t->response_node == response_node &&
 167                     t->tlabel == tlabel)
 168                         return t;
 169         }
 170 
 171         t = malloc(sizeof *t);
 172         if (!t)
 173                 exit(EXIT_FAILURE);
 174         t->request_node = request_node;
 175         t->response_node = response_node;
 176         t->tlabel = tlabel;
 177         list_init(&t->request_list);
 178         list_init(&t->response_list);
 179 
 180         list_append(&pending_transaction_list, &t->link);
 181 
 182         return t;
 183 }
 184 
 185 static void
 186 link_transaction_destroy(struct link_transaction *t)
 187 {
 188         struct subaction *sa;
 189 
 190         while (!list_empty(&t->request_list)) {
 191                 sa = list_head(&t->request_list, struct subaction, link);
 192                 list_remove(&sa->link);
 193                 subaction_destroy(sa);
 194         }
 195         while (!list_empty(&t->response_list)) {
 196                 sa = list_head(&t->response_list, struct subaction, link);
 197                 list_remove(&sa->link);
 198                 subaction_destroy(sa);
 199         }
 200         free(t);
 201 }
 202 
 203 struct protocol_decoder {
 204         const char *name;
 205         int (*decode)(struct link_transaction *t);
 206 };
 207 
 208 static const struct protocol_decoder protocol_decoders[] = {
 209         { "FCP", decode_fcp }
 210 };
 211 
 212 static void
 213 handle_transaction(struct link_transaction *t)
 214 {
 215         struct subaction *sa;
 216         int i;
 217 
 218         if (!t->request) {
 219                 printf("BUG in handle_transaction\n");
 220                 return;
 221         }
 222 
 223         for (i = 0; i < array_length(protocol_decoders); i++)
 224                 if (protocol_decoders[i].decode(t))
 225                         break;
 226 
 227         /* HACK: decode only fcp right now. */
 228         return;
 229 
 230         decode_link_packet(&t->request->packet, t->request->length,
 231                            PACKET_FIELD_TRANSACTION, 0);
 232         if (t->response)
 233                 decode_link_packet(&t->response->packet, t->request->length,
 234                                    PACKET_FIELD_TRANSACTION, 0);
 235         else
 236                 printf("[no response]");
 237 
 238         if (option_verbose) {
 239                 list_for_each_entry(sa, &t->request_list, link)
 240                         print_packet((uint32_t *) &sa->packet, sa->length);
 241                 list_for_each_entry(sa, &t->response_list, link)
 242                         print_packet((uint32_t *) &sa->packet, sa->length);
 243         }
 244         printf("\r\n");
 245 
 246         link_transaction_destroy(t);
 247 }
 248 
 249 static void
 250 clear_pending_transaction_list(void)
 251 {
 252         struct link_transaction *t;
 253 
 254         while (!list_empty(&pending_transaction_list)) {
 255                 t = list_head(&pending_transaction_list,
 256                               struct link_transaction, link);
 257                 list_remove(&t->link);
 258                 link_transaction_destroy(t);
 259                 /* print unfinished transactions */
 260         }
 261 }
 262 
 263 static const char * const tcode_names[] = {
 264         [0x0] = "write_quadlet_request",        [0x6] = "read_quadlet_response",
 265         [0x1] = "write_block_request",          [0x7] = "read_block_response",
 266         [0x2] = "write_response",               [0x8] = "cycle_start",
 267         [0x3] = "reserved",                     [0x9] = "lock_request",
 268         [0x4] = "read_quadlet_request",         [0xa] = "iso_data",
 269         [0x5] = "read_block_request",           [0xb] = "lock_response",
 270 };
 271 
 272 static const char * const ack_names[] = {
 273         [0x0] = "no ack",                       [0x8] = "reserved (0x08)",
 274         [0x1] = "ack_complete",                 [0x9] = "reserved (0x09)",
 275         [0x2] = "ack_pending",                  [0xa] = "reserved (0x0a)",
 276         [0x3] = "reserved (0x03)",              [0xb] = "reserved (0x0b)",
 277         [0x4] = "ack_busy_x",                   [0xc] = "reserved (0x0c)",
 278         [0x5] = "ack_busy_a",                   [0xd] = "ack_data_error",
 279         [0x6] = "ack_busy_b",                   [0xe] = "ack_type_error",
 280         [0x7] = "reserved (0x07)",              [0xf] = "reserved (0x0f)",
 281 };
 282 
 283 static const char * const rcode_names[] = {
 284         [0x0] = "complete",                     [0x4] = "conflict_error",
 285         [0x1] = "reserved (0x01)",              [0x5] = "data_error",
 286         [0x2] = "reserved (0x02)",              [0x6] = "type_error",
 287         [0x3] = "reserved (0x03)",              [0x7] = "address_error",
 288 };
 289 
 290 static const char * const retry_names[] = {
 291         [0x0] = "retry_1",
 292         [0x1] = "retry_x",
 293         [0x2] = "retry_a",
 294         [0x3] = "retry_b",
 295 };
 296 
 297 enum {
 298         PACKET_RESERVED,
 299         PACKET_REQUEST,
 300         PACKET_RESPONSE,
 301         PACKET_OTHER,
 302 };
 303 
 304 struct packet_info {
 305         const char *name;
 306         int type;
 307         int response_tcode;
 308         const struct packet_field *fields;
 309         int field_count;
 310 };
 311 
 312 struct packet_field {
 313         const char *name; /* Short name for field. */
 314         int offset;     /* Location of field, specified in bits; */
 315                         /* negative means from end of packet.    */
 316         int width;      /* Width of field, 0 means use data_length. */
 317         int flags;      /* Show options. */
 318         const char * const *value_names;
 319 };
 320 
 321 #define COMMON_REQUEST_FIELDS                                           \
 322         { "dest", 0, 16, PACKET_FIELD_TRANSACTION },                    \
 323         { "tl", 16, 6 },                                                \
 324         { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },              \
 325         { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names },      \
 326         { "pri", 28, 4, PACKET_FIELD_DETAIL },                          \
 327         { "src", 32, 16, PACKET_FIELD_TRANSACTION },                    \
 328         { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
 329 
 330 #define COMMON_RESPONSE_FIELDS                                          \
 331         { "dest", 0, 16 },                                              \
 332         { "tl", 16, 6 },                                                \
 333         { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },              \
 334         { "tcode", 24, 4, 0, tcode_names },                             \
 335         { "pri", 28, 4, PACKET_FIELD_DETAIL },                          \
 336         { "src", 32, 16 },                                              \
 337         { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
 338 
 339 static const struct packet_field read_quadlet_request_fields[] = {
 340         COMMON_REQUEST_FIELDS,
 341         { "crc", 96, 32, PACKET_FIELD_DETAIL },
 342         { "ack", 156, 4, 0, ack_names },
 343 };
 344 
 345 static const struct packet_field read_quadlet_response_fields[] = {
 346         COMMON_RESPONSE_FIELDS,
 347         { "data", 96, 32, PACKET_FIELD_TRANSACTION },
 348         { "crc", 128, 32, PACKET_FIELD_DETAIL },
 349         { "ack", 188, 4, 0, ack_names },
 350 };
 351 
 352 static const struct packet_field read_block_request_fields[] = {
 353         COMMON_REQUEST_FIELDS,
 354         { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
 355         { "extended_tcode", 112, 16 },
 356         { "crc", 128, 32, PACKET_FIELD_DETAIL },
 357         { "ack", 188, 4, 0, ack_names },
 358 };
 359 
 360 static const struct packet_field block_response_fields[] = {
 361         COMMON_RESPONSE_FIELDS,
 362         { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
 363         { "extended_tcode", 112, 16 },
 364         { "crc", 128, 32, PACKET_FIELD_DETAIL },
 365         { "data", 160, 0, PACKET_FIELD_TRANSACTION },
 366         { "crc", -64, 32, PACKET_FIELD_DETAIL },
 367         { "ack", -4, 4, 0, ack_names },
 368 };
 369 
 370 static const struct packet_field write_quadlet_request_fields[] = {
 371         COMMON_REQUEST_FIELDS,
 372         { "data", 96, 32, PACKET_FIELD_TRANSACTION },
 373         { "ack", -4, 4, 0, ack_names },
 374 };
 375 
 376 static const struct packet_field block_request_fields[] = {
 377         COMMON_REQUEST_FIELDS,
 378         { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
 379         { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
 380         { "crc", 128, 32, PACKET_FIELD_DETAIL },
 381         { "data", 160, 0, PACKET_FIELD_TRANSACTION },
 382         { "crc", -64, 32, PACKET_FIELD_DETAIL },
 383         { "ack", -4, 4, 0, ack_names },
 384 };
 385 
 386 static const struct packet_field write_response_fields[] = {
 387         COMMON_RESPONSE_FIELDS,
 388         { "reserved", 64, 32, PACKET_FIELD_DETAIL },
 389         { "ack", -4, 4, 0, ack_names },
 390 };
 391 
 392 static const struct packet_field iso_data_fields[] = {
 393         { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
 394         { "tag", 16, 2 },
 395         { "channel", 18, 6 },
 396         { "tcode", 24, 4, 0, tcode_names },
 397         { "sy", 28, 4 },
 398         { "crc", 32, 32, PACKET_FIELD_DETAIL },
 399         { "data", 64, 0 },
 400         { "crc", -64, 32, PACKET_FIELD_DETAIL },
 401         { "ack", -4, 4, 0, ack_names },
 402 };
 403 
 404 static const struct packet_info packet_info[] = {
 405         {
 406                 .name           = "write_quadlet_request",
 407                 .type           = PACKET_REQUEST,
 408                 .response_tcode = TCODE_WRITE_RESPONSE,
 409                 .fields         = write_quadlet_request_fields,
 410                 .field_count    = array_length(write_quadlet_request_fields)
 411         },
 412         {
 413                 .name           = "write_block_request",
 414                 .type           = PACKET_REQUEST,
 415                 .response_tcode = TCODE_WRITE_RESPONSE,
 416                 .fields         = block_request_fields,
 417                 .field_count    = array_length(block_request_fields)
 418         },
 419         {
 420                 .name           = "write_response",
 421                 .type           = PACKET_RESPONSE,
 422                 .fields         = write_response_fields,
 423                 .field_count    = array_length(write_response_fields)
 424         },
 425         {
 426                 .name           = "reserved",
 427                 .type           = PACKET_RESERVED,
 428         },
 429         {
 430                 .name           = "read_quadlet_request",
 431                 .type           = PACKET_REQUEST,
 432                 .response_tcode = TCODE_READ_QUADLET_RESPONSE,
 433                 .fields         = read_quadlet_request_fields,
 434                 .field_count    = array_length(read_quadlet_request_fields)
 435         },
 436         {
 437                 .name           = "read_block_request",
 438                 .type           = PACKET_REQUEST,
 439                 .response_tcode = TCODE_READ_BLOCK_RESPONSE,
 440                 .fields         = read_block_request_fields,
 441                 .field_count    = array_length(read_block_request_fields)
 442         },
 443         {
 444                 .name           = "read_quadlet_response",
 445                 .type           = PACKET_RESPONSE,
 446                 .fields         = read_quadlet_response_fields,
 447                 .field_count    = array_length(read_quadlet_response_fields)
 448         },
 449         {
 450                 .name           = "read_block_response",
 451                 .type           = PACKET_RESPONSE,
 452                 .fields         = block_response_fields,
 453                 .field_count    = array_length(block_response_fields)
 454         },
 455         {
 456                 .name           = "cycle_start",
 457                 .type           = PACKET_OTHER,
 458                 .fields         = write_quadlet_request_fields,
 459                 .field_count    = array_length(write_quadlet_request_fields)
 460         },
 461         {
 462                 .name           = "lock_request",
 463                 .type           = PACKET_REQUEST,
 464                 .fields         = block_request_fields,
 465                 .field_count    = array_length(block_request_fields)
 466         },
 467         {
 468                 .name           = "iso_data",
 469                 .type           = PACKET_OTHER,
 470                 .fields         = iso_data_fields,
 471                 .field_count    = array_length(iso_data_fields)
 472         },
 473         {
 474                 .name           = "lock_response",
 475                 .type           = PACKET_RESPONSE,
 476                 .fields         = block_response_fields,
 477                 .field_count    = array_length(block_response_fields)
 478         },
 479 };
 480 
 481 static int
 482 handle_request_packet(uint32_t *data, size_t length)
 483 {
 484         struct link_packet *p = (struct link_packet *) data;
 485         struct subaction *sa, *prev;
 486         struct link_transaction *t;
 487 
 488         t = link_transaction_lookup(p->common.source, p->common.destination,
 489                         p->common.tlabel);
 490         sa = subaction_create(data, length);
 491         t->request = sa;
 492 
 493         if (!list_empty(&t->request_list)) {
 494                 prev = list_tail(&t->request_list,
 495                                  struct subaction, link);
 496 
 497                 if (!ACK_BUSY(prev->ack)) {
 498                         /*
 499                          * error, we should only see ack_busy_* before the
 500                          * ack_pending/ack_complete -- this is an ack_pending
 501                          * instead (ack_complete would have finished the
 502                          * transaction).
 503                          */
 504                 }
 505 
 506                 if (prev->packet.common.tcode != sa->packet.common.tcode ||
 507                     prev->packet.common.tlabel != sa->packet.common.tlabel) {
 508                         /* memcmp() ? */
 509                         /* error, these should match for retries. */
 510                 }
 511         }
 512 
 513         list_append(&t->request_list, &sa->link);
 514 
 515         switch (sa->ack) {
 516         case ACK_COMPLETE:
 517                 if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
 518                     p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
 519                         /* error, unified transactions only allowed for write */;
 520                 list_remove(&t->link);
 521                 handle_transaction(t);
 522                 break;
 523 
 524         case ACK_NO_ACK:
 525         case ACK_DATA_ERROR:
 526         case ACK_TYPE_ERROR:
 527                 list_remove(&t->link);
 528                 handle_transaction(t);
 529                 break;
 530 
 531         case ACK_PENDING:
 532                 /* request subaction phase over, wait for response. */
 533                 break;
 534 
 535         case ACK_BUSY_X:
 536         case ACK_BUSY_A:
 537         case ACK_BUSY_B:
 538                 /* ok, wait for retry. */
 539                 /* check that retry protocol is respected. */
 540                 break;
 541         }
 542 
 543         return 1;
 544 }
 545 
 546 static int
 547 handle_response_packet(uint32_t *data, size_t length)
 548 {
 549         struct link_packet *p = (struct link_packet *) data;
 550         struct subaction *sa, *prev;
 551         struct link_transaction *t;
 552 
 553         t = link_transaction_lookup(p->common.destination, p->common.source,
 554                         p->common.tlabel);
 555         if (list_empty(&t->request_list)) {
 556                 /* unsolicited response */
 557         }
 558 
 559         sa = subaction_create(data, length);
 560         t->response = sa;
 561 
 562         if (!list_empty(&t->response_list)) {
 563                 prev = list_tail(&t->response_list, struct subaction, link);
 564 
 565                 if (!ACK_BUSY(prev->ack)) {
 566                         /*
 567                          * error, we should only see ack_busy_* before the
 568                          * ack_pending/ack_complete
 569                          */
 570                 }
 571 
 572                 if (prev->packet.common.tcode != sa->packet.common.tcode ||
 573                     prev->packet.common.tlabel != sa->packet.common.tlabel) {
 574                         /* use memcmp() instead? */
 575                         /* error, these should match for retries. */
 576                 }
 577         } else {
 578                 prev = list_tail(&t->request_list, struct subaction, link);
 579                 if (prev->ack != ACK_PENDING) {
 580                         /*
 581                          * error, should not get response unless last request got
 582                          * ack_pending.
 583                          */
 584                 }
 585 
 586                 if (packet_info[prev->packet.common.tcode].response_tcode !=
 587                     sa->packet.common.tcode) {
 588                         /* error, tcode mismatch */
 589                 }
 590         }
 591 
 592         list_append(&t->response_list, &sa->link);
 593 
 594         switch (sa->ack) {
 595         case ACK_COMPLETE:
 596         case ACK_NO_ACK:
 597         case ACK_DATA_ERROR:
 598         case ACK_TYPE_ERROR:
 599                 list_remove(&t->link);
 600                 handle_transaction(t);
 601                 /* transaction complete, remove t from pending list. */
 602                 break;
 603 
 604         case ACK_PENDING:
 605                 /* error for responses. */
 606                 break;
 607 
 608         case ACK_BUSY_X:
 609         case ACK_BUSY_A:
 610         case ACK_BUSY_B:
 611                 /* no problem, wait for next retry */
 612                 break;
 613         }
 614 
 615         return 1;
 616 }
 617 
 618 static int
 619 handle_packet(uint32_t *data, size_t length)
 620 {
 621         if (length == 0) {
 622                 printf("bus reset\r\n");
 623                 clear_pending_transaction_list();
 624         } else if (length > sizeof(struct phy_packet)) {
 625                 struct link_packet *p = (struct link_packet *) data;
 626 
 627                 switch (packet_info[p->common.tcode].type) {
 628                 case PACKET_REQUEST:
 629                         return handle_request_packet(data, length);
 630 
 631                 case PACKET_RESPONSE:
 632                         return handle_response_packet(data, length);
 633 
 634                 case PACKET_OTHER:
 635                 case PACKET_RESERVED:
 636                         return 0;
 637                 }
 638         }
 639 
 640         return 1;
 641 }
 642 
 643 static unsigned int
 644 get_bits(struct link_packet *packet, int offset, int width)
 645 {
 646         uint32_t *data = (uint32_t *) packet;
 647         uint32_t index, shift, mask;
 648 
 649         index = offset / 32 + 1;
 650         shift = 32 - (offset & 31) - width;
 651         mask = width == 32 ? ~0 : (1 << width) - 1;
 652 
 653         return (data[index] >> shift) & mask;
 654 }
 655 
 656 #if __BYTE_ORDER == __LITTLE_ENDIAN
 657 #define byte_index(i) ((i) ^ 3)
 658 #elif __BYTE_ORDER == __BIG_ENDIAN
 659 #define byte_index(i) (i)
 660 #else
 661 #error unsupported byte order.
 662 #endif
 663 
 664 static void
 665 dump_data(unsigned char *data, int length)
 666 {
 667         int i, print_length;
 668 
 669         if (length > 128)
 670                 print_length = 128;
 671         else
 672                 print_length = length;
 673 
 674         for (i = 0; i < print_length; i++)
 675                 printf("%s%02hhx",
 676                        (i % 4 == 0 && i != 0) ? " " : "",
 677                        data[byte_index(i)]);
 678 
 679         if (print_length < length)
 680                 printf(" (%d more bytes)", length - print_length);
 681 }
 682 
 683 static void
 684 decode_link_packet(struct link_packet *packet, size_t length,
 685                    int include_flags, int exclude_flags)
 686 {
 687         const struct packet_info *pi;
 688         int data_length = 0;
 689         int i;
 690 
 691         pi = &packet_info[packet->common.tcode];
 692 
 693         for (i = 0; i < pi->field_count; i++) {
 694                 const struct packet_field *f = &pi->fields[i];
 695                 int offset;
 696 
 697                 if (f->flags & exclude_flags)
 698                         continue;
 699                 if (include_flags && !(f->flags & include_flags))
 700                         continue;
 701 
 702                 if (f->offset < 0)
 703                         offset = length * 8 + f->offset - 32;
 704                 else
 705                         offset = f->offset;
 706 
 707                 if (f->value_names != NULL) {
 708                         uint32_t bits;
 709 
 710                         bits = get_bits(packet, offset, f->width);
 711                         printf("%s", f->value_names[bits]);
 712                 } else if (f->width == 0) {
 713                         printf("%s=[", f->name);
 714                         dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
 715                         printf("]");
 716                 } else {
 717                         unsigned long long bits;
 718                         int high_width, low_width;
 719 
 720                         if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
 721                                 /* Bit field spans quadlet boundary. */
 722                                 high_width = ((offset + 31) & ~31) - offset;
 723                                 low_width = f->width - high_width;
 724 
 725                                 bits = get_bits(packet, offset, high_width);
 726                                 bits = (bits << low_width) |
 727                                         get_bits(packet, offset + high_width, low_width);
 728                         } else {
 729                                 bits = get_bits(packet, offset, f->width);
 730                         }
 731 
 732                         printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
 733 
 734                         if (f->flags & PACKET_FIELD_DATA_LENGTH)
 735                                 data_length = bits;
 736                 }
 737 
 738                 if (i < pi->field_count - 1)
 739                         printf(", ");
 740         }
 741 }
 742 
 743 static void
 744 print_packet(uint32_t *data, size_t length)
 745 {
 746         int i;
 747 
 748         printf("%6u  ", data[0]);
 749 
 750         if (length == 4) {
 751                 printf("bus reset");
 752         } else if (length < sizeof(struct phy_packet)) {
 753                 printf("short packet: ");
 754                 for (i = 1; i < length / 4; i++)
 755                         printf("%s%08x", i == 0 ? "[" : " ", data[i]);
 756                 printf("]");
 757 
 758         } else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
 759                 struct phy_packet *pp = (struct phy_packet *) data;
 760 
 761                 /* phy packet are 3 quadlets: the 1 quadlet payload,
 762                  * the bitwise inverse of the payload and the snoop
 763                  * mode ack */
 764 
 765                 switch (pp->common.identifier) {
 766                 case PHY_PACKET_CONFIGURATION:
 767                         if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
 768                                 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
 769                         } else {
 770                                 printf("phy config:");
 771                                 if (pp->phy_config.set_root)
 772                                         printf(" set_root_id=%02x", pp->phy_config.root_id);
 773                                 if (pp->phy_config.set_gap_count)
 774                                         printf(" set_gap_count=%d", pp->phy_config.gap_count);
 775                         }
 776                         break;
 777 
 778                 case PHY_PACKET_LINK_ON:
 779                         printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
 780                         break;
 781 
 782                 case PHY_PACKET_SELF_ID:
 783                         if (pp->self_id.extended) {
 784                                 printf("extended self id: phy_id=%02x, seq=%d",
 785                                        pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
 786                         } else {
 787                                 static const char * const speed_names[] = {
 788                                         "S100", "S200", "S400", "BETA"
 789                                 };
 790                                 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
 791                                        pp->self_id.phy_id,
 792                                        (pp->self_id.link_active ? "active" : "not active"),
 793                                        pp->self_id.gap_count,
 794                                        speed_names[pp->self_id.phy_speed],
 795                                        (pp->self_id.contender ? ", irm contender" : ""),
 796                                        (pp->self_id.initiated_reset ? ", initiator" : ""));
 797                         }
 798                         break;
 799                 default:
 800                         printf("unknown phy packet: ");
 801                         for (i = 1; i < length / 4; i++)
 802                                 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
 803                         printf("]");
 804                         break;
 805                 }
 806         } else {
 807                 struct link_packet *packet = (struct link_packet *) data;
 808 
 809                 decode_link_packet(packet, length, 0,
 810                                    option_verbose ? 0 : PACKET_FIELD_DETAIL);
 811         }
 812 
 813         if (option_hex) {
 814                 printf("  [");
 815                 dump_data((unsigned char *) data + 4, length - 4);
 816                 printf("]");
 817         }
 818 
 819         printf("\r\n");
 820 }
 821 
 822 #define HIDE_CURSOR     "\033[?25l"
 823 #define SHOW_CURSOR     "\033[?25h"
 824 #define CLEAR           "\033[H\033[2J"
 825 
 826 static void
 827 print_stats(uint32_t *data, size_t length)
 828 {
 829         static int bus_reset_count, short_packet_count, phy_packet_count;
 830         static int tcode_count[16];
 831         static struct timeval last_update;
 832         struct timeval now;
 833         int i;
 834 
 835         if (length == 0)
 836                 bus_reset_count++;
 837         else if (length < sizeof(struct phy_packet))
 838                 short_packet_count++;
 839         else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
 840                 phy_packet_count++;
 841         else {
 842                 struct link_packet *packet = (struct link_packet *) data;
 843                 tcode_count[packet->common.tcode]++;
 844         }
 845 
 846         gettimeofday(&now, NULL);
 847         if (now.tv_sec <= last_update.tv_sec &&
 848             now.tv_usec < last_update.tv_usec + 500000)
 849                 return;
 850 
 851         last_update = now;
 852         printf(CLEAR HIDE_CURSOR
 853                "  bus resets              : %8d\n"
 854                "  short packets           : %8d\n"
 855                "  phy packets             : %8d\n",
 856                bus_reset_count, short_packet_count, phy_packet_count);
 857 
 858         for (i = 0; i < array_length(packet_info); i++)
 859                 if (packet_info[i].type != PACKET_RESERVED)
 860                         printf("  %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
 861         printf(SHOW_CURSOR "\n");
 862 }
 863 
 864 static struct termios saved_attributes;
 865 
 866 static void
 867 reset_input_mode(void)
 868 {
 869         tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
 870 }
 871 
 872 static void
 873 set_input_mode(void)
 874 {
 875         struct termios tattr;
 876 
 877         /* Make sure stdin is a terminal. */
 878         if (!isatty(STDIN_FILENO)) {
 879                 fprintf(stderr, "Not a terminal.\n");
 880                 exit(EXIT_FAILURE);
 881         }
 882 
 883         /* Save the terminal attributes so we can restore them later. */
 884         tcgetattr(STDIN_FILENO, &saved_attributes);
 885         atexit(reset_input_mode);
 886 
 887         /* Set the funny terminal modes. */
 888         tcgetattr(STDIN_FILENO, &tattr);
 889         tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
 890         tattr.c_cc[VMIN] = 1;
 891         tattr.c_cc[VTIME] = 0;
 892         tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
 893 }
 894 
 895 int main(int argc, const char *argv[])
 896 {
 897         uint32_t buf[128 * 1024];
 898         uint32_t filter;
 899         int length, retval, view;
 900         int fd = -1;
 901         FILE *output = NULL, *input = NULL;
 902         poptContext con;
 903         char c;
 904         struct pollfd pollfds[2];
 905 
 906         sys_sigint_handler = signal(SIGINT, sigint_handler);
 907 
 908         con = poptGetContext(NULL, argc, argv, options, 0);
 909         retval = poptGetNextOpt(con);
 910         if (retval < -1) {
 911                 poptPrintUsage(con, stdout, 0);
 912                 return -1;
 913         }
 914 
 915         if (option_version) {
 916                 printf("dump tool for nosy sniffer, version %s\n", VERSION);
 917                 return 0;
 918         }
 919 
 920         if (__BYTE_ORDER != __LITTLE_ENDIAN)
 921                 fprintf(stderr, "warning: nosy has only been tested on little "
 922                         "endian machines\n");
 923 
 924         if (option_input != NULL) {
 925                 input = fopen(option_input, "r");
 926                 if (input == NULL) {
 927                         fprintf(stderr, "Could not open %s, %m\n", option_input);
 928                         return -1;
 929                 }
 930         } else {
 931                 fd = open(option_nosy_device, O_RDWR);
 932                 if (fd < 0) {
 933                         fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
 934                         return -1;
 935                 }
 936                 set_input_mode();
 937         }
 938 
 939         if (strcmp(option_view, "transaction") == 0)
 940                 view = VIEW_TRANSACTION;
 941         else if (strcmp(option_view, "stats") == 0)
 942                 view = VIEW_STATS;
 943         else
 944                 view = VIEW_PACKET;
 945 
 946         if (option_output) {
 947                 output = fopen(option_output, "w");
 948                 if (output == NULL) {
 949                         fprintf(stderr, "Could not open %s, %m\n", option_output);
 950                         return -1;
 951                 }
 952         }
 953 
 954         setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
 955 
 956         filter = ~0;
 957         if (!option_iso)
 958                 filter &= ~(1 << TCODE_STREAM_DATA);
 959         if (!option_cycle_start)
 960                 filter &= ~(1 << TCODE_CYCLE_START);
 961         if (view == VIEW_STATS)
 962                 filter = ~(1 << TCODE_CYCLE_START);
 963 
 964         ioctl(fd, NOSY_IOC_FILTER, filter);
 965 
 966         ioctl(fd, NOSY_IOC_START);
 967 
 968         pollfds[0].fd = fd;
 969         pollfds[0].events = POLLIN;
 970         pollfds[1].fd = STDIN_FILENO;
 971         pollfds[1].events = POLLIN;
 972 
 973         while (run) {
 974                 if (input != NULL) {
 975                         if (fread(&length, sizeof length, 1, input) != 1)
 976                                 return 0;
 977                         fread(buf, 1, length, input);
 978                 } else {
 979                         poll(pollfds, 2, -1);
 980                         if (pollfds[1].revents) {
 981                                 read(STDIN_FILENO, &c, sizeof c);
 982                                 switch (c) {
 983                                 case 'q':
 984                                         if (output != NULL)
 985                                                 fclose(output);
 986                                         return 0;
 987                                 }
 988                         }
 989 
 990                         if (pollfds[0].revents)
 991                                 length = read(fd, buf, sizeof buf);
 992                         else
 993                                 continue;
 994                 }
 995 
 996                 if (output != NULL) {
 997                         fwrite(&length, sizeof length, 1, output);
 998                         fwrite(buf, 1, length, output);
 999                 }
1000 
1001                 switch (view) {
1002                 case VIEW_TRANSACTION:
1003                         handle_packet(buf, length);
1004                         break;
1005                 case VIEW_PACKET:
1006                         print_packet(buf, length);
1007                         break;
1008                 case VIEW_STATS:
1009                         print_stats(buf, length);
1010                         break;
1011                 }
1012         }
1013 
1014         if (output != NULL)
1015                 fclose(output);
1016 
1017         close(fd);
1018 
1019         poptFreeContext(con);
1020 
1021         return 0;
1022 }

/* [<][>][^][v][top][bottom][index][help] */