Merge pull request #25 from paulofduarte/wip-crap

Bringing A314 code from Niklas branch
This commit is contained in:
beeanyew
2021-05-16 02:07:55 +02:00
committed by GitHub
18 changed files with 2793 additions and 0 deletions

1414
a314/a314.cc Normal file

File diff suppressed because it is too large Load Diff

33
a314/a314.h Normal file
View File

@@ -0,0 +1,33 @@
// A314 emulation.
#ifndef A314_H
#define A314_H
#ifdef __cplusplus
extern "C" {
#endif
#define A314_ENABLED 1
extern unsigned int a314_base;
extern int a314_base_configured;
#define A314_COM_AREA_SIZE (64 * 1024)
int a314_init();
void a314_set_mem_base_size(unsigned int base, unsigned int size);
void a314_process_events();
unsigned int a314_read_memory_8(unsigned int address);
unsigned int a314_read_memory_16(unsigned int address);
unsigned int a314_read_memory_32(unsigned int address);
void a314_write_memory_8(unsigned int address, unsigned int value);
void a314_write_memory_16(unsigned int address, unsigned int value);
void a314_write_memory_32(unsigned int address, unsigned int value);
#ifdef __cplusplus
}
#endif
#endif /* A314_H */

43
a314/a314device/a314.h Normal file
View File

@@ -0,0 +1,43 @@
#ifndef DEVICES_A314_H
#define DEVICES_A314_H
#include <exec/io.h>
#define A314_NAME "a314.device"
#define A314_CONNECT (CMD_NONSTD+0)
#define A314_READ (CMD_NONSTD+1)
#define A314_WRITE (CMD_NONSTD+2)
#define A314_EOS (CMD_NONSTD+3)
#define A314_RESET (CMD_NONSTD+4)
#define A314_CONNECT_OK 0
#define A314_CONNECT_SOCKET_IN_USE 1
#define A314_CONNECT_RESET 2
#define A314_CONNECT_UNKNOWN_SERVICE 3
#define A314_READ_OK 0
#define A314_READ_EOS 1
#define A314_READ_RESET 2
#define A314_WRITE_OK 0
#define A314_WRITE_EOS_SENT 1
#define A314_WRITE_RESET 2
#define A314_EOS_OK 0
#define A314_EOS_EOS_SENT 1
#define A314_EOS_RESET 2
#define A314_RESET_OK 0
#define MEMF_A314 (1<<7)
struct A314_IORequest
{
struct IORequest a314_Request;
ULONG a314_Socket;
STRPTR a314_Buffer;
WORD a314_Length;
};
#endif

View File

@@ -0,0 +1,623 @@
/*
* Copyright (c) 2018 Niklas Ekström
*/
#include <exec/types.h>
#include <exec/interrupts.h>
#include <exec/lists.h>
#include <exec/memory.h>
#include <exec/nodes.h>
#include <exec/ports.h>
#include <exec/io.h>
#include <exec/errors.h>
#include <exec/libraries.h>
#include <exec/devices.h>
#include <exec/execbase.h>
#include <libraries/dos.h>
#include <proto/exec.h>
#include <string.h>
#include "a314.h"
#include "debug.h"
#include "device.h"
#include "protocol.h"
#include "sockets.h"
#include "fix_mem_region.h"
#include "startup.h"
int used_in_r2a()
{
return (ca->r2a_tail - ca->r2a_head) & 255;
}
int used_in_a2r()
{
return (ca->a2r_tail - ca->a2r_head) & 255;
}
BOOL room_in_a2r(int len)
{
return used_in_a2r() + 3 + len <= 255;
}
void append_a2r_packet(UBYTE type, UBYTE stream_id, UBYTE length, UBYTE *data)
{
UBYTE index = ca->a2r_tail;
ca->a2r_buffer[index++] = length;
ca->a2r_buffer[index++] = type;
ca->a2r_buffer[index++] = stream_id;
for (int i = 0; i < (int)length; i++)
ca->a2r_buffer[index++] = *data++;
ca->a2r_tail = index;
}
void close_socket(struct Socket *s, BOOL should_send_reset)
{
debug_printf("Called close socket\n");
if (s->pending_connect != NULL)
{
struct A314_IORequest *ior = s->pending_connect;
ior->a314_Request.io_Error = A314_CONNECT_RESET;
ReplyMsg((struct Message *)ior);
s->pending_connect = NULL;
}
if (s->pending_read != NULL)
{
struct A314_IORequest *ior = s->pending_read;
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_RESET;
ReplyMsg((struct Message *)ior);
s->pending_read = NULL;
}
if (s->pending_write != NULL)
{
struct A314_IORequest *ior = s->pending_write;
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_WRITE_RESET; // A314_EOS_RESET == A314_WRITE_RESET
ReplyMsg((struct Message *)ior);
s->pending_write = NULL;
}
if (s->rq_head != NULL)
{
struct QueuedData *qd = s->rq_head;
while (qd != NULL)
{
struct QueuedData *next = qd->next;
FreeMem(qd, sizeof(struct QueuedData) + qd->length);
qd = next;
}
s->rq_head = NULL;
s->rq_tail = NULL;
}
remove_from_send_queue(s);
// No operations can be pending when SOCKET_CLOSED is set.
// However, may not be able to delete socket yet, because is waiting to send PKT_RESET.
s->flags |= SOCKET_CLOSED;
BOOL should_delete_socket = TRUE;
if (should_send_reset)
{
if (send_queue_head == NULL && room_in_a2r(0))
{
append_a2r_packet(PKT_RESET, s->stream_id, 0, NULL);
}
else
{
s->flags |= SOCKET_SHOULD_SEND_RESET;
add_to_send_queue(s, 0);
should_delete_socket = FALSE;
}
}
if (should_delete_socket)
delete_socket(s);
}
// When a message is received on R2A it is written to this buffer,
// to avoid dealing with the issue that R2A is a circular buffer.
// This is somewhat inefficient, so may want to change that to read from R2A directly.
UBYTE received_packet[256];
static void handle_pkt_connect_response(UBYTE length, struct Socket *s)
{
debug_printf("Received a CONNECT RESPONSE packet from rpi\n");
if (s->pending_connect == NULL)
{
debug_printf("SERIOUS ERROR: received a CONNECT RESPONSE even though no connect was pending\n");
// Should reset stream?
}
else if (length != 1)
{
debug_printf("SERIOUS ERROR: received a CONNECT RESPONSE whose length was not 1\n");
// Should reset stream?
}
else
{
UBYTE result = received_packet[0];
if (result == 0)
{
struct A314_IORequest *ior = s->pending_connect;
ior->a314_Request.io_Error = A314_CONNECT_OK;
ReplyMsg((struct Message *)ior);
s->pending_connect = NULL;
}
else
{
struct A314_IORequest *ior = s->pending_connect;
ior->a314_Request.io_Error = A314_CONNECT_UNKNOWN_SERVICE;
ReplyMsg((struct Message *)ior);
s->pending_connect = NULL;
close_socket(s, FALSE);
}
}
}
static void handle_pkt_data(UBYTE length, struct Socket *s)
{
debug_printf("Received a DATA packet from rpi\n");
if (s->pending_read != NULL)
{
struct A314_IORequest *ior = s->pending_read;
if (ior->a314_Length < length)
close_socket(s, TRUE);
else
{
memcpy(ior->a314_Buffer, received_packet, length);
ior->a314_Length = length;
ior->a314_Request.io_Error = A314_READ_OK;
ReplyMsg((struct Message *)ior);
s->pending_read = NULL;
}
}
else
{
struct QueuedData *qd = (struct QueuedData *)AllocMem(sizeof(struct QueuedData) + length, 0);
qd->next = NULL,
qd->length = length;
memcpy(qd->data, received_packet, length);
if (s->rq_head == NULL)
s->rq_head = qd;
else
s->rq_tail->next = qd;
s->rq_tail = qd;
}
}
static void handle_pkt_eos(struct Socket *s)
{
debug_printf("Received a EOS packet from rpi\n");
s->flags |= SOCKET_RCVD_EOS_FROM_RPI;
if (s->pending_read != NULL)
{
struct A314_IORequest *ior = s->pending_read;
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_EOS;
ReplyMsg((struct Message *)ior);
s->pending_read = NULL;
s->flags |= SOCKET_SENT_EOS_TO_APP;
if (s->flags & SOCKET_SENT_EOS_TO_RPI)
close_socket(s, FALSE);
}
}
static void handle_r2a_packet(UBYTE type, UBYTE stream_id, UBYTE length)
{
struct Socket *s = find_socket_by_stream_id(stream_id);
if (s != NULL && type == PKT_RESET)
{
debug_printf("Received a RESET packet from rpi\n");
close_socket(s, FALSE);
return;
}
if (s == NULL || (s->flags & SOCKET_CLOSED))
{
// Ignore this packet. The only packet that can do anything useful on a closed
// channel is CONNECT, which is not handled at this time.
return;
}
if (type == PKT_CONNECT_RESPONSE)
{
handle_pkt_connect_response(length, s);
}
else if (type == PKT_DATA)
{
handle_pkt_data(length, s);
}
else if (type == PKT_EOS)
{
handle_pkt_eos(s);
}
}
void handle_packets_received_r2a()
{
while (used_in_r2a() != 0)
{
UBYTE index = ca->r2a_head;
UBYTE len = ca->r2a_buffer[index++];
UBYTE type = ca->r2a_buffer[index++];
UBYTE stream_id = ca->r2a_buffer[index++];
for (int i = 0; i < len; i++)
received_packet[i] = ca->r2a_buffer[index++];
ca->r2a_head = index;
handle_r2a_packet(type, stream_id, len);
}
}
void handle_room_in_a2r()
{
while (send_queue_head != NULL)
{
struct Socket *s = send_queue_head;
if (!room_in_a2r(s->send_queue_required_length))
break;
remove_from_send_queue(s);
if (s->pending_connect != NULL)
{
struct A314_IORequest *ior = s->pending_connect;
int len = ior->a314_Length;
append_a2r_packet(PKT_CONNECT, s->stream_id, (UBYTE)len, ior->a314_Buffer);
}
else if (s->pending_write != NULL)
{
struct A314_IORequest *ior = s->pending_write;
int len = ior->a314_Length;
if (ior->a314_Request.io_Command == A314_WRITE)
{
append_a2r_packet(PKT_DATA, s->stream_id, (UBYTE)len, ior->a314_Buffer);
ior->a314_Request.io_Error = A314_WRITE_OK;
ReplyMsg((struct Message *)ior);
s->pending_write = NULL;
}
else // A314_EOS
{
append_a2r_packet(PKT_EOS, s->stream_id, 0, NULL);
ior->a314_Request.io_Error = A314_EOS_OK;
ReplyMsg((struct Message *)ior);
s->pending_write = NULL;
s->flags |= SOCKET_SENT_EOS_TO_RPI;
if (s->flags & SOCKET_SENT_EOS_TO_APP)
close_socket(s, FALSE);
}
}
else if (s->flags & SOCKET_SHOULD_SEND_RESET)
{
append_a2r_packet(PKT_RESET, s->stream_id, 0, NULL);
delete_socket(s);
}
else
{
debug_printf("SERIOUS ERROR: Was in send queue but has nothing to send\n");
}
}
}
static void handle_app_connect(struct A314_IORequest *ior, struct Socket *s)
{
debug_printf("Received a CONNECT request from application\n");
if (s != NULL)
{
ior->a314_Request.io_Error = A314_CONNECT_SOCKET_IN_USE;
ReplyMsg((struct Message *)ior);
}
else if (ior->a314_Length + 3 > 255)
{
ior->a314_Request.io_Error = A314_CONNECT_RESET;
ReplyMsg((struct Message *)ior);
}
else
{
s = create_socket(ior->a314_Request.io_Message.mn_ReplyPort->mp_SigTask, ior->a314_Socket);
s->pending_connect = ior;
s->flags = 0;
int len = ior->a314_Length;
if (send_queue_head == NULL && room_in_a2r(len))
{
append_a2r_packet(PKT_CONNECT, s->stream_id, (UBYTE)len, ior->a314_Buffer);
}
else
{
add_to_send_queue(s, len);
}
}
}
static void handle_app_read(struct A314_IORequest *ior, struct Socket *s)
{
debug_printf("Received a READ request from application\n");
if (s == NULL || (s->flags & SOCKET_CLOSED))
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_RESET;
ReplyMsg((struct Message *)ior);
}
else
{
if (s->pending_connect != NULL || s->pending_read != NULL)
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_RESET;
ReplyMsg((struct Message *)ior);
close_socket(s, TRUE);
}
else if (s->rq_head != NULL)
{
struct QueuedData *qd = s->rq_head;
int len = qd->length;
if (ior->a314_Length < len)
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_RESET;
ReplyMsg((struct Message *)ior);
close_socket(s, TRUE);
}
else
{
s->rq_head = qd->next;
if (s->rq_head == NULL)
s->rq_tail = NULL;
memcpy(ior->a314_Buffer, qd->data, len);
FreeMem(qd, sizeof(struct QueuedData) + len);
ior->a314_Length = len;
ior->a314_Request.io_Error = A314_READ_OK;
ReplyMsg((struct Message *)ior);
}
}
else if (s->flags & SOCKET_RCVD_EOS_FROM_RPI)
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_READ_EOS;
ReplyMsg((struct Message *)ior);
s->flags |= SOCKET_SENT_EOS_TO_APP;
if (s->flags & SOCKET_SENT_EOS_TO_RPI)
close_socket(s, FALSE);
}
else
s->pending_read = ior;
}
}
static void handle_app_write(struct A314_IORequest *ior, struct Socket *s)
{
debug_printf("Received a WRITE request from application\n");
if (s == NULL || (s->flags & SOCKET_CLOSED))
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_WRITE_RESET;
ReplyMsg((struct Message *)ior);
}
else
{
int len = ior->a314_Length;
if (s->pending_connect != NULL || s->pending_write != NULL || (s->flags & SOCKET_RCVD_EOS_FROM_APP) || len + 3 > 255)
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_WRITE_RESET;
ReplyMsg((struct Message *)ior);
close_socket(s, TRUE);
}
else
{
if (send_queue_head == NULL && room_in_a2r(len))
{
append_a2r_packet(PKT_DATA, s->stream_id, (UBYTE)len, ior->a314_Buffer);
ior->a314_Request.io_Error = A314_WRITE_OK;
ReplyMsg((struct Message *)ior);
}
else
{
s->pending_write = ior;
add_to_send_queue(s, len);
}
}
}
}
static void handle_app_eos(struct A314_IORequest *ior, struct Socket *s)
{
debug_printf("Received an EOS request from application\n");
if (s == NULL || (s->flags & SOCKET_CLOSED))
{
ior->a314_Request.io_Error = A314_EOS_RESET;
ReplyMsg((struct Message *)ior);
}
else
{
if (s->pending_connect != NULL || s->pending_write != NULL || (s->flags & SOCKET_RCVD_EOS_FROM_APP))
{
ior->a314_Length = 0;
ior->a314_Request.io_Error = A314_EOS_RESET;
ReplyMsg((struct Message *)ior);
close_socket(s, TRUE);
}
else
{
s->flags |= SOCKET_RCVD_EOS_FROM_APP;
if (send_queue_head == NULL && room_in_a2r(0))
{
append_a2r_packet(PKT_EOS, s->stream_id, 0, NULL);
ior->a314_Request.io_Error = A314_EOS_OK;
ReplyMsg((struct Message *)ior);
s->flags |= SOCKET_SENT_EOS_TO_RPI;
if (s->flags & SOCKET_SENT_EOS_TO_APP)
close_socket(s, FALSE);
}
else
{
s->pending_write = ior;
add_to_send_queue(s, 0);
}
}
}
}
static void handle_app_reset(struct A314_IORequest *ior, struct Socket *s)
{
debug_printf("Received a RESET request from application\n");
if (s == NULL || (s->flags & SOCKET_CLOSED))
{
ior->a314_Request.io_Error = A314_RESET_OK;
ReplyMsg((struct Message *)ior);
}
else
{
ior->a314_Request.io_Error = A314_RESET_OK;
ReplyMsg((struct Message *)ior);
close_socket(s, TRUE);
}
}
static void handle_app_request(struct A314_IORequest *ior)
{
struct Socket *s = find_socket(ior->a314_Request.io_Message.mn_ReplyPort->mp_SigTask, ior->a314_Socket);
switch (ior->a314_Request.io_Command)
{
case A314_CONNECT:
handle_app_connect(ior, s);
break;
case A314_READ:
handle_app_read(ior, s);
break;
case A314_WRITE:
handle_app_write(ior, s);
break;
case A314_EOS:
handle_app_eos(ior, s);
break;
case A314_RESET:
handle_app_reset(ior, s);
break;
default:
ior->a314_Request.io_Error = IOERR_NOCMD;
ReplyMsg((struct Message *)ior);
break;
}
}
void task_main()
{
while (TRUE)
{
debug_printf("Waiting for signal\n");
ULONG signal = Wait(SIGF_MSGPORT | SIGF_INT);
UBYTE prev_a2r_tail = ca->a2r_tail;
UBYTE prev_r2a_head = ca->r2a_head;
if (signal & SIGF_MSGPORT)
{
ca->a_enable = 0;
struct Message *msg;
while (msg = GetMsg(&task_mp))
handle_app_request((struct A314_IORequest *)msg);
}
UBYTE a_enable = 0;
while (a_enable == 0)
{
handle_packets_received_r2a();
handle_room_in_a2r();
UBYTE r_events = 0;
if (ca->a2r_tail != prev_a2r_tail)
r_events |= R_EVENT_A2R_TAIL;
if (ca->r2a_head != prev_r2a_head)
r_events |= R_EVENT_R2A_HEAD;
UBYTE discard_value = ca->a_events;
if (ca->r2a_head == ca->r2a_tail)
{
if (send_queue_head == NULL)
a_enable = A_EVENT_R2A_TAIL;
else if (!room_in_a2r(send_queue_head->send_queue_required_length))
a_enable = A_EVENT_R2A_TAIL | A_EVENT_A2R_HEAD;
if (a_enable != 0)
{
ca->a_enable = a_enable;
if (r_events != 0)
ca->r_events = r_events;
}
}
}
}
// There is currently no way to unload a314.device.
//debug_printf("Shutting down\n");
//RemIntServer(INTB_PORTS, &ports_interrupt);
//RemIntServer(INTB_VERTB, &vertb_interrupt);
//FreeMem(ca, sizeof(struct ComArea));
// Stack and task structure should be reclaimed.
}

View File

@@ -0,0 +1 @@
vc romtag.asm a314driver.c device.c startup.c fix_mem_region.c sockets.c int_server.asm -O3 -nostdlib -o a314.device

3
a314/a314device/debug.h Normal file
View File

@@ -0,0 +1,3 @@
#define DEBUG 0
//#define debug_printf(...) do { if (DEBUG) fprintf(stdout, __VA_ARGS__); } while (0)
#define debug_printf(...)

121
a314/a314device/device.c Normal file
View File

@@ -0,0 +1,121 @@
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/devices.h>
#include <exec/errors.h>
#include <exec/ports.h>
#include <libraries/dos.h>
#include <proto/exec.h>
#include "device.h"
#include "a314.h"
#include "startup.h"
#include "fix_mem_region.h"
char device_name[] = A314_NAME;
char id_string[] = A314_NAME " 1.1 (28 Nov 2020)";
struct ExecBase *SysBase;
BPTR saved_seg_list;
BOOL running = FALSE;
static struct Library *init_device(__reg("a6") struct ExecBase *sys_base, __reg("a0") BPTR seg_list, __reg("d0") struct Library *dev)
{
SysBase = *(struct ExecBase **)4;
saved_seg_list = seg_list;
// We are being called from InitResident() in initializers.asm.
// MakeLibrary() was executed before we got here.
dev->lib_Node.ln_Type = NT_DEVICE;
dev->lib_Node.ln_Name = device_name;
dev->lib_Flags = LIBF_SUMUSED | LIBF_CHANGED;
dev->lib_Version = 1;
dev->lib_Revision = 0;
dev->lib_IdString = (APTR)id_string;
// AddDevice() is executed after we return.
return dev;
}
static BPTR expunge(__reg("a6") struct Library *dev)
{
// There is currently no support for unloading a314.device.
if (TRUE) //dev->lib_OpenCnt != 0)
{
dev->lib_Flags |= LIBF_DELEXP;
return 0;
}
/*
BPTR seg_list = saved_seg_list;
Remove(&dev->lib_Node);
FreeMem((char *)dev - dev->lib_NegSize, dev->lib_NegSize + dev->lib_PosSize);
return seg_list;
*/
}
static void open(__reg("a6") struct Library *dev, __reg("a1") struct A314_IORequest *ior, __reg("d0") ULONG unitnum, __reg("d1") ULONG flags)
{
dev->lib_OpenCnt++;
if (dev->lib_OpenCnt == 1 && !running)
{
if (!task_start())
{
ior->a314_Request.io_Error = IOERR_OPENFAIL;
ior->a314_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
dev->lib_OpenCnt--;
return;
}
running = TRUE;
}
ior->a314_Request.io_Error = 0;
ior->a314_Request.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
}
static BPTR close(__reg("a6") struct Library *dev, __reg("a1") struct A314_IORequest *ior)
{
ior->a314_Request.io_Device = NULL;
ior->a314_Request.io_Unit = NULL;
dev->lib_OpenCnt--;
if (dev->lib_OpenCnt == 0 && (dev->lib_Flags & LIBF_DELEXP))
return expunge(dev);
return 0;
}
static void begin_io(__reg("a6") struct Library *dev, __reg("a1") struct A314_IORequest *ior)
{
PutMsg(&task_mp, (struct Message *)ior);
ior->a314_Request.io_Flags &= ~IOF_QUICK;
}
static ULONG abort_io(__reg("a6") struct Library *dev, __reg("a1") struct A314_IORequest *ior)
{
// There is currently no support for aborting an IORequest.
return IOERR_NOCMD;
}
static ULONG device_vectors[] =
{
(ULONG)open,
(ULONG)close,
(ULONG)expunge,
0,
(ULONG)begin_io,
(ULONG)abort_io,
(ULONG)translate_address_a314,
-1,
};
ULONG auto_init_tables[] =
{
sizeof(struct Library),
(ULONG)device_vectors,
0,
(ULONG)init_device,
};

2
a314/a314device/device.h Normal file
View File

@@ -0,0 +1,2 @@
extern char device_name[];
extern char id_string[];

View File

@@ -0,0 +1,130 @@
#include <exec/types.h>
#include <exec/execbase.h>
#include <exec/memory.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include "a314.h"
#include "fix_mem_region.h"
#include "protocol.h"
struct MemChunkList
{
struct MemChunk *first;
struct MemChunk *last;
ULONG free;
};
void add_chunk(struct MemChunkList *l, struct MemChunk *mc)
{
if (l->first == NULL)
l->first = mc;
else
l->last->mc_Next = mc;
l->last = mc;
l->free += mc->mc_Bytes;
}
struct MemHeader *split_region(struct MemHeader *lower, ULONG split_at)
{
struct MemHeader *upper = (struct MemHeader *)AllocMem(sizeof(struct MemHeader), MEMF_PUBLIC | MEMF_CLEAR);
struct MemChunkList ll = {NULL, NULL, 0};
struct MemChunkList ul = {NULL, NULL, 0};
struct MemChunk *mc = lower->mh_First;
while (mc != NULL)
{
struct MemChunk *next_chunk = mc->mc_Next;
mc->mc_Next = NULL;
ULONG start = (ULONG)mc;
ULONG end = start + mc->mc_Bytes;
if (end <= split_at)
add_chunk(&ll, mc);
else if (split_at <= start)
add_chunk(&ul, mc);
else
{
mc->mc_Bytes = split_at - start;
add_chunk(&ll, mc);
struct MemChunk *new_chunk = (struct MemChunk *)split_at;
new_chunk->mc_Next = NULL;
new_chunk->mc_Bytes = end - split_at;
add_chunk(&ul, new_chunk);
}
mc = next_chunk;
}
upper->mh_Node.ln_Type = NT_MEMORY;
upper->mh_Node.ln_Pri = lower->mh_Node.ln_Pri;
upper->mh_Node.ln_Name = lower->mh_Node.ln_Name; // Use a custom name?
upper->mh_Attributes = lower->mh_Attributes;
lower->mh_First = ll.first;
upper->mh_First = ul.first;
upper->mh_Lower = (APTR)split_at;
upper->mh_Upper = lower->mh_Upper;
lower->mh_Upper = (APTR)split_at;
lower->mh_Free = ll.free;
upper->mh_Free = ul.free;
return upper;
}
BOOL overlap(struct MemHeader *mh, ULONG lower, ULONG upper)
{
return lower < (ULONG)(mh->mh_Upper) && (ULONG)(mh->mh_Lower) < upper;
}
void mark_region_a314(ULONG address, ULONG size)
{
struct List *memlist = &(SysBase->MemList);
for (struct Node *node = memlist->lh_Head; node->ln_Succ != NULL; node = node->ln_Succ)
{
struct MemHeader *mh = (struct MemHeader *)node;
if (overlap(mh, address, address + size))
{
if ((ULONG)mh->mh_Lower < address)
{
mh->mh_Attributes &= ~MEMF_A314;
mh = split_region(mh, address);
}
else
Remove((struct Node *)mh);
if (address + size < (ULONG)mh->mh_Upper)
{
struct MemHeader *new_mh = split_region(mh, address + size);
new_mh->mh_Attributes &= ~MEMF_A314;
Enqueue(memlist, (struct Node *)new_mh);
}
mh->mh_Attributes |= MEMF_A314;
Enqueue(memlist, (struct Node *)mh);
return;
}
}
}
BOOL fix_memory()
{
Forbid();
mark_region_a314(ca->mem_base, ca->mem_size);
Permit();
return TRUE;
}
ULONG translate_address_a314(__reg("a0") void *address)
{
ULONG offset = (ULONG)address - ca->mem_base;
if (offset < ca->mem_size)
return offset;
return -1;
}

View File

@@ -0,0 +1,4 @@
#include <exec/types.h>
extern ULONG translate_address_a314(__reg("a0") void *address);
extern BOOL fix_memory();

View File

@@ -0,0 +1,23 @@
XDEF _IntServer
CODE
SIGB_INT equ 14
SIGF_INT equ (1 << SIGB_INT)
; a1 points to interrupt_data
_IntServer: move.l 4(a1),a5 ; interrupt_data.ca
move.b 0(a5),d0 ; A_EVENTS
and.b 1(a5),d0 ; A_ENABLE
beq.s should_not_signal
move.b #0,1(a5)
move.l $4.w,a6
move.l #SIGF_INT,d0
move.l 0(a1),a1 ; interrupt_data.task
jsr -324(a6) ; Signal()
should_not_signal:
moveq #0,d0
rts

View File

@@ -0,0 +1,9 @@
#ifndef PROTO_A314_H
#define PROTO_A314_H
extern struct Library *A314Base;
ULONG __TranslateAddressA314(__reg("a6") void *, __reg("a0") void *)="\tjsr\t-42(a6)";
#define TranslateAddressA314(address) __TranslateAddressA314(A314Base, address)
#endif

View File

@@ -0,0 +1,42 @@
#include <exec/types.h>
// Packet types that are sent across the physical channel.
#define PKT_DRIVER_STARTED 1
#define PKT_DRIVER_SHUTTING_DOWN 2
#define PKT_SETTINGS 3
#define PKT_CONNECT 4
#define PKT_CONNECT_RESPONSE 5
#define PKT_DATA 6
#define PKT_EOS 7
#define PKT_RESET 8
// Events that are communicated via IRQ from Amiga to Raspberry.
#define R_EVENT_A2R_TAIL 1
#define R_EVENT_R2A_HEAD 2
#define R_EVENT_STARTED 4
// Events that are communicated from Raspberry to Amiga.
#define A_EVENT_R2A_TAIL 1
#define A_EVENT_A2R_HEAD 2
// The communication area, used to create the physical channel.
struct ComArea
{
volatile UBYTE a_events;
volatile UBYTE a_enable;
volatile UBYTE r_events;
volatile UBYTE r_enable;
ULONG mem_base;
ULONG mem_size;
volatile UBYTE a2r_tail;
volatile UBYTE r2a_head;
volatile UBYTE r2a_tail;
volatile UBYTE a2r_head;
UBYTE a2r_buffer[256];
UBYTE r2a_buffer[256];
};
extern struct ComArea *ca;

View File

@@ -0,0 +1,23 @@
RTC_MATCHWORD: equ $4afc
RTF_AUTOINIT: equ (1<<7)
NT_DEVICE: equ 3
VERSION: equ 1
PRIORITY: equ 0
section code,code
moveq #-1,d0
rts
romtag:
dc.w RTC_MATCHWORD
dc.l romtag
dc.l endcode
dc.b RTF_AUTOINIT
dc.b VERSION
dc.b NT_DEVICE
dc.b PRIORITY
dc.l _device_name
dc.l _id_string
dc.l _auto_init_tables
endcode:

115
a314/a314device/sockets.c Normal file
View File

@@ -0,0 +1,115 @@
#include <proto/exec.h>
#include "sockets.h"
struct List active_sockets;
struct Socket *send_queue_head = NULL;
struct Socket *send_queue_tail = NULL;
static UBYTE next_stream_id = 1;
extern void NewList(struct List *l);
void init_sockets()
{
NewList(&active_sockets);
}
struct Socket *find_socket(void *sig_task, ULONG socket)
{
for (struct Node *node = active_sockets.lh_Head; node->ln_Succ != NULL; node = node->ln_Succ)
{
struct Socket *s = (struct Socket *)node;
if (s->sig_task == sig_task && s->socket == socket)
return s;
}
return NULL;
}
struct Socket *find_socket_by_stream_id(UBYTE stream_id)
{
for (struct Node *node = active_sockets.lh_Head; node->ln_Succ != NULL; node = node->ln_Succ)
{
struct Socket *s = (struct Socket *)node;
if (s->stream_id == stream_id)
return s;
}
return NULL;
}
static UBYTE allocate_stream_id()
{
// Bug: If all stream ids are allocated then this loop won't terminate.
while (1)
{
UBYTE stream_id = next_stream_id;
next_stream_id += 2;
if (find_socket_by_stream_id(stream_id) == NULL)
return stream_id;
}
}
static void free_stream_id(UBYTE stream_id)
{
// Currently do nothing.
// Could speed up allocate_stream_id using a bitmap?
}
struct Socket *create_socket(struct Task *task, ULONG id)
{
struct Socket *s = (struct Socket *)AllocMem(sizeof(struct Socket), MEMF_CLEAR);
s->sig_task = task;
s->socket = id;
s->stream_id = allocate_stream_id();
AddTail(&active_sockets, (struct Node *)s);
return s;
}
void delete_socket(struct Socket *s)
{
Remove((struct Node *)s);
free_stream_id(s->stream_id);
FreeMem(s, sizeof(struct Socket));
}
void add_to_send_queue(struct Socket *s, UWORD required_length)
{
s->send_queue_required_length = required_length;
s->next_in_send_queue = NULL;
if (send_queue_head == NULL)
send_queue_head = s;
else
send_queue_tail->next_in_send_queue = s;
send_queue_tail = s;
s->flags |= SOCKET_IN_SEND_QUEUE;
}
void remove_from_send_queue(struct Socket *s)
{
if (s->flags & SOCKET_IN_SEND_QUEUE)
{
if (send_queue_head == s)
{
send_queue_head = s->next_in_send_queue;
if (send_queue_head == NULL)
send_queue_tail = NULL;
}
else
{
struct Socket *curr = send_queue_head;
while (curr->next_in_send_queue != s)
curr = curr->next_in_send_queue;
curr->next_in_send_queue = s->next_in_send_queue;
if (send_queue_tail == s)
send_queue_tail = curr;
}
s->next_in_send_queue = NULL;
s->flags &= ~SOCKET_IN_SEND_QUEUE;
}
}

57
a314/a314device/sockets.h Normal file
View File

@@ -0,0 +1,57 @@
#include <exec/types.h>
#include <exec/lists.h>
// Used to store received data until application asks for it using a A314_READ.
struct QueuedData
{
struct QueuedData *next;
UWORD length;
UBYTE data[];
};
// Socket flags, these are bit masks, can have many of them.
#define SOCKET_RCVD_EOS_FROM_APP 0x0004
#define SOCKET_RCVD_EOS_FROM_RPI 0x0008
#define SOCKET_SENT_EOS_TO_APP 0x0010
#define SOCKET_SENT_EOS_TO_RPI 0x0020
#define SOCKET_CLOSED 0x0040
#define SOCKET_SHOULD_SEND_RESET 0x0080
#define SOCKET_IN_SEND_QUEUE 0x0100
struct Socket
{
struct MinNode node;
void *sig_task;
ULONG socket;
UBYTE stream_id;
UBYTE pad1;
UWORD flags;
struct A314_IORequest *pending_connect;
struct A314_IORequest *pending_read;
struct A314_IORequest *pending_write;
struct Socket *next_in_send_queue;
UWORD send_queue_required_length;
// Data that is received on the stream, but the application didn't read yet.
struct QueuedData *rq_head;
struct QueuedData *rq_tail;
};
extern struct Socket *send_queue_head;
extern struct Socket *send_queue_tail;
extern void init_sockets();
extern struct Socket *create_socket(struct Task *task, ULONG id);
extern void delete_socket(struct Socket *s);
extern struct Socket *find_socket(void *sig_task, ULONG socket);
extern struct Socket *find_socket_by_stream_id(UBYTE stream_id);
extern void add_to_send_queue(struct Socket *s, UWORD required_length);
extern void remove_from_send_queue(struct Socket *s);

136
a314/a314device/startup.c Normal file
View File

@@ -0,0 +1,136 @@
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/tasks.h>
#include <hardware/intbits.h>
#include <libraries/expansion.h>
#include <libraries/expansionbase.h>
#include <proto/exec.h>
#include <proto/expansion.h>
#include "a314.h"
#include "device.h"
#include "protocol.h"
#include "startup.h"
#include "fix_mem_region.h"
#include "debug.h"
#define A314_MANUFACTURER 0x07db
#define A314_PRODUCT 0xa3
#define TASK_PRIORITY 80
#define TASK_STACK_SIZE 1024
struct ExpansionBase *ExpansionBase;
struct MsgPort task_mp;
struct Task *task;
struct ComArea *ca;
struct InterruptData
{
struct Task *task;
struct ComArea *ca;
};
struct InterruptData interrupt_data;
struct Interrupt ports_interrupt;
extern void task_main();
extern void init_sockets();
extern void IntServer();
void NewList(struct List *l)
{
l->lh_Head = (struct Node *)&(l->lh_Tail);
l->lh_Tail = NULL;
l->lh_TailPred = (struct Node *)&(l->lh_Head);
}
static struct Task *create_task(char *name, long priority, char *initialPC, unsigned long stacksize)
{
char *stack = AllocMem(stacksize, MEMF_CLEAR);
if (stack == NULL)
return NULL;
struct Task *tc = AllocMem(sizeof(struct Task), MEMF_CLEAR | MEMF_PUBLIC);
if (tc == NULL)
{
FreeMem(stack, stacksize);
return NULL;
}
tc->tc_Node.ln_Type = NT_TASK;
tc->tc_Node.ln_Pri = priority;
tc->tc_Node.ln_Name = name;
tc->tc_SPLower = (APTR)stack;
tc->tc_SPUpper = (APTR)(stack + stacksize);
tc->tc_SPReg = (APTR)(stack + stacksize);
AddTask(tc, initialPC, 0);
return tc;
}
static void init_message_port()
{
task_mp.mp_Node.ln_Name = device_name;
task_mp.mp_Node.ln_Pri = 0;
task_mp.mp_Node.ln_Type = NT_MSGPORT;
task_mp.mp_Flags = PA_SIGNAL;
task_mp.mp_SigBit = SIGB_MSGPORT;
task_mp.mp_SigTask = task;
NewList(&(task_mp.mp_MsgList));
}
static void add_interrupt_handler()
{
interrupt_data.task = task;
interrupt_data.ca = ca;
ports_interrupt.is_Node.ln_Type = NT_INTERRUPT;
ports_interrupt.is_Node.ln_Pri = 0;
ports_interrupt.is_Node.ln_Name = device_name;
ports_interrupt.is_Data = (APTR)&interrupt_data;
ports_interrupt.is_Code = IntServer;
AddIntServer(INTB_PORTS, &ports_interrupt);
}
BOOL task_start()
{
ExpansionBase = (struct ExpansionBase *)OpenLibrary(EXPANSIONNAME, 0);
if (!ExpansionBase)
return FALSE;
struct ConfigDev *cd = FindConfigDev(NULL, A314_MANUFACTURER, A314_PRODUCT);
if (!cd)
{
CloseLibrary((struct Library *)ExpansionBase);
return FALSE;
}
ca = (struct ComArea *)cd->cd_BoardAddr;
if (!fix_memory())
return FALSE;
task = create_task(device_name, TASK_PRIORITY, (void *)task_main, TASK_STACK_SIZE);
if (task == NULL)
{
debug_printf("Unable to create task\n");
return FALSE;
}
init_message_port();
init_sockets();
ca->a_enable = 0;
unsigned char discard_value = ca->a_events;
ca->r_events = R_EVENT_STARTED;
add_interrupt_handler();
ca->a_enable = A_EVENT_R2A_TAIL;
return TRUE;
}

14
a314/a314device/startup.h Normal file
View File

@@ -0,0 +1,14 @@
#include <exec/types.h>
#include <exec/tasks.h>
#include <exec/ports.h>
#define SIGB_INT 14
#define SIGB_MSGPORT 15
#define SIGF_INT (1 << SIGB_INT)
#define SIGF_MSGPORT (1 << SIGB_MSGPORT)
extern struct Task *task;
extern struct MsgPort task_mp;
extern BOOL task_start();