}
memcpy(hw, mod->template, sizeof *hw);
hw->vm = vm;
+ hw->mod = mod;
if (mod->data_init(hw, data)) {
vm->warn_cb_("failed to init hw module data");
free(hw);
return NULL;
}
- hw->data_free = mod->data_free;
return hw;
}
void dcpu16_hw_del(struct dcpu16_hw **hw) {
if (hw) {
if (*hw) {
- if ((*hw)->data_free) {
- (*hw)->data_free(*hw);
+ if ((*hw)->mod->data_free) {
+ (*hw)->mod->data_free(*hw);
}
free(*hw);
*hw = NULL;
}
}
-/* dcpu16_hw_add
+/* dcpu16_hw_ctl
+ * invokes per-module controls for hw device
+ */
+int dcpu16_hw_ctl(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
+ if (hw) {
+ if (hw->mod) {
+ if (hw->mod->ctl) {
+ if (cmd) {
+ return hw->mod->ctl(hw, cmd, data_in, data_out);
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/* dcpu16_hw_attach
* registers new 'hardware' device with system
*/
int dcpu16_hw_attach(struct dcpu16 *vm, struct dcpu16_hw *hw) {
};
typedef void (dcpu16_hw_signal_t)(struct dcpu16 *, struct dcpu16_hw *);
-typedef void (dcpu16_hw_data_free_t)(struct dcpu16_hw *);
/* these are used to define hardware attached to the system */
struct dcpu16_hw {
struct dcpu16 *vm; /* which system do I belong to */
+ struct dcpu16_hw_module *mod; /* whence I came */
char *name_;
DCPU16_WORD id_l;
dcpu16_hw_signal_t *cycle;
dcpu16_hw_signal_t *reset;
- dcpu16_hw_data_free_t *data_free;
void *data;
};
+/* human-readable text describing hw module control operations, for convenience's sake */
+struct dcpu16_hw_ctl_cmd {
+ char *command;
+ char *data_in_type;
+ char *data_out_type;
+ char *description;
+};
typedef int (dcpu16_hw_data_init_t)(struct dcpu16_hw *, void *);
+typedef void (dcpu16_hw_data_free_t)(struct dcpu16_hw *);
+typedef int (dcpu16_hw_ctl_t)(struct dcpu16_hw *, const char *, void *, void *);
struct dcpu16_hw_module {
struct dcpu16_hw *template;
dcpu16_hw_data_init_t *data_init;
dcpu16_hw_data_free_t *data_free;
+ dcpu16_hw_ctl_t *ctl;
+ struct dcpu16_hw_ctl_cmd *ctl_cmd;
};
/* instantiate a new core */
struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *, struct dcpu16_hw_module *, void *);
void dcpu16_hw_del(struct dcpu16_hw **);
+/* set options on hardware objects */
+int dcpu16_hw_ctl(struct dcpu16_hw *, const char *, void *, void *);
+
/* register new 'hardware' device with system */
int dcpu16_hw_attach(struct dcpu16 *, struct dcpu16_hw *);
.template = &hw_,
.data_init = clock_data_init_,
.data_free = clock_data_free_,
+ .ctl = NULL,
+ .ctl_cmd = NULL,
};
struct dcpu16_hw *hw = (struct dcpu16_hw *)cl->screen->screenData;
struct keyboard_ *keyboard = (struct keyboard_ *)hw->data;
- keysym_rfbtodcpu(key, &dcpu_key);
+ hw->vm->trace_cb_("%s>> down:%u rfb_key:0x%04x", down, key);
- fprintf(stderr, "%s: down:%u key:0x%04x dcpu_key:0x%04x\n",
- __func__,
- down,
- key,
- dcpu_key);
-
- fprintf(stderr, "%s: hw:%p name:%s vm:%p\n",
- __func__,
- VOIDP(hw),
- hw->name_,
- VOIDP(hw->vm));
+ if (keysym_rfbtodcpu(key, &dcpu_key)) {
+ /* unhandled key event */
+ return;
+ }
keyboard->keys_pressed[dcpu_key] = (down ? 1 : 0);
if (down) {
(void)vm;
keyboard->interrupt_message = 0;
- memset(keyboard->buf, 0, keyboard->buf_sz);
+ keyboard->buf_head = 0;
+ keyboard->buf_tail = 0;
+ memset(keyboard->keys_pressed, 0, sizeof keyboard->keys_pressed);
}
static
}
}
+static struct dcpu16_hw_ctl_cmd ctl_[] = {
+ { "buffer_size", "const size_t *", "size_t *", "get or set current buffer size" },
+ { "associate_rfbScreen", "rfbScreenInfoPtr", "NULL", "associates this keyboard instance with an rfb display" },
+ { NULL, NULL, NULL, NULL }
+};
+static
+int keyboard_data_ctl_(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
+ if (strcmp(cmd, "buffer_size") == 0) {
+ struct keyboard_ *keyboard = (struct keyboard_ *)hw->data;
+ void *tmp_ptr;
+ const size_t *buf_sz_in = (const size_t *)data_in;
+ size_t *buf_sz_out = (size_t *)data_out;
+
+ if (buf_sz_out) {
+ *buf_sz_out = keyboard->buf_sz;
+ }
+
+ if (buf_sz_in) {
+ hw->vm->trace_cb_("%s>> resizing buffer from %zu to %zu", __func__, keyboard->buf_sz, *buf_sz_in);
+
+ tmp_ptr = realloc(keyboard->buf, *buf_sz_in);
+ if (tmp_ptr == NULL) {
+ hw->vm->warn_cb_("%s():%s", "realloc", strerror(errno));
+ return -1;
+ }
+ keyboard->buf = tmp_ptr;
+ keyboard->buf_sz = *buf_sz_in;
+ keyboard->buf_head = keyboard->buf_tail = 0;
+ }
+
+ return 0;
+ }
+
+#ifdef HAVE_LIBVNCSERVER
+ if (strcmp(cmd, "associate_rfbScreen") == 0) {
+ rfbScreenInfoPtr rfbScreen = (rfbScreenInfoPtr)data_in;
+ (void)data_out;
+
+ if (rfbScreen == NULL)
+ return -EFAULT;
+
+ rfbScreen->screenData = hw;
+ rfbScreen->kbdAddEvent = keyboard_rfbevent_;
+
+ return 0;
+ }
+#endif /* HAVE_LIBVNCSERVER */
+
+ return -EINVAL;
+}
+
static struct dcpu16_hw hw_ = {
.vm = NULL,
.name_ = "Generic Keyboard (compatible)",
.template = &hw_,
.data_init = keyboard_data_init_,
.data_free = keyboard_data_free_,
+ .ctl = keyboard_data_ctl_,
+ .ctl_cmd = ctl_,
};
#ifndef KEYBOARD_H_Y2G5EOAS
#define KEYBOARD_H_Y2G5EOAS
-#ifdef HAVE_LIBVNCSERVER
-#include "rfb/rfb.h"
-#endif /* HAVE_LIBVNCSERVER */
-
#include "dcpu16.h"
extern struct dcpu16_hw_module dcpu16_hw_module_keyboard;
-#ifdef HAVE_LIBVNCSERVER
-void keyboard_vnc_associate(struct dcpu16_hw *, rfbScreenInfoPtr);
-#endif /* HAVE_LIBVNCSERVER */
-
#endif /* KEYBOARD_H_Y2G5EOAS */
#include "chargen-4x8.h"
#include "hw_lem1802.h"
+/* lem1802
+ *
+ * TODO:
+ * multiple vnc displays
+ */
+
#ifdef DEBUG
#define TRACE(...) do { printf("[debug] "); printf(__VA_ARGS__); printf("\n"); } while (0)
#else /* DEBUG */
return s;
}
-/* set up a new screen to see our pixels */
-void lem1802_vnc_associate(struct dcpu16_hw *hw, rfbScreenInfoPtr s) {
- struct lem1802_ *display = (struct lem1802_ *)hw->data;
-
- s->desktopName = "NYA ELEKTRISKA LEM1802";
- s->frameBuffer = (char *)display->pixbuf;
-
- TRACE("%s>> s:%p\n", __func__, VOIDP(s));
-}
/* notify rfb server that pixels may have changed */
static
{ NULL, NULL, NULL }
};
-int lem1802_renderer_set(struct dcpu16_hw *hw, const char *renderer, void *data) {
- struct renderer_ *r;
-
- for (r = lem1802_renderers_; r->renderer; r++) {
- if (strcmp(renderer, r->name) == 0) {
- ((struct lem1802_ *)(hw->data))->render = r->renderer;
- ((struct lem1802_ *)(hw->data))->renderer_data = data;
- TRACE("%s>> renderer set to %s", __func__, renderer);
- return 0;
- }
- }
-
- return -1;
-}
char *lem1802_renderers_iter(void **iterp, char **name, char **args) {
struct renderer_ **r = (struct renderer_ **)iterp;
void lem1802_data_free_(struct dcpu16_hw *hw) {
if (hw) {
if (hw->data) {
- /* FIXME: free renderer data */
- hw->vm->warn_cb_("FIXME");
-
if (((struct lem1802_ *)(hw->data))->pixbuf) {
free(((struct lem1802_ *)(hw->data))->pixbuf);
((struct lem1802_ *)(hw->data))->pixbuf = NULL;
}
-
free(hw->data);
hw->data = NULL;
}
}
}
+static struct dcpu16_hw_ctl_cmd ctl_[] = {
+ { "blink_rate", "const unsigned int *rate", "unsigned int *rate", "sets or gets cycles per blink toggle" },
+ { "refresh_rate", "const unsigned int *rate", "unsigned int *rate", "sets or gets cycles per screen refresh" },
+#ifdef HAVE_LIBVNCSERVER
+ { "associate_rfbScreen", "rfbScreenInfoPtr", "NULL", "associates this lem1802 instance with an rfb display" },
+#endif /* HAVE_LIBVNCSERVER */
+ { "renderer", "const char *", "NULL", "sets this lem1802 instance to use renderer" },
+ { "renderer_data", "void *", "NULL", "sets renderer-specific data" },
+ { NULL, NULL, NULL, NULL }
+};
+int lem1802_data_ctl_(struct dcpu16_hw *hw, const char *cmd, void *data_in, void *data_out) {
+ if (strcmp(cmd, "blink_rate") == 0) {
+ struct lem1802_ *display = (struct lem1802_ *)hw->data;
+ const unsigned int *rate_in = (const unsigned int *)data_in;
+ unsigned int *rate_out = (unsigned int *)data_out;
+
+ if (rate_out) {
+ *rate_out = display->blink_rate;
+ }
+
+ if (rate_in) {
+ display->blink_rate = *rate_in;
+ }
+
+ return 0;
+ }
+
+ if (strcmp(cmd, "refresh_rate") == 0) {
+ struct lem1802_ *display = (struct lem1802_ *)hw->data;
+ const unsigned int *rate_in = (const unsigned int *)data_in;
+ unsigned int *rate_out = (unsigned int *)data_out;
+
+ if (rate_out) {
+ *rate_out = display->refresh_rate;
+ }
+
+ if (rate_in) {
+ display->refresh_rate = *rate_in;
+ }
+
+ return 0;
+ }
+
+#ifdef HAVE_LIBVNCSERVER
+ if (strcmp(cmd, "associate_rfbScreen") == 0) {
+ struct lem1802_ *display = (struct lem1802_ *)hw->data;
+ rfbScreenInfoPtr rfbScreen = (rfbScreenInfoPtr)data_out;
+ (void)data_in;
+
+ if (rfbScreen == NULL)
+ return -EFAULT;
+
+ rfbScreen->desktopName = "NYA ELEKTRISKA LEM1802";
+ rfbScreen->frameBuffer = (char *)display->pixbuf;
+
+ return 0;
+ }
+#endif /* HAVE_LIBVNCSERVER */
+
+ if (strcmp(cmd, "renderer") == 0) {
+ struct lem1802_ *display = (struct lem1802_ *)hw->data;
+ char *renderer = (char *)data_in;
+ (void)data_out;
+ struct renderer_ *r;
+
+ for (r = lem1802_renderers_; r->renderer; r++) {
+ if (strcmp(renderer, r->name) == 0) {
+ display->render = r->renderer;
+ TRACE("%s>> renderer set to %s", __func__, renderer);
+ return 0;
+ }
+ }
+
+ hw->vm->warn_cb_("unknown renderer '%s'", renderer);
+
+ return -ENOENT;
+ }
+
+ if (strcmp(cmd, "renderer_data") == 0) {
+ struct lem1802_ *display = (struct lem1802_ *)hw->data;
+ (void)data_out;
+
+ display->renderer_data = data_in;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
static struct dcpu16_hw hw_ = {
.name_ = "LEM1802 - Low Energy Monitor",
.template = &hw_,
.data_init = lem1802_data_init_,
.data_free = lem1802_data_free_,
+ .ctl = lem1802_data_ctl_,
+ .ctl_cmd = ctl_,
};
extern struct dcpu16_hw_module dcpu16_hw_module_lem1802;
-int lem1802_renderer_set(struct dcpu16_hw *, const char *, void *);
char *lem1802_renderers_iter(void **, char **, char **);
#ifdef HAVE_LIBVNCSERVER
rfbScreenInfoPtr lem1802_rfb_new(int argc, char *argv[]);
-void lem1802_vnc_associate(struct dcpu16_hw *, rfbScreenInfoPtr);
#endif /* HAVE_LIBVNCSERVER */
#endif /* LEM1802_H_WH5E5NOE */
.template = &hw_,
.data_init = spc2000_data_init_,
.data_free = spc2000_data_free_,
+ .ctl = NULL,
+ .ctl_cmd = NULL,
};
return 0;
}
- lem1802_vnc_associate(hw, s->screen);
+ if (dcpu16_hw_ctl(hw, "associate_rfbScreen", s->screen, NULL)) {
+ fprintf(stderr, "failed to configure display/vnc");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
s->attached_display = hw;
rfbScreen_start(s->screen);
renderer_data = s->screen;
}
#endif /* HAVE_LIBVNCSERVER */
- if (lem1802_renderer_set(hw, renderer, renderer_data)) {
- fprintf(stderr, "failed to set back-end renderer for display\n");
- dcpu16_hw_del(&hw);
- return 0;
- }
+ dcpu16_hw_ctl(hw, "renderer", (char *)renderer, NULL);
+ dcpu16_hw_ctl(hw, "renderer_data", renderer_data, NULL);
if (dcpu16_hw_attach(vm, hw)) {
fprintf(stderr, "failed to attach new display\n");
return 0;
}
COMMAND_HELP(display) {
+ struct renderer_ {
+ char *name;
+ char *args;
+ int (*renderer)(void *, void *, size_t, size_t);
+ } *r;
char *name, *args;
void *iter;
);
fprintf(f, "Supported renderers:\n");
+
+ if (dcpu16_hw_module_lem1802.ctl(NULL, "get_renderers", NULL, &r)) {
+ fprintf(stderr, "error fetching list of renderers\n");
+ return;
+ }
+
+ while (r->name) {
+ fprintf(f, "name:%s args:%s\n", r->name, r->args);
+ }
+
iter = NULL;
while ( (lem1802_renderers_iter(&iter, &name, &args)) ) {
fprintf(f, "\t%s %s\n", name, args);
dcpu16_hw_del(&hw);
return 0;
}
- keyboard_vnc_associate(hw, s->screen);
+ if (dcpu16_hw_ctl(hw, "associate_rfbScreen", s->screen, NULL)) {
+ fprintf(stderr, "failed to configure keyboard/vnc\n");
+ dcpu16_hw_del(&hw);
+ return 0;
+ }
s->attached_keyboard = hw;
if (dcpu16_hw_attach(vm, hw)) {