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