2000-06-14 11:01:42 -04:00
|
|
|
/*
|
|
|
|
* libraw1394 - library for raw access to the 1394 bus with the Linux subsystem.
|
|
|
|
*
|
2002-10-13 18:54:49 -04:00
|
|
|
* Copyright (C) 1999,2000,2001,2002 Andreas Bombe
|
2002-10-23 17:18:49 -04:00
|
|
|
* 2001, 2002 Manfred Weihs <weihs@ict.tuwien.ac.at>
|
|
|
|
* 2002 Christian Toegel <christian.toegel@gmx.at>
|
2000-06-14 11:01:42 -04:00
|
|
|
*
|
|
|
|
* 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.
|
2002-10-23 17:18:49 -04:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* Contributions:
|
|
|
|
*
|
|
|
|
* Manfred Weihs <weihs@ict.tuwien.ac.at>
|
|
|
|
* configuration ROM manipulation
|
|
|
|
* address range mapping
|
|
|
|
* Christian Toegel <christian.toegel@gmx.at>
|
|
|
|
* address range mapping
|
|
|
|
* reset notification control (switch on/off)
|
|
|
|
* reset with selection of type (short/long)
|
2000-06-14 11:01:42 -04:00
|
|
|
*/
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2000-05-28 17:00:56 -04:00
|
|
|
#include <config.h>
|
1999-12-02 18:07:38 -05:00
|
|
|
#include <errno.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <fcntl.h>
|
2000-06-22 12:22:00 -04:00
|
|
|
#include <unistd.h>
|
1999-12-02 18:07:38 -05:00
|
|
|
|
|
|
|
#include "raw1394.h"
|
|
|
|
#include "kernel-raw1394.h"
|
|
|
|
#include "raw1394_private.h"
|
|
|
|
|
|
|
|
|
2001-05-13 21:05:58 -04:00
|
|
|
static int bus_reset_default(struct raw1394_handle *handle, unsigned int gen)
|
1999-12-02 18:07:38 -05:00
|
|
|
{
|
2001-05-13 21:05:58 -04:00
|
|
|
raw1394_update_generation(handle, gen);
|
1999-12-02 18:07:38 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-10-23 17:18:49 -04:00
|
|
|
static int arm_tag_handler_default(struct raw1394_handle *handle, unsigned long tag,
|
|
|
|
byte_t request_type, unsigned int requested_length,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
struct raw1394_arm_reqhandle *rh;
|
2002-12-20 02:26:18 -05:00
|
|
|
struct raw1394_arm_request_response *arm_req_resp;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
|
|
|
if (tag) {
|
|
|
|
rh = (struct raw1394_arm_reqhandle *)tag;
|
2002-12-20 02:26:18 -05:00
|
|
|
arm_req_resp = (struct raw1394_arm_request_response *) data;
|
2002-10-23 17:18:49 -04:00
|
|
|
return rh->arm_callback(handle, arm_req_resp,
|
|
|
|
requested_length, rh->pcontext,
|
|
|
|
request_type);
|
|
|
|
} else {
|
|
|
|
/* error ... */
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1999-12-29 17:24:32 -05:00
|
|
|
int _raw1394_sync_cb(struct raw1394_handle *unused, struct sync_cb_data *data,
|
|
|
|
int error)
|
|
|
|
{
|
|
|
|
data->errcode = error;
|
|
|
|
data->done = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
1999-12-02 18:07:38 -05:00
|
|
|
|
|
|
|
static unsigned int init_rawdevice(struct raw1394_handle *h)
|
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
|
|
|
req.type = RAW1394_REQ_INITIALIZE;
|
|
|
|
req.misc = RAW1394_KERNELAPI_VERSION;
|
2000-08-07 20:29:08 -04:00
|
|
|
h->protocol_version = RAW1394_KERNELAPI_VERSION;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(h->fd, &req, sizeof(req)) < 0) return -1;
|
|
|
|
if (read(h->fd, &req, sizeof(req)) < 0) return -1;
|
2000-08-07 20:29:08 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (req.error == RAW1394_ERROR_COMPAT && req.misc == 3) {
|
2000-08-07 20:29:08 -04:00
|
|
|
h->protocol_version = 3;
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(h->fd, &req, sizeof(req)) < 0) return -1;
|
|
|
|
if (read(h->fd, &req, sizeof(req)) < 0) return -1;
|
2000-08-07 20:29:08 -04:00
|
|
|
}
|
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (req.error) {
|
1999-12-02 18:07:38 -05:00
|
|
|
errno = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
2004-11-25 13:46:29 -05:00
|
|
|
memset(h->buffer, 0, HBUF_SIZE);
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
return req.generation;
|
1999-12-02 18:07:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-18 20:11:48 -05:00
|
|
|
struct raw1394_handle *raw1394_new_handle(void)
|
1999-12-02 18:07:38 -05:00
|
|
|
{
|
|
|
|
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);
|
2000-06-22 12:22:00 -04:00
|
|
|
if (handle->generation == -1) {
|
1999-12-02 18:07:38 -05:00
|
|
|
close(handle->fd);
|
|
|
|
free(handle);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-01-18 20:11:48 -05:00
|
|
|
handle->err = 0;
|
1999-12-02 18:07:38 -05:00
|
|
|
handle->bus_reset_handler = bus_reset_default;
|
|
|
|
handle->tag_handler = tag_handler_default;
|
2002-10-23 17:18:49 -04:00
|
|
|
handle->arm_tag_handler = arm_tag_handler_default;
|
2003-01-05 15:58:19 -05:00
|
|
|
memset(handle->iso_handler, 0, sizeof(handle->iso_handler));
|
2003-01-05 23:08:00 -05:00
|
|
|
handle->iso_buffer = NULL;
|
2003-01-15 08:14:47 -05:00
|
|
|
handle->iso_mode = ISO_INACTIVE;
|
1999-12-02 18:07:38 -05:00
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
|
|
|
void raw1394_destroy_handle(struct raw1394_handle *handle)
|
|
|
|
{
|
2002-11-18 02:40:21 -05:00
|
|
|
if (handle) {
|
2003-01-15 08:14:47 -05:00
|
|
|
if(handle->iso_mode != ISO_INACTIVE) {
|
2002-11-18 02:40:21 -05:00
|
|
|
raw1394_iso_shutdown(handle);
|
|
|
|
}
|
|
|
|
close(handle->fd);
|
|
|
|
free(handle);
|
|
|
|
}
|
1999-12-02 18:07:38 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
int raw1394_get_fd(struct raw1394_handle *handle)
|
|
|
|
{
|
|
|
|
return handle->fd;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int raw1394_get_generation(struct raw1394_handle *handle)
|
|
|
|
{
|
|
|
|
return handle->generation;
|
|
|
|
}
|
|
|
|
|
2001-05-13 21:05:58 -04:00
|
|
|
void raw1394_update_generation(struct raw1394_handle *handle, unsigned int gen)
|
|
|
|
{
|
|
|
|
handle->generation = gen;
|
|
|
|
}
|
|
|
|
|
1999-12-02 18:07:38 -05:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2000-08-07 20:29:08 -04:00
|
|
|
nodeid_t raw1394_get_irm_id(struct raw1394_handle *handle)
|
|
|
|
{
|
|
|
|
return handle->irm_id;
|
|
|
|
}
|
|
|
|
|
2002-10-13 18:54:49 -04:00
|
|
|
void raw1394_set_userdata(struct raw1394_handle *handle, void *data)
|
2000-04-05 18:41:31 -04:00
|
|
|
{
|
2002-10-13 18:54:49 -04:00
|
|
|
handle->userdata = data;
|
2000-04-05 18:41:31 -04:00
|
|
|
}
|
|
|
|
|
2002-10-13 18:54:49 -04:00
|
|
|
void *raw1394_get_userdata(struct raw1394_handle *handle)
|
2000-04-05 18:41:31 -04:00
|
|
|
{
|
2002-10-13 18:54:49 -04:00
|
|
|
return handle->userdata;
|
2000-04-05 18:41:31 -04:00
|
|
|
}
|
1999-12-02 18:07:38 -05:00
|
|
|
|
|
|
|
int raw1394_get_port_info(struct raw1394_handle *handle,
|
|
|
|
struct raw1394_portinfo *pinf, int maxports)
|
|
|
|
{
|
|
|
|
int num;
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
1999-12-02 18:07:38 -05:00
|
|
|
struct raw1394_khost_list *khl;
|
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
|
|
|
req.type = RAW1394_REQ_LIST_CARDS;
|
|
|
|
req.generation = handle->generation;
|
|
|
|
req.recvb = ptr2int(pinf);
|
|
|
|
req.length = sizeof(struct raw1394_portinfo) * maxports;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
|
|
|
while (1) {
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -1;
|
|
|
|
if (read(handle->fd, &req, sizeof(req)) < 0) return -1;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (!req.error) break;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (req.error == RAW1394_ERROR_GENERATION) {
|
|
|
|
handle->generation = req.generation;
|
1999-12-02 18:07:38 -05:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
return req.misc;
|
1999-12-02 18:07:38 -05:00
|
|
|
}
|
|
|
|
|
2002-10-13 18:54:49 -04:00
|
|
|
|
1999-12-02 18:07:38 -05:00
|
|
|
int raw1394_set_port(struct raw1394_handle *handle, int port)
|
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
req.type = RAW1394_REQ_SET_CARD;
|
|
|
|
req.generation = handle->generation;
|
|
|
|
req.misc = port;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -1;
|
|
|
|
if (read(handle->fd, &req, sizeof(req)) < 0) return -1;
|
1999-12-02 18:07:38 -05:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
switch (req.error) {
|
1999-12-02 18:07:38 -05:00
|
|
|
case RAW1394_ERROR_GENERATION:
|
2003-07-22 10:54:19 -04:00
|
|
|
handle->generation = req.generation;
|
1999-12-02 18:07:38 -05:00
|
|
|
errno = ESTALE;
|
|
|
|
return -1;
|
|
|
|
case RAW1394_ERROR_INVALID_ARG:
|
|
|
|
errno = EINVAL;
|
|
|
|
return -1;
|
|
|
|
case RAW1394_ERROR_NONE:
|
2000-08-07 20:29:08 -04:00
|
|
|
if (handle->protocol_version == 3) {
|
2003-07-22 10:54:19 -04:00
|
|
|
handle->num_of_nodes = req.misc & 0xffff;
|
|
|
|
handle->local_id = req.misc >> 16;
|
2000-08-07 20:29:08 -04:00
|
|
|
} else {
|
2003-07-22 10:54:19 -04:00
|
|
|
handle->num_of_nodes = req.misc & 0xff;
|
|
|
|
handle->irm_id = ((req.misc >> 8) & 0xff) | 0xffc0;
|
|
|
|
handle->local_id = req.misc >> 16;
|
2000-08-07 20:29:08 -04:00
|
|
|
}
|
2003-07-22 10:54:19 -04:00
|
|
|
handle->generation = req.generation;
|
1999-12-02 18:07:38 -05:00
|
|
|
return 0;
|
|
|
|
default:
|
|
|
|
errno = 0;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2000-07-05 16:40:51 -04:00
|
|
|
|
2003-03-26 17:48:46 -05:00
|
|
|
raw1394handle_t raw1394_new_handle_on_port(int port)
|
|
|
|
{
|
|
|
|
raw1394handle_t handle = raw1394_new_handle();
|
|
|
|
if (!handle)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
tryagain:
|
2003-04-07 18:23:20 -04:00
|
|
|
if (raw1394_get_port_info(handle, NULL, 0) < 0) {
|
|
|
|
raw1394_destroy_handle(handle);
|
2003-03-26 17:48:46 -05:00
|
|
|
return NULL;
|
2003-04-07 18:23:20 -04:00
|
|
|
}
|
2003-03-26 17:48:46 -05:00
|
|
|
|
|
|
|
if (raw1394_set_port(handle, port)) {
|
|
|
|
if (errno == ESTALE || errno == EINTR) {
|
|
|
|
goto tryagain;
|
|
|
|
} else {
|
|
|
|
raw1394_destroy_handle(handle);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return handle;
|
|
|
|
}
|
|
|
|
|
2002-10-23 17:18:49 -04:00
|
|
|
int raw1394_reset_bus_new(struct raw1394_handle *handle, int type)
|
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
req.type = RAW1394_REQ_RESET_BUS;
|
|
|
|
req.generation = handle->generation;
|
|
|
|
req.misc = type;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -1;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
|
|
|
return 0; /* success */
|
|
|
|
}
|
|
|
|
|
2002-10-13 18:54:49 -04:00
|
|
|
|
2000-07-05 16:40:51 -04:00
|
|
|
int raw1394_reset_bus(struct raw1394_handle *handle)
|
2002-10-23 17:18:49 -04:00
|
|
|
{
|
|
|
|
return raw1394_reset_bus_new (handle, RAW1394_LONG_RESET);
|
|
|
|
}
|
|
|
|
|
|
|
|
int raw1394_busreset_notify (struct raw1394_handle *handle,
|
|
|
|
int off_on_switch)
|
2000-07-05 16:40:51 -04:00
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
2000-07-05 16:40:51 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
2000-07-05 16:40:51 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
req.type = RAW1394_REQ_RESET_NOTIFY;
|
|
|
|
req.generation = handle->generation;
|
|
|
|
req.misc = off_on_switch;
|
2000-07-05 16:40:51 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -1;
|
2000-07-05 16:40:51 -04:00
|
|
|
|
2002-10-23 17:18:49 -04:00
|
|
|
return 0; /* success */
|
|
|
|
}
|
|
|
|
|
|
|
|
int raw1394_update_config_rom(raw1394handle_t handle, const quadlet_t
|
|
|
|
*new_rom, size_t size, unsigned char rom_version)
|
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
2002-10-23 17:18:49 -04:00
|
|
|
int status;
|
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
req.type = RAW1394_REQ_UPDATE_ROM;
|
|
|
|
req.sendb = (unsigned long) new_rom;
|
|
|
|
req.length = size;
|
|
|
|
req.misc = rom_version;
|
|
|
|
req.recvb = (unsigned long) &status;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -8;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
|
|
|
int raw1394_get_config_rom(raw1394handle_t handle, quadlet_t *buffer,
|
|
|
|
size_t buffersize, size_t *rom_size, unsigned char *rom_version)
|
|
|
|
{
|
2003-07-22 10:54:19 -04:00
|
|
|
struct raw1394_request req;
|
2002-10-23 17:18:49 -04:00
|
|
|
int status;
|
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
CLEAR_REQ(&req);
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
req.type = RAW1394_REQ_GET_ROM;
|
|
|
|
req.recvb = (unsigned long) buffer;
|
|
|
|
req.length = buffersize;
|
|
|
|
req.tag = (unsigned long) rom_size;
|
|
|
|
req.address = (unsigned long) rom_version;
|
|
|
|
req.sendb = (unsigned long) &status;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
2003-07-22 10:54:19 -04:00
|
|
|
if (write(handle->fd, &req, sizeof(req)) < 0) return -8;
|
2002-10-23 17:18:49 -04:00
|
|
|
|
|
|
|
return status;
|
2000-07-05 16:40:51 -04:00
|
|
|
}
|