// SPDX-License-Identifier: GPL-2.0-or-later
/*
* nosy-dump - Interface to snoop mode driver for TI PCILynx 1394 controllers
* Copyright (C) 2002-2006 Kristian Høgsberg
*/
#include <byteswap.h>
#include <endian.h>
#include <fcntl.h>
#include <linux/firewire-constants.h>
#include <poll.h>
#include <popt.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <unistd.h>
#include "list.h"
#include "nosy-dump.h"
#include "nosy-user.h"
enum {
PACKET_FIELD_DETAIL = 0x01,
PACKET_FIELD_DATA_LENGTH = 0x02,
/* Marks the fields we print in transaction view. */
PACKET_FIELD_TRANSACTION = 0x04,
};
static void print_packet(uint32_t *data, size_t length);
static void decode_link_packet(struct link_packet *packet, size_t length,
int include_flags, int exclude_flags);
static int run = 1;
sig_t sys_sigint_handler;
static char *option_nosy_device = "/dev/nosy";
static char *option_view = "packet";
static char *option_output;
static char *option_input;
static int option_hex;
static int option_iso;
static int option_cycle_start;
static int option_version;
static int option_verbose;
enum {
VIEW_TRANSACTION,
VIEW_PACKET,
VIEW_STATS,
};
static const struct poptOption options[] = {
{
.longName = "device",
.shortName = 'd',
.argInfo = POPT_ARG_STRING,
.arg = &option_nosy_device,
.descrip = "Path to nosy device.",
.argDescrip = "DEVICE"
},
{
.longName = "view",
.argInfo = POPT_ARG_STRING,
.arg = &option_view,
.descrip = "Specify view of bus traffic: packet, transaction or stats.",
.argDescrip = "VIEW"
},
{
.longName = "hex",
.shortName = 'x',
.argInfo = POPT_ARG_NONE,
.arg = &option_hex,
.descrip = "Print each packet in hex.",
},
{
.longName = "iso",
.argInfo = POPT_ARG_NONE,
.arg = &option_iso,
.descrip = "Print iso packets.",
},
{
.longName = "cycle-start",
.argInfo = POPT_ARG_NONE,
.arg = &option_cycle_start,
.descrip = "Print cycle start packets.",
},
{
.longName = "verbose",
.shortName = 'v',
.argInfo = POPT_ARG_NONE,
.arg = &option_verbose,
.descrip = "Verbose packet view.",
},
{
.longName = "output",
.shortName = 'o',
.argInfo = POPT_ARG_STRING,
.arg = &option_output,
.descrip = "Log to output file.",
.argDescrip = "FILENAME"
},
{
.longName = "input",
.shortName = 'i',
.argInfo = POPT_ARG_STRING,
.arg = &option_input,
.descrip = "Decode log from file.",
.argDescrip = "FILENAME"
},
{
.longName = "version",
.argInfo = POPT_ARG_NONE,
.arg = &option_version,
.descrip = "Specify print version info.",
},
POPT_AUTOHELP
POPT_TABLEEND
};
/* Allow all ^C except the first to interrupt the program in the usual way. */
static void
sigint_handler(int signal_num)
{
if (run == 1) {
run = 0;
signal(SIGINT, SIG_DFL);
}
}
static struct subaction *
subaction_create(uint32_t *data, size_t length)
{
struct subaction *sa;
/* we put the ack in the subaction struct for easy access. */
sa = malloc(sizeof *sa - sizeof sa->packet + length);
if (!sa)
exit(EXIT_FAILURE);
sa->ack = data[length / 4 - 1];
sa->length = length;
memcpy(&sa->packet, data, length);
return sa;
}
static void
subaction_destroy(struct subaction *sa)
{
free(sa);
}
static struct list pending_transaction_list = {
&pending_transaction_list, &pending_transaction_list
};
static struct link_transaction *
link_transaction_lookup(int request_node, int response_node, int tlabel)
{
struct link_transaction *t;
list_for_each_entry(t, &pending_transaction_list, link) {
if (t->request_node == request_node &&
t->response_node == response_node &&
t->tlabel == tlabel)
return t;
}
t = malloc(sizeof *t);
if (!t)
exit(EXIT_FAILURE);
t->request_node = request_node;
t->response_node = response_node;
t->tlabel = tlabel;
list_init(&t->request_list);
list_init(&t->response_list);
list_append(&pending_transaction_list, &t->link);
return t;
}
static void
link_transaction_destroy(struct link_transaction *t)
{
struct subaction *sa;
while (!list_empty(&t->request_list)) {
sa = list_head(&t->request_list, struct subaction, link);
list_remove(&sa->link);
subaction_destroy(sa);
}
while (!list_empty(&t->response_list)) {
sa = list_head(