tools/firewire: nosy-dump: fix it on x86-64
[linux-3.10.git] / 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   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 }