start unfinished code

This commit is contained in:
Peter McGoron 2022-09-26 13:17:04 -04:00
commit a31884d443
7 changed files with 2492 additions and 0 deletions

8
README.md Normal file
View File

@ -0,0 +1,8 @@
# spyderta
Spyderta is a shim program to allow programs designed for Sederta PCI devices
to communicate with a generic IEEE1394 FireWire card by interfacing over the
network to a Linux host.
NOTE: 1394ethbridge uses a MODIFIED version of libraw1394 that modifies
how memory allocation works. See https://software.mcgoron.com/peter/libraw1394

190
common/msg.c Normal file
View File

@ -0,0 +1,190 @@
#include <stdbool.h>
#include "msg.h"
/*
* send async [1]
* [10: bus][6: node][48 : address][8: tcode][8 : tlabel][16 : len][data ...]
*/
#define SEND_ASYNC_LEN (10 + 6 + 48 + 8 + 8 + 16)/8
/*
* send iso [2]
* [8 : channel][8 : tag][8 : synch][16 : len][data ...]
*/
#define SEND_ISO_LEN (8 + 8 + 8 + 16)/8
/*
* allocate [3]
* [48: start] [48: len]
*/
#define ALLOCATE_LEN (48 + 48)/8
static bool parse_send_async(struct msg_state *st) {
const char *p = st->buf + 1;
const size_t l = sdslen(st->buf) - 1;
if (l < SEND_ASYNC_LEN)
return false;
st->msg.send_async.len = p[10] << 8 | p[11];
if (l < SEND_ASYNC_LEN + len)
return false;
st->msg.send_async.bus = p[0] << 8 | p[1];
st->msg.send_async.node = bus & 0x3F;
st->msg.send_async.bus >>= 6;
st->msg.send_async.addr = p[2] << 40 | p[3] << 32 | p[4] << 24 | p[5] << 16
| p[6] << 8 | p[7];
st->msg.send_async.tcode = p[8];
st->msg.send_async.tlabel = p[9];
st->msg.send_async.buf = p + SEND_ASYNC_LEN;
(*st->on_read[MSG_SEND_ASYNC])(&st->msg);
sdsrange(st->buf, SEND_ASYNC_LEN + len, sdslen(st->buf));
st->state = PARSE_VERSION_MESSAGE;
return true;
}
static bool parse_version_message(struct msg_state *st) {
if (sdslen(st->buf) == 0)
return false;
/* Unknown version: ignore byte and continue */
if (st->buf[0] >> 6 != 0)
return true;
st->msgtype = st->buf[0] & 0x3F;
switch (st->msgtype) {
case MSG_SEND_ASYNC:
st->state = PARSE_SEND_ASYNC;
break;
case MSG_SEND_ISO:
st->state = PARSE_SEND_ISO;
break;
case MSG_ALLOCATE:
st->state = PARSE_ALLOCATE;
/* Error or noop */
default:
st->state = PARSE_VERSION_MESSAGE;
break;
}
return true;
}
static bool parse_allocate(struct msg_state *st) {
if (l < ALLOCATE_LEN)
return false;
st->msg.allocate.start = p[0] << 40 | p[1] << 32 | p[2] << 24 | p[3] << 16
| p[4] << 8 | p[5];
st->msg.allocate.len = p[6] << 40 | p[7] << 32 | p[8] << 24 | p[9] << 16
| p[10] << 8 | p[11];
(*st->on_read[MSG_SEND_ALLOCATE])(&st->msg);
return true;
}
static bool parse_send_iso(struct msg_state *st) {
const char *p = st->buf + 1;
const size_t l = sdslen(st->buf) - 1;
if (l < SEND_ISO_LEN)
return false;
st->msg.send_iso.len = p[3] << 8 | p[4];
if (l < SEND_ISO_LEN + len)
return false;
st->msg.send_iso.ch = p[0];
st->msg.send_iso.tag = p[1];
st->msg.send_iso.synch = p[2];
st->msg.send_iso.buf = p + SEND_ISO_LEN;
(*st->on_read[MSG_SEND_ASYNC])(&st->msg);
sdsrange(st->buf, SEND_ISO_LEN + len, sdslen(st->buf));
st->state = PARSE_VERSION_MESSAGE;
return true;
}
bool parse_packet(struct msg_state *st) {
switch(st->state) {
case PARSE_VERSION_MESSAGE:
return parse_version_message(st);
case PARSE_SEND_ASYNC:
return parse_send_async(st);
case PARSE_ALLOCATE:
return parse_allocate(st);
case PARSE_SEND_ISO:
return parse_send_iso(st);
}
}
static int sendall(SOCKET sck, unsigned char *msg, size_t msglen) {
int bytes_sent = 0;
do {
int n = send(sck, msg + bytes_sent, msglen - bytes_sent, 0);
if (n == SOCKET_ERROR) {
return 0;
}
bytes_sent += n;
} while (bytes_sent < msglen);
return 1;
}
int msg_send_alloc(SOCKET sck, uint64_t start, uint64_t len) {
unsigned char *msg;
int r;
msg = malloc(ALLOCATE_LEN);
msg[0] = MSG_ALLOCATE;
msg[1] = start >> 40 & 0xFF;
msg[2] = start >> 32 & 0xFF;
msg[3] = start >> 24 & 0xFF;
msg[4] = start >> 16 & 0xFF;
msg[5] = start >> 8 & 0xFF;
msg[6] = start & 0xFF;
msg[7] = len >> 40 & 0xFF;
msg[8] = len >> 32 & 0xFF;
msg[9] = len >> 24 & 0xFF;
msg[10] = len >> 16 & 0xFF;
msg[11] = len >> 8 & 0xFF;
msg[12] = len & 0xFF;
r = sendall(sck, msg, ALLOCATE_LEN);
free(msg);
return r;
}
int msg_send_async(SOCKET sck, uint16_t bus, uint8_t node, uint64_t addr,
uint8_t tcode, uint8_t tag, uint16_t len, void *data) {
unsigned char *msg;
size_t msglen = SEND_ASYNC_LEN + 1 + len;
int r;
msg = malloc(msglen);
msg[0] = MSG_SEND_ASYNC;
msg[1] = buf >> 8;
msg[2] = (bus & 0x3F << 6) | node;
msg[3] = (addr >> 40) & 0xFF;
msg[4] = (addr >> 32) & 0xFF;
msg[5] = (addr >> 24) & 0xFF;
msg[6] = (addr >> 16) & 0xFF;
msg[7] = (addr >> 8) & 0xFF;
msg[8] = addr & 0xFF;
msg[9] = tcode;
msg[10] = tag;
msg[11] = len >> 8;
msg[12] = len & 0xFF;
if (data)
memcpy(msg + 13, data, len);
r = sendall(sck, msg, msglen);
free(msg);
return r;
}

72
common/msg.h Normal file
View File

@ -0,0 +1,72 @@
#include "sds.h"
#ifdef WINDOWS
# include <windows.h>
#else
# include <sys/socket.h>
# include <unistd.h>
typedef int SOCKET;
#endif
union msg {
struct {
uint16_t bus;
uint8_t node;
uint64_t addr;
uint8_t tcode;
uint8_t tlabel;
uint8_t extcode;
uint16_t len;
char *buf;
} send_async;
struct {
uint8_t ch;
uint8_t tag;
uint8_t synch;
uint16_t len;
char *buf;
} iso;
struct {
uint64_t start;
uint64_t length;
} allocate;
};
enum {
MSG_SEND_INVALID = -1,
MSG_NOOP = 0,
MSG_SEND_ASYNC = 1,
MSG_SEND_ISO = 2,
MSG_ALLOCATE = 3,
MSG_TYPES_LEN
};
enum parsestate {
PARSE_VERSION_MESSAGE,
PARSE_SEND_ASYNC,
PARSE_SEND_ISO,
PARSE_ALLOCATE
}
typedef void (*msg_exec)(int, union msg *);
struct msg_state {
char *buf;
enum msgtype type;
int msgtype;
union msg msg;
enum parsestate state;
msg_exec on_read[MSG_TYPES_LEN];
};
/* Message Header:
[2 : version][6 : message]
* noop [0]
* (none)
*/

1313
common/sds.c Normal file

File diff suppressed because it is too large Load Diff

274
common/sds.h Normal file
View File

@ -0,0 +1,274 @@
/* SDSLib 2.0 -- A C dynamic strings library
*
* Copyright (c) 2006-2015, Salvatore Sanfilippo <antirez at gmail dot com>
* Copyright (c) 2015, Oran Agra
* Copyright (c) 2015, Redis Labs, Inc
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Redis nor the names of its contributors may be used
* to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SDS_H
#define __SDS_H
#define SDS_MAX_PREALLOC (1024*1024)
extern const char *SDS_NOINIT;
#include <sys/types.h>
#include <stdarg.h>
#include <stdint.h>
typedef char *sds;
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
#define SDS_HDR_VAR(T,s) struct sdshdr##T *sh = (void*)((s)-(sizeof(struct sdshdr##T)));
#define SDS_HDR(T,s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)
static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->len;
case SDS_TYPE_16:
return SDS_HDR(16,s)->len;
case SDS_TYPE_32:
return SDS_HDR(32,s)->len;
case SDS_TYPE_64:
return SDS_HDR(64,s)->len;
}
return 0;
}
static inline size_t sdsavail(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5: {
return 0;
}
case SDS_TYPE_8: {
SDS_HDR_VAR(8,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_16: {
SDS_HDR_VAR(16,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_32: {
SDS_HDR_VAR(32,s);
return sh->alloc - sh->len;
}
case SDS_TYPE_64: {
SDS_HDR_VAR(64,s);
return sh->alloc - sh->len;
}
}
return 0;
}
static inline void sdssetlen(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len = newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len = newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len = newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len = newlen;
break;
}
}
static inline void sdsinclen(sds s, size_t inc) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
{
unsigned char *fp = ((unsigned char*)s)-1;
unsigned char newlen = SDS_TYPE_5_LEN(flags)+inc;
*fp = SDS_TYPE_5 | (newlen << SDS_TYPE_BITS);
}
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->len += inc;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->len += inc;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->len += inc;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->len += inc;
break;
}
}
/* sdsalloc() = sdsavail() + sdslen() */
static inline size_t sdsalloc(const sds s) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:
return SDS_HDR(8,s)->alloc;
case SDS_TYPE_16:
return SDS_HDR(16,s)->alloc;
case SDS_TYPE_32:
return SDS_HDR(32,s)->alloc;
case SDS_TYPE_64:
return SDS_HDR(64,s)->alloc;
}
return 0;
}
static inline void sdssetalloc(sds s, size_t newlen) {
unsigned char flags = s[-1];
switch(flags&SDS_TYPE_MASK) {
case SDS_TYPE_5:
/* Nothing to do, this type has no total allocation info. */
break;
case SDS_TYPE_8:
SDS_HDR(8,s)->alloc = newlen;
break;
case SDS_TYPE_16:
SDS_HDR(16,s)->alloc = newlen;
break;
case SDS_TYPE_32:
SDS_HDR(32,s)->alloc = newlen;
break;
case SDS_TYPE_64:
SDS_HDR(64,s)->alloc = newlen;
break;
}
}
sds sdsnewlen(const void *init, size_t initlen);
sds sdsnew(const char *init);
sds sdsempty(void);
sds sdsdup(const sds s);
void sdsfree(sds s);
sds sdsgrowzero(sds s, size_t len);
sds sdscatlen(sds s, const void *t, size_t len);
sds sdscat(sds s, const char *t);
sds sdscatsds(sds s, const sds t);
sds sdscpylen(sds s, const char *t, size_t len);
sds sdscpy(sds s, const char *t);
sds sdscatvprintf(sds s, const char *fmt, va_list ap);
#ifdef __GNUC__
sds sdscatprintf(sds s, const char *fmt, ...)
__attribute__((format(printf, 2, 3)));
#else
sds sdscatprintf(sds s, const char *fmt, ...);
#endif
sds sdscatfmt(sds s, char const *fmt, ...);
sds sdstrim(sds s, const char *cset);
void sdsrange(sds s, ssize_t start, ssize_t end);
void sdsupdatelen(sds s);
void sdsclear(sds s);
int sdscmp(const sds s1, const sds s2);
sds *sdssplitlen(const char *s, ssize_t len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count);
void sdstolower(sds s);
void sdstoupper(sds s);
sds sdsfromlonglong(long long value);
sds sdscatrepr(sds s, const char *p, size_t len);
sds *sdssplitargs(const char *line, int *argc);
sds sdsmapchars(sds s, const char *from, const char *to, size_t setlen);
sds sdsjoin(char **argv, int argc, char *sep);
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);
/* Low level functions exposed to the user API */
sds sdsMakeRoomFor(sds s, size_t addlen);
void sdsIncrLen(sds s, ssize_t incr);
sds sdsRemoveFreeSpace(sds s);
size_t sdsAllocSize(sds s);
void *sdsAllocPtr(sds s);
/* Export the allocator used by SDS to the program using SDS.
* Sometimes the program SDS is linked to, may use a different set of
* allocators, but may want to allocate or free things that SDS will
* respectively free or allocate. */
void *sds_malloc(size_t size);
void *sds_realloc(void *ptr, size_t size);
void sds_free(void *ptr);
#ifdef REDIS_TEST
int sdsTest(int argc, char *argv[]);
#endif
#endif

266
linux/1394ethbridge.c Normal file
View File

@ -0,0 +1,266 @@
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <poll.h>
#include <libraw1394/raw1394.h>
enum {
SERVER_FD = 0,
IEEE_FD = 1,
CLIENT_FD = 2,
DESCRIPTORS = 3
};
static struct msg_state client_state;
static raw1394handle_t ieee_handle;
static struct pollfd pollfds[DESCRIPTORS] = {{0}};
static void verr(char *fmt, va_list va) {
int n = 0;
if (fmt)
n = vfprintf(stderr, fmt, va);
if (errno)
fprintf(stderr, "%s%s\n", n ? ": " : "", strerror(errno));
else
fprintf(stderr, "\n");
exit(1);
}
static void err(char *fmt, ...) {
va_list va;
va_start(va, fmt);
verr(fmt, va);
va_end(va);
}
static void server_accept(void) {
int fd = accept(pollfds[SERVER_FD], NULL, NULL);
if (pollfds[CLIENT_FD].fd >= 0) {
close(fd);
return;
}
if (fd < 0) {
if (errno != ECONNABORTED)
err("accept");
else
return;
}
pollfds[CLIENT_FD].fd = fd;
client_state.state = PARSE_VERSION_MESSAGE;
client_state.type = MESSAGE_INVALID;
if (client_state.buf) {
sdsclear(client_state.buf);
} else {
client_state.buf = sdsempty();
}
}
static void iterate(void) {
if (raw1394_loop_iterate(ieee_handle) < 0)
err("raw1394_loop_iterate");
}
/* 0b111111 = 0x3F
* if tags[x] < 0, then tag is not allocated
*/
#define TAG_NUM 0x40
static long tag_to_handle[TAG_NUM];
static void handle_send_async(union msg *msg) {
switch (msg->send_async.tcode) {
case TCODE_WRITE_QUADLET_REQUEST:
case TCODE_WRITE_BLOCK_REQUEST:
raw1394_start_write(ieee_handle, msg->send_async.node,
msg->send_async.addr, msg->send_async.len,
msg->send_async.buf, msg->send_async.tlabel);
break;
case TCODE_READ_QUADLET_REQUEST:
case TCODE_READ_BLOCK_REQUEST:
raw1394_start_read(ieee_handle, msg->send_async.node,
msg->send_async.addr, msg->send_async.len,
msg->send_async.buf, msg->send_async.tlabel);
break;
case TCODE_WRITE_RESONSE: case TCODE_READ_QUADLET_RESPONSE:
case TCODE_READ_BLOCK_RESPONSE:
if (msg->send_async.tlabel < TAG_NUM &&
tags_to_handle[msg->send_async.tlabel] >= 0) {
raw1394_send_rw_response(ieee_handle, msg->send_async.tcode,
msg->send_async.buf, msg->send_async.len,
tags_to_handle[msg->send_async.tlabel]);
tags_to_handle[msg->send_async.tlabel] = 0;
}
break;
/* FIXME: implement lock request */
}
}
static void handle_send_iso(union msg *msg) {
/* do nothing */
}
static int arm_handler(raw1394handle_t handle, raw1394_arm_allocation_t *arm,
int tcode, unsigned long long offset, int source_node_id,
int card, unsigned kernel_handle, size_t length, void *data)
{
(void)handle;
uint8_t tag;
/* Allocate tags.
* Tags are temporarily allocated since the real tag is stored in the
* kernel in the kernel_handle.
*
* firewire-cdev: bus is only 1023?
*/
for (tag = 0; tag < MAX_TAG; tag++) {
if (tag_to_handle[tag] < 0)
break;
}
if (tag == MAX_TAG)
return -1;
tag_to_handle[tag] = kernel_handle;
if (msg_send_async(pollfds[SERVER_FD].fd, 1023, source_node_id, offset,
tcode, tag, length, data) < 0)
tag_to_handle[tag] = -1;
/* TODO: return an error response */
return 0;
}
static void handle_allocation(union msg *msg) {
/* may fail due to overlap: ignore */
raw1394_arm_register(ieee_handle, msg->allocate.start, msg->allocate.length,
ARM_READ | ARM_WRITE | ARM_LOCK,
ARM_READ | ARM_WRITE | ARM_LOCK,
0 /* ignored */);
}
static bool read_client(void) {
char buf[512];
ssize_t len;
int msgtype;
len = read(pollfds[CLIENT_FD].fd, buf, sizeof(buf));
if (len <= 0)
return false;
client_state.buf = sdscatlen(client_state.buf, buf, len);
while (!parse_packet(fdstate));
return true;
}
static bool client_process(void) {
if (fd->revents & POLLERR)
return false;
if (fd->revents & POLLIN)
if (!read_client(fd, fdstate))
return false;
if (!(fd->revents & POLLIN) && fd->revents & POLLHUP)
return false;
return true;
}
static int open_server(const char *port) {
int r;
struct addrinfo *serv;
int sock;
if ((r = getaddrinfo(NULL, port, &(struct addrinfo){
.ai_family = AF_INET,
.ai_socktype = SOCK_STREAM,
.ai_flags = AI_PASSIVE
}, &serv) != 0) {
err("getaddrinfo: %s", gai_strerror(r));
}
for (struct addrinfo *p = serv; p; p = p->ai_next) {
sock = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (sock < 0)
continue;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR) < 0)
continue;
if (bind(sock, p->ai_addr, p->ai_addrlen) < 0)
continue;
break;
}
if (!p)
err("socket");
freeaddrinfo(serv);
if (listen(p, 5) < 0)
err("listen");
return sock;
}
static int setup_port(int port) {
int num;
int fd;
static struct raw1394_portinfo ports[PORTSNUM] = {0};
ieee_handle = raw1394_new_handle();
if (!ieee_handle)
err("raw1394_new_handle");
num = raw1394_get_port_info(ieee_handle, ports, PORTSNUM);
do {
for (int i = 0; i < num && i < PORTSNUM; i++)
fprintf(stderr, "[%d/%d]: %s w/ %d\n", i + 1, num,
ports[i].name, ports[i].nodes);
errno = 0;
raw1394_set_port(ieee_handle, port);
} while (errno != ESTALE);
if (errno)
die("raw1394_set_port");
fd = raw1394_get_fd(ieee_handle);
if (fd < 0)
die("raw1394_get_fd");
return fd;
}
int main(void) {
pollfds[IEEE_FD].fd = setup_port(0);
pollfds[IEEE_FD].events = POLLIN | POLLPRI;
pollfds[SERVER_FD].fd = open_server("1394");
pollfds[SERVER_FD].events = POLLIN | POLLPRI;
pollfds[CLIENT_FD].fd = -1;
for (int i = 0; i < TAG_NUM; i++)
tag_to_handle[i] = -1;
client_state.on_read[PARSE_SEND_ASYNC] = ieee_process;
while (1) {
if (poll(pollfds, DESCRIPTORS, -1) <= 0)
err("poll");
if (pollfds[SERVER_FD].revents & (POLLIN | POLLPRI)) {
server_accept();
} else if (pollfds[IEEE_FD].revents & (POLLIN | POLLPRI)) {
ieee_process();
}
if (!client_process()) {
close(pollfds[CLIENT_FD].fd);
pollfds[CLIENT_FD].fd = -1;
// Reset Firewire
raw1394_destroy_handle(ieee_handle);
pollfds[IEEE_FD].fd = setup_port(0);
}
}
}

369
win/shim.c Normal file
View File

@ -0,0 +1,369 @@
#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "sdnet.h"
#define export __declspec(dllexport)
#define ADDR "192.168.1.1"
#define PORT 1394
static FILE *log;
static SOCKET sock = INVALID_SOCKET;
static WSADATA wsd;
static FILE *makelog(void) {
char buf[128];
time_t t = time(NULL);
snprintf(buf, sizeof(buf), "logfile-%lu.txt", (unsigned long) t);
return fopen(buf, "w");
}
static SOCKET makesock(void) {
struct addrinfo hints, *ai, *p;
SOCKET s;
if (WSAStartup(MAKEWORD(2,2), &wsd) != 0) {
fputs(log, "wsa\n");
return INVALID_SOCKET;
}
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
if (getaddrinfo(ADDR, PORT, &hints, &ai) != 0) {
fputs(log, "getaddrinfo\n");
return INVALID_SOCKET;
}
for (p = ai; p; p = p->ai_next) {
s = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (s == INVALID_SOCKET)
continue;
if (connect(s, p->ai_addr, (int)->ai_addrlen) == SOCKET_ERROR) {
closesocket(s);
continue;
}
break;
}
freeaddrinfo(ai);
if (!p) {
fputs(log, "getaddrinfo socket connect\n");
return INVALID_SOCKET;
}
return s;
}
export LONG sdNET_OpenAdapter(PHANDLE hDevice, ULONG wwuid,
ULONG adpNumber) {
(void)wwuid;
(void)adpNumber;
if (!log)
return sdNET_ERR_ADAPTER_BUSY;
log = makelog();
if (!log)
return sdNET_ERR_ADAPTER_BUSY;
fputs(log, "open log\n");
sock = makesock();
if (!sock)
return sdNET_ERR_ADAPTER_BUSY;
*hDevice = 1394;
return sdNET_ERR_SUCCESS;
}
export LONG sdNET_CloseAdapter(PHANDLE hDevice) {
if (*hDevice != 1394)
return sdNET_ERR_INVALID_HANDLE;
fputs(log, "Closing\n");
fclose(log);
closesocket(sock);
log = NULL;
sock = INVALID_SOCKET;
return sdNET_ERR_INVALID_HANDLE;
}
static int dump_tcode(unsigned long tcode)
{
unsigned long other = tcode & ~IEEE1394_tCODE_MASK;
int is_iso = 0;
fprint(logfile, "Transaction Code: ");
switch (tcode & IEEE1394_tCODE_MASK) {
case IEEE1394_QUAD_WRREQ:
log("Async request subaction, quadlet");
break;
case IEEE1394_BLOCK_WRREQ:
log(Async request subaction, block");
break;
case IEEE1394_WRRESP:
log("Async response subaction for both write request types, no payload");
break;
case IEEE1394_QUAD_RDREQ:
log("Async request subaction, no payload");
break;
case IEEE1394_BLOCK_RDREQ:
log("Async request subaction quadlet payload");
break;
case IEEE1394_QUAD_RDRESP:
log("Async response subaction to request for quadlet, quadlet payload");
break;
case IEEE1394_BLOCK_RDRESP:
log("Async response subaction to request for block, block payload");
break;
case IEEE1394_CYCLE_START_REQ:
log("Async request to start isochronous cycle, quadlet payload");
break;
case IEEE1394_LOCK_REQ:
log("Async request subaction, block payload");
break;
case IEEE1394_ISOBLOCK_REQ:
log("Isochronous subaction, block payload");
is_iso = 1;
break;
case IEEE194_LOCK_RESP:
log("Asynchronous request subaction for lock request, block payload");
break;
default:
log("Unknown code %lu", tcode & IEEE1394_tCODE_MASK);
break;
}
if (other) {
log("Other transaction code: %lu", other);
}
log("\n");
return is_iso;
}
static void dump_data(unsigned long len, unsigned long *data)
{
/* Dump in base52 instead? */
unsigned long i;
log("Data length: %lu\n", len);
log("Data:");
for (i = 0; i < len >> 2; i++) {
fprintf(" %08lX", *data);
data++;
}
log("\n");
}
static void dump_asy(PsdNET_Packet_t p)
{
fprintf(logfile,
"Asynchronous Packet.\n"
"Bus: %lu\n"
"Node: %lu\n"
"Address Offset, High: 0x%08lX\n"
"Address Offset, Low: 0x%08lX\n"
"Transaction Label: %lu\n",
p->type.asy.bus,
p->type.asy.node,
p->type.asy.offsetHigh,
p->type.asy.offsetLow
);
log("Retry code: ");
switch (p->type.asy.retryCode) {
case IEEE1394_Retry_0:
log("Initial subaction.\n");
break;
case IEEE1394_Retry_X:
log("Retry subaction from acknowledge busy, or retry from acknowledge busy A or B.\n");
break;
case IEEE1394_Retry_A:
log("Retry subaction, dual-phase retry node, A.\n");
break;
case IEEE1394_Retry_B:
log("Retry subaction, dual-phase retry node, B.\n");
break;
default:
log("Unknown %lu\n", p->type.asy.retryCode);
break;
}
log("Response code: ");
switch(p->type.asy.rCode) {
case IEEE1394_RESP_COMPLETE:
log("Complete\n");
break;
case IEEE1394_RESP_CONFLICT_ERROR:
log("Resource conflict\n");
break;
case IEEE1394_RESP_DATA_ERROR:
log("Hardware error\n");
break;
case IEEE1394_RESP_TYPE_ERROR:
log("Invalid value or transaction\n");
break;
case IEEE1394_RESP_ADDR_ERROR:
log("Destination not accessable\n");
break;
default:
log("Unknown %lu\n", p->type.asy.rCode);
}
log("Extended response code: ");
switch (p->type.asy.xtCode) {
case IEEE1394_MASK_SWAP:
log("Mask swap\n");
break;
case IEEE1394_COMPARE_SWAP:
log("Compare swap\n");
break;
case IEEE1394_FETCH_ADD:
log("Fetch add\n");
break;
case IEEE1394_BOUNDED_ADD:
log("Bounded add\n");
break;
case IEEE1394_WRAP_ADD:
log("Wrap add\n");
break;
case IEEE1394_VENDER_DEP:
log("Vendor dependent\n");
default:
log("Unknown %lu\n", p->type.asy.xtCode);
}
}
static void dump_iso(PsdNET_Packet_t p)
{
log("Isochronous packet.\n"
"Channel: %lu\n"
"Synchronization code: %lu\n",
p->type.iso.channel,
p->type.iso.synchro);
log("Tag: ");
switch (p->type.iso.tag) {
case IEEE1394_TAG_UNFORMATTED:
log("Unformatted\n");
break;
case IEEE1394_TAG_FORMAT1:
log("1\n");
break;
case IEEE1394_TAG_FORMAT2:
log("2\n");
break;
case IEEE1394_TAG_FORMAT3:
log("3\n");
break;
default:
log("Unknown tag %lu\n", p->type.iso.tag);
break;
}
}
static void dump_packet(PsdNET_Packet_t p)
{
log("Timeout: %lu\n", p->tCode);
log("Flags:");
if (p->flags & SDNET__NOBLOCKINGMODE) {
log(" Nonblocking");
} else if (p->flags & SDNET__BLOCKINGMODE) {
log(" Blocking");
}
log("\n");
if (dump_tcode(p->tCode) == 1)
dump_iso(p);
else
dump_asy(p);
log("Acknowledge code: ");
switch (p->ack) {
case IEEE1394_ACK_COMPLETE:
log("Accepted and completed\n");
break;
case IEEE1394_ACK_PENDING:
log("Accepted and pending\n");
break;
case IEEE1394_ACK_BUSY_X:
log("Rejected, retry\n");
break;
case IEEE1394_ACK_BUSY_A:
log("Rejected, retry at phase A\n");
break;
case IEEE1394_ACK_BUSY_B:
log("Rejected, retry at phase B\n");
break;
case IEEE1394_ACK_DATA_ERROR:
log("CRC/length check fail\n");
break;
case IEEE1394_ACK_TYPE_ERROR:
log("Unsupported or incorrect value, or invalid transaction\n");
default:
log("Unknown %lu\n", p->ack);
}
log("Speed: ");
switch (p->speed) {
case IEEE1394_ASYSPD_100Mbits:
case IEEE1394_ISOSPD_100Mbits:
log("100\n");
break;
case IEEE1394_ASYSPD200Mbits:
case IEEE1394_ISOSPD200Mbits:
log("200\n");
break;
case IEEE1394_ASYSPD400Mbits:
case IEEE1394_ISOSPD400Mbits:
log("400\n");
break;
default:
log("Unknown %lu\n", p->speed);
}
dump_data(p->datalen, p->data);
}
export LONG sdNET_SendAsyncPacket(PHANDLE hDevice, PsdNET_Packet_t pk) {
fputs(log, "Send Async\n");
dump_packet(pk);
/* TODO: convert pk->asy.data and pk->asy.datalen from long to octet */
msg_send_async(sock, pk->asy.bus, pk->asy.node,
pk->asy.offset_high << 32 | pk->asy.offset_low,
pk->tcode, pk->asy.tLabel, pk->asy.datalen, pk->asy.data);
return sdNET_ERR_TIMEOUT;
}
export LONG sdNET_SendIsochPacket(PHANDLE hDevice, PsdNET_Packet_t pk) {
fputs(log, "Send Isoch\n");
dump_packet(pk);
return sdNET_ERR_TIMEOUT;
}
export LONG sdNET_ReceivePacket(PHANDLE hDevice, PsdNET_Packet_t pk) {
char buf[512];
fputs(log, "Receive One\n");
return sdNET_ERR_TIMEOUT;
}
export LONG sdNET_IOControl(PHANDLE hDevice, ULONG cmd, PVOID iodata) {
fputs(log, "IOControl\n");
return sdNET_ERR_IOCTL_FAILED;
}
export LONG sdNET_MultiReceive(PHANDLE hDevice, PsdNET_MultiPk_t multiPk) {
fputs(log, "Recv many\n");
return sdNET_ERR_TIMEOUT;
}