UDI - Adding an attempt at a BochsGA UDI GFX driver
[tpg/acess2.git] / UDI / drivers / gfx_bochs / bochsga_core.c
diff --git a/UDI/drivers/gfx_bochs/bochsga_core.c b/UDI/drivers/gfx_bochs/bochsga_core.c
new file mode 100644 (file)
index 0000000..c851b07
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * UDI Bochs Graphics Driver
+ * By John Hodge (thePowersGang)
+ *
+ * bochsga_core.c
+ * - Core Code
+ */
+#define UDI_VERSION    0x101
+#define UDI_GFX_VERSION        0x101
+#include <udi.h>
+#include <udi_physio.h>
+#include <udi_gfx.h>
+#define DEBUG_ENABLED  1
+#include "../helpers.h"
+#include "../helpers_gfx.h"
+#include "bochsga_common.h"
+
+// --- Management Metalang
+void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
+
+       // TODO: Set up region data     
+
+       udi_usage_res(cb);
+}
+
+void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
+{
+       rdata_t *rdata = UDI_GCB(cb)->context;
+       udi_instance_attr_list_t *attr_list = cb->attr_list;
+       
+       switch(enumeration_level)
+       {
+       case UDI_ENUMERATE_START:
+       case UDI_ENUMERATE_START_RESCAN:
+               cb->attr_valid_length = attr_list - cb->attr_list;
+               udi_enumerate_ack(cb, UDI_ENUMERATE_OK, BOCHSGA_OPS_GFX);
+               break;
+       case UDI_ENUMERATE_NEXT:
+               udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
+               break;
+       }
+}
+void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
+{
+}
+void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb)
+{
+}
+// ---
+void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb);
+void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb, udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status);
+void bochsga_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle);
+void bochsga_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel);
+void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb);
+
+void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->event)
+       {
+       case UDI_CHANNEL_CLOSED:
+               break;
+       case UDI_CHANNEL_BOUND: {
+               rdata->active_cb = gcb;
+               udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
+               udi_bus_bind_req( bus_bind_cb );
+               // continue at bochsga_bus_dev_bus_bind_ack
+               return; }
+       }
+}
+void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
+       udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       // Set up PIO handles
+       rdata->init.pio_index = -1;
+       bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
+       // V V V V
+}
+void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
+{
+       rdata_t *rdata = gcb->context;
+       if( rdata->init.pio_index != -1 )
+       {
+               rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
+       }
+       
+       rdata->init.pio_index ++;
+       if( rdata->init.pio_index < N_PIO )
+       {
+               const struct s_pio_ops  *ops = &bochsga_pio_ops[rdata->init.pio_index];
+               udi_pio_map(bochsga_bus_dev_bind__pio_map, gcb,
+                       ops->regset_idx, ops->base_offset, ops->length,
+                       ops->trans_list, ops->list_length,
+                       UDI_PIO_LITTLE_ENDIAN, 0, 0
+                       );
+               return ;
+       }
+       
+       udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK);
+       // = = = = =
+}
+void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
+{
+}
+void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
+{
+}
+void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
+{
+}
+// ---
+// GFX Provider ops
+void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb)
+{
+       // No operation
+}
+void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb)
+{
+       // TODO: ACK bind if nothing already bound
+}
+void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb)
+{
+       // TODO: Release internal state?
+}
+void bochsga_gfx_set_connector_req$pio(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
+{
+       udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t);
+       udi_gfx_set_connector_ack(cb);
+}
+void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               if( rdata->output_enable != !!value )
+               {
+                       rdata->output_enable = !!value;
+                       udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                               rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+                       return ;
+               }
+               udi_gfx_set_connector_ack(cb);
+               return;
+       // Change input engine
+       // - 
+       case UDI_GFX_PROP_INPUT:
+               if( rdata->outputstate.engine != value )
+               {
+                       // Validate
+                       if( !(0 <= value && value <= N_ENGINES) ) {
+                               udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
+                               return ;
+                       }
+                       
+                       // Change saved bitdepth (requires cycling enable)
+                       rdata->outputstate.engine = value;
+                       rdata->outputstate.bitdepth = bochsga_engine_defs[value].bitdepth;
+               }
+               udi_gfx_set_connector_ack(cb);
+               return;
+       // Alter output dimensions
+       case UDI_GFX_PROP_WIDTH:
+               if( value % 8 != 0 ) {
+                       // Qemu doesn't like resolutions not a multiple of 8
+                       return ;
+               }
+               if( !(320 <= value && value <= rdata->limits.max_width) ) {
+                       return ;
+               } 
+               rdata->outputstate.width = value;
+               udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                       rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               if( !(240 <= value && value <= rdata->limits.max_height) ) {
+                       return ;
+               } 
+               rdata->outputstate.height = value;
+               udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
+                       rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
+               return;
+       }
+       CONTIN(bochsga_gfx_set_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
+}
+void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               udi_gfx_get_connector_ack(cb, !!rdata->output_enable);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.bitdepth/8-1);
+               return;
+       case UDI_GFX_PROP_WIDTH:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.width);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               udi_gfx_get_connector_ack(cb, rdata->outputstate.height);
+               return;
+       case UDI_GFX_PROP_CONNECTOR_TYPE:
+               udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN);
+               return;
+       case UDI_GFX_PROP_SIGNAL:
+               udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED);
+               return;
+       }
+       CONTIN(bochsga_gfx_get_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_get_connector_ack(cb, 0);
+}
+void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               // 2 values: 0 and 1
+               gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               // 0--3 with a step of 1
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, 0, 3, 1);
+               return;
+       case UDI_GFX_PROP_WIDTH:
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
+                       BOCHSGA_MIN_WIDTH, rdata->limits.max_width, 8); // qemu restricts to 8 step
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
+                       BOCHSGA_MIN_HEIGHT, rdata->limits.max_height, 8); // step of 8 for neatness
+               return;
+       case UDI_GFX_PROP_CONNECTOR_TYPE:
+               gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN);
+               return;
+       case UDI_GFX_PROP_SIGNAL:
+               gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED);
+               return;
+       }
+       CONTIN(bochsga_gfx_range_connector_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_range_cb_t      *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
+       udi_gfx_range_connector_ack(cb);
+}
+// --- Engine Manipulation ---
+void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_get_engine_ack(cb, 0);
+               return;
+       }
+       
+       engine_t *engine = &rdata->engines[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_WIDTH:
+               engine->width = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               engine->height = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               if( value >= bochsga_engine_defs[cb->subsystem].op_map.op_count ) {
+                       // Bad value
+                       udi_gfx_set_engine_ack(cb);
+                       return;
+               }
+               engine->op_idx = value;
+               udi_gfx_set_engine_ack(cb);
+               return;
+       }
+       CONTIN(bochsga_gfx_set_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_set_engine_ack(cb);
+}
+void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_get_engine_ack(cb, 0);
+               return;
+       }
+       
+       const engine_t *engine = &rdata->engines[cb->subsystem];
+       const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               udi_gfx_get_engine_ack(cb, 1);
+               return;
+       
+       case UDI_GFX_PROP_INPUT:
+               udi_gfx_get_engine_ack(cb, -1);
+               return;
+       
+       case UDI_GFX_PROP_WIDTH:
+               udi_gfx_get_engine_ack(cb, engine->width);
+               return;
+       case UDI_GFX_PROP_HEIGHT:
+               udi_gfx_get_engine_ack(cb, engine->height);
+               return;
+       
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               udi_gfx_get_engine_ack(cb, engine->op_idx);
+               return;
+       case UDI_GFX_PROP_OPERATOR_OPCODE:
+       case UDI_GFX_PROP_OPERATOR_ARG_1:
+       case UDI_GFX_PROP_OPERATOR_ARG_2:
+       case UDI_GFX_PROP_OPERATOR_ARG_3:
+               udi_gfx_get_engine_ack(cb, gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
+               return;
+       }
+       CONTIN(bochsga_gfx_get_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
+       udi_gfx_get_engine_ack(cb, 0);
+}
+void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb)
+{
+       udi_cb_t        *gcb = UDI_GCB(cb);
+       rdata_t *rdata = gcb->context;
+       
+       if( cb->subsystem >= N_ENGINES ) {
+               udi_gfx_range_engine_ack(cb);
+               return;
+       }
+       
+       engine_t *engine = &rdata->engines[cb->subsystem];
+       const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
+       
+       switch(cb->attribute)
+       {
+       case UDI_GFX_PROP_ENABLE:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1);
+               return;
+       case UDI_GFX_PROP_INPUT:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1);
+               return;
+       
+       case UDI_GFX_PROP_OPERATOR_INDEX:
+               gfxhelpers_return_range_simple(udi_gfx_range_engine_ack, cb, 0, engine->op_idx-1, 1);
+               return;
+       case UDI_GFX_PROP_OPERATOR_OPCODE:
+       case UDI_GFX_PROP_OPERATOR_ARG_1:
+       case UDI_GFX_PROP_OPERATOR_ARG_2:
+       case UDI_GFX_PROP_OPERATOR_ARG_3:
+               gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb,
+                       gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
+               return;
+       }
+       CONTIN(bochsga_gfx_range_engine_req, udi_log_write,
+               (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
+               (udi_status_t status)
+               );
+       udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
+       udi_gfx_range_engine_ack( cb );
+}
+void bochsga_gfx_command_req(udi_gfx_command_cb_t *cb)
+{
+       // Need to parse the GLX stream
+}
+
+// ====================================================================
+// - Management ops
+udi_mgmt_ops_t bochsga_mgmt_ops = {
+       bochsga_usage_ind,
+       bochsga_enumerate_req,
+       bochsga_devmgmt_req,
+       bochsga_final_cleanup_req
+};
+udi_ubit8_t    bochsga_mgmt_op_flags[4] = {0,0,0,0};
+// - Bus Ops
+udi_bus_device_ops_t   bochsga_bus_dev_ops = {
+       bochsga_bus_dev_channel_event_ind,
+       bochsga_bus_dev_bus_bind_ack,
+       bochsga_bus_dev_bus_unbind_ack,
+       bochsga_bus_dev_intr_attach_ack,
+       bochsga_bus_dev_intr_detach_ack
+};
+udi_ubit8_t    bochsga_bus_dev_ops_flags[5] = {0};
+// - GFX provider ops
+udi_gfx_provider_ops_t bochsga_gfx_ops = {
+       bochsga_gfx_channel_event_ind,
+       bochsga_gfx_bind_req,
+       bochsga_gfx_unbind_req,
+       bochsga_gfx_set_connector_req,
+       bochsga_gfx_set_engine_req,
+       bochsga_gfx_get_connector_req,
+       bochsga_gfx_get_engine_req,
+       bochsga_gfx_range_connector_req,
+       bochsga_gfx_range_engine_req,
+       bochsga_gfx_command_req
+};
+udi_ubit8_t    bochsga_gfx_ops_flags[10] = {0};
+// --
+udi_primary_init_t     bochsga_pri_init = {
+       .mgmt_ops = &bochsga_mgmt_ops,
+       .mgmt_op_flags = bochsga_mgmt_op_flags,
+       .mgmt_scratch_requirement = 0,
+       .enumeration_attr_list_length = 0,
+       .rdata_size = sizeof(rdata_t),
+       .child_data_size = 0,
+       .per_parent_paths = 0
+};
+udi_ops_init_t bochsga_ops_list[] = {
+       {
+               BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
+               0,
+               (udi_ops_vector_t*)&bochsga_bus_dev_ops,
+               bochsga_bus_dev_ops_flags
+       },
+       {
+               BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM,
+               0,
+               (udi_ops_vector_t*)&bochsga_gfx_ops,
+               bochsga_gfx_ops_flags
+       },
+       {0}
+};
+udi_cb_init_t bochsga_cb_init_list[] = {
+       {BOCHSGA_CB_BUS_BIND,    BOCHSGA_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_BIND,    BOCHSGA_META_GFX, UDI_GFX_BIND_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_STATE,   BOCHSGA_META_GFX, UDI_GFX_STATE_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_RANGE,   BOCHSGA_META_GFX, UDI_GFX_RANGE_CB_NUM, 0, 0,NULL},
+       {BOCHSGA_CB_GFX_COMMAND, BOCHSGA_META_GFX, UDI_GFX_COMMAND_CB_NUM, 0, 0,NULL},
+       {0}
+};
+const udi_init_t       udi_init_info = {
+       .primary_init_info = &bochsga_pri_init,
+       .ops_init_list = bochsga_ops_list,
+       .cb_init_list = bochsga_cb_init_list,
+};

UCC git Repository :: git.ucc.asn.au