summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar abombe 1999-12-02 23:07:38 +0000
committerGravatar abombe 1999-12-02 23:07:38 +0000
commit0f5ef10baaba0890f7e9bed6545e0614b65e7884 (patch)
tree115fc38dea3113e5937f33fba540764e0802c80b
Initial revision
git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@1 53a565d1-3bb7-0310-b661-cf11e63c67ab
-rw-r--r--AUTHORS2
-rw-r--r--ChangeLog0
-rw-r--r--INSTALL182
-rw-r--r--Makefile.am5
-rw-r--r--NEWS0
-rw-r--r--README50
-rw-r--r--configure.in9
-rw-r--r--debian/README7
-rw-r--r--src/Makefile.am20
-rw-r--r--src/csr.h23
-rw-r--r--src/eventloop.c81
-rw-r--r--src/kernel-raw1394.h102
-rw-r--r--src/main.c179
-rw-r--r--src/raw1394.h132
-rw-r--r--src/raw1394_private.h23
-rw-r--r--src/readwrite.c96
-rw-r--r--src/testlibraw.c119
17 files changed, 1030 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..ad9f046
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Andreas Bombe <andreas.bombe@munich.netsurf.de>
+ or: <bombe@informatik.tu-muenchen.de>
diff --git a/ChangeLog b/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/ChangeLog
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..b42a17a
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,182 @@
+Basic Installation
+==================
+
+ These are generic installation instructions.
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation. It uses
+those values to create a `Makefile' in each directory of the package.
+It may also create one or more `.h' files containing system-dependent
+definitions. Finally, it creates a shell script `config.status' that
+you can run in the future to recreate the current configuration, a file
+`config.cache' that saves the results of its tests to speed up
+reconfiguring, and a file `config.log' containing compiler output
+(useful mainly for debugging `configure').
+
+ If you need to do unusual things to compile the package, please try
+to figure out how `configure' could check whether to do them, and mail
+diffs or instructions to the address given in the `README' so they can
+be considered for the next release. If at some point `config.cache'
+contains results you don't want to keep, you may remove or edit it.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need `configure.in' if you want to change
+it or regenerate `configure' using a newer version of `autoconf'.
+
+The simplest way to compile this package is:
+
+ 1. `cd' to the directory containing the package's source code and type
+ `./configure' to configure the package for your system. If you're
+ using `csh' on an old version of System V, you might need to type
+ `sh ./configure' instead to prevent `csh' from trying to execute
+ `configure' itself.
+
+ Running `configure' takes awhile. While running, it prints some
+ messages telling which features it is checking for.
+
+ 2. Type `make' to compile the package.
+
+ 3. Optionally, type `make check' to run any self-tests that come with
+ the package.
+
+ 4. Type `make install' to install the programs and any data files and
+ documentation.
+
+ 5. You can remove the program binaries and object files from the
+ source code directory by typing `make clean'. To also remove the
+ files that `configure' created (so you can compile the package for
+ a different kind of computer), type `make distclean'. There is
+ also a `make maintainer-clean' target, but that is intended mainly
+ for the package's developers. If you use it, you may have to get
+ all sorts of other programs in order to regenerate files that came
+ with the distribution.
+
+Compilers and Options
+=====================
+
+ Some systems require unusual options for compilation or linking that
+the `configure' script does not know about. You can give `configure'
+initial values for variables by setting them in the environment. Using
+a Bourne-compatible shell, you can do that on the command line like
+this:
+ CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure
+
+Or on systems that have the `env' program, you can do it like this:
+ env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure
+
+Compiling For Multiple Architectures
+====================================
+
+ You can compile the package for more than one kind of computer at the
+same time, by placing the object files for each architecture in their
+own directory. To do this, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.
+
+ If you have to use a `make' that does not supports the `VPATH'
+variable, you have to compile the package for one architecture at a time
+in the source code directory. After you have installed the package for
+one architecture, use `make distclean' before reconfiguring for another
+architecture.
+
+Installation Names
+==================
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If you
+give `configure' the option `--exec-prefix=PATH', the package will use
+PATH as the prefix for installing programs and libraries.
+Documentation and other data files will still use the regular prefix.
+
+ In addition, if you use an unusual directory layout you can give
+options like `--bindir=PATH' to specify different values for particular
+kinds of files. Run `configure --help' for a list of the directories
+you can set and what kinds of files go in them.
+
+ If the package supports it, you can cause programs to be installed
+with an extra prefix or suffix on their names by giving `configure' the
+option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'.
+
+Optional Features
+=================
+
+ Some packages pay attention to `--enable-FEATURE' options to
+`configure', where FEATURE indicates an optional part of the package.
+They may also pay attention to `--with-PACKAGE' options, where PACKAGE
+is something like `gnu-as' or `x' (for the X Window System). The
+`README' should mention any `--enable-' and `--with-' options that the
+package recognizes.
+
+ For packages that use the X Window System, `configure' can usually
+find the X include and library files automatically, but if it doesn't,
+you can use the `configure' options `--x-includes=DIR' and
+`--x-libraries=DIR' to specify their locations.
+
+Specifying the System Type
+==========================
+
+ There may be some features `configure' can not figure out
+automatically, but needs to determine by the type of host the package
+will run on. Usually `configure' can figure that out, but if it prints
+a message saying it can not guess the host type, give it the
+`--host=TYPE' option. TYPE can either be a short name for the system
+type, such as `sun4', or a canonical name with three fields:
+ CPU-COMPANY-SYSTEM
+
+See the file `config.sub' for the possible values of each field. If
+`config.sub' isn't included in this package, then this package doesn't
+need to know the host type.
+
+ If you are building compiler tools for cross-compiling, you can also
+use the `--target=TYPE' option to select the type of system they will
+produce code for and the `--build=TYPE' option to select the type of
+system on which you are compiling the package.
+
+Sharing Defaults
+================
+
+ If you want to set default values for `configure' scripts to share,
+you can create a site shell script called `config.site' that gives
+default values for variables like `CC', `cache_file', and `prefix'.
+`configure' looks for `PREFIX/share/config.site' if it exists, then
+`PREFIX/etc/config.site' if it exists. Or, you can set the
+`CONFIG_SITE' environment variable to the location of the site script.
+A warning: not all `configure' scripts look for a site script.
+
+Operation Controls
+==================
+
+ `configure' recognizes the following options to control how it
+operates.
+
+`--cache-file=FILE'
+ Use and save the results of the tests in FILE instead of
+ `./config.cache'. Set FILE to `/dev/null' to disable caching, for
+ debugging `configure'.
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+`-q'
+ Do not print messages saying which checks are being made. To
+ suppress all normal output, redirect it to `/dev/null' (any error
+ messages will still be shown).
+
+`--srcdir=DIR'
+ Look for the package's source code in directory DIR. Usually
+ `configure' can determine that directory automatically.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`configure' also accepts some other, not widely useful, options.
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..f4d9da2
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,5 @@
+# process this file with automake to create a Makefile.in
+
+SUBDIRS = src
+
+EXTRA_DIST = debian/*
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/NEWS
diff --git a/README b/README
new file mode 100644
index 0000000..30f2747
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+
+ libraw1394
+ ==========
+
+1. About libraw1394
+
+ libraw1394 is the only supported interface to the kernel side raw1394 of
+the Linux IEEE-1394 subsystem, which provides direct access to the connected
+1394 buses to user space. Through libraw1394/raw1394, applications can directly
+send to and receive from other nodes without requiring a kernel driver for the
+protocol in question.
+
+ The reason for making a library the interface to the kernel is to avoid
+a program dependancy on the kernel version, which would hinder development and
+optimization of raw1394. If development changed the protocol and made it
+incompatible with previous versions only the libraw1394 has to be upgraded to
+match the kernel version (instead of all applications).
+
+
+2. Copyleft
+
+ libraw1394 itself is licensed under the Lesser General Public License
+(short LGPL, see file COPYING.LIB in the source distribution). Other files in
+the source archives not belonging to but being part of the build procedure of
+libraw1394 are under their own licenses, as stated at the top of the individual
+files.
+
+
+3. API documentation
+
+ There is currently no external document describing the library functions,
+but you can find documentation for all functions in the header file raw1394.h.
+
+
+4. Multithreading
+
+ This library should be multithreadable with the restriction that one
+raw1394handle_t may be used only within a single thread. Multiple threads
+operating on the same handle would royally mess up the kernel-user protocol.
+Simply use separate handles for each thread in which you need to use libraw1394.
+
+
+5. Maintainer
+
+ Maintainer of libraw1394 is currently Andreas Bombe. Send suggestions,
+bug reports and fixes to andreas.bombe@munich.netsurf.de. See the file AUTHORS
+for a complete list of contributors to libraw1394.
+
+
+1999-11-23 Andreas Bombe
diff --git a/configure.in b/configure.in
new file mode 100644
index 0000000..1179638
--- /dev/null
+++ b/configure.in
@@ -0,0 +1,9 @@
+# process this file with autoconf to get a configure script
+
+AC_INIT(Makefile.am)
+AM_INIT_AUTOMAKE(libraw1394, 0.3)
+
+AC_PROG_CC
+AM_PROG_LIBTOOL
+
+AC_OUTPUT([ Makefile src/Makefile ])
diff --git a/debian/README b/debian/README
new file mode 100644
index 0000000..e892c89
--- /dev/null
+++ b/debian/README
@@ -0,0 +1,7 @@
+
+ There's nothing here so far, as you probably noticed. I intend to
+package libraw1394 for Debian as soon as it gets stable and I become a Debian
+maintainer for this package. Or as soon as I grok Debian's package management
+system, for that matter...
+
+Andreas Bombe
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..4905126
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,20 @@
+
+# the libraw1394 itself
+
+lib_LTLIBRARIES = libraw1394.la
+
+libraw1394_la_LDFLAGS = -version-info 0:0:0
+
+libraw1394_la_SOURCES = \
+ main.c \
+ eventloop.c \
+ readwrite.c \
+ kernel-raw1394.h \
+ raw1394_private.h
+
+# headers to be installed
+pkginclude_HEADERS = raw1394.h csr.h
+
+# testlibraw
+noinst_PROGRAMS = testlibraw
+testlibraw_LDADD = libraw1394.la
diff --git a/src/csr.h b/src/csr.h
new file mode 100644
index 0000000..13f7c13
--- /dev/null
+++ b/src/csr.h
@@ -0,0 +1,23 @@
+
+#define CSR_REGISTER_BASE 0xfffff0000000ULL
+
+/* register offsets relative to CSR_REGISTER_BASE */
+#define CSR_STATE_CLEAR 0x0
+#define CSR_STATE_SET 0x4
+#define CSR_NODE_IDS 0x8
+#define CSR_RESET_START 0xc
+#define CSR_SPLIT_TIMEOUT_HI 0x18
+#define CSR_SPLIT_TIMEOUT_LO 0x1c
+#define CSR_CYCLE_TIME 0x200
+#define CSR_BUS_TIME 0x204
+#define CSR_BUSY_TIMEOUT 0x210
+#define CSR_BUS_MANAGER_ID 0x21c
+#define CSR_BANDWIDTH_AVAILABLE 0x220
+#define CSR_CHANNELS_AVAILABLE_HI 0x224
+#define CSR_CHANNELS_AVAILABLE_LO 0x228
+#define CSR_CONFIG_ROM 0x400
+#define CSR_CONFIG_ROM_END 0x800
+#define CSR_TOPOLOGY_MAP 0x1000
+#define CSR_TOPOLOGY_MAP_END 0x1400
+#define CSR_SPEED_MAP 0x2000
+#define CSR_SPEED_MAP_END 0x3000
diff --git a/src/eventloop.c b/src/eventloop.c
new file mode 100644
index 0000000..32b053c
--- /dev/null
+++ b/src/eventloop.c
@@ -0,0 +1,81 @@
+
+#include <unistd.h>
+
+#include "raw1394.h"
+#include "kernel-raw1394.h"
+#include "raw1394_private.h"
+
+
+int raw1394_loop_iterate(struct raw1394_handle *handle)
+{
+ struct raw1394_request *req = &handle->req;
+ int retval = 0;
+
+ if (read(handle->fd, req, sizeof(*req)) < 0) {
+ return -1;
+ }
+
+ switch (req->type) {
+ case RAW1394_REQ_BUS_RESET:
+ handle->generation = req->generation;
+ handle->num_of_nodes = req->misc & 0xffff;
+ handle->local_id = req->misc >> 16;
+
+ if (handle->bus_reset_handler) {
+ retval = handle->bus_reset_handler(handle);
+ }
+ break;
+
+ case RAW1394_REQ_ISO_RECEIVE:
+ if (handle->iso_handler) {
+ retval = handle->iso_handler(handle,
+ (handle->buffer[0] >> 8)
+ & 0x3f, req->length,
+ handle->buffer);
+ }
+ break;
+
+ default:
+ if (handle->tag_handler) {
+ retval = handle->tag_handler(handle, req->tag,
+ req->error);
+ }
+ break;
+ }
+
+ return retval;
+}
+
+
+bus_reset_handler_t raw1394_set_bus_reset_handler(struct raw1394_handle *handle,
+ bus_reset_handler_t new)
+{
+ bus_reset_handler_t old;
+
+ old = handle->bus_reset_handler;
+ handle->bus_reset_handler = new;
+
+ return old;
+}
+
+tag_handler_t raw1394_set_tag_handler(struct raw1394_handle *handle,
+ tag_handler_t new)
+{
+ tag_handler_t old;
+
+ old = handle->tag_handler;
+ handle->tag_handler = new;
+
+ return old;
+}
+
+iso_handler_t raw1394_set_iso_handler(struct raw1394_handle *handle,
+ iso_handler_t new)
+{
+ iso_handler_t old;
+
+ old = handle->iso_handler;
+ handle->iso_handler = new;
+
+ return old;
+}
diff --git a/src/kernel-raw1394.h b/src/kernel-raw1394.h
new file mode 100644
index 0000000..fe8ea72
--- /dev/null
+++ b/src/kernel-raw1394.h
@@ -0,0 +1,102 @@
+
+#ifndef IEEE1394_RAW1394_H
+#define IEEE1394_RAW1394_H
+
+#define RAW1394_DEVICE_MAJOR 171
+#define RAW1394_DEVICE_NAME "raw1394"
+
+#define RAW1394_KERNELAPI_VERSION 1
+
+/* state: opened */
+#define RAW1394_REQ_INITIALIZE 1
+
+/* state: initialized */
+#define RAW1394_REQ_LIST_CARDS 2
+#define RAW1394_REQ_SET_CARD 3
+
+/* state: connected */
+#define RAW1394_REQ_ASYNC_READ 100
+#define RAW1394_REQ_ASYNC_WRITE 101
+#define RAW1394_REQ_LOCK 102
+#define RAW1394_REQ_LOCK64 103
+
+#define RAW1394_REQ_ISO_LISTEN 200
+
+/* kernel to user */
+#define RAW1394_REQ_BUS_RESET 10000
+#define RAW1394_REQ_ISO_RECEIVE 10001
+
+/* error codes */
+#define RAW1394_ERROR_NONE 0
+#define RAW1394_ERROR_COMPAT (-1001)
+#define RAW1394_ERROR_STATE_ORDER (-1002)
+#define RAW1394_ERROR_GENERATION (-1003)
+#define RAW1394_ERROR_INVALID_ARG (-1004)
+#define RAW1394_ERROR_MEMFAULT (-1005)
+#define RAW1394_ERROR_ALREADY (-1006)
+
+#define RAW1394_ERROR_EXCESSIVE (-1020)
+#define RAW1394_ERROR_UNTIDY_LEN (-1021)
+
+#define RAW1394_ERROR_SEND_ERROR (-1100)
+#define RAW1394_ERROR_ABORTED (-1101)
+#define RAW1394_ERROR_TIMEOUT (-1102)
+
+
+struct raw1394_request {
+ int type;
+ int error;
+ int misc;
+
+ unsigned int generation;
+ octlet_t address;
+
+ unsigned long tag;
+
+ size_t length;
+ quadlet_t *sendb;
+ quadlet_t *recvb;
+};
+
+struct raw1394_khost_list {
+ int nodes;
+ char name[32];
+};
+
+#ifdef __KERNEL__
+
+struct file_info {
+ struct list_head list;
+
+ enum { opened, initialized, connected } state;
+
+ struct hpsb_host *host;
+
+ struct list_head req_pending;
+ struct list_head req_complete;
+ struct semaphore complete_sem;
+ spinlock_t reqlists_lock;
+ wait_queue_head_t poll_wait_complete;
+
+ u64 listen_channels;
+};
+
+struct pending_request {
+ struct list_head list;
+ struct file_info *file_info;
+ struct hpsb_packet *packet;
+ struct tq_struct tq;
+ quadlet_t *data;
+ int free_data;
+ struct raw1394_request req;
+};
+
+struct host_info {
+ struct list_head list;
+ struct hpsb_host *host;
+ struct list_head file_info_list;
+};
+
+#endif /* __KERNEL__ */
+
+#endif /* IEEE1394_RAW1394_H */
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..7cc8fe1
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,179 @@
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include "raw1394.h"
+#include "kernel-raw1394.h"
+#include "raw1394_private.h"
+
+
+static int bus_reset_default(struct raw1394_handle *handle)
+{
+ return 0;
+}
+
+static int tag_handler_default(struct raw1394_handle *handle, unsigned long tag,
+ int error)
+{
+ struct raw1394_reqhandle *rh;
+
+ if (tag) {
+ rh = (struct raw1394_reqhandle *)tag;
+ return rh->callback(handle, rh->data, error);
+ } else {
+ return -1;
+ }
+}
+
+static int iso_handler_default(struct raw1394_handle *handle, int channel,
+ size_t length, quadlet_t *data)
+{
+ return 0;
+}
+
+
+static unsigned int init_rawdevice(struct raw1394_handle *h)
+{
+ struct raw1394_request *req = &h->req;
+
+ CLEAR_REQ(req);
+ req->type = RAW1394_REQ_INITIALIZE;
+ req->misc = RAW1394_KERNELAPI_VERSION;
+
+ if (write(h->fd, req, sizeof(*req)) < 0) return -1;
+ if (read(h->fd, req, sizeof(*req)) < 0) return -1;
+ if (req->error) {
+ errno = 0;
+ return -1;
+ }
+
+ return req->generation;
+}
+
+
+struct raw1394_handle *raw1394_get_handle(void)
+{
+ struct raw1394_handle *handle;
+
+ handle = malloc(sizeof(struct raw1394_handle));
+ if (!handle) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ handle->fd = open("/dev/raw1394", O_RDWR);
+ if (handle->fd < 0) {
+ free(handle);
+ return NULL;
+ }
+
+ handle->generation = init_rawdevice(handle);
+ if (handle->generation < 0) {
+ close(handle->fd);
+ free(handle);
+ return NULL;
+ }
+
+ handle->bus_reset_handler = bus_reset_default;
+ handle->tag_handler = tag_handler_default;
+ handle->iso_handler = iso_handler_default;
+ return handle;
+}
+
+void raw1394_destroy_handle(struct raw1394_handle *handle)
+{
+ if (handle) {
+ close(handle->fd);
+ free(handle);
+ }
+}
+
+int raw1394_get_fd(struct raw1394_handle *handle)
+{
+ return handle->fd;
+}
+
+unsigned int raw1394_get_generation(struct raw1394_handle *handle)
+{
+ return handle->generation;
+}
+
+int raw1394_get_nodecount(struct raw1394_handle *handle)
+{
+ return handle->num_of_nodes;
+}
+
+nodeid_t raw1394_get_local_id(struct raw1394_handle *handle)
+{
+ return handle->local_id;
+}
+
+
+int raw1394_get_port_info(struct raw1394_handle *handle,
+ struct raw1394_portinfo *pinf, int maxports)
+{
+ int num;
+ struct raw1394_request *req = &handle->req;
+ struct raw1394_khost_list *khl;
+
+ CLEAR_REQ(req);
+ req->type = RAW1394_REQ_LIST_CARDS;
+ req->generation = handle->generation;
+ req->recvb = handle->buffer;
+ req->length = HBUF_SIZE;
+
+ while (1) {
+ if (write(handle->fd, req, sizeof(*req)) < 0) return -1;
+ if (read(handle->fd, req, sizeof(*req)) < 0) return -1;
+
+ if (!req->error) break;
+
+ if (req->error == RAW1394_ERROR_GENERATION) {
+ handle->generation = req->generation;
+ continue;
+ }
+
+ return -1;
+ }
+
+ for (num = req->misc, khl = (struct raw1394_khost_list *)handle->buffer;
+ num && maxports; num--, maxports--, pinf++, khl++) {
+ pinf->nodes = khl->nodes;
+ strcpy(pinf->name, khl->name);
+ }
+
+ return req->misc;
+}
+
+int raw1394_set_port(struct raw1394_handle *handle, int port)
+{
+ struct raw1394_request *req = &handle->req;
+
+ CLEAR_REQ(req);
+
+ req->type = RAW1394_REQ_SET_CARD;
+ req->generation = handle->generation;
+ req->misc = port;
+
+ if (write(handle->fd, req, sizeof(*req)) < 0) return -1;
+ if (read(handle->fd, req, sizeof(*req)) < 0) return -1;
+
+ switch (req->error) {
+ case RAW1394_ERROR_GENERATION:
+ handle->generation = req->generation;
+ errno = ESTALE;
+ return -1;
+ case RAW1394_ERROR_INVALID_ARG:
+ errno = EINVAL;
+ return -1;
+ case RAW1394_ERROR_NONE:
+ handle->num_of_nodes = req->misc & 0xffff;
+ handle->local_id = req->misc >> 16;
+ return 0;
+ default:
+ errno = 0;
+ return -1;
+ }
+}
diff --git a/src/raw1394.h b/src/raw1394.h
new file mode 100644
index 0000000..de9dcb7
--- /dev/null
+++ b/src/raw1394.h
@@ -0,0 +1,132 @@
+
+#ifndef _LIBRAW1394_RAW1394_H
+#define _LIBRAW1394_RAW1394_H
+
+#include <sys/types.h>
+typedef u_int32_t quadlet_t;
+typedef u_int64_t octlet_t;
+typedef u_int64_t nodeaddr_t;
+typedef u_int16_t nodeid_t;
+
+
+typedef struct raw1394_handle *raw1394handle_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Required as initialization. One handle can control one port, it is possible
+ * to use multiple handles. raw1394_get_handle returns NULL for failure,
+ * raw1394_destroy_handle accepts NULL. If raw1394_get_handle returns NULL and
+ * errno is 0, this version of libraw1394 is incompatible with the kernel.
+ */
+raw1394handle_t raw1394_get_handle(void);
+void raw1394_destroy_handle(raw1394handle_t handle);
+
+/*
+ * Get the fd of this handle to select()/poll() on it. Don't try to mess around
+ * with it any other way. Valid only after the handle got attached to a port.
+ */
+int raw1394_get_fd(raw1394handle_t handle);
+
+unsigned int raw1394_get_generation(raw1394handle_t handle);
+nodeid_t raw1394_get_local_id(raw1394handle_t handle);
+
+/* Get number of nodes on bus. */
+int raw1394_get_nodecount(raw1394handle_t handle);
+
+/*
+ * Returns number of available ports (port == one IEEE 1394 card or onboard
+ * chip). A maximum number of maxport raw1394_portinfos will be filled out at
+ * *pinf, zero is valid if you're only interested in the number of ports (which
+ * is returned).
+ */
+struct raw1394_portinfo {
+ int nodes;
+ char name[32];
+};
+
+int raw1394_get_port_info(raw1394handle_t handle, struct raw1394_portinfo *pinf,
+ int maxports);
+
+/*
+ * Attach handle to port (counted from zero). Returns zero for success or -1
+ * for failure. If in the case of failure errno is set to ESTALE the generation
+ * number has changed and you should reget the port info.
+ */
+int raw1394_set_port(raw1394handle_t handle, int port);
+
+
+/*
+ * Get one new message through handle and process it. See below for handler
+ * registering functions. This function will return -1 for an error or the
+ * return value of the handler which got executed. Default handlers always
+ * return zero.
+ */
+int raw1394_loop_iterate(raw1394handle_t handle);
+
+/*
+ * Set the handler that will be called when a bus reset message is encountered.
+ * The default action is to do nothing. Returns old handler.
+ */
+typedef int (*bus_reset_handler_t)(raw1394handle_t);
+bus_reset_handler_t raw1394_set_bus_reset_handler(raw1394handle_t handle,
+ bus_reset_handler_t new);
+
+/*
+ * Set the handler that will be called when an async read/write/lock returns.
+ * The default action is to call the callback in the raw1394_reqhandle pointed
+ * to by tag. Returns old handler.
+ */
+typedef int (*tag_handler_t)(raw1394handle_t, unsigned long tag, int errcode);
+tag_handler_t raw1394_set_tag_handler(raw1394handle_t handle,
+ tag_handler_t new);
+
+/*
+ * Set the handler that will be called when an iso packet arrives (data points
+ * to the iso packet header). The default action is to do nothing. Returns old
+ * handler.
+ *
+ * Iso receive is not implemented yet.
+ */
+typedef int (*iso_handler_t)(raw1394handle_t, int channel, size_t length,
+ quadlet_t *data);
+iso_handler_t raw1394_set_iso_handler(raw1394handle_t handle,
+ iso_handler_t new);
+
+
+/*
+ * This is the general request handle. It is used by the default tag handler
+ * when a request completes, it calls the callback and passes it the data
+ * pointer and the error code of the request.
+ */
+typedef int (*req_callback_t)(raw1394handle_t, void *data, int errcode);
+struct raw1394_reqhandle {
+ req_callback_t callback;
+ void *data;
+};
+
+/*
+ * Passes custom tag. Use pointer to raw1394_reqhandle if you use the standard
+ * tag handler.
+ */
+int raw1394_start_read(struct raw1394_handle *handle, nodeid_t node,
+ nodeaddr_t addr, size_t length, quadlet_t *buffer,
+ unsigned long tag);
+
+/*
+ * This does the complete transaction and will return when it's finished. It
+ * will call raw1394_loop_iterate() as often as necessary, return values of
+ * handlers called will be lost.
+ */
+int raw1394_read(struct raw1394_handle *handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *buffer);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBRAW1394_RAW1394_H */
diff --git a/src/raw1394_private.h b/src/raw1394_private.h
new file mode 100644
index 0000000..06c2746
--- /dev/null
+++ b/src/raw1394_private.h
@@ -0,0 +1,23 @@
+
+#ifndef _RAW1394_PRIVATE_H
+#define _RAW1394_PRIVATE_H
+
+struct raw1394_handle {
+ int fd;
+ unsigned int generation;
+
+ nodeid_t local_id;
+ int num_of_nodes;
+
+ bus_reset_handler_t bus_reset_handler;
+ tag_handler_t tag_handler;
+ iso_handler_t iso_handler;
+
+ struct raw1394_request req;
+ quadlet_t buffer[2048];
+};
+
+#define HBUF_SIZE 8192
+#define CLEAR_REQ(reqp) memset((reqp), 0, sizeof(struct raw1394_request))
+
+#endif /* _RAW1394_PRIVATE_H */
diff --git a/src/readwrite.c b/src/readwrite.c
new file mode 100644
index 0000000..37e9f71
--- /dev/null
+++ b/src/readwrite.c
@@ -0,0 +1,96 @@
+
+#include <unistd.h>
+
+#include "raw1394.h"
+#include "kernel-raw1394.h"
+#include "raw1394_private.h"
+
+
+struct sync_cb_data {
+ int done;
+ int errcode;
+};
+
+static int sync_cb(struct raw1394_handle *unused,
+ struct sync_cb_data *data, int error)
+{
+ data->errcode = error;
+ data->done = 1;
+ return 0;
+}
+
+
+int raw1394_start_read(struct raw1394_handle *handle, nodeid_t node,
+ nodeaddr_t addr, size_t length, quadlet_t *buffer,
+ unsigned long tag)
+{
+ struct raw1394_request *req = &handle->req;
+
+ CLEAR_REQ(req);
+
+ req->type = RAW1394_REQ_ASYNC_READ;
+ req->generation = handle->generation;
+ req->tag = tag;
+
+ req->address = ((u_int64_t)node << 48) | addr;
+ req->length = length;
+ req->recvb = buffer;
+
+ return (int)write(handle->fd, req, sizeof(*req));
+}
+
+int raw1394_start_write(struct raw1394_handle *handle, nodeid_t node,
+ nodeaddr_t addr, size_t length, quadlet_t *data,
+ unsigned long tag)
+{
+ struct raw1394_request *req = &handle->req;
+
+ CLEAR_REQ(req);
+
+ req->type = RAW1394_REQ_ASYNC_WRITE;
+ req->generation = handle->generation;
+ req->tag = tag;
+
+ req->address = ((u_int64_t)node << 48) | addr;
+ req->length = length;
+ req->sendb = data;
+
+ return (int)write(handle->fd, req, sizeof(*req));
+}
+
+
+
+#define SYNCFUNC_VARS \
+ struct sync_cb_data sd = { 0, 0 }; \
+ struct raw1394_reqhandle rh = { (req_callback_t)sync_cb, &sd }; \
+ int err
+
+#define SYNCFUNC_BODY \
+ if (err < 0) return err; \
+ while (!sd.done) raw1394_loop_iterate(handle); \
+ return sd.errcode
+
+int raw1394_read(struct raw1394_handle *handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *buffer)
+{
+ SYNCFUNC_VARS;
+
+ err = raw1394_start_read(handle, node, addr, length, buffer,
+ (unsigned long)&rh);
+
+ SYNCFUNC_BODY;
+}
+
+int raw1394_write(struct raw1394_handle *handle, nodeid_t node, nodeaddr_t addr,
+ size_t length, quadlet_t *data)
+{
+ SYNCFUNC_VARS;
+
+ err = raw1394_start_write(handle, node, addr, length, data,
+ (unsigned long)&rh);
+
+ SYNCFUNC_BODY;
+}
+
+#undef SYNCFUNC_VARS
+#undef SYNCFUNC_BODY
diff --git a/src/testlibraw.c b/src/testlibraw.c
new file mode 100644
index 0000000..59f0ada
--- /dev/null
+++ b/src/testlibraw.c
@@ -0,0 +1,119 @@
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "raw1394.h"
+#include "csr.h"
+
+
+#define TESTADDR (CSR_REGISTER_BASE + CSR_CYCLE_TIME)
+
+const char not_compatible[] = "\
+This libraw1394 does not work with your version of Linux. You need a different
+version that matches your kernel (see kernel help text for the raw1394 option to
+find out which is the correct version).\n";
+
+const char not_loaded[] = "\
+This probably means that you don't have raw1394 support in the kernel or that
+you haven't loaded the raw1394 module.\n";
+
+
+quadlet_t buffer;
+
+int my_tag_handler(struct raw1394_handle *handle, unsigned long tag, int error)
+{
+ if (error < 0) {
+ printf("completed with error %d\n", error);
+ } else {
+ printf("completed with 0x%08x, value 0x%08x\n", error, buffer);
+ }
+
+ return 0;
+}
+
+
+
+int main(int argc, char **argv)
+{
+ raw1394handle_t handle;
+ int i, numcards;
+ struct raw1394_portinfo pinf[16];
+
+ tag_handler_t std_handler;
+ int retval;
+
+
+ handle = raw1394_get_handle();
+
+ if (!handle) {
+ if (!errno) {
+ printf(not_compatible);
+ } else {
+ perror("couldn't get handle");
+ printf(not_loaded);
+ }
+ exit(1);
+ }
+
+ printf("successfully got handle\n");
+ printf("current generation number: %d\n", raw1394_get_generation(handle));
+
+ numcards = raw1394_get_port_info(handle, pinf, 16);
+ if (numcards < 0) {
+ perror("couldn't get card info");
+ exit(1);
+ } else {
+ printf("%d card(s) found\n", numcards);
+ }
+
+ if (!numcards) {
+ exit(0);
+ }
+
+ for (i = 0; i < numcards; i++) {
+ printf(" nodes on bus: %2d, card name: %s\n", pinf[i].nodes,
+ pinf[i].name);
+ }
+
+ if (raw1394_set_port(handle, 0) < 0) {
+ perror("couldn't set port");
+ exit(1);
+ }
+
+ printf("using first card found: %d nodes on bus, local ID is %d\n",
+ raw1394_get_nodecount(handle),
+ raw1394_get_local_id(handle) & 0x3f);
+
+ printf("\ndoing transactions with custom tag handler\n");
+ std_handler = raw1394_set_tag_handler(handle, my_tag_handler);
+ for (i = 0; i < pinf[0].nodes; i++) {
+ printf("trying to send read request to node %d... ", i);
+ fflush(stdout);
+ buffer = 0;
+
+ if (raw1394_start_read(handle, 0xffc0 | i, TESTADDR, 4,
+ &buffer, 0) < 0) {
+ perror("failed");
+ continue;
+ }
+ raw1394_loop_iterate(handle);
+ }
+
+ printf("\nusing standard tag handler and synchronous calls\n");
+ raw1394_set_tag_handler(handle, std_handler);
+ for (i = 0; i < pinf[0].nodes; i++) {
+ printf("trying to read from node %d... ", i);
+ fflush(stdout);
+ buffer = 0;
+
+ retval = raw1394_read(handle, 0xffc0 | i, TESTADDR, 4, &buffer);
+ if (retval < 0) {
+ printf("failed with error %d\n", retval);
+ } else {
+ printf("completed with 0x%08x, value 0x%08x\n", retval,
+ buffer);
+ }
+ }
+
+ exit(0);
+}