aboutsummaryrefslogtreecommitdiffstats
path: root/linux/1394ethbridge.c
diff options
context:
space:
mode:
authorGravatar Peter McGoron 2022-09-26 13:17:04 -0400
committerGravatar Peter McGoron 2022-09-26 13:17:04 -0400
commita31884d44375d99c1ac47e27150b3b05d42871ef (patch)
tree9a26a9aebc1ccf8a33085f34d5c3b00c7d4e4347 /linux/1394ethbridge.c
start unfinished code
Diffstat (limited to 'linux/1394ethbridge.c')
-rw-r--r--linux/1394ethbridge.c266
1 files changed, 266 insertions, 0 deletions
diff --git a/linux/1394ethbridge.c b/linux/1394ethbridge.c
new file mode 100644
index 0000000..c7fffcf
--- /dev/null
+++ b/linux/1394ethbridge.c
@@ -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);
+ }
+ }
+}