]> Pileus Git - ~andy/linux/blob - tools/firewire/nosy-dump.c
tools/firewire: nosy-dump: work around segfault in decode_fcp
[~andy/linux] / tools / firewire / nosy-dump.c
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   if (!t->request) {
234     printf("BUG in handle_transaction\n");
235     return;
236   }
237
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)
255       print_packet((uint32_t *) &sa->packet, sa->length);
256     list_for_each_entry(sa, &t->response_list, link)
257       print_packet((uint32_t *) &sa->packet, sa->length);
258   }
259   printf("\r\n");
260
261   link_transaction_destroy(t);
262 }
263
264 void
265 clear_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
277 static 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
292 static 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
311 static 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
322 static const char * const retry_names[] = {
323   "retry_1",
324   "retry_x",
325   "retry_a",
326   "retry_b",
327 };
328
329 enum {
330   PACKET_RESERVED,
331   PACKET_REQUEST,
332   PACKET_RESPONSE,
333   PACKET_OTHER,
334 };
335
336 struct packet_info {
337   const char *name;
338   int type;
339   int response_tcode;
340   struct packet_field *fields;
341   int field_count;
342 };
343
344 struct 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
371 struct 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
377 struct 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
384 struct 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
392 struct 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
402 struct 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
408 struct 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
418 struct 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
424 struct 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
436 static 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
513 int
514 handle_packet(uint32_t *data, size_t length)
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
648 unsigned int get_bits(struct link_packet *packet, int offset, int width)
649 {
650   uint32_t *data = (uint32_t *) packet;
651   uint32_t index, shift, mask;
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
668 void 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
686 static void
687 decode_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) {
711       uint32_t bits;
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
748 static void
749 print_packet(uint32_t *data, size_t length)
750 {
751   int i;
752
753   printf("%6u  ", data[0]);
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++)
760       printf("%s%08x", i == 0 ? "[" : " ", data[i]);
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++)
811         printf("%s%08x", i == 0 ? "[" : " ", data[i]);
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
836 static void
837 print_stats(uint32_t *data, size_t length)
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
874 struct termios saved_attributes;
875
876 void
877 reset_input_mode (void)
878 {
879   tcsetattr (STDIN_FILENO, TCSANOW, &saved_attributes);
880 }
881
882 void
883 set_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
905 int 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) {
967     uint32_t buf[128 * 1024];
968     uint32_t filter;
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);
976     if (view == VIEW_STATS)
977       filter = ~(1 << TCODE_CYCLE_START);
978
979     ioctl(fd, NOSY_IOC_FILTER, filter);
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 }