Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
0004  * Copyright (C) 2002-2006 Kristian Høgsberg
0005  */
0006 
0007 #include <byteswap.h>
0008 #include <endian.h>
0009 #include <fcntl.h>
0010 #include <linux/firewire-constants.h>
0011 #include <poll.h>
0012 #include <popt.h>
0013 #include <signal.h>
0014 #include <stdio.h>
0015 #include <stdlib.h>
0016 #include <string.h>
0017 #include <sys/ioctl.h>
0018 #include <sys/time.h>
0019 #include <termios.h>
0020 #include <unistd.h>
0021 
0022 #include "list.h"
0023 #include "nosy-dump.h"
0024 #include "nosy-user.h"
0025 
0026 enum {
0027     PACKET_FIELD_DETAIL     = 0x01,
0028     PACKET_FIELD_DATA_LENGTH    = 0x02,
0029     /* Marks the fields we print in transaction view. */
0030     PACKET_FIELD_TRANSACTION    = 0x04,
0031 };
0032 
0033 static void print_packet(uint32_t *data, size_t length);
0034 static void decode_link_packet(struct link_packet *packet, size_t length,
0035                    int include_flags, int exclude_flags);
0036 static int run = 1;
0037 sig_t sys_sigint_handler;
0038 
0039 static char *option_nosy_device = "/dev/nosy";
0040 static char *option_view = "packet";
0041 static char *option_output;
0042 static char *option_input;
0043 static int option_hex;
0044 static int option_iso;
0045 static int option_cycle_start;
0046 static int option_version;
0047 static int option_verbose;
0048 
0049 enum {
0050     VIEW_TRANSACTION,
0051     VIEW_PACKET,
0052     VIEW_STATS,
0053 };
0054 
0055 static const struct poptOption options[] = {
0056     {
0057         .longName   = "device",
0058         .shortName  = 'd',
0059         .argInfo    = POPT_ARG_STRING,
0060         .arg        = &option_nosy_device,
0061         .descrip    = "Path to nosy device.",
0062         .argDescrip = "DEVICE"
0063     },
0064     {
0065         .longName   = "view",
0066         .argInfo    = POPT_ARG_STRING,
0067         .arg        = &option_view,
0068         .descrip    = "Specify view of bus traffic: packet, transaction or stats.",
0069         .argDescrip = "VIEW"
0070     },
0071     {
0072         .longName   = "hex",
0073         .shortName  = 'x',
0074         .argInfo    = POPT_ARG_NONE,
0075         .arg        = &option_hex,
0076         .descrip    = "Print each packet in hex.",
0077     },
0078     {
0079         .longName   = "iso",
0080         .argInfo    = POPT_ARG_NONE,
0081         .arg        = &option_iso,
0082         .descrip    = "Print iso packets.",
0083     },
0084     {
0085         .longName   = "cycle-start",
0086         .argInfo    = POPT_ARG_NONE,
0087         .arg        = &option_cycle_start,
0088         .descrip    = "Print cycle start packets.",
0089     },
0090     {
0091         .longName   = "verbose",
0092         .shortName  = 'v',
0093         .argInfo    = POPT_ARG_NONE,
0094         .arg        = &option_verbose,
0095         .descrip    = "Verbose packet view.",
0096     },
0097     {
0098         .longName   = "output",
0099         .shortName  = 'o',
0100         .argInfo    = POPT_ARG_STRING,
0101         .arg        = &option_output,
0102         .descrip    = "Log to output file.",
0103         .argDescrip = "FILENAME"
0104     },
0105     {
0106         .longName   = "input",
0107         .shortName  = 'i',
0108         .argInfo    = POPT_ARG_STRING,
0109         .arg        = &option_input,
0110         .descrip    = "Decode log from file.",
0111         .argDescrip = "FILENAME"
0112     },
0113     {
0114         .longName   = "version",
0115         .argInfo    = POPT_ARG_NONE,
0116         .arg        = &option_version,
0117         .descrip    = "Specify print version info.",
0118     },
0119     POPT_AUTOHELP
0120     POPT_TABLEEND
0121 };
0122 
0123 /* Allow all ^C except the first to interrupt the program in the usual way. */
0124 static void
0125 sigint_handler(int signal_num)
0126 {
0127     if (run == 1) {
0128         run = 0;
0129         signal(SIGINT, SIG_DFL);
0130     }
0131 }
0132 
0133 static struct subaction *
0134 subaction_create(uint32_t *data, size_t length)
0135 {
0136     struct subaction *sa;
0137 
0138     /* we put the ack in the subaction struct for easy access. */
0139     sa = malloc(sizeof *sa - sizeof sa->packet + length);
0140     if (!sa)
0141         exit(EXIT_FAILURE);
0142     sa->ack = data[length / 4 - 1];
0143     sa->length = length;
0144     memcpy(&sa->packet, data, length);
0145 
0146     return sa;
0147 }
0148 
0149 static void
0150 subaction_destroy(struct subaction *sa)
0151 {
0152     free(sa);
0153 }
0154 
0155 static struct list pending_transaction_list = {
0156     &pending_transaction_list, &pending_transaction_list
0157 };
0158 
0159 static struct link_transaction *
0160 link_transaction_lookup(int request_node, int response_node, int tlabel)
0161 {
0162     struct link_transaction *t;
0163 
0164     list_for_each_entry(t, &pending_transaction_list, link) {
0165         if (t->request_node == request_node &&
0166             t->response_node == response_node &&
0167             t->tlabel == tlabel)
0168             return t;
0169     }
0170 
0171     t = malloc(sizeof *t);
0172     if (!t)
0173         exit(EXIT_FAILURE);
0174     t->request_node = request_node;
0175     t->response_node = response_node;
0176     t->tlabel = tlabel;
0177     list_init(&t->request_list);
0178     list_init(&t->response_list);
0179 
0180     list_append(&pending_transaction_list, &t->link);
0181 
0182     return t;
0183 }
0184 
0185 static void
0186 link_transaction_destroy(struct link_transaction *t)
0187 {
0188     struct subaction *sa;
0189 
0190     while (!list_empty(&t->request_list)) {
0191         sa = list_head(&t->request_list, struct subaction, link);
0192         list_remove(&sa->link);
0193         subaction_destroy(sa);
0194     }
0195     while (!list_empty(&t->response_list)) {
0196         sa = list_head(&t->response_list, struct subaction, link);
0197         list_remove(&sa->link);
0198         subaction_destroy(sa);
0199     }
0200     free(t);
0201 }
0202 
0203 struct protocol_decoder {
0204     const char *name;
0205     int (*decode)(struct link_transaction *t);
0206 };
0207 
0208 static const struct protocol_decoder protocol_decoders[] = {
0209     { "FCP", decode_fcp }
0210 };
0211 
0212 static void
0213 handle_transaction(struct link_transaction *t)
0214 {
0215     struct subaction *sa;
0216     int i;
0217 
0218     if (!t->request) {
0219         printf("BUG in handle_transaction\n");
0220         return;
0221     }
0222 
0223     for (i = 0; i < array_length(protocol_decoders); i++)
0224         if (protocol_decoders[i].decode(t))
0225             break;
0226 
0227     /* HACK: decode only fcp right now. */
0228     return;
0229 
0230     decode_link_packet(&t->request->packet, t->request->length,
0231                PACKET_FIELD_TRANSACTION, 0);
0232     if (t->response)
0233         decode_link_packet(&t->response->packet, t->request->length,
0234                    PACKET_FIELD_TRANSACTION, 0);
0235     else
0236         printf("[no response]");
0237 
0238     if (option_verbose) {
0239         list_for_each_entry(sa, &t->request_list, link)
0240             print_packet((uint32_t *) &sa->packet, sa->length);
0241         list_for_each_entry(sa, &t->response_list, link)
0242             print_packet((uint32_t *) &sa->packet, sa->length);
0243     }
0244     printf("\r\n");
0245 
0246     link_transaction_destroy(t);
0247 }
0248 
0249 static void
0250 clear_pending_transaction_list(void)
0251 {
0252     struct link_transaction *t;
0253 
0254     while (!list_empty(&pending_transaction_list)) {
0255         t = list_head(&pending_transaction_list,
0256                   struct link_transaction, link);
0257         list_remove(&t->link);
0258         link_transaction_destroy(t);
0259         /* print unfinished transactions */
0260     }
0261 }
0262 
0263 static const char * const tcode_names[] = {
0264     [0x0] = "write_quadlet_request",    [0x6] = "read_quadlet_response",
0265     [0x1] = "write_block_request",      [0x7] = "read_block_response",
0266     [0x2] = "write_response",       [0x8] = "cycle_start",
0267     [0x3] = "reserved",         [0x9] = "lock_request",
0268     [0x4] = "read_quadlet_request",     [0xa] = "iso_data",
0269     [0x5] = "read_block_request",       [0xb] = "lock_response",
0270 };
0271 
0272 static const char * const ack_names[] = {
0273     [0x0] = "no ack",           [0x8] = "reserved (0x08)",
0274     [0x1] = "ack_complete",         [0x9] = "reserved (0x09)",
0275     [0x2] = "ack_pending",          [0xa] = "reserved (0x0a)",
0276     [0x3] = "reserved (0x03)",      [0xb] = "reserved (0x0b)",
0277     [0x4] = "ack_busy_x",           [0xc] = "reserved (0x0c)",
0278     [0x5] = "ack_busy_a",           [0xd] = "ack_data_error",
0279     [0x6] = "ack_busy_b",           [0xe] = "ack_type_error",
0280     [0x7] = "reserved (0x07)",      [0xf] = "reserved (0x0f)",
0281 };
0282 
0283 static const char * const rcode_names[] = {
0284     [0x0] = "complete",         [0x4] = "conflict_error",
0285     [0x1] = "reserved (0x01)",      [0x5] = "data_error",
0286     [0x2] = "reserved (0x02)",      [0x6] = "type_error",
0287     [0x3] = "reserved (0x03)",      [0x7] = "address_error",
0288 };
0289 
0290 static const char * const retry_names[] = {
0291     [0x0] = "retry_1",
0292     [0x1] = "retry_x",
0293     [0x2] = "retry_a",
0294     [0x3] = "retry_b",
0295 };
0296 
0297 enum {
0298     PACKET_RESERVED,
0299     PACKET_REQUEST,
0300     PACKET_RESPONSE,
0301     PACKET_OTHER,
0302 };
0303 
0304 struct packet_info {
0305     const char *name;
0306     int type;
0307     int response_tcode;
0308     const struct packet_field *fields;
0309     int field_count;
0310 };
0311 
0312 struct packet_field {
0313     const char *name; /* Short name for field. */
0314     int offset; /* Location of field, specified in bits; */
0315             /* negative means from end of packet.    */
0316     int width;  /* Width of field, 0 means use data_length. */
0317     int flags;  /* Show options. */
0318     const char * const *value_names;
0319 };
0320 
0321 #define COMMON_REQUEST_FIELDS                       \
0322     { "dest", 0, 16, PACKET_FIELD_TRANSACTION },            \
0323     { "tl", 16, 6 },                        \
0324     { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },      \
0325     { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names },  \
0326     { "pri", 28, 4, PACKET_FIELD_DETAIL },              \
0327     { "src", 32, 16, PACKET_FIELD_TRANSACTION },            \
0328     { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
0329 
0330 #define COMMON_RESPONSE_FIELDS                      \
0331     { "dest", 0, 16 },                      \
0332     { "tl", 16, 6 },                        \
0333     { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names },      \
0334     { "tcode", 24, 4, 0, tcode_names },             \
0335     { "pri", 28, 4, PACKET_FIELD_DETAIL },              \
0336     { "src", 32, 16 },                      \
0337     { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
0338 
0339 static const struct packet_field read_quadlet_request_fields[] = {
0340     COMMON_REQUEST_FIELDS,
0341     { "crc", 96, 32, PACKET_FIELD_DETAIL },
0342     { "ack", 156, 4, 0, ack_names },
0343 };
0344 
0345 static const struct packet_field read_quadlet_response_fields[] = {
0346     COMMON_RESPONSE_FIELDS,
0347     { "data", 96, 32, PACKET_FIELD_TRANSACTION },
0348     { "crc", 128, 32, PACKET_FIELD_DETAIL },
0349     { "ack", 188, 4, 0, ack_names },
0350 };
0351 
0352 static const struct packet_field read_block_request_fields[] = {
0353     COMMON_REQUEST_FIELDS,
0354     { "data_length", 96, 16, PACKET_FIELD_TRANSACTION },
0355     { "extended_tcode", 112, 16 },
0356     { "crc", 128, 32, PACKET_FIELD_DETAIL },
0357     { "ack", 188, 4, 0, ack_names },
0358 };
0359 
0360 static const struct packet_field block_response_fields[] = {
0361     COMMON_RESPONSE_FIELDS,
0362     { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH },
0363     { "extended_tcode", 112, 16 },
0364     { "crc", 128, 32, PACKET_FIELD_DETAIL },
0365     { "data", 160, 0, PACKET_FIELD_TRANSACTION },
0366     { "crc", -64, 32, PACKET_FIELD_DETAIL },
0367     { "ack", -4, 4, 0, ack_names },
0368 };
0369 
0370 static const struct packet_field write_quadlet_request_fields[] = {
0371     COMMON_REQUEST_FIELDS,
0372     { "data", 96, 32, PACKET_FIELD_TRANSACTION },
0373     { "ack", -4, 4, 0, ack_names },
0374 };
0375 
0376 static const struct packet_field block_request_fields[] = {
0377     COMMON_REQUEST_FIELDS,
0378     { "data_length", 96, 16, PACKET_FIELD_DATA_LENGTH | PACKET_FIELD_TRANSACTION },
0379     { "extended_tcode", 112, 16, PACKET_FIELD_TRANSACTION },
0380     { "crc", 128, 32, PACKET_FIELD_DETAIL },
0381     { "data", 160, 0, PACKET_FIELD_TRANSACTION },
0382     { "crc", -64, 32, PACKET_FIELD_DETAIL },
0383     { "ack", -4, 4, 0, ack_names },
0384 };
0385 
0386 static const struct packet_field write_response_fields[] = {
0387     COMMON_RESPONSE_FIELDS,
0388     { "reserved", 64, 32, PACKET_FIELD_DETAIL },
0389     { "ack", -4, 4, 0, ack_names },
0390 };
0391 
0392 static const struct packet_field iso_data_fields[] = {
0393     { "data_length", 0, 16, PACKET_FIELD_DATA_LENGTH },
0394     { "tag", 16, 2 },
0395     { "channel", 18, 6 },
0396     { "tcode", 24, 4, 0, tcode_names },
0397     { "sy", 28, 4 },
0398     { "crc", 32, 32, PACKET_FIELD_DETAIL },
0399     { "data", 64, 0 },
0400     { "crc", -64, 32, PACKET_FIELD_DETAIL },
0401     { "ack", -4, 4, 0, ack_names },
0402 };
0403 
0404 static const struct packet_info packet_info[] = {
0405     {
0406         .name       = "write_quadlet_request",
0407         .type       = PACKET_REQUEST,
0408         .response_tcode = TCODE_WRITE_RESPONSE,
0409         .fields     = write_quadlet_request_fields,
0410         .field_count    = array_length(write_quadlet_request_fields)
0411     },
0412     {
0413         .name       = "write_block_request",
0414         .type       = PACKET_REQUEST,
0415         .response_tcode = TCODE_WRITE_RESPONSE,
0416         .fields     = block_request_fields,
0417         .field_count    = array_length(block_request_fields)
0418     },
0419     {
0420         .name       = "write_response",
0421         .type       = PACKET_RESPONSE,
0422         .fields     = write_response_fields,
0423         .field_count    = array_length(write_response_fields)
0424     },
0425     {
0426         .name       = "reserved",
0427         .type       = PACKET_RESERVED,
0428     },
0429     {
0430         .name       = "read_quadlet_request",
0431         .type       = PACKET_REQUEST,
0432         .response_tcode = TCODE_READ_QUADLET_RESPONSE,
0433         .fields     = read_quadlet_request_fields,
0434         .field_count    = array_length(read_quadlet_request_fields)
0435     },
0436     {
0437         .name       = "read_block_request",
0438         .type       = PACKET_REQUEST,
0439         .response_tcode = TCODE_READ_BLOCK_RESPONSE,
0440         .fields     = read_block_request_fields,
0441         .field_count    = array_length(read_block_request_fields)
0442     },
0443     {
0444         .name       = "read_quadlet_response",
0445         .type       = PACKET_RESPONSE,
0446         .fields     = read_quadlet_response_fields,
0447         .field_count    = array_length(read_quadlet_response_fields)
0448     },
0449     {
0450         .name       = "read_block_response",
0451         .type       = PACKET_RESPONSE,
0452         .fields     = block_response_fields,
0453         .field_count    = array_length(block_response_fields)
0454     },
0455     {
0456         .name       = "cycle_start",
0457         .type       = PACKET_OTHER,
0458         .fields     = write_quadlet_request_fields,
0459         .field_count    = array_length(write_quadlet_request_fields)
0460     },
0461     {
0462         .name       = "lock_request",
0463         .type       = PACKET_REQUEST,
0464         .fields     = block_request_fields,
0465         .field_count    = array_length(block_request_fields)
0466     },
0467     {
0468         .name       = "iso_data",
0469         .type       = PACKET_OTHER,
0470         .fields     = iso_data_fields,
0471         .field_count    = array_length(iso_data_fields)
0472     },
0473     {
0474         .name       = "lock_response",
0475         .type       = PACKET_RESPONSE,
0476         .fields     = block_response_fields,
0477         .field_count    = array_length(block_response_fields)
0478     },
0479 };
0480 
0481 static int
0482 handle_request_packet(uint32_t *data, size_t length)
0483 {
0484     struct link_packet *p = (struct link_packet *) data;
0485     struct subaction *sa, *prev;
0486     struct link_transaction *t;
0487 
0488     t = link_transaction_lookup(p->common.source, p->common.destination,
0489             p->common.tlabel);
0490     sa = subaction_create(data, length);
0491     t->request = sa;
0492 
0493     if (!list_empty(&t->request_list)) {
0494         prev = list_tail(&t->request_list,
0495                  struct subaction, link);
0496 
0497         if (!ACK_BUSY(prev->ack)) {
0498             /*
0499              * error, we should only see ack_busy_* before the
0500              * ack_pending/ack_complete -- this is an ack_pending
0501              * instead (ack_complete would have finished the
0502              * transaction).
0503              */
0504         }
0505 
0506         if (prev->packet.common.tcode != sa->packet.common.tcode ||
0507             prev->packet.common.tlabel != sa->packet.common.tlabel) {
0508             /* memcmp() ? */
0509             /* error, these should match for retries. */
0510         }
0511     }
0512 
0513     list_append(&t->request_list, &sa->link);
0514 
0515     switch (sa->ack) {
0516     case ACK_COMPLETE:
0517         if (p->common.tcode != TCODE_WRITE_QUADLET_REQUEST &&
0518             p->common.tcode != TCODE_WRITE_BLOCK_REQUEST)
0519             /* error, unified transactions only allowed for write */;
0520         list_remove(&t->link);
0521         handle_transaction(t);
0522         break;
0523 
0524     case ACK_NO_ACK:
0525     case ACK_DATA_ERROR:
0526     case ACK_TYPE_ERROR:
0527         list_remove(&t->link);
0528         handle_transaction(t);
0529         break;
0530 
0531     case ACK_PENDING:
0532         /* request subaction phase over, wait for response. */
0533         break;
0534 
0535     case ACK_BUSY_X:
0536     case ACK_BUSY_A:
0537     case ACK_BUSY_B:
0538         /* ok, wait for retry. */
0539         /* check that retry protocol is respected. */
0540         break;
0541     }
0542 
0543     return 1;
0544 }
0545 
0546 static int
0547 handle_response_packet(uint32_t *data, size_t length)
0548 {
0549     struct link_packet *p = (struct link_packet *) data;
0550     struct subaction *sa, *prev;
0551     struct link_transaction *t;
0552 
0553     t = link_transaction_lookup(p->common.destination, p->common.source,
0554             p->common.tlabel);
0555     if (list_empty(&t->request_list)) {
0556         /* unsolicited response */
0557     }
0558 
0559     sa = subaction_create(data, length);
0560     t->response = sa;
0561 
0562     if (!list_empty(&t->response_list)) {
0563         prev = list_tail(&t->response_list, struct subaction, link);
0564 
0565         if (!ACK_BUSY(prev->ack)) {
0566             /*
0567              * error, we should only see ack_busy_* before the
0568              * ack_pending/ack_complete
0569              */
0570         }
0571 
0572         if (prev->packet.common.tcode != sa->packet.common.tcode ||
0573             prev->packet.common.tlabel != sa->packet.common.tlabel) {
0574             /* use memcmp() instead? */
0575             /* error, these should match for retries. */
0576         }
0577     } else {
0578         prev = list_tail(&t->request_list, struct subaction, link);
0579         if (prev->ack != ACK_PENDING) {
0580             /*
0581              * error, should not get response unless last request got
0582              * ack_pending.
0583              */
0584         }
0585 
0586         if (packet_info[prev->packet.common.tcode].response_tcode !=
0587             sa->packet.common.tcode) {
0588             /* error, tcode mismatch */
0589         }
0590     }
0591 
0592     list_append(&t->response_list, &sa->link);
0593 
0594     switch (sa->ack) {
0595     case ACK_COMPLETE:
0596     case ACK_NO_ACK:
0597     case ACK_DATA_ERROR:
0598     case ACK_TYPE_ERROR:
0599         list_remove(&t->link);
0600         handle_transaction(t);
0601         /* transaction complete, remove t from pending list. */
0602         break;
0603 
0604     case ACK_PENDING:
0605         /* error for responses. */
0606         break;
0607 
0608     case ACK_BUSY_X:
0609     case ACK_BUSY_A:
0610     case ACK_BUSY_B:
0611         /* no problem, wait for next retry */
0612         break;
0613     }
0614 
0615     return 1;
0616 }
0617 
0618 static int
0619 handle_packet(uint32_t *data, size_t length)
0620 {
0621     if (length == 0) {
0622         printf("bus reset\r\n");
0623         clear_pending_transaction_list();
0624     } else if (length > sizeof(struct phy_packet)) {
0625         struct link_packet *p = (struct link_packet *) data;
0626 
0627         switch (packet_info[p->common.tcode].type) {
0628         case PACKET_REQUEST:
0629             return handle_request_packet(data, length);
0630 
0631         case PACKET_RESPONSE:
0632             return handle_response_packet(data, length);
0633 
0634         case PACKET_OTHER:
0635         case PACKET_RESERVED:
0636             return 0;
0637         }
0638     }
0639 
0640     return 1;
0641 }
0642 
0643 static unsigned int
0644 get_bits(struct link_packet *packet, int offset, int width)
0645 {
0646     uint32_t *data = (uint32_t *) packet;
0647     uint32_t index, shift, mask;
0648 
0649     index = offset / 32 + 1;
0650     shift = 32 - (offset & 31) - width;
0651     mask = width == 32 ? ~0 : (1 << width) - 1;
0652 
0653     return (data[index] >> shift) & mask;
0654 }
0655 
0656 #if __BYTE_ORDER == __LITTLE_ENDIAN
0657 #define byte_index(i) ((i) ^ 3)
0658 #elif __BYTE_ORDER == __BIG_ENDIAN
0659 #define byte_index(i) (i)
0660 #else
0661 #error unsupported byte order.
0662 #endif
0663 
0664 static void
0665 dump_data(unsigned char *data, int length)
0666 {
0667     int i, print_length;
0668 
0669     if (length > 128)
0670         print_length = 128;
0671     else
0672         print_length = length;
0673 
0674     for (i = 0; i < print_length; i++)
0675         printf("%s%02hhx",
0676                (i % 4 == 0 && i != 0) ? " " : "",
0677                data[byte_index(i)]);
0678 
0679     if (print_length < length)
0680         printf(" (%d more bytes)", length - print_length);
0681 }
0682 
0683 static void
0684 decode_link_packet(struct link_packet *packet, size_t length,
0685            int include_flags, int exclude_flags)
0686 {
0687     const struct packet_info *pi;
0688     int data_length = 0;
0689     int i;
0690 
0691     pi = &packet_info[packet->common.tcode];
0692 
0693     for (i = 0; i < pi->field_count; i++) {
0694         const struct packet_field *f = &pi->fields[i];
0695         int offset;
0696 
0697         if (f->flags & exclude_flags)
0698             continue;
0699         if (include_flags && !(f->flags & include_flags))
0700             continue;
0701 
0702         if (f->offset < 0)
0703             offset = length * 8 + f->offset - 32;
0704         else
0705             offset = f->offset;
0706 
0707         if (f->value_names != NULL) {
0708             uint32_t bits;
0709 
0710             bits = get_bits(packet, offset, f->width);
0711             printf("%s", f->value_names[bits]);
0712         } else if (f->width == 0) {
0713             printf("%s=[", f->name);
0714             dump_data((unsigned char *) packet + (offset / 8 + 4), data_length);
0715             printf("]");
0716         } else {
0717             unsigned long long bits;
0718             int high_width, low_width;
0719 
0720             if ((offset & ~31) != ((offset + f->width - 1) & ~31)) {
0721                 /* Bit field spans quadlet boundary. */
0722                 high_width = ((offset + 31) & ~31) - offset;
0723                 low_width = f->width - high_width;
0724 
0725                 bits = get_bits(packet, offset, high_width);
0726                 bits = (bits << low_width) |
0727                     get_bits(packet, offset + high_width, low_width);
0728             } else {
0729                 bits = get_bits(packet, offset, f->width);
0730             }
0731 
0732             printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits);
0733 
0734             if (f->flags & PACKET_FIELD_DATA_LENGTH)
0735                 data_length = bits;
0736         }
0737 
0738         if (i < pi->field_count - 1)
0739             printf(", ");
0740     }
0741 }
0742 
0743 static void
0744 print_packet(uint32_t *data, size_t length)
0745 {
0746     int i;
0747 
0748     printf("%6u  ", data[0]);
0749 
0750     if (length == 4) {
0751         printf("bus reset");
0752     } else if (length < sizeof(struct phy_packet)) {
0753         printf("short packet: ");
0754         for (i = 1; i < length / 4; i++)
0755             printf("%s%08x", i == 0 ? "[" : " ", data[i]);
0756         printf("]");
0757 
0758     } else if (length == sizeof(struct phy_packet) && data[1] == ~data[2]) {
0759         struct phy_packet *pp = (struct phy_packet *) data;
0760 
0761         /* phy packet are 3 quadlets: the 1 quadlet payload,
0762          * the bitwise inverse of the payload and the snoop
0763          * mode ack */
0764 
0765         switch (pp->common.identifier) {
0766         case PHY_PACKET_CONFIGURATION:
0767             if (!pp->phy_config.set_root && !pp->phy_config.set_gap_count) {
0768                 printf("ext phy config: phy_id=%02x", pp->phy_config.root_id);
0769             } else {
0770                 printf("phy config:");
0771                 if (pp->phy_config.set_root)
0772                     printf(" set_root_id=%02x", pp->phy_config.root_id);
0773                 if (pp->phy_config.set_gap_count)
0774                     printf(" set_gap_count=%d", pp->phy_config.gap_count);
0775             }
0776             break;
0777 
0778         case PHY_PACKET_LINK_ON:
0779             printf("link-on packet, phy_id=%02x", pp->link_on.phy_id);
0780             break;
0781 
0782         case PHY_PACKET_SELF_ID:
0783             if (pp->self_id.extended) {
0784                 printf("extended self id: phy_id=%02x, seq=%d",
0785                        pp->ext_self_id.phy_id, pp->ext_self_id.sequence);
0786             } else {
0787                 static const char * const speed_names[] = {
0788                     "S100", "S200", "S400", "BETA"
0789                 };
0790                 printf("self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
0791                        pp->self_id.phy_id,
0792                        (pp->self_id.link_active ? "active" : "not active"),
0793                        pp->self_id.gap_count,
0794                        speed_names[pp->self_id.phy_speed],
0795                        (pp->self_id.contender ? ", irm contender" : ""),
0796                        (pp->self_id.initiated_reset ? ", initiator" : ""));
0797             }
0798             break;
0799         default:
0800             printf("unknown phy packet: ");
0801             for (i = 1; i < length / 4; i++)
0802                 printf("%s%08x", i == 0 ? "[" : " ", data[i]);
0803             printf("]");
0804             break;
0805         }
0806     } else {
0807         struct link_packet *packet = (struct link_packet *) data;
0808 
0809         decode_link_packet(packet, length, 0,
0810                    option_verbose ? 0 : PACKET_FIELD_DETAIL);
0811     }
0812 
0813     if (option_hex) {
0814         printf("  [");
0815         dump_data((unsigned char *) data + 4, length - 4);
0816         printf("]");
0817     }
0818 
0819     printf("\r\n");
0820 }
0821 
0822 #define HIDE_CURSOR "\033[?25l"
0823 #define SHOW_CURSOR "\033[?25h"
0824 #define CLEAR       "\033[H\033[2J"
0825 
0826 static void
0827 print_stats(uint32_t *data, size_t length)
0828 {
0829     static int bus_reset_count, short_packet_count, phy_packet_count;
0830     static int tcode_count[16];
0831     static struct timeval last_update;
0832     struct timeval now;
0833     int i;
0834 
0835     if (length == 0)
0836         bus_reset_count++;
0837     else if (length < sizeof(struct phy_packet))
0838         short_packet_count++;
0839     else if (length == sizeof(struct phy_packet) && data[1] == ~data[2])
0840         phy_packet_count++;
0841     else {
0842         struct link_packet *packet = (struct link_packet *) data;
0843         tcode_count[packet->common.tcode]++;
0844     }
0845 
0846     gettimeofday(&now, NULL);
0847     if (now.tv_sec <= last_update.tv_sec &&
0848         now.tv_usec < last_update.tv_usec + 500000)
0849         return;
0850 
0851     last_update = now;
0852     printf(CLEAR HIDE_CURSOR
0853            "  bus resets              : %8d\n"
0854            "  short packets           : %8d\n"
0855            "  phy packets             : %8d\n",
0856            bus_reset_count, short_packet_count, phy_packet_count);
0857 
0858     for (i = 0; i < array_length(packet_info); i++)
0859         if (packet_info[i].type != PACKET_RESERVED)
0860             printf("  %-24s: %8d\n", packet_info[i].name, tcode_count[i]);
0861     printf(SHOW_CURSOR "\n");
0862 }
0863 
0864 static struct termios saved_attributes;
0865 
0866 static void
0867 reset_input_mode(void)
0868 {
0869     tcsetattr(STDIN_FILENO, TCSANOW, &saved_attributes);
0870 }
0871 
0872 static void
0873 set_input_mode(void)
0874 {
0875     struct termios tattr;
0876 
0877     /* Make sure stdin is a terminal. */
0878     if (!isatty(STDIN_FILENO)) {
0879         fprintf(stderr, "Not a terminal.\n");
0880         exit(EXIT_FAILURE);
0881     }
0882 
0883     /* Save the terminal attributes so we can restore them later. */
0884     tcgetattr(STDIN_FILENO, &saved_attributes);
0885     atexit(reset_input_mode);
0886 
0887     /* Set the funny terminal modes. */
0888     tcgetattr(STDIN_FILENO, &tattr);
0889     tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */
0890     tattr.c_cc[VMIN] = 1;
0891     tattr.c_cc[VTIME] = 0;
0892     tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
0893 }
0894 
0895 int main(int argc, const char *argv[])
0896 {
0897     uint32_t buf[128 * 1024];
0898     uint32_t filter;
0899     int length, retval, view;
0900     int fd = -1;
0901     FILE *output = NULL, *input = NULL;
0902     poptContext con;
0903     char c;
0904     struct pollfd pollfds[2];
0905 
0906     sys_sigint_handler = signal(SIGINT, sigint_handler);
0907 
0908     con = poptGetContext(NULL, argc, argv, options, 0);
0909     retval = poptGetNextOpt(con);
0910     if (retval < -1) {
0911         poptPrintUsage(con, stdout, 0);
0912         return -1;
0913     }
0914 
0915     if (option_version) {
0916         printf("dump tool for nosy sniffer, version %s\n", VERSION);
0917         return 0;
0918     }
0919 
0920     if (__BYTE_ORDER != __LITTLE_ENDIAN)
0921         fprintf(stderr, "warning: nosy has only been tested on little "
0922             "endian machines\n");
0923 
0924     if (option_input != NULL) {
0925         input = fopen(option_input, "r");
0926         if (input == NULL) {
0927             fprintf(stderr, "Could not open %s, %m\n", option_input);
0928             return -1;
0929         }
0930     } else {
0931         fd = open(option_nosy_device, O_RDWR);
0932         if (fd < 0) {
0933             fprintf(stderr, "Could not open %s, %m\n", option_nosy_device);
0934             return -1;
0935         }
0936         set_input_mode();
0937     }
0938 
0939     if (strcmp(option_view, "transaction") == 0)
0940         view = VIEW_TRANSACTION;
0941     else if (strcmp(option_view, "stats") == 0)
0942         view = VIEW_STATS;
0943     else
0944         view = VIEW_PACKET;
0945 
0946     if (option_output) {
0947         output = fopen(option_output, "w");
0948         if (output == NULL) {
0949             fprintf(stderr, "Could not open %s, %m\n", option_output);
0950             return -1;
0951         }
0952     }
0953 
0954     setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
0955 
0956     filter = ~0;
0957     if (!option_iso)
0958         filter &= ~(1 << TCODE_STREAM_DATA);
0959     if (!option_cycle_start)
0960         filter &= ~(1 << TCODE_CYCLE_START);
0961     if (view == VIEW_STATS)
0962         filter = ~(1 << TCODE_CYCLE_START);
0963 
0964     ioctl(fd, NOSY_IOC_FILTER, filter);
0965 
0966     ioctl(fd, NOSY_IOC_START);
0967 
0968     pollfds[0].fd = fd;
0969     pollfds[0].events = POLLIN;
0970     pollfds[1].fd = STDIN_FILENO;
0971     pollfds[1].events = POLLIN;
0972 
0973     while (run) {
0974         if (input != NULL) {
0975             if (fread(&length, sizeof length, 1, input) != 1)
0976                 return 0;
0977             fread(buf, 1, length, input);
0978         } else {
0979             poll(pollfds, 2, -1);
0980             if (pollfds[1].revents) {
0981                 read(STDIN_FILENO, &c, sizeof c);
0982                 switch (c) {
0983                 case 'q':
0984                     if (output != NULL)
0985                         fclose(output);
0986                     return 0;
0987                 }
0988             }
0989 
0990             if (pollfds[0].revents)
0991                 length = read(fd, buf, sizeof buf);
0992             else
0993                 continue;
0994         }
0995 
0996         if (output != NULL) {
0997             fwrite(&length, sizeof length, 1, output);
0998             fwrite(buf, 1, length, output);
0999         }
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 }