ba8d2119ba
Quoting the errno manual: "[errno] is set by system calls and some library functions in the event of an error to indicate what went wrong. Its value is significant only when the return value of the call indicated an error (i.e., -1 from most system calls; -1 or NULL from most library functions); a function that succeeds is allowed to change errno. Valid error numbers are all nonzero; errno is never set to zero by any system call or library function." Dumpiso and sendiso checked for raw1394_set_port() failure by looking at errno rather than by looking at the function's return code. This happened to work on top of raw1394 by lucky incident but no longer works on top of firewire-core. Reported-by: Vladimir Romanov <blueboar2@gmail.com> Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>
269 lines
8 KiB
C
269 lines
8 KiB
C
/*
|
|
* libraw1394 - library for raw access to the 1394 bus with the Linux subsystem.
|
|
*
|
|
* Copyright (C) 1999,2000 Andreas Bombe
|
|
*
|
|
* This library is licensed under the GNU Lesser General Public License (LGPL),
|
|
* version 2.1 or later. See the file COPYING.LIB in the distribution for
|
|
* details.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <getopt.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "../src/raw1394.h"
|
|
|
|
#define BUFFER 1000
|
|
#define PACKET_MAX 4096
|
|
|
|
u_int64_t listen_channels;
|
|
unsigned long which_port;
|
|
char *filename;
|
|
int file;
|
|
enum raw1394_iso_dma_recv_mode mode = RAW1394_DMA_DEFAULT;
|
|
|
|
void usage_exit(int exitcode)
|
|
{
|
|
fprintf(stderr,
|
|
"Usage: dumpiso [opts] [FILE]\n"
|
|
"Dump IEEE 1394 isochronous channels to FILE or standard output.\n"
|
|
"\n"
|
|
"-c --channels CHANNELS Listen on these channels; CHANNELS is either a\n"
|
|
" number X or a range X-Y.\n"
|
|
"-p --port PORT Choose 1394 chip PORT. (default: 0)\n"
|
|
"-h --help Show this help.\n"
|
|
);
|
|
|
|
exit(exitcode);
|
|
}
|
|
|
|
void parse_args(int argc, char **argv)
|
|
{
|
|
int i;
|
|
char *tail;
|
|
unsigned long chan1, chan2;
|
|
|
|
int c;
|
|
int index;
|
|
static struct option opts[] = {
|
|
{ "channels", required_argument, NULL, 'c' },
|
|
{ "port", required_argument, NULL, 'p' },
|
|
{ "help", no_argument, NULL, 'h' },
|
|
{ 0 }
|
|
};
|
|
|
|
while (1) {
|
|
c = getopt_long(argc, argv, "hc:p:", opts, &index);
|
|
if (c == -1) break;
|
|
|
|
switch (c) {
|
|
case 'c':
|
|
chan1 = strtoul(optarg, &tail, 10);
|
|
chan2 = chan1;
|
|
|
|
if (*tail) {
|
|
if (tail[0] != '-' || !tail[1]) {
|
|
fprintf(stderr,
|
|
"invalid argument to channels: %s\n",
|
|
optarg);
|
|
usage_exit(1);
|
|
}
|
|
|
|
tail++;
|
|
chan2 = strtoul(tail, &tail, 10);
|
|
if (*tail) {
|
|
fprintf(stderr,
|
|
"invalid argument to channels: %s\n",
|
|
optarg);
|
|
usage_exit(1);
|
|
}
|
|
} else {
|
|
mode = RAW1394_DMA_PACKET_PER_BUFFER;
|
|
}
|
|
|
|
if (chan2 < chan1) {
|
|
unsigned long x = chan1;
|
|
chan1 = chan2;
|
|
chan2 = x;
|
|
}
|
|
|
|
if (chan2 > 63) {
|
|
fprintf(stderr,
|
|
"invalid channel numbers: %s\n",
|
|
optarg);
|
|
exit(1);
|
|
}
|
|
|
|
for (i = chan1; i <= chan2; i++)
|
|
listen_channels |= 1ULL << i;
|
|
|
|
break;
|
|
case 'p':
|
|
which_port = strtoul(optarg, &tail, 10);
|
|
if (*tail) {
|
|
fprintf(stderr,
|
|
"invalid argument to port: %s\n",
|
|
optarg);
|
|
usage_exit(1);
|
|
}
|
|
break;
|
|
case 'h':
|
|
usage_exit(0);
|
|
case '?':
|
|
usage_exit(1);
|
|
default:
|
|
abort();
|
|
}
|
|
}
|
|
|
|
argv += optind;
|
|
argc -= optind;
|
|
|
|
if (argc > 1) {
|
|
fprintf(stderr, "Too many arguments.\n");
|
|
usage_exit(1);
|
|
}
|
|
|
|
if (argc) filename = *argv;
|
|
|
|
if (!listen_channels) listen_channels = ~0ULL;
|
|
}
|
|
|
|
void write_header()
|
|
{
|
|
static char header[32] = "1394 isodump v2";
|
|
int i;
|
|
|
|
for (i = 0; i < 8; i++)
|
|
header[i+16] = (listen_channels >> (56 - 8*i)) & 0xff;
|
|
|
|
i = 0;
|
|
while (i < 32) {
|
|
int ret;
|
|
ret = write(file, header + i, 32 - i);
|
|
|
|
if (ret < 0) {
|
|
perror("header write");
|
|
exit(1);
|
|
}
|
|
|
|
i += ret;
|
|
}
|
|
}
|
|
|
|
void open_dumpfile()
|
|
{
|
|
if (!filename || !filename[0] || (filename[0] == '-' && !filename[1])) {
|
|
file = fileno(stdout);
|
|
write_header();
|
|
return;
|
|
}
|
|
|
|
file = creat(filename, 0666);
|
|
if (file < 0) {
|
|
perror("dumpfile open");
|
|
exit(1);
|
|
}
|
|
|
|
write_header();
|
|
}
|
|
|
|
static enum raw1394_iso_disposition
|
|
iso_handler(raw1394handle_t handle, unsigned char *data,
|
|
unsigned int length, unsigned char channel,
|
|
unsigned char tag, unsigned char sy, unsigned int cycle,
|
|
unsigned int dropped)
|
|
{
|
|
int ret;
|
|
unsigned char pad = 0;
|
|
static unsigned int counter = 0;
|
|
|
|
if (++counter % 1000 == 0)
|
|
fprintf(stderr, "\r%uK packets", counter/1000);
|
|
|
|
/* write header */
|
|
if (write(file, &length, sizeof(length)) != sizeof(length) ||
|
|
write(file, &channel, sizeof(channel)) != sizeof(channel) ||
|
|
write(file, &tag, sizeof(tag)) != sizeof(tag) ||
|
|
write(file, &sy, sizeof(sy)) != sizeof(sy) ||
|
|
write(file, &pad, sizeof(pad)) != sizeof(pad)) {
|
|
perror("data write");
|
|
return RAW1394_ISO_ERROR;
|
|
}
|
|
|
|
while (length) {
|
|
ret = write(file, data, length);
|
|
if (ret < 0) {
|
|
perror("data write");
|
|
return RAW1394_ISO_ERROR;
|
|
}
|
|
|
|
length -= ret;
|
|
data += ret;
|
|
}
|
|
|
|
return RAW1394_ISO_OK;
|
|
}
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
raw1394handle_t handle;
|
|
int i, ret;
|
|
|
|
parse_args(argc, argv);
|
|
|
|
fprintf(stderr, "port: %ld\nchannels: %#016llx\nfile: %s\n", which_port,
|
|
(long long unsigned)listen_channels, filename);
|
|
|
|
handle = raw1394_new_handle();
|
|
if (!handle) {
|
|
if (!errno)
|
|
fprintf(stderr,
|
|
"No working kernel driver found.\n");
|
|
else
|
|
perror("raw1394_get_handle");
|
|
exit(1);
|
|
}
|
|
|
|
do {
|
|
if (raw1394_get_port_info(handle, NULL, 0) <= which_port) {
|
|
fprintf(stderr, "Port %ld does not exist.\n",
|
|
which_port);
|
|
exit(1);
|
|
}
|
|
|
|
ret = raw1394_set_port(handle, which_port);
|
|
} while (ret < 0 && errno == ESTALE);
|
|
|
|
if (ret < 0) {
|
|
perror("raw1394_set_port");
|
|
exit(1);
|
|
}
|
|
|
|
open_dumpfile();
|
|
|
|
if (mode == RAW1394_DMA_DEFAULT) {
|
|
raw1394_iso_multichannel_recv_init(handle, iso_handler,
|
|
BUFFER, 2048, -1); /* >2048 makes rawiso stall! */
|
|
raw1394_iso_recv_set_channel_mask(handle, listen_channels);
|
|
|
|
} else for (i = 0; i < 64; i++) {
|
|
if (!(listen_channels & 1ULL << i))
|
|
continue;
|
|
raw1394_iso_recv_init(handle, iso_handler, BUFFER, PACKET_MAX,
|
|
i, mode, -1);
|
|
}
|
|
raw1394_iso_recv_start(handle, -1, -1, 0);
|
|
|
|
while (raw1394_loop_iterate(handle) == 0);
|
|
|
|
fprintf(stderr, "\n");
|
|
raw1394_iso_shutdown(handle);
|
|
raw1394_destroy_handle(handle);
|
|
|
|
return 0;
|
|
}
|