start unfinished code
This commit is contained in:
commit
a31884d443
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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)
|
||||
*/
|
File diff suppressed because it is too large
Load Diff
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
Reference in New Issue