30 #include <sys/ioctl.h>
48 int include_flags,
int exclude_flags);
52 static char *option_nosy_device =
"/dev/nosy";
53 static char *option_view =
"packet";
54 static char *option_output;
55 static char *option_input;
56 static int option_hex;
57 static int option_iso;
58 static int option_cycle_start;
59 static int option_version;
60 static int option_verbose;
68 static const struct poptOption
options[] = {
72 .argInfo = POPT_ARG_STRING,
73 .arg = &option_nosy_device,
74 .descrip =
"Path to nosy device.",
75 .argDescrip =
"DEVICE"
79 .argInfo = POPT_ARG_STRING,
81 .descrip =
"Specify view of bus traffic: packet, transaction or stats.",
87 .argInfo = POPT_ARG_NONE,
89 .descrip =
"Print each packet in hex.",
93 .argInfo = POPT_ARG_NONE,
95 .descrip =
"Print iso packets.",
98 .longName =
"cycle-start",
99 .argInfo = POPT_ARG_NONE,
100 .arg = &option_cycle_start,
101 .descrip =
"Print cycle start packets.",
104 .longName =
"verbose",
106 .argInfo = POPT_ARG_NONE,
107 .arg = &option_verbose,
108 .descrip =
"Verbose packet view.",
111 .longName =
"output",
113 .argInfo = POPT_ARG_STRING,
114 .arg = &option_output,
115 .descrip =
"Log to output file.",
116 .argDescrip =
"FILENAME"
121 .argInfo = POPT_ARG_STRING,
122 .arg = &option_input,
123 .descrip =
"Decode log from file.",
124 .argDescrip =
"FILENAME"
127 .longName =
"version",
128 .argInfo = POPT_ARG_NONE,
129 .arg = &option_version,
130 .descrip =
"Specify print version info.",
138 sigint_handler(
int signal_num)
153 sa->
ack = data[length / 4 - 1];
166 static struct list pending_transaction_list = {
167 &pending_transaction_list, &pending_transaction_list
186 list_init(&t->request_list);
189 list_append(&pending_transaction_list, &t->
link);
199 while (!list_empty(&t->request_list)) {
201 list_remove(&sa->
link);
202 subaction_destroy(sa);
206 list_remove(&sa->
link);
207 subaction_destroy(sa);
228 printf(
"BUG in handle_transaction\n");
233 if (protocol_decoders[i].decode(t))
247 if (option_verbose) {
251 print_packet((
uint32_t *) &sa->packet, sa->length);
255 link_transaction_destroy(t);
259 clear_pending_transaction_list(
void)
263 while (!list_empty(&pending_transaction_list)) {
266 list_remove(&t->
link);
267 link_transaction_destroy(t);
272 static const char *
const tcode_names[] = {
273 [0x0] =
"write_quadlet_request", [0x6] =
"read_quadlet_response",
274 [0x1] =
"write_block_request", [0x7] =
"read_block_response",
275 [0x2] =
"write_response", [0x8] =
"cycle_start",
276 [0x3] =
"reserved", [0x9] =
"lock_request",
277 [0x4] =
"read_quadlet_request", [0xa] =
"iso_data",
278 [0x5] =
"read_block_request", [0xb] =
"lock_response",
281 static const char *
const ack_names[] = {
282 [0x0] =
"no ack", [0x8] =
"reserved (0x08)",
283 [0x1] =
"ack_complete", [0x9] =
"reserved (0x09)",
284 [0x2] =
"ack_pending", [0xa] =
"reserved (0x0a)",
285 [0x3] =
"reserved (0x03)", [0xb] =
"reserved (0x0b)",
286 [0x4] =
"ack_busy_x", [0xc] =
"reserved (0x0c)",
287 [0x5] =
"ack_busy_a", [0xd] =
"ack_data_error",
288 [0x6] =
"ack_busy_b", [0xe] =
"ack_type_error",
289 [0x7] =
"reserved (0x07)", [0xf] =
"reserved (0x0f)",
292 static const char *
const rcode_names[] = {
293 [0x0] =
"complete", [0x4] =
"conflict_error",
294 [0x1] =
"reserved (0x01)", [0x5] =
"data_error",
295 [0x2] =
"reserved (0x02)", [0x6] =
"type_error",
296 [0x3] =
"reserved (0x03)", [0x7] =
"address_error",
299 static const char *
const retry_names[] = {
330 #define COMMON_REQUEST_FIELDS \
331 { "dest", 0, 16, PACKET_FIELD_TRANSACTION }, \
333 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
334 { "tcode", 24, 4, PACKET_FIELD_TRANSACTION, tcode_names }, \
335 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
336 { "src", 32, 16, PACKET_FIELD_TRANSACTION }, \
337 { "offs", 48, 48, PACKET_FIELD_TRANSACTION }
339 #define COMMON_RESPONSE_FIELDS \
342 { "rt", 22, 2, PACKET_FIELD_DETAIL, retry_names }, \
343 { "tcode", 24, 4, 0, tcode_names }, \
344 { "pri", 28, 4, PACKET_FIELD_DETAIL }, \
346 { "rcode", 48, 4, PACKET_FIELD_TRANSACTION, rcode_names }
348 static const struct packet_field read_quadlet_request_fields[] = {
351 {
"ack", 156, 4, 0, ack_names },
354 static const struct packet_field read_quadlet_response_fields[] = {
358 {
"ack", 188, 4, 0, ack_names },
361 static const struct packet_field read_block_request_fields[] = {
364 {
"extended_tcode", 112, 16 },
366 {
"ack", 188, 4, 0, ack_names },
369 static const struct packet_field block_response_fields[] = {
372 {
"extended_tcode", 112, 16 },
376 {
"ack", -4, 4, 0, ack_names },
379 static const struct packet_field write_quadlet_request_fields[] = {
382 {
"ack", -4, 4, 0, ack_names },
385 static const struct packet_field block_request_fields[] = {
392 {
"ack", -4, 4, 0, ack_names },
395 static const struct packet_field write_response_fields[] = {
398 {
"ack", -4, 4, 0, ack_names },
404 {
"channel", 18, 6 },
405 {
"tcode", 24, 4, 0, tcode_names },
410 {
"ack", -4, 4, 0, ack_names },
415 .
name =
"write_quadlet_request",
418 .fields = write_quadlet_request_fields,
419 .field_count =
array_length(write_quadlet_request_fields)
422 .name =
"write_block_request",
425 .fields = block_request_fields,
429 .name =
"write_response",
431 .fields = write_response_fields,
439 .name =
"read_quadlet_request",
442 .fields = read_quadlet_request_fields,
443 .field_count =
array_length(read_quadlet_request_fields)
446 .name =
"read_block_request",
449 .fields = read_block_request_fields,
453 .name =
"read_quadlet_response",
455 .fields = read_quadlet_response_fields,
456 .field_count =
array_length(read_quadlet_response_fields)
459 .name =
"read_block_response",
461 .fields = block_response_fields,
465 .name =
"cycle_start",
467 .fields = write_quadlet_request_fields,
468 .field_count =
array_length(write_quadlet_request_fields)
471 .name =
"lock_request",
473 .fields = block_request_fields,
479 .fields = iso_data_fields,
483 .name =
"lock_response",
485 .fields = block_response_fields,
497 t = link_transaction_lookup(p->
common.source, p->
common.destination,
499 sa = subaction_create(data, length);
502 if (!list_empty(&t->request_list)) {
515 if (prev->
packet.common.tcode != sa->
packet.common.tcode ||
516 prev->
packet.common.tlabel != sa->
packet.common.tlabel) {
522 list_append(&t->request_list, &sa->
link);
529 list_remove(&t->
link);
530 handle_transaction(t);
536 list_remove(&t->
link);
537 handle_transaction(t);
556 handle_response_packet(
uint32_t *data,
size_t length)
562 t = link_transaction_lookup(p->
common.destination, p->
common.source,
564 if (list_empty(&t->request_list)) {
568 sa = subaction_create(data, length);
581 if (prev->
packet.common.tcode != sa->
packet.common.tcode ||
582 prev->
packet.common.tlabel != sa->
packet.common.tlabel) {
596 sa->
packet.common.tcode) {
608 list_remove(&t->
link);
609 handle_transaction(t);
628 handle_packet(
uint32_t *data,
size_t length)
632 clear_pending_transaction_list();
633 }
else if (length >
sizeof(
struct phy_packet)) {
638 return handle_request_packet(data, length);
641 return handle_response_packet(data, length);
658 index = offset / 32 + 1;
659 shift = 32 - (offset & 31) - width;
660 mask = width == 32 ? ~0 : (1 <<
width) - 1;
662 return (data[index] >> shift) &
mask;
665 #if __BYTE_ORDER == __LITTLE_ENDIAN
666 #define byte_index(i) ((i) ^ 3)
667 #elif __BYTE_ORDER == __BIG_ENDIAN
668 #define byte_index(i) (i)
670 #error unsupported byte order.
674 dump_data(
unsigned char *data,
int length)
683 for (i = 0; i < print_length; i++)
685 (i % 4 == 0 && i != 0) ?
" " :
"",
688 if (print_length < length)
689 printf(
" (%d more bytes)", length - print_length);
693 decode_link_packet(
struct link_packet *packet,
size_t length,
694 int include_flags,
int exclude_flags)
696 const struct packet_info *pi;
700 pi = &packet_info[packet->
common.tcode];
706 if (f->
flags & exclude_flags)
708 if (include_flags && !(f->
flags & include_flags))
712 offset = length * 8 + f->
offset - 32;
719 bits = get_bits(packet, offset, f->
width);
721 }
else if (f->
width == 0) {
723 dump_data((
unsigned char *) packet + (offset / 8 + 4), data_length);
726 unsigned long long bits;
727 int high_width, low_width;
729 if ((offset & ~31) != ((offset + f->
width - 1) & ~31)) {
731 high_width = ((offset + 31) & ~31) -
offset;
732 low_width = f->
width - high_width;
734 bits = get_bits(packet, offset, high_width);
735 bits = (bits << low_width) |
736 get_bits(packet, offset + high_width, low_width);
738 bits = get_bits(packet, offset, f->
width);
747 if (i < pi->field_count - 1)
753 print_packet(
uint32_t *data,
size_t length)
761 }
else if (length <
sizeof(
struct phy_packet)) {
763 for (i = 1; i < length / 4; i++)
764 printf(
"%s%08x", i == 0 ?
"[" :
" ", data[i]);
767 }
else if (length ==
sizeof(
struct phy_packet) && data[1] == ~data[2]) {
774 switch (pp->
common.identifier) {
793 printf(
"extended self id: phy_id=%02x, seq=%d",
796 static const char *
const speed_names[] = {
797 "S100",
"S200",
"S400",
"BETA"
799 printf(
"self id: phy_id=%02x, link %s, gap_count=%d, speed=%s%s%s",
801 (pp->
self_id.link_active ?
"active" :
"not active"),
803 speed_names[pp->
self_id.phy_speed],
804 (pp->
self_id.contender ?
", irm contender" :
""),
805 (pp->
self_id.initiated_reset ?
", initiator" :
""));
809 printf(
"unknown phy packet: ");
810 for (i = 1; i < length / 4; i++)
811 printf(
"%s%08x", i == 0 ?
"[" :
" ", data[i]);
818 decode_link_packet(packet, length, 0,
824 dump_data((
unsigned char *) data + 4, length - 4);
831 #define HIDE_CURSOR "\033[?25l"
832 #define SHOW_CURSOR "\033[?25h"
833 #define CLEAR "\033[H\033[2J"
836 print_stats(
uint32_t *data,
size_t length)
838 static int bus_reset_count, short_packet_count, phy_packet_count;
839 static int tcode_count[16];
840 static struct timeval last_update;
847 short_packet_count++;
848 else if (length ==
sizeof(
struct phy_packet) && data[1] == ~data[2])
852 tcode_count[packet->
common.tcode]++;
862 " bus resets : %8d\n"
863 " short packets : %8d\n"
864 " phy packets : %8d\n",
865 bus_reset_count, short_packet_count, phy_packet_count);
869 printf(
" %-24s: %8d\n", packet_info[i].
name, tcode_count[i]);
873 static struct termios saved_attributes;
876 reset_input_mode(
void)
878 tcsetattr(STDIN_FILENO,
TCSANOW, &saved_attributes);
887 if (!isatty(STDIN_FILENO)) {
888 fprintf(stderr,
"Not a terminal.\n");
893 tcgetattr(STDIN_FILENO, &saved_attributes);
894 atexit(reset_input_mode);
897 tcgetattr(STDIN_FILENO, &tattr);
899 tattr.c_cc[
VMIN] = 1;
900 tattr.c_cc[
VTIME] = 0;
901 tcsetattr(STDIN_FILENO,
TCSAFLUSH, &tattr);
917 con = poptGetContext(
NULL, argc, argv,
options, 0);
918 retval = poptGetNextOpt(con);
920 poptPrintUsage(con, stdout, 0);
924 if (option_version) {
930 fprintf(stderr,
"warning: nosy has only been tested on little "
931 "endian machines\n");
933 if (option_input !=
NULL) {
934 input = fopen(option_input,
"r");
936 fprintf(stderr,
"Could not open %s, %m\n", option_input);
942 fprintf(stderr,
"Could not open %s, %m\n", option_nosy_device);
948 if (
strcmp(option_view,
"transaction") == 0)
950 else if (
strcmp(option_view,
"stats") == 0)
956 output = fopen(option_output,
"w");
957 if (output ==
NULL) {
958 fprintf(stderr,
"Could not open %s, %m\n", option_output);
963 setvbuf(stdout,
NULL, _IOLBF, BUFSIZ);
968 if (!option_cycle_start)
979 pollfds[1].
fd = STDIN_FILENO;
984 if (fread(&length,
sizeof length, 1, input) != 1)
986 fread(buf, 1, length, input);
988 poll(pollfds, 2, -1);
990 read(STDIN_FILENO, &c,
sizeof c);
999 if (pollfds[0].revents)
1000 length =
read(fd, buf,
sizeof buf);
1005 if (output !=
NULL) {
1006 fwrite(&length,
sizeof length, 1, output);
1007 fwrite(buf, 1, length, output);
1012 handle_packet(buf, length);
1015 print_packet(buf, length);
1018 print_stats(buf, length);
1028 poptFreeContext(con);