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