summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nosy-dump.c210
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: