| /* |
| * 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; |
| } |