--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/symbian-qemu-0.9.1-12/qemu-symbian-svp/python-plugin.c Fri Jul 31 15:01:17 2009 +0100
@@ -0,0 +1,1940 @@
+#include "Python.h"
+#include "structmember.h"
+#include "hw/hw.h"
+#include "sysemu.h"
+#include "devtree.h"
+#include "qemu-char.h"
+#include "display_state.h"
+#include "hw/gui.h"
+#include "hw/fb_render_engine.h"
+#include "qemu-timer.h"
+
+static void qemu_py_die(void)
+{
+ PyErr_Print();
+ exit(1);
+}
+
+#define qemu_py_assert(x) do { if (!(x)) { qemu_py_die(); } } while (0)
+
+static void qemu_py_load_module(const char *name)
+{
+ PyObject *module;
+ module = PyImport_ImportModule(name);
+ if (!module)
+ qemu_py_die();
+}
+
+static int64_t qemu_py_int64_from_pynum(PyObject *ob)
+{
+ if (PyInt_Check(ob))
+ return PyInt_AsLong(ob);
+ return PyLong_AsLongLong(ob);
+}
+
+static uint64_t qemu_py_uint64_from_pynum(PyObject *ob)
+{
+ if (PyInt_Check(ob))
+ return PyInt_AsUnsignedLongMask(ob);
+ return PyLong_AsUnsignedLongLongMask(ob);
+}
+
+typedef struct {
+ PyObject_HEAD
+ PyObject *size;
+ PyObject *readl;
+ PyObject *writel;
+} qemu_py_ioregion;
+
+static void qemu_py_ioregion_dealloc(qemu_py_ioregion *self)
+{
+ Py_CLEAR(self->size);
+ Py_CLEAR(self->readl);
+ Py_CLEAR(self->writel);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int qemu_py_ioregion_init(qemu_py_ioregion *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"size", "readl", "writel", NULL};
+ PyObject *obsize;
+ PyObject *readl;
+ PyObject *writel;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|OO", kwlist,
+ &obsize, &readl, &writel))
+ return -1;
+
+ Py_INCREF(obsize);
+ self->size = obsize;
+ Py_INCREF(readl);
+ self->readl = readl;
+ Py_INCREF(writel);
+ self->writel = writel;
+
+ return 0;
+}
+
+static PyMemberDef qemu_py_ioregion_members[] = {
+ {"size", T_OBJECT, offsetof(qemu_py_ioregion, size), 0,
+ "size"},
+ {"readl", T_OBJECT, offsetof(qemu_py_ioregion, readl), 0,
+ "32-bit read"},
+ {"writel", T_OBJECT, offsetof(qemu_py_ioregion, writel), 0,
+ "32-bit write"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_ioregionType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.ioregion", /* tp_name */
+ sizeof(qemu_py_ioregion), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_ioregion_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU IORegion", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ qemu_py_ioregion_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_ioregion_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ QEMUFile *f;
+} qemu_py_file;
+
+static void qemu_py_file_dealloc(qemu_py_file *self)
+{
+ self->f = NULL;
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int qemu_py_file_init(qemu_py_file *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"f", NULL};
+ PyObject *obdata;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obdata))
+ return -1;
+
+ self->f = PyCObject_AsVoidPtr(obdata);
+ if (PyErr_Occurred())
+ return -1;
+
+ return 0;
+}
+
+static PyObject *qemu_py_file_get_u32(qemu_py_file *self, PyObject *args)
+{
+ uint32_t val;
+
+ if (self->f) {
+ val = qemu_get_be32(self->f);
+ return PyLong_FromUnsignedLong(val);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_file_put_u32(qemu_py_file *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"value", NULL};
+ PyObject *obval;
+ uint32_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obval))
+ return NULL;
+
+ val = qemu_py_uint64_from_pynum(obval);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (self->f)
+ qemu_put_be32(self->f, val);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_file_get_u64(qemu_py_file *self, PyObject *args)
+{
+ uint64_t val;
+
+ if (self->f) {
+ val = qemu_get_be64(self->f);
+ return PyLong_FromUnsignedLongLong(val);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_file_get_s64(qemu_py_file *self, PyObject *args)
+{
+ int64_t val;
+
+ if (self->f) {
+ val = qemu_get_be64(self->f);
+ return PyLong_FromLongLong(val);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_file_put_u64(qemu_py_file *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"value", NULL};
+ PyObject *obval;
+ uint64_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obval))
+ return NULL;
+
+ val = qemu_py_uint64_from_pynum(obval);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (self->f)
+ qemu_put_be64(self->f, val);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_file_put_s64(qemu_py_file *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"value", NULL};
+ PyObject *obval;
+ int64_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obval))
+ return NULL;
+
+ val = qemu_py_int64_from_pynum(obval);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (self->f)
+ qemu_put_be64(self->f, val);
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef qemu_py_file_methods[] = {
+ {"get_u32", (PyCFunction)qemu_py_file_get_u32, METH_NOARGS,
+ "Read unsigned 32-bit value"},
+ {"put_u32", (PyCFunction)qemu_py_file_put_u32, METH_VARARGS|METH_KEYWORDS,
+ "Write unsigned 32-bit value"},
+ {"get_u64", (PyCFunction)qemu_py_file_get_u64, METH_NOARGS,
+ "Read unsigned 64-bit value"},
+ {"put_u64", (PyCFunction)qemu_py_file_put_u64, METH_VARARGS|METH_KEYWORDS,
+ "Write unsigned 64-bit value"},
+ {"get_s64", (PyCFunction)qemu_py_file_get_s64, METH_NOARGS,
+ "Read signed 64-bit value"},
+ {"put_s64", (PyCFunction)qemu_py_file_put_s64, METH_VARARGS|METH_KEYWORDS,
+ "Write signed 64-bit value"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_fileType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.file", /* tp_name */
+ sizeof(qemu_py_file), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_file_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU File Object", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ qemu_py_file_methods, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_file_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ ptimer_state *ptimer;
+} qemu_py_ptimer;
+
+static void qemu_py_ptimer_dealloc(qemu_py_ptimer *self)
+{
+ self->ptimer = NULL;
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static void qemu_py_ptimer_tick(void *opaque)
+{
+ PyObject *fn = opaque;
+ PyObject *obval;
+
+ obval = PyObject_CallFunctionObjArgs(fn, NULL);
+ qemu_py_assert(obval);
+ Py_DECREF(obval);
+}
+
+static int qemu_py_ptimer_init(qemu_py_ptimer *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"tick", "freq", NULL};
+ PyObject *tick;
+ PyObject *obfreq = NULL;
+ uint64_t freq;
+ QEMUBH *bh;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O", kwlist,
+ &tick, &obfreq))
+ return -1;
+
+ if (!PyCallable_Check(tick)) {
+ PyErr_SetString(PyExc_TypeError, "tick handler must be callable");
+ return -1;
+ }
+ if (obfreq) {
+ freq = qemu_py_uint64_from_pynum(obfreq);
+ if (PyErr_Occurred())
+ return -1;
+ } else {
+ freq = 0;
+ }
+ Py_INCREF(tick);
+ bh = qemu_bh_new(qemu_py_ptimer_tick, tick);
+ self->ptimer = ptimer_init(bh);
+ if (freq)
+ ptimer_set_freq(self->ptimer, freq);
+
+ return 0;
+}
+
+static PyObject *qemu_py_ptimer_run(qemu_py_ptimer *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"oneshot", NULL};
+ int oneshot;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", kwlist, &oneshot))
+ return NULL;
+
+ ptimer_run(self->ptimer, oneshot != 0);
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_ptimer_stop(qemu_py_ptimer *self, PyObject *args)
+{
+ ptimer_stop(self->ptimer);
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_ptimer_set_limit(qemu_py_ptimer *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"limit", "reload", NULL};
+ PyObject *oblimit;
+ uint64_t limit;
+ int reload;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &oblimit,
+ &reload))
+ return NULL;
+
+ limit = qemu_py_uint64_from_pynum(oblimit);
+ if (PyErr_Occurred())
+ return NULL;
+
+ ptimer_set_limit(self->ptimer, limit, reload != 0);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_ptimer_get(qemu_py_ptimer *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"f", NULL};
+ qemu_py_file *f;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
+ &qemu_py_fileType, &f))
+ return NULL;
+
+ qemu_get_ptimer(f->f, self->ptimer);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_ptimer_put(qemu_py_ptimer *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"f", NULL};
+ qemu_py_file *f;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
+ &qemu_py_fileType, &f))
+ return NULL;
+
+ qemu_put_ptimer(f->f, self->ptimer);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_ptimer_get_count(qemu_py_ptimer *self, void *closure)
+{
+ return PyLong_FromUnsignedLongLong(ptimer_get_count(self->ptimer));
+}
+
+static int qemu_py_ptimer_set_count(qemu_py_ptimer *self, PyObject *obval,
+ void *closure)
+{
+ uint64_t val;
+ if (obval == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Cannot delete ptimer count");
+ return -1;
+ }
+
+ val = qemu_py_uint64_from_pynum(obval);
+ if (PyErr_Occurred())
+ return -1;
+
+ ptimer_set_count(self->ptimer, val);
+
+ return 0;
+}
+
+static PyGetSetDef qemu_py_ptimer_getseters [] = {
+ {"count", (getter)qemu_py_ptimer_get_count,
+ (setter)qemu_py_ptimer_set_count,
+ "current counter value", NULL},
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef qemu_py_ptimer_methods[] = {
+ {"run", (PyCFunction)qemu_py_ptimer_run, METH_VARARGS|METH_KEYWORDS,
+ "Start timer"},
+ {"stop", (PyCFunction)qemu_py_ptimer_stop, METH_NOARGS,
+ "Stop timer"},
+ {"set_limit", (PyCFunction)qemu_py_ptimer_set_limit,
+ METH_VARARGS|METH_KEYWORDS,
+ "Set reload value"},
+ {"get", (PyCFunction)qemu_py_ptimer_get, METH_VARARGS|METH_KEYWORDS,
+ "Restore state"},
+ {"put", (PyCFunction)qemu_py_ptimer_put, METH_VARARGS|METH_KEYWORDS,
+ "Save state"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_ptimerType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.ptimer", /* tp_name */
+ sizeof(qemu_py_ptimer), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_ptimer_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU Periodic Timer", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ qemu_py_ptimer_methods, /* tp_methods */
+ 0, /* tp_members */
+ qemu_py_ptimer_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_ptimer_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ render_data *rdata;
+} qemu_py_palette;
+
+static void qemu_py_palette_dealloc(qemu_py_palette *self)
+{
+ self->rdata = NULL;
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int qemu_py_palette_init(qemu_py_palette *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"rdata", NULL};
+ PyObject *obdata;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obdata))
+ return -1;
+
+ self->rdata = PyCObject_AsVoidPtr(obdata);
+ if (PyErr_Occurred())
+ return -1;
+
+ return 0;
+}
+
+static Py_ssize_t qemu_py_palette_len(PyObject *o)
+{
+ return 256;
+}
+
+static PyObject *qemu_py_palette_getitem(PyObject *o, Py_ssize_t i)
+{
+ qemu_py_palette *self = (qemu_py_palette *)o;
+
+ if (i < 0 || i >= 256) {
+ PyErr_SetString(PyExc_ValueError, "Palette index must be 0-255");
+ return NULL;
+ }
+
+ return PyLong_FromUnsignedLong(get_palette_value(self->rdata, i));
+}
+
+static int qemu_py_palette_setitem(PyObject *o, Py_ssize_t i, PyObject *obval)
+{
+ qemu_py_palette *self = (qemu_py_palette *)o;
+ uint32_t val;
+
+ if (i < 0 || i >= 256) {
+ PyErr_SetString(PyExc_ValueError, "Palette index must be 0-255");
+ return -1;
+ }
+
+ val = PyLong_AsUnsignedLongMask(obval);
+ if (PyErr_Occurred())
+ return -1;
+ set_palette_value(self->rdata, i, val);
+ return 0;
+}
+
+static PySequenceMethods qemu_py_palette_seq = {
+ .sq_length = qemu_py_palette_len,
+ .sq_item = qemu_py_palette_getitem,
+ .sq_ass_item = qemu_py_palette_setitem
+};
+
+static PyTypeObject qemu_py_paletteType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.palette", /* tp_name */
+ sizeof(qemu_py_palette), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_palette_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ &qemu_py_palette_seq, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU Framebuffer Palette", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ 0, /* tp_methods */
+ 0, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_palette_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+typedef struct {
+ PyObject_HEAD
+ render_data *rdata;
+ DisplayState *ds;
+ PyObject *update_cb;
+ PyObject *palette;
+ int need_update;
+} qemu_py_render;
+
+static void qemu_py_render_dealloc(qemu_py_render *self)
+{
+ if (self->rdata)
+ destroy_render_data(self->rdata);
+ self->rdata = NULL;
+ Py_CLEAR(self->palette);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static void qemu_py_update_display(void *opaque)
+{
+ qemu_py_render *self = opaque;
+ PyObject *obval;
+ PyObject *fn;
+ int do_update;
+
+ if (nographic || ds_get_bits_per_pixel(self->ds) == 0)
+ return;
+
+ fn = self->update_cb;
+
+ if (fn && PyCallable_Check(fn)) {
+ obval = PyObject_CallFunctionObjArgs(fn, NULL);
+ qemu_py_assert(obval);
+ do_update = PyInt_AsLong(obval);
+ qemu_py_assert(!PyErr_Occurred());
+ Py_DECREF(obval);
+
+ if (!do_update)
+ return;
+ }
+
+ render(self->ds, self->rdata, self->need_update);
+ self->need_update = 0;
+}
+
+static void qemu_py_invalidate_display(void *opaque)
+{
+ qemu_py_render *self = opaque;
+ self->need_update = 1;
+}
+
+static int qemu_py_render_init(qemu_py_render *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"name", "width", "height", NULL};
+ int width;
+ int height;
+ char *name;
+ PyObject *ob;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "sii", kwlist,
+ &name, &width, &height))
+ return -1;
+
+ self->ds = gui_get_graphic_console(name,
+ qemu_py_update_display,
+ qemu_py_invalidate_display,
+ NULL, self);
+
+ if (!self->ds) {
+ PyErr_SetString(PyExc_AssertionError, "Display creation failed");
+ return -1;
+ }
+
+ if (width && height) {
+ if (!gui_resize_vt(self->ds, width, height)) {
+ /* can't resize */
+ width = height = 0;
+ }
+ }
+ if (!width)
+ width = ds_get_width(self->ds);
+ if (!height)
+ height = ds_get_height(self->ds);
+
+ self->rdata = create_render_data();
+ set_cols(self->rdata, width);
+ set_rows(self->rdata, height);
+
+ ob = PyCObject_FromVoidPtr(self->rdata, NULL);
+ if (!ob)
+ return -1;
+ self->palette =
+ PyObject_CallFunctionObjArgs((PyObject *)&qemu_py_paletteType,
+ ob, NULL);
+ if (!self->palette)
+ return -1;
+ Py_DECREF(ob);
+ return 0;
+}
+
+static PyObject *qemu_py_render_get(qemu_py_render *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"f", NULL};
+ qemu_py_file *f;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
+ &qemu_py_fileType, &f))
+ return NULL;
+
+ qemu_get_render_data(f->f, self->rdata);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_render_put(qemu_py_render *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"f", NULL};
+ qemu_py_file *f;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
+ &qemu_py_fileType, &f))
+ return NULL;
+
+ qemu_put_render_data(f->f, self->rdata);
+
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef qemu_py_render_members[] = {
+ {"update", T_OBJECT, offsetof(qemu_py_render, update_cb), 0,
+ "Display update callback"},
+ {"palette", T_OBJECT, offsetof(qemu_py_render, palette), 0,
+ "palette"},
+ {NULL} /* Sentinel */
+};
+
+enum {
+ QEMU_PY_FB_BASE,
+ QEMU_PY_FB_WIDTH,
+ QEMU_PY_FB_HEIGHT,
+ QEMU_PY_FB_ORIENTATION,
+ QEMU_PY_FB_BLANK,
+ QEMU_PY_FB_BPP,
+ QEMU_PY_FB_COLOR_ORDER,
+ QEMU_PY_FB_BYTE_ORDER,
+ QEMU_PY_FB_PIXEL_ORDER,
+ QEMU_PY_FB_ROW_PITCH
+};
+
+static PyObject *
+qemu_py_render_getattr(qemu_py_render *self, void *closure)
+{
+ /* FIXME: should be target_phys_addr_t? */
+ uint32_t val;
+ render_data *rdata = self->rdata;
+
+ switch ((size_t)closure) {
+ case QEMU_PY_FB_BASE:
+ val = get_fb_base_in_target(rdata);
+ break;
+ case QEMU_PY_FB_WIDTH:
+ val = get_cols(rdata);
+ break;
+ case QEMU_PY_FB_HEIGHT:
+ val = get_rows(rdata);
+ break;
+ case QEMU_PY_FB_ORIENTATION:
+ val = get_orientation(rdata);
+ break;
+ case QEMU_PY_FB_BLANK:
+ val = get_blank_mode(rdata);
+ break;
+ case QEMU_PY_FB_BPP:
+ switch (get_src_bpp(rdata)) {
+ case BPP_SRC_1: val = 1; break;
+ case BPP_SRC_2: val = 2; break;
+ case BPP_SRC_4: val = 4; break;
+ case BPP_SRC_8: val = 8; break;
+ case BPP_SRC_15: val = 15; break;
+ case BPP_SRC_16: val = 16; break;
+ case BPP_SRC_24: val = 24; break;
+ case BPP_SRC_32: val = 32; break;
+ default: val = 0; break;
+ }
+ break;
+ case QEMU_PY_FB_COLOR_ORDER:
+ val = get_color_order(rdata);
+ break;
+ case QEMU_PY_FB_BYTE_ORDER:
+ val = get_byte_order(rdata);
+ break;
+ case QEMU_PY_FB_PIXEL_ORDER:
+ val = get_pixel_order(rdata);
+ break;
+ case QEMU_PY_FB_ROW_PITCH:
+ val = get_row_pitch(rdata);
+ break;
+ default:
+ val = -1;
+ }
+ return PyLong_FromUnsignedLong(val);
+}
+
+static int
+qemu_py_render_setattr(qemu_py_render *self, PyObject *obval, void *closure)
+{
+ /* FIXME: should be target_phys_addr_t? */
+ uint32_t val;
+ render_data *rdata = self->rdata;
+
+ if (obval == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Cannot delete attribute");
+ return -1;
+ }
+
+ val = PyInt_AsUnsignedLongMask(obval);
+ if (PyErr_Occurred())
+ return -1;
+
+ switch ((size_t)closure) {
+ case QEMU_PY_FB_BASE:
+ set_fb_base_from_target(rdata, val);
+ break;
+ case QEMU_PY_FB_WIDTH:
+ set_cols(rdata, val);
+ break;
+ case QEMU_PY_FB_HEIGHT:
+ set_rows(rdata, val);
+ break;
+ case QEMU_PY_FB_ORIENTATION:
+ set_orientation(rdata, val);
+ break;
+ case QEMU_PY_FB_BLANK:
+ set_blank_mode(rdata, val);
+ break;
+ case QEMU_PY_FB_BPP:
+ switch (val) {
+ case 1: val = BPP_SRC_1; break;
+ case 2: val = BPP_SRC_2; break;
+ case 4: val = BPP_SRC_4; break;
+ case 8: val = BPP_SRC_8; break;
+ case 15: val = BPP_SRC_15; break;
+ case 16: val = BPP_SRC_16; break;
+ case 24: val = BPP_SRC_24; break;
+ case 32: val = BPP_SRC_32; break;
+ default: val = get_src_bpp(rdata); break;
+ }
+ set_src_bpp(rdata, val);
+ break;
+ case QEMU_PY_FB_COLOR_ORDER:
+ set_color_order(rdata, val);
+ break;
+ case QEMU_PY_FB_BYTE_ORDER:
+ set_byte_order(rdata, val);
+ break;
+ case QEMU_PY_FB_PIXEL_ORDER:
+ set_pixel_order(rdata, val);
+ break;
+ case QEMU_PY_FB_ROW_PITCH:
+ set_row_pitch(rdata, val);
+ break;
+ default:
+ val = -1;
+ break;
+ }
+ return 0;
+}
+
+static PyGetSetDef qemu_py_render_getseters [] = {
+ {"base", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "base address", (void *)(size_t)QEMU_PY_FB_BASE},
+ {"width", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "screen width", (void *)(size_t)QEMU_PY_FB_WIDTH},
+ {"height", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "screen height", (void *)(size_t)QEMU_PY_FB_HEIGHT},
+ {"orientation", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "screen orientation", (void *)(size_t)QEMU_PY_FB_ORIENTATION},
+ {"blank", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "blanking mode", (void *)(size_t)QEMU_PY_FB_BLANK},
+ {"bpp", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "color depth", (void *)(size_t)QEMU_PY_FB_BPP},
+ {"color_order", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "color order", (void *)(size_t)QEMU_PY_FB_COLOR_ORDER},
+ {"byte_order", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "byte order", (void *)(size_t)QEMU_PY_FB_BYTE_ORDER},
+ {"pixel_order", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "pixel packing order", (void *)(size_t)QEMU_PY_FB_PIXEL_ORDER},
+ {"row_pitch", (getter)qemu_py_render_getattr,
+ (setter)qemu_py_render_setattr,
+ "row pitch", (void *)(size_t)QEMU_PY_FB_ROW_PITCH},
+ {NULL} /* Sentinel */
+
+};
+
+static PyMethodDef qemu_py_render_methods[] = {
+ {"get", (PyCFunction)qemu_py_render_get, METH_VARARGS|METH_KEYWORDS,
+ "Restore state"},
+ {"put", (PyCFunction)qemu_py_render_put, METH_VARARGS|METH_KEYWORDS,
+ "Save state"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_renderType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.render", /* tp_name */
+ sizeof(qemu_py_render), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_render_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU Framebuffer Render Engine", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ qemu_py_render_methods, /* tp_methods */
+ qemu_py_render_members, /* tp_members */
+ qemu_py_render_getseters, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_render_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+
+typedef struct {
+ PyObject_HEAD
+ CharDriverState *chr;
+ PyObject *can_receive_cb;
+ PyObject *receive_cb;
+ PyObject *event_cb;
+} qemu_py_chardev;
+
+static void qemu_py_chardev_dealloc(qemu_py_chardev *self)
+{
+ Py_CLEAR(self->can_receive_cb);
+ Py_CLEAR(self->receive_cb);
+ Py_CLEAR(self->event_cb);
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int qemu_py_chardev_can_receive(void *opaque)
+{
+ qemu_py_chardev *self = opaque;
+ PyObject *obval;
+ int val;
+
+ if (!self->can_receive_cb)
+ return 0;
+
+ obval = PyObject_CallFunctionObjArgs(self->can_receive_cb, NULL);
+ qemu_py_assert(obval);
+ val = PyInt_AsLong(obval);
+ qemu_py_assert(!PyErr_Occurred());
+ Py_DECREF(obval);
+ return val;
+}
+
+static void qemu_py_chardev_receive(void *opaque, const uint8_t *buf, int size)
+{
+ qemu_py_chardev *self = opaque;
+ PyObject *obval;
+ PyObject *obbuf;
+
+ if (!self->receive_cb)
+ return;
+
+ obbuf = PyBuffer_FromMemory((void *)buf, size);
+ qemu_py_assert(obbuf);
+ obval = PyObject_CallFunctionObjArgs(self->receive_cb, obbuf, NULL);
+ Py_DECREF(obbuf);
+ qemu_py_assert(obval);
+ Py_DECREF(obval);
+}
+
+static void qemu_py_chardev_event(void *opaque, int event)
+{
+ qemu_py_chardev *self = opaque;
+ PyObject *obval;
+ PyObject *obevent;
+
+ if (!self->event_cb)
+ return;
+
+ obevent = PyInt_FromLong(event);
+ qemu_py_assert(obevent);
+ obval = PyObject_CallFunctionObjArgs(self->event_cb, obevent, NULL);
+ Py_DECREF(obevent);
+ qemu_py_assert(obval);
+ Py_DECREF(obval);
+}
+
+static int qemu_py_chardev_init(qemu_py_chardev *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"chardev", NULL};
+ PyObject *obchr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obchr))
+ return -1;
+
+ self->chr = PyCObject_AsVoidPtr(obchr);
+ if (PyErr_Occurred())
+ return -1;
+
+ if (self->chr) {
+ qemu_chr_add_handlers(self->chr, qemu_py_chardev_can_receive,
+ qemu_py_chardev_receive,
+ qemu_py_chardev_event, self);
+ }
+
+ return 0;
+}
+
+static PyObject *qemu_py_chardev_set_handlers(qemu_py_chardev *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"can_receive", "receive", "event", NULL};
+ PyObject *obcan_receive;
+ PyObject *obreceive;
+ PyObject *obevent = Py_None;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|O", kwlist,
+ &obcan_receive, &obreceive, &obevent))
+ return NULL;
+
+ if (!self->chr)
+ Py_RETURN_NONE;
+
+ Py_CLEAR(self->can_receive_cb);
+ Py_CLEAR(self->receive_cb);
+ Py_CLEAR(self->event_cb);
+ if (!PyCallable_Check(obcan_receive)) {
+ PyErr_SetString(PyExc_TypeError,
+ "can_receive handler must be callable");
+ return NULL;
+ }
+ self->can_receive_cb = obcan_receive;
+ Py_INCREF(obcan_receive);
+ if (!PyCallable_Check(obreceive)) {
+ PyErr_SetString(PyExc_TypeError, "receive handler must be callable");
+ return NULL;
+ }
+ self->receive_cb = obreceive;
+ Py_INCREF(obreceive);
+ if (obevent != Py_None) {
+ if (!PyCallable_Check(obreceive)) {
+ PyErr_SetString(PyExc_TypeError, "event handler must be callable");
+ return NULL;
+ }
+ self->event_cb = obevent;
+ Py_INCREF(obevent);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_chardev_write(qemu_py_chardev *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"data", NULL};
+ PyObject *obdata;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obdata))
+ return NULL;
+
+ if (!self->chr)
+ Py_RETURN_NONE;
+
+ if (PyString_Check(obdata)) {
+ char *data;
+ Py_ssize_t len;
+ if (PyString_AsStringAndSize(obdata, &data, &len) < 0)
+ return NULL;
+ qemu_chr_write(self->chr, (uint8_t *)data, len);
+ } else {
+ uint8_t ch;
+ ch = PyInt_AsLong(obdata);
+ if (PyErr_Occurred())
+ return NULL;
+ qemu_chr_write(self->chr, &ch, 1);
+ }
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef qemu_py_chardev_members[] = {
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef qemu_py_chardev_methods[] = {
+ {"set_handlers", (PyCFunction)qemu_py_chardev_set_handlers,
+ METH_VARARGS|METH_KEYWORDS,
+ "Set event handlers"},
+ {"write", (PyCFunction)qemu_py_chardev_write, METH_VARARGS|METH_KEYWORDS,
+ "Write a byte or string"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_chardevType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.chardev", /* tp_name */
+ sizeof(qemu_py_chardev), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_chardev_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT, /* tp_flags */
+ "QEMU Character Device", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ qemu_py_chardev_methods, /* tp_methods */
+ qemu_py_chardev_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_chardev_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+
+typedef struct {
+ PyObject_HEAD
+ QEMUDevice *qdev;
+} qemu_py_devclass;
+
+static void qemu_py_devclass_dealloc(qemu_py_devclass *self)
+{
+ self->ob_type->tp_free((PyObject*)self);
+}
+
+static int qemu_py_devclass_init(qemu_py_devclass *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"qdev", NULL};
+ PyObject *obqdev;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obqdev))
+ return -1;
+
+ self->qdev = PyCObject_AsVoidPtr(obqdev);
+ if (PyErr_Occurred())
+ return -1;
+
+ return 0;
+}
+
+
+/* FIXME: Turn ths into an actual IRQ object? */
+static PyObject *qemu_py_set_irq_level(qemu_py_devclass *self, PyObject *args)
+{
+ int ok;
+ int irq_num;
+ int level;
+
+ ok = PyArg_ParseTuple(args, "ii", &irq_num, &level);
+ if (!ok)
+ return NULL;
+
+ if (!self->qdev) {
+ PyErr_SetString(PyExc_ValueError, "device not initialized");
+ return NULL;
+ }
+ qdev_set_irq_level(self->qdev, irq_num, level);
+
+ Py_RETURN_NONE;
+}
+
+/* PyLong_AsUnsignedLongLongMask doesn't seem to work on Int objects.
+ This wrapper automatically picks the right routine. */
+static target_phys_addr_t qemu_py_physaddr_from_pynum(PyObject *ob)
+{
+ if (PyInt_Check(ob))
+ return PyInt_AsUnsignedLongMask(ob);
+ return PyLong_AsUnsignedLongLongMask(ob);
+}
+
+static PyObject *qemu_py_dma_readb(qemu_py_chardev *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"addr", NULL};
+ PyObject *obaddr;
+ target_phys_addr_t addr;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obaddr))
+ return NULL;
+
+ addr = qemu_py_physaddr_from_pynum(obaddr);
+ if (PyErr_Occurred())
+ return NULL;
+
+ return PyInt_FromLong(ldub_phys(addr));
+}
+
+static PyObject *qemu_py_dma_writeb(qemu_py_chardev *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"addr", "value", NULL};
+ PyObject *obaddr;
+ PyObject *obval;
+ target_phys_addr_t addr;
+ uint8_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &obaddr, &obval))
+ return NULL;
+
+ addr = qemu_py_physaddr_from_pynum(obaddr);
+ if (PyErr_Occurred())
+ return NULL;
+
+ val = PyInt_AsLong(obval);
+ if (PyErr_Occurred())
+ return NULL;
+
+ stb_phys(addr, val);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_dma_readl(qemu_py_chardev *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"addr", NULL};
+ PyObject *obaddr;
+ target_phys_addr_t addr;
+ uint8_t buf[4];
+ uint32_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &obaddr))
+ return NULL;
+
+ addr = qemu_py_physaddr_from_pynum(obaddr);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (addr & 3) {
+ cpu_physical_memory_read(addr, buf, 4);
+ val = ldl_p(buf);
+ } else {
+ val = ldl_phys(addr);
+ }
+ return PyLong_FromUnsignedLong(val);
+}
+
+static PyObject *qemu_py_dma_writel(qemu_py_chardev *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"addr", "value", NULL};
+ PyObject *obaddr;
+ PyObject *obval;
+ target_phys_addr_t addr;
+ uint8_t buf[4];
+ uint32_t val;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist,
+ &obaddr, &obval))
+ return NULL;
+
+ addr = qemu_py_physaddr_from_pynum(obaddr);
+ if (PyErr_Occurred())
+ return NULL;
+
+ val = PyInt_AsLong(obval);
+ if (PyErr_Occurred())
+ return NULL;
+
+ if (addr & 3) {
+ stl_p(buf, val);
+ cpu_physical_memory_write(addr, buf, 4);
+ } else {
+ stl_phys(addr, val);
+ }
+
+ Py_RETURN_NONE;
+}
+
+static void qemu_py_set_irq_input(void *opaque, int irq, int level)
+{
+ PyObject *fn = opaque;
+ PyObject *obirq;
+ PyObject *oblevel;
+ PyObject *obval;
+
+ obirq = PyInt_FromLong(irq);
+ qemu_py_assert(obirq);
+ oblevel = level ? Py_True : Py_False;
+ Py_INCREF(oblevel);
+ obval = PyObject_CallFunctionObjArgs(fn, obirq, oblevel, NULL);
+ qemu_py_assert(obval);
+ Py_DECREF(obval);
+ Py_DECREF(obirq);
+ Py_DECREF(oblevel);
+}
+
+static PyObject *qemu_py_create_interrupts(qemu_py_devclass *self,
+ PyObject *args, PyObject *kwds)
+{
+ static char *kwlist[] = {"callback", "count", NULL};
+ PyObject *obcallback;
+ int count;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist,
+ &obcallback, &count))
+ return NULL;
+
+ if (!PyCallable_Check(obcallback)) {
+ PyErr_SetString(PyExc_TypeError, "irq handler must be callable");
+ return NULL;
+ }
+
+ Py_INCREF(obcallback);
+ qdev_create_interrupts(self->qdev, qemu_py_set_irq_input, obcallback,
+ count);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_dummy_loadsave(qemu_py_devclass *self, PyObject *args)
+{
+ Py_RETURN_NONE;
+}
+
+static PyMemberDef qemu_py_devclass_members[] = {
+#if 0
+ {"irqs", T_INT, offsetof(qemu_py_devclass, num_irqs), 0,
+ "Number of irqs"},
+#endif
+ {NULL} /* Sentinel */
+};
+
+static PyMethodDef qemu_py_devclass_methods[] = {
+ {"set_irq_level", (PyCFunction)qemu_py_set_irq_level, METH_VARARGS,
+ "Set IRQ state"},
+ {"create_interrupts", (PyCFunction)qemu_py_create_interrupts,
+ METH_VARARGS|METH_KEYWORDS,
+ "Create IRQ inputs"},
+ {"dma_readb", (PyCFunction)qemu_py_dma_readb, METH_VARARGS|METH_KEYWORDS,
+ "Read a byte from system memory"},
+ {"dma_writeb", (PyCFunction)qemu_py_dma_writeb, METH_VARARGS|METH_KEYWORDS,
+ "Write a byte to system memory"},
+ {"dma_readl", (PyCFunction)qemu_py_dma_readl, METH_VARARGS|METH_KEYWORDS,
+ "Read a 32-bit word from system memory"},
+ {"dma_writel", (PyCFunction)qemu_py_dma_writel, METH_VARARGS|METH_KEYWORDS,
+ "Write a 32-bit word to system memory"},
+ {"load", (PyCFunction)qemu_py_dummy_loadsave, METH_VARARGS,
+ "load snapshot state"},
+ {"save", (PyCFunction)qemu_py_dummy_loadsave, METH_VARARGS,
+ "save snapshot state"},
+ {NULL} /* Sentinel */
+};
+
+static PyTypeObject qemu_py_devclassType = {
+ PyObject_HEAD_INIT(NULL)
+ 0, /* ob_size */
+ "qemu.devclass", /* tp_name */
+ sizeof(qemu_py_devclass), /* tp_basicsize */
+ 0, /* tp_itemsize */
+ (destructor)qemu_py_devclass_dealloc, /* tp_dealloc */
+ 0, /* tp_print */
+ 0, /* tp_getattr */
+ 0, /* tp_setattr */
+ 0, /* tp_compare */
+ 0, /* tp_repr */
+ 0, /* tp_as_number */
+ 0, /* tp_as_sequence */
+ 0, /* tp_as_mapping */
+ 0, /* tp_hash */
+ 0, /* tp_call */
+ 0, /* tp_str */
+ 0, /* tp_getattro */
+ 0, /* tp_setattro */
+ 0, /* tp_as_buffer */
+ Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
+ "QEMU device class objects", /* tp_doc */
+ 0, /* tp_traverse */
+ 0, /* tp_clear */
+ 0, /* tp_richcompare */
+ 0, /* tp_weaklistoffset */
+ 0, /* tp_iter */
+ 0, /* tp_iternext */
+ qemu_py_devclass_methods, /* tp_methods */
+ qemu_py_devclass_members, /* tp_members */
+ 0, /* tp_getset */
+ 0, /* tp_base */
+ 0, /* tp_dict */
+ 0, /* tp_descr_get */
+ 0, /* tp_descr_set */
+ 0, /* tp_dictoffset */
+ (initproc)qemu_py_devclass_init, /* tp_init */
+ 0, /* tp_alloc */
+ 0, /* tp_new */
+};
+
+typedef struct
+{
+ PyObject *dev;
+ int n;
+ PyObject *region;
+} qemu_py_callback_info;
+
+static uint32_t qemu_py_read(void *opaque, target_phys_addr_t offset)
+{
+ qemu_py_callback_info *info = opaque;
+ PyObject *r;
+ PyObject *fn;
+ PyObject *oboffset;
+ PyObject *obval;
+ uint32_t val;
+
+ r = info->region;
+ qemu_py_assert(r);
+ fn = PyObject_GetAttrString(r, "readl");
+ qemu_py_assert(fn);
+ oboffset = PyInt_FromLong(offset);
+ obval = PyObject_CallFunctionObjArgs(fn, info->dev, oboffset, NULL);
+ Py_DECREF(oboffset);
+ Py_DECREF(fn);
+ qemu_py_assert(obval);
+ val = PyLong_AsUnsignedLongMask(obval);
+ qemu_py_assert(!PyErr_Occurred());
+ Py_DECREF(obval);
+ return val;
+}
+
+static void qemu_py_write(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ qemu_py_callback_info *info = opaque;
+ PyObject *r;
+ PyObject *fn;
+ PyObject *oboffset;
+ PyObject *obval;
+
+ r = info->region;
+ qemu_py_assert(r);
+ fn = PyObject_GetAttrString(r, "writel");
+ qemu_py_assert(fn);
+ oboffset = PyInt_FromLong(offset);
+ obval = PyLong_FromUnsignedLong(value);
+ PyObject_CallFunctionObjArgs(fn, info->dev, oboffset, obval, NULL);
+ Py_DECREF(oboffset);
+ Py_DECREF(obval);
+ Py_DECREF(fn);
+ qemu_py_assert(!PyErr_Occurred());
+}
+
+static CPUReadMemoryFunc *qemu_py_readfn[] = {
+ qemu_py_read,
+ qemu_py_read,
+ qemu_py_read
+};
+
+static CPUWriteMemoryFunc *qemu_py_writefn[] = {
+ qemu_py_write,
+ qemu_py_write,
+ qemu_py_write
+};
+
+static void qemu_py_dev_create(QEMUDevice *dev)
+{
+ PyObject *ob;
+ PyObject *devclass;
+ PyObject *regions;
+ PyObject *obqdev;
+ qemu_py_devclass *self;
+ qemu_py_callback_info *callbacks;
+ Py_ssize_t pos;
+ PyObject *properties;
+ PyObject *key;
+ PyObject *value;
+ int num_regions;
+ int i;
+
+ devclass = qdev_get_class_opaque(dev);
+ obqdev = PyCObject_FromVoidPtr(dev, NULL);
+ ob = PyObject_CallFunctionObjArgs(devclass, obqdev, NULL);
+ qemu_py_assert(ob);
+ Py_DECREF(obqdev);
+ self = (qemu_py_devclass *)ob;
+ self->qdev = dev;
+ qdev_set_opaque(dev, ob);
+
+ value = PyString_FromString(qdev_get_name(dev));
+ PyObject_SetAttrString(ob, "name", value);
+
+ regions = PyObject_GetAttrString(devclass, "regions");
+ qemu_py_assert(regions);
+ num_regions = PyList_Size(regions);
+ callbacks = qemu_mallocz(num_regions * sizeof(callbacks[0]));
+ for (i = 0; i < num_regions; i++) {
+ callbacks[i].dev = ob;
+ callbacks[i].n = i;
+ callbacks[i].region = PyList_GetItem(regions, i);
+ Py_INCREF(callbacks[i].region);
+ qdev_set_region_opaque(dev, i, &callbacks[i]);
+ }
+ Py_DECREF(regions);
+
+ properties = PyObject_GetAttrString(devclass, "properties");
+ qemu_py_assert(properties);
+ pos = 0;
+ while (PyDict_Next(properties, &pos, &key, &value)) {
+ char *key_name = PyString_AsString(key);
+ qemu_py_assert(key_name);
+ if (strcmp(key_name, "chardev") == 0) {
+ CharDriverState *chr;
+ PyObject *obchr;
+ chr = qdev_get_chardev(dev);
+ obchr = PyCObject_FromVoidPtr(chr, NULL);
+ qemu_py_assert(obchr);
+ value =
+ PyObject_CallFunctionObjArgs((PyObject *)&qemu_py_chardevType,
+ obchr, NULL);
+ qemu_py_assert(value);
+ Py_DECREF(obchr);
+ } else if (PyLong_Check(value) || PyInt_Check(value)) {
+ long intval;
+ intval = qdev_get_property_int(dev, key_name);
+ value = PyInt_FromLong(intval);
+ } else {
+ const char *strval;
+ strval = qdev_get_property_string(dev, key_name);
+ value = PyString_FromString(strval);
+ }
+ if (PyDict_SetItem(properties, key, value) < 0) {
+ Py_DECREF(value);
+ }
+
+ }
+ Py_DECREF(properties);
+
+ PyObject_CallMethod(ob, "create", NULL);
+ qemu_py_assert(!PyErr_Occurred());
+}
+
+static PyObject *qemu_py_create_file(QEMUFile *f)
+{
+ PyObject *obfile;
+ PyObject *obarg;
+
+ obarg = PyCObject_FromVoidPtr(f, NULL);
+ if (!obarg)
+ return NULL;
+ obfile = PyObject_CallFunctionObjArgs((PyObject *)&qemu_py_fileType,
+ obarg, NULL);
+ Py_DECREF(obarg);
+ return obfile;
+}
+
+static void qemu_py_save(QEMUFile *f, void *opaque)
+{
+ PyObject *self = opaque;
+ PyObject *obfile;
+ PyObject *obresult;
+
+
+ obfile = qemu_py_create_file(f);
+ qemu_py_assert(obfile);
+ obresult = PyObject_CallMethod(self, "save", "O", obfile);
+ qemu_py_assert(obresult);
+ Py_DECREF(obfile);
+ Py_DECREF(obresult);
+}
+
+static int qemu_py_load(QEMUFile *f, void *opaque, int version_id)
+{
+ PyObject *self = opaque;
+ PyObject *obfile;
+ PyObject *obresult;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ obfile = qemu_py_create_file(f);
+ qemu_py_assert(obfile);
+ obresult = PyObject_CallMethod(self, "load", "O", obfile);
+ /* TODO: Graceful error handling. */
+ qemu_py_assert(obresult);
+ Py_DECREF(obfile);
+ Py_DECREF(obresult);
+
+ return 0;
+}
+
+static PyObject *qemu_py_register_device(PyObject *self, PyObject *args)
+{
+ int ok;
+ QEMUDeviceClass *dc;
+ PyObject *devclass;
+ PyObject *regions;
+ PyObject *attr;
+ PyObject *properties;
+ Py_ssize_t pos;
+ PyObject *key;
+ PyObject *value;
+ int i;
+ char *name;
+ int num_irqs;
+
+ ok = PyArg_ParseTuple(args, "O", &devclass);
+ if (!ok)
+ return NULL;
+
+ if (!PyType_Check(devclass)
+ || !PyObject_IsSubclass(devclass, (PyObject *)&qemu_py_devclassType)) {
+
+ PyErr_SetString(PyExc_TypeError, "Expected qemu.devclass derivative");
+ return NULL;
+ }
+
+ Py_INCREF(devclass);
+
+ attr = PyObject_GetAttrString(devclass, "irqs");
+ if (!attr)
+ return NULL;
+ num_irqs = PyInt_AsLong(attr);
+ if (PyErr_Occurred())
+ return NULL;
+ Py_DECREF(attr);
+
+ attr = PyObject_GetAttrString(devclass, "name");
+ if (!attr)
+ return NULL;
+ name = PyString_AsString(attr);
+ if (PyErr_Occurred())
+ return NULL;
+
+ dc = qdev_new(name, qemu_py_dev_create, num_irqs);
+
+ Py_DECREF(attr);
+
+ qdev_add_class_opaque(dc, devclass);
+
+ regions = PyObject_GetAttrString(devclass, "regions");
+ if (!regions)
+ return NULL;
+ if (!PyList_Check(regions)) {
+ PyErr_SetString(PyExc_TypeError, "devclass.regions must be a list");
+ return NULL;
+ }
+ for (i = 0; i < PyList_Size(regions); i++) {
+ target_phys_addr_t size;
+ PyObject *r;
+
+ r = PyList_GetItem(regions, i);
+ if (!r)
+ return NULL;
+
+ attr = PyObject_GetAttrString(r, "size");
+ size = PyInt_AsLong(attr);
+ if (PyErr_Occurred())
+ return NULL;
+ qdev_add_registers(dc, qemu_py_readfn, qemu_py_writefn, size);
+ Py_DECREF(attr);
+ }
+ Py_DECREF(regions);
+
+ properties = PyObject_GetAttrString(devclass, "properties");
+ if (!properties)
+ return NULL;
+ if (!PyDict_Check(properties)) {
+ Py_DECREF(properties);
+ PyErr_SetString(PyExc_TypeError,
+ "qemu.devclass.properties must be a dict");
+ return NULL;
+ }
+ pos = 0;
+ while (PyDict_Next(properties, &pos, &key, &value)) {
+ char *key_name = PyString_AsString(key);
+ if (!key_name)
+ goto bad_property;
+ if (strcmp(key_name, "chardev") == 0) {
+ qdev_add_chardev(dc);
+ } else if (PyString_Check(value)) {
+ qdev_add_property_string(dc, key_name, PyString_AsString(value));
+ } else if (PyLong_Check(value) || PyInt_Check(value)) {
+ long intval;
+ intval = PyLong_AsLong(value);
+ if (PyErr_Occurred())
+ goto bad_property;
+ qdev_add_property_int(dc, key_name, PyLong_AsLong(value));
+ } else {
+ PyErr_SetString(PyExc_TypeError,
+ "qemu.devclass.properties value must be int or string");
+ bad_property:
+ Py_DECREF(properties);
+ return NULL;
+ }
+ }
+ Py_DECREF(properties);
+
+ /* TODO: Implement savevm versioning. */
+ qdev_add_savevm(dc, 1, qemu_py_save, qemu_py_load);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *qemu_py_get_clock(PyObject *self, PyObject *args)
+{
+ return PyLong_FromUnsignedLongLong((uint64_t)qemu_get_clock(vm_clock));
+}
+
+static PyObject *qemu_py_start_time(PyObject *self, PyObject *args)
+{
+ struct tm tm;
+ uint64_t t;
+ qemu_get_timedate(&tm, 0);
+ t = mktimegm(&tm);
+ return PyLong_FromUnsignedLongLong(t);
+}
+
+static void qemu_py_keyboard_event(void *opaque, int keycode)
+{
+ PyObject *fn = opaque;
+ PyObject *obval;
+ PyObject *obkey;
+
+ obkey = PyInt_FromLong(keycode);
+ obval = PyObject_CallFunctionObjArgs(fn, obkey, NULL);
+ qemu_py_assert(obval);
+ Py_DECREF(obkey);
+ Py_DECREF(obval);
+}
+
+static PyObject *qemu_py_register_keyboard(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"handler", NULL};
+ PyObject *fn;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &fn))
+ return NULL;
+
+ if (!PyCallable_Check(fn)) {
+ PyErr_SetString(PyExc_TypeError, "keyboard handler must be callable");
+ return NULL;
+ }
+
+ Py_INCREF(fn);
+ gui_register_dev_key_callback(qemu_py_keyboard_event, fn);
+
+ Py_RETURN_NONE;
+}
+
+static void qemu_py_mouse_event(void *opaque, int dx, int dy, int dz,
+ int buttons)
+{
+ PyObject *fn = opaque;
+ PyObject *obval;
+ PyObject *obx;
+ PyObject *oby;
+ PyObject *obz;
+ PyObject *obbuttons;
+
+ obx = PyInt_FromLong(dx);
+ oby = PyInt_FromLong(dy);
+ obz = PyInt_FromLong(dz);
+ obbuttons = PyInt_FromLong(buttons);
+ obval = PyObject_CallFunctionObjArgs(fn, obx, oby, obz, obbuttons, NULL);
+ qemu_py_assert(obval);
+ Py_DECREF(obx);
+ Py_DECREF(oby);
+ Py_DECREF(obz);
+ Py_DECREF(obbuttons);
+ Py_DECREF(obval);
+}
+
+static PyObject *qemu_py_register_mouse(PyObject *self, PyObject *args,
+ PyObject *kwds)
+{
+ static char *kwlist[] = {"handler", "absolute", NULL};
+ PyObject *fn;
+ int absolute;
+
+ if (!PyArg_ParseTupleAndKeywords(args, kwds, "Oi", kwlist, &fn, &absolute))
+ return NULL;
+
+ if (!PyCallable_Check(fn)) {
+ PyErr_SetString(PyExc_TypeError, "mouse handler must be callable");
+ return NULL;
+ }
+
+ Py_INCREF(fn);
+ gui_register_mouse_event_handler(qemu_py_mouse_event, fn, absolute, "dev");
+
+ Py_RETURN_NONE;
+}
+
+static PyMethodDef qemu_py_methods[] =
+{
+ {"register_device", qemu_py_register_device, METH_VARARGS,
+ "Register new device class"},
+ {"get_clock", qemu_py_get_clock, METH_NOARGS,
+ "Get current virtual time"},
+ {"start_time", qemu_py_start_time, METH_NOARGS,
+ "Get VM start time (seconds sice epoch)"},
+ {"register_keyboard", (PyCFunction)qemu_py_register_keyboard,
+ METH_VARARGS|METH_KEYWORDS,
+ "Register keyboard event handler"},
+ {"register_mouse", (PyCFunction)qemu_py_register_mouse,
+ METH_VARARGS|METH_KEYWORDS,
+ "Register mouse event handler"},
+ {NULL}
+};
+
+static void qemu_py_add_class(PyObject *module, const char *name,
+ PyTypeObject *type)
+{
+ if (!type->tp_new)
+ type->tp_new = PyType_GenericNew;
+ if (PyType_Ready(type) < 0)
+ qemu_py_die();
+ Py_INCREF(type);
+ PyModule_AddObject(module, name, (PyObject *)type);
+}
+
+static void qemu_py_init_interface(void)
+{
+ PyObject *m;
+ m = Py_InitModule("qemu", qemu_py_methods);
+
+ /* FIXME: Add default attributes to qemu_py_devclass. */
+ qemu_py_add_class(m, "devclass", &qemu_py_devclassType);
+ qemu_py_add_class(m, "ioregion", &qemu_py_ioregionType);
+ qemu_py_add_class(m, "chardev", &qemu_py_chardevType);
+ qemu_py_add_class(m, "render", &qemu_py_renderType);
+ qemu_py_add_class(m, "palette", &qemu_py_paletteType);
+ qemu_py_add_class(m, "ptimer", &qemu_py_ptimerType);
+ qemu_py_add_class(m, "file", &qemu_py_fileType);
+}
+
+#define PLUGIN_INIT_SCRIPT "import sys\nsys.path.insert(0, \"%s/plugins\")"
+void qemu_python_init(char *argv0)
+{
+ char *buf;
+ Py_SetProgramName(argv0);
+ Py_Initialize();
+
+ /* Nasty hack to look for plugin modules. */
+ buf = qemu_mallocz(strlen(bios_dir) + strlen(PLUGIN_INIT_SCRIPT));
+ sprintf(buf, PLUGIN_INIT_SCRIPT, bios_dir);
+#ifdef _WIN32
+ {
+ char *p;
+ /* Windows path separators (backslash) are interpreted as escape
+ characters in a python string. Fortunately python also accepts
+ unix path separators (forward slash), so use those instead. */
+ for (p = buf; *p; p++) {
+ if (*p == '\\')
+ *p = '/';
+ }
+ }
+#endif
+ PyRun_SimpleString(buf);
+ qemu_free(buf);
+
+ qemu_py_init_interface();
+
+ qemu_py_load_module("qemu_arm_plugins");
+}