diff options
-rw-r--r-- | nosy-dump.c | 210 |
1 files changed, 163 insertions, 47 deletions
diff --git a/nosy-dump.c b/nosy-dump.c index c68dccc..75c86ec 100644 --- a/nosy-dump.c +++ b/nosy-dump.c @@ -9,7 +9,9 @@ #include <sys/time.h> #include <endian.h> #include <popt.h> +#include <poll.h> #include <byteswap.h> +#include <termios.h> #include "nosy-user.h" #include "list.h" @@ -22,8 +24,11 @@ print_packet(unsigned long *data, size_t length); static char *option_nosy_device = "/dev/nosy"; static char *option_view = "packet"; +static char *option_output = NULL; +static char *option_input = NULL; static int option_hex; static int option_version; +static int option_verbose; #define SPEED_100 0x0 #define SPEED_200 0x1 @@ -36,7 +41,7 @@ enum { }; static const struct poptOption options[] = { - { + { longName: "device", shortName: 'd', argInfo: POPT_ARG_STRING, @@ -44,9 +49,8 @@ static const struct poptOption options[] = { descrip: "Path to nosy device.", argDescrip: "DEVICE" }, - { + { longName: "view", - shortName: 'v', argInfo: POPT_ARG_STRING, arg: &option_view, descrip: "Specify view of bus traffic: packet, transaction or stats.", @@ -58,9 +62,31 @@ static const struct poptOption options[] = { argInfo: POPT_ARG_NONE, arg: &option_hex, descrip: "Print each packet in hex.", - argDescrip: "HEX" }, - { + { + longName: "verbose", + shortName: 'v', + argInfo: POPT_ARG_NONE, + arg: &option_verbose, + descrip: "Verbose packet view.", + }, + { + longName: "output", + shortName: 'o', + argInfo: POPT_ARG_STRING, + arg: &option_output, + descrip: "Log to output file.", + argDescrip: "FILENAME" + }, + { + longName: "input", + shortName: 'i', + argInfo: POPT_ARG_STRING, + arg: &option_input, + descrip: "Decode log from file.", + argDescrip: "FILENAME" + }, + { longName: "version", argInfo: POPT_ARG_NONE, arg: &option_version, @@ -367,13 +393,13 @@ handle_transaction(struct link_transaction *t) { struct subaction *sa; - printf("completed transaction (%04x->%04x, tlabel=%x)\n", + printf("completed transaction (%04x->%04x, tlabel=%x)\r\n", t->request_node, t->response_node, t->tlabel); list_for_each_entry(sa, &t->request_list, link) print_packet((unsigned long *) &sa->packet, sa->length); list_for_each_entry(sa, &t->response_list, link) print_packet((unsigned long *) &sa->packet, sa->length); - printf("\n"); + printf("\r\n"); link_transaction_destroy(t); } @@ -458,51 +484,56 @@ struct packet_info { int field_count; }; +enum { + PACKET_FIELD_DETAIL = 0x01, +}; + struct packet_field { const char *name; /* Short name for field. */ int offset; /* Location of field, specified in bits. * Negative means from end of packet */ int width; /* Width of field, 0 means use data_length. */ + int flags; /* Show options. */ const char * const *value_names; }; -#define COMMON_REQUEST_FIELDS \ - { "dest", 0, 16 }, \ - { "tl", 16, 6 }, \ - { "rt", 22, 2, retry_names }, \ - { "tcode", 24, 4, tcode_names }, \ - { "pri", 28, 4 }, \ - { "src", 32, 16 }, \ +#define COMMON_REQUEST_FIELDS \ + { "dest", 0, 16 }, \ + { "tl", 16, 6 }, \ + { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \ + { "tcode", 24, 4, 0, tcode_names }, \ + { "pri", 28, 4, PACKET_FIELD_DETAIL }, \ + { "src", 32, 16 }, \ { "offs", 48, 48 } -#define COMMON_RESPONSE_FIELDS \ - { "dest", 0, 16 }, \ - { "tl", 16, 6 }, \ - { "rt", 22, 2, retry_names }, \ - { "tcode", 24, 4, tcode_names }, \ - { "pri", 28, 4 }, \ - { "src", 32, 16 }, \ - { "rcode", 48, 4, rcode_names } \ +#define COMMON_RESPONSE_FIELDS \ + { "dest", 0, 16 }, \ + { "tl", 16, 6 }, \ + { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \ + { "tcode", 24, 4, 0, tcode_names }, \ + { "pri", 28, 4, PACKET_FIELD_DETAIL }, \ + { "src", 32, 16 }, \ + { "rcode", 48, 4, 0, rcode_names } struct packet_field read_quadlet_request_fields[] = { COMMON_REQUEST_FIELDS, - { "crc", 96, 32 }, - { "ack", 156, 4, ack_names } + { "crc", 96, 32, PACKET_FIELD_DETAIL }, + { "ack", 156, 4, 0, ack_names } }; struct packet_field read_quadlet_response_fields[] = { COMMON_RESPONSE_FIELDS, { "data", 96, 32 }, - { "crc", 128, 32 }, - { "ack", 188, 4, ack_names } + { "crc", 128, 32, PACKET_FIELD_DETAIL }, + { "ack", 188, 4, 0, ack_names } }; struct packet_field read_block_request_fields[] = { COMMON_REQUEST_FIELDS, { "data_length", 96, 16 }, { "extended_tcode", 112, 16 }, - { "crc", 128, 32 }, - { "ack", 188, 4, ack_names }, + { "crc", 128, 32, PACKET_FIELD_DETAIL }, + { "ack", 188, 4, 0, ack_names }, }; struct packet_field read_block_response_fields[] = { @@ -511,34 +542,34 @@ struct packet_field read_block_response_fields[] = { { "extended_tcode", 112, 16 }, { "crc", 128, 32 }, { "data", 160, 0 }, - { "crc", -64, 32 }, - { "ack", -4, 4, ack_names } + { "crc", -64, 32, PACKET_FIELD_DETAIL }, + { "ack", -4, 4, 0, ack_names } }; struct packet_field write_quadlet_request_fields[] = { COMMON_REQUEST_FIELDS, { "data", 96, 32 }, - { "ack", -4, 4, ack_names } + { "ack", -4, 4, 0, ack_names } }; struct packet_field write_block_request_fields[] = { COMMON_REQUEST_FIELDS, { "data_length", 96, 16 }, { "extended_tcode", 112, 16 }, - { "crc", 128, 32 }, + { "crc", 128, 32, PACKET_FIELD_DETAIL }, { "data", 160, 0 }, - { "crc", -64, 32 }, - { "ack", -4, 4, ack_names } + { "crc", -64, 32, PACKET_FIELD_DETAIL }, + { "ack", -4, 4, 0, ack_names } }; struct packet_field write_response_fields[] = { COMMON_RESPONSE_FIELDS, { "reserved", 64, 32 }, - { "ack", -4, 4, ack_names } + { "ack", -4, 4, 0, ack_names } }; struct packet_field cycle_start_fields[] = { - { "tcode", 24, 4, tcode_names }, + { "tcode", 24, 4, 0, tcode_names }, }; @@ -617,7 +648,7 @@ void handle_packet(unsigned long *data, size_t length) { if (length == 0) { - printf("bus reset\n"); + printf("bus reset\r\n"); clear_pending_transaction_list(); } else if (length > sizeof(struct phy_packet)) { @@ -780,11 +811,14 @@ void decode_link_packet(struct link_packet *packet, size_t length) int i; pi = &packet_info[packet->common.tcode]; - + for (i = 0; i < pi->field_count; i++) { struct packet_field *f = &pi->fields[i]; int offset; + if ((f->flags & PACKET_FIELD_DETAIL) && !option_verbose) + continue; + if (f->offset < 0) offset = length * 8 + f->offset - 32; else @@ -821,7 +855,7 @@ void decode_link_packet(struct link_packet *packet, size_t length) else bits = get_bits(packet, offset, f->width); - printf("%s=0x%llx", f->name, bits); + printf("%s=0x%0*llx", f->name, (f->width + 3) / 4, bits); } if (i < pi->field_count - 1) @@ -909,7 +943,7 @@ print_packet(unsigned long *data, size_t length) printf("]"); } - printf("\n"); + printf("\r\n"); } #define HIDE_CURSOR "\033[?25l" @@ -954,13 +988,46 @@ print_stats(unsigned long *data, size_t length) printf(SHOW_CURSOR "\n"); } -int main(int argc, const char *argv[]) +struct termios saved_attributes; + +void +reset_input_mode (void) { - int fd; + tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes); +} +void +set_input_mode (void) +{ + struct termios tattr; + + /* Make sure stdin is a terminal. */ + if (!isatty(STDIN_FILENO)) { + fprintf(stderr, "Not a terminal.\n"); + exit(EXIT_FAILURE); + } + + /* Save the terminal attributes so we can restore them later. */ + tcgetattr(STDIN_FILENO, &saved_attributes); + atexit(reset_input_mode); + + /* Set the funny terminal modes. */ + tcgetattr(STDIN_FILENO, &tattr); + tattr.c_lflag &= ~(ICANON|ECHO); /* Clear ICANON and ECHO. */ + tattr.c_cc[VMIN] = 1; + tattr.c_cc[VTIME] = 0; + tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr); +} + +int main(int argc, const char *argv[]) +{ + int fd = -1; + FILE *output = NULL, *input = NULL; poptContext con; int retval; int view; + char c; + struct pollfd pollfds[2]; con = poptGetContext(NULL, argc, argv, options, 0); retval = poptGetNextOpt(con); @@ -978,10 +1045,20 @@ int main(int argc, const char *argv[]) fprintf(stderr, "warning: nosy has only been tested on little " "endian machines\n"); - fd = open(option_nosy_device, O_RDWR); - if (fd < 0) { - fprintf(stderr, "Could not open %s, %m\n", option_nosy_device); - return -1; + if (option_input != NULL) { + input = fopen(option_input, "r"); + if (input == NULL) { + fprintf(stderr, "Could not open %s, %m\n", option_input); + return -1; + } + } + else { + fd = open(option_nosy_device, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Could not open %s, %m\n", option_nosy_device); + return -1; + } + set_input_mode(); } if (strcmp(option_view, "transaction") == 0) @@ -991,6 +1068,14 @@ int main(int argc, const char *argv[]) else view = VIEW_PACKET; + if (option_output) { + output = fopen(option_output, "w"); + if (output == NULL) { + fprintf(stderr, "Could not open %s, %m\n", option_output); + return -1; + } + } + setvbuf(stdout, NULL, _IOLBF, BUFSIZ); if (1) { @@ -1005,8 +1090,39 @@ int main(int argc, const char *argv[]) ioctl(fd, NOSY_IOC_START); + pollfds[0].fd = fd; + pollfds[0].events = POLLIN; + pollfds[1].fd = STDIN_FILENO; + pollfds[1].events = POLLIN; + while (1) { - length = read(fd, buf, sizeof buf); + if (input != NULL) { + if (fread(&length, sizeof length, 1, input) != 1) + return 0; + fread(buf, 1, length, input); + } + else { + poll(pollfds, 2, 0); + if (pollfds[1].revents) { + read(STDIN_FILENO, &c, sizeof c); + switch (c) { + case 'q': + if (output != NULL) + fclose(output); + return 0; + } + } + + if (pollfds[0].revents) + length = read(fd, buf, sizeof buf); + else + continue; + } + + if (output != NULL) { + fwrite(&length, sizeof length, 1, output); + fwrite(buf, 1, length, output); + } switch (view) { case VIEW_TRANSACTION: |