From: Justin Wind Date: Sun, 20 May 2012 20:52:09 +0000 (-0700) Subject: further reorg of module abstraction and control interface X-Git-Url: http://git.squeep.com/?p=dcpu16;a=commitdiff_plain;h=94be117719b907e351bb2bf1096f6195daecd2aa further reorg of module abstraction and control interface --- diff --git a/dcpu16.c b/dcpu16.c index a0e1ad0..2b39baf 100644 --- a/dcpu16.c +++ b/dcpu16.c @@ -1369,13 +1369,13 @@ struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *vm, struct dcpu16_hw_module *mod, } 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; } @@ -1384,8 +1384,8 @@ struct dcpu16_hw *dcpu16_hw_new(struct dcpu16 *vm, struct dcpu16_hw_module *mod, 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; @@ -1393,7 +1393,24 @@ void dcpu16_hw_del(struct dcpu16_hw **hw) { } } -/* 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) { diff --git a/dcpu16.h b/dcpu16.h index 9ca3912..f70372a 100644 --- a/dcpu16.h +++ b/dcpu16.h @@ -68,10 +68,10 @@ struct dcpu16_acct_cb { }; 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; @@ -84,15 +84,25 @@ struct dcpu16_hw { 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 */ @@ -117,6 +127,9 @@ DCPU16_WORD dcpu16_disassemble_print(struct dcpu16 *, DCPU16_WORD); 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 *); diff --git a/hw_clock.c b/hw_clock.c index f70dcf4..83eaa80 100644 --- a/hw_clock.c +++ b/hw_clock.c @@ -104,4 +104,6 @@ struct dcpu16_hw_module dcpu16_hw_module_clock = { .template = &hw_, .data_init = clock_data_init_, .data_free = clock_data_free_, + .ctl = NULL, + .ctl_cmd = NULL, }; diff --git a/hw_keyboard.c b/hw_keyboard.c index 428971d..592b673 100644 --- a/hw_keyboard.c +++ b/hw_keyboard.c @@ -70,19 +70,12 @@ void keyboard_rfbevent_(rfbBool down, rfbKeySym key, rfbClientPtr cl) { 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) { @@ -112,7 +105,9 @@ void keyboard_reset_(struct dcpu16 *vm, struct dcpu16_hw *hw) { (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 @@ -191,6 +186,57 @@ void keyboard_data_free_(struct dcpu16_hw *hw) { } } +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)", @@ -209,4 +255,6 @@ struct dcpu16_hw_module dcpu16_hw_module_keyboard = { .template = &hw_, .data_init = keyboard_data_init_, .data_free = keyboard_data_free_, + .ctl = keyboard_data_ctl_, + .ctl_cmd = ctl_, }; diff --git a/hw_keyboard.h b/hw_keyboard.h index bb44a93..b8ea777 100644 --- a/hw_keyboard.h +++ b/hw_keyboard.h @@ -1,16 +1,8 @@ #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 */ diff --git a/hw_lem1802.c b/hw_lem1802.c index f17ebc7..06b0d5a 100644 --- a/hw_lem1802.c +++ b/hw_lem1802.c @@ -18,6 +18,12 @@ #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 */ @@ -337,15 +343,6 @@ rfbScreenInfoPtr lem1802_rfb_new(int argc, char *argv[]) { 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 @@ -512,20 +509,6 @@ static struct renderer_ { { 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; @@ -572,20 +555,106 @@ int lem1802_data_init_(struct dcpu16_hw *hw, void *data) { 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", @@ -604,5 +673,7 @@ struct dcpu16_hw_module dcpu16_hw_module_lem1802 = { .template = &hw_, .data_init = lem1802_data_init_, .data_free = lem1802_data_free_, + .ctl = lem1802_data_ctl_, + .ctl_cmd = ctl_, }; diff --git a/hw_lem1802.h b/hw_lem1802.h index df333e9..38ffbb0 100644 --- a/hw_lem1802.h +++ b/hw_lem1802.h @@ -9,12 +9,10 @@ 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 */ diff --git a/hw_spc2000.c b/hw_spc2000.c index f074895..c967822 100644 --- a/hw_spc2000.c +++ b/hw_spc2000.c @@ -103,4 +103,6 @@ struct dcpu16_hw_module dcpu16_hw_module_spc2000 = { .template = &hw_, .data_init = spc2000_data_init_, .data_free = spc2000_data_free_, + .ctl = NULL, + .ctl_cmd = NULL, }; diff --git a/vm-dcpu16.c b/vm-dcpu16.c index b8a3532..a6dc67d 100644 --- a/vm-dcpu16.c +++ b/vm-dcpu16.c @@ -564,18 +564,19 @@ COMMAND_IMPL(display) { 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"); @@ -586,6 +587,11 @@ COMMAND_IMPL(display) { 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; @@ -596,6 +602,16 @@ COMMAND_HELP(display) { ); 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); @@ -624,7 +640,11 @@ COMMAND_IMPL(keyboard) { 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)) {