commit 0f5ef10baaba0890f7e9bed6545e0614b65e7884 Author: abombe Date: Thu Dec 2 23:07:38 1999 +0000 Initial revision git-svn-id: svn://svn.linux1394.org/libraw1394/trunk@1 53a565d1-3bb7-0310-b661-cf11e63c67ab diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 0000000..ad9f046 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,2 @@ +Andreas Bombe + or: diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..e69de29 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 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 + +#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 +#include +#include +#include + +#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 +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 + +#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 +#include + +#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); +}