2 * UDI Bochs Graphics Driver
3 * By John Hodge (thePowersGang)
8 #define UDI_VERSION 0x101
9 #define UDI_PHYSIO_VERSION 0x101
10 #define UDI_GFX_VERSION 0x101
12 #include <udi_physio.h>
14 #define DEBUG_ENABLED 1
15 #include "../helpers.h"
16 #include "../helpers_gfx.h"
17 #include "bochsga_common.h"
19 // --- Management Metalang
20 void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
22 rdata_t *rdata = UDI_GCB(cb)->context;
23 //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
25 // TODO: Set up region data
30 void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
32 rdata_t *rdata = UDI_GCB(cb)->context;
33 udi_instance_attr_list_t *attr_list = cb->attr_list;
35 switch(enumeration_level)
37 case UDI_ENUMERATE_START:
38 case UDI_ENUMERATE_START_RESCAN:
39 cb->attr_valid_length = attr_list - cb->attr_list;
40 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, BOCHSGA_OPS_GFX);
42 case UDI_ENUMERATE_NEXT:
43 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
47 void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
50 void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb)
54 void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb);
55 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);
56 void bochsga_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle);
57 void bochsga_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel);
58 void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb);
60 void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
62 udi_cb_t *gcb = UDI_GCB(cb);
63 rdata_t *rdata = gcb->context;
67 case UDI_CHANNEL_CLOSED:
69 case UDI_CHANNEL_BOUND: {
70 rdata->active_cb = gcb;
71 udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
72 udi_bus_bind_req( bus_bind_cb );
73 // continue at bochsga_bus_dev_bus_bind_ack
77 void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
78 udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
80 udi_cb_t *gcb = UDI_GCB(cb);
81 rdata_t *rdata = gcb->context;
84 rdata->init.pio_index = -1;
85 bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
88 void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
90 rdata_t *rdata = gcb->context;
91 if( rdata->init.pio_index != -1 )
93 rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
96 rdata->init.pio_index ++;
97 if( rdata->init.pio_index < N_PIO )
99 const struct s_pio_ops *ops = &bochsga_pio_ops[rdata->init.pio_index];
100 udi_pio_map(bochsga_bus_dev_bind__pio_map, gcb,
101 ops->regset_idx, ops->base_offset, ops->length,
102 ops->trans_list, ops->list_length,
103 UDI_PIO_LITTLE_ENDIAN, 0, 0
108 udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK);
111 void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
114 void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
117 void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
122 void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb)
126 void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb)
128 // TODO: ACK bind if nothing already bound
130 void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb)
132 // TODO: Release internal state?
134 void bochsga_gfx_set_connector_req$pio(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
136 udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t);
137 udi_gfx_set_connector_ack(cb);
139 void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
141 udi_cb_t *gcb = UDI_GCB(cb);
142 rdata_t *rdata = gcb->context;
144 switch(cb->attribute)
146 case UDI_GFX_PROP_ENABLE:
147 if( rdata->output_enable != !!value )
149 rdata->output_enable = !!value;
150 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
151 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
154 udi_gfx_set_connector_ack(cb);
156 // Change input engine
158 case UDI_GFX_PROP_INPUT:
159 if( rdata->outputstate.engine != value )
162 if( !(0 <= value && value <= N_ENGINES) ) {
163 udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
167 // Change saved bitdepth (requires cycling enable)
168 rdata->outputstate.engine = value;
169 rdata->outputstate.bitdepth = bochsga_engine_defs[value].bitdepth;
171 udi_gfx_set_connector_ack(cb);
173 // Alter output dimensions
174 case UDI_GFX_PROP_WIDTH:
175 if( value % 8 != 0 ) {
176 // Qemu doesn't like resolutions not a multiple of 8
179 if( !(320 <= value && value <= rdata->limits.max_width) ) {
182 rdata->outputstate.width = value;
183 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
184 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
186 case UDI_GFX_PROP_HEIGHT:
187 if( !(240 <= value && value <= rdata->limits.max_height) ) {
190 rdata->outputstate.height = value;
191 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
192 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
195 CONTIN(bochsga_gfx_set_connector_req, udi_log_write,
196 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
197 (udi_status_t status)
199 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
200 udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
202 void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb)
204 udi_cb_t *gcb = UDI_GCB(cb);
205 rdata_t *rdata = gcb->context;
207 switch(cb->attribute)
209 case UDI_GFX_PROP_ENABLE:
210 udi_gfx_get_connector_ack(cb, !!rdata->output_enable);
212 case UDI_GFX_PROP_INPUT:
213 udi_gfx_get_connector_ack(cb, rdata->outputstate.bitdepth/8-1);
215 case UDI_GFX_PROP_WIDTH:
216 udi_gfx_get_connector_ack(cb, rdata->outputstate.width);
218 case UDI_GFX_PROP_HEIGHT:
219 udi_gfx_get_connector_ack(cb, rdata->outputstate.height);
221 case UDI_GFX_PROP_CONNECTOR_TYPE:
222 udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN);
224 case UDI_GFX_PROP_SIGNAL:
225 udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED);
228 CONTIN(bochsga_gfx_get_connector_req, udi_log_write,
229 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
230 (udi_status_t status)
232 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
233 udi_gfx_get_connector_ack(cb, 0);
235 void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb)
237 udi_cb_t *gcb = UDI_GCB(cb);
238 rdata_t *rdata = gcb->context;
240 switch(cb->attribute)
242 case UDI_GFX_PROP_ENABLE:
244 gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1);
246 case UDI_GFX_PROP_INPUT:
247 // 0--3 with a step of 1
248 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, 0, 3, 1);
250 case UDI_GFX_PROP_WIDTH:
251 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
252 BOCHSGA_MIN_WIDTH, rdata->limits.max_width, 8); // qemu restricts to 8 step
254 case UDI_GFX_PROP_HEIGHT:
255 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
256 BOCHSGA_MIN_HEIGHT, rdata->limits.max_height, 8); // step of 8 for neatness
258 case UDI_GFX_PROP_CONNECTOR_TYPE:
259 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN);
261 case UDI_GFX_PROP_SIGNAL:
262 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED);
265 CONTIN(bochsga_gfx_range_connector_req, udi_log_write,
266 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
267 (udi_status_t status)
269 udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
270 udi_gfx_range_connector_ack(cb);
272 // --- Engine Manipulation ---
273 void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
275 udi_cb_t *gcb = UDI_GCB(cb);
276 rdata_t *rdata = gcb->context;
278 if( cb->subsystem >= N_ENGINES ) {
279 udi_gfx_get_engine_ack(cb, 0);
283 engine_t *engine = &rdata->engines[cb->subsystem];
285 switch(cb->attribute)
287 case UDI_GFX_PROP_WIDTH:
288 engine->width = value;
289 udi_gfx_set_engine_ack(cb);
291 case UDI_GFX_PROP_HEIGHT:
292 engine->height = value;
293 udi_gfx_set_engine_ack(cb);
295 case UDI_GFX_PROP_OPERATOR_INDEX:
296 if( value >= bochsga_engine_defs[cb->subsystem].op_map.op_count ) {
298 udi_gfx_set_engine_ack(cb);
301 engine->op_idx = value;
302 udi_gfx_set_engine_ack(cb);
305 CONTIN(bochsga_gfx_set_engine_req, udi_log_write,
306 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
307 (udi_status_t status)
309 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
310 udi_gfx_set_engine_ack(cb);
312 void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb)
314 udi_cb_t *gcb = UDI_GCB(cb);
315 rdata_t *rdata = gcb->context;
317 if( cb->subsystem >= N_ENGINES ) {
318 udi_gfx_get_engine_ack(cb, 0);
322 const engine_t *engine = &rdata->engines[cb->subsystem];
323 const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
325 switch(cb->attribute)
327 case UDI_GFX_PROP_ENABLE:
328 udi_gfx_get_engine_ack(cb, 1);
331 case UDI_GFX_PROP_INPUT:
332 udi_gfx_get_engine_ack(cb, -1);
335 case UDI_GFX_PROP_WIDTH:
336 udi_gfx_get_engine_ack(cb, engine->width);
338 case UDI_GFX_PROP_HEIGHT:
339 udi_gfx_get_engine_ack(cb, engine->height);
342 case UDI_GFX_PROP_OPERATOR_INDEX:
343 udi_gfx_get_engine_ack(cb, engine->op_idx);
345 case UDI_GFX_PROP_OPERATOR_OPCODE:
346 case UDI_GFX_PROP_OPERATOR_ARG_1:
347 case UDI_GFX_PROP_OPERATOR_ARG_2:
348 case UDI_GFX_PROP_OPERATOR_ARG_3:
349 udi_gfx_get_engine_ack(cb, gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
352 CONTIN(bochsga_gfx_get_engine_req, udi_log_write,
353 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
354 (udi_status_t status)
356 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
357 udi_gfx_get_engine_ack(cb, 0);
359 void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb)
361 udi_cb_t *gcb = UDI_GCB(cb);
362 rdata_t *rdata = gcb->context;
364 if( cb->subsystem >= N_ENGINES ) {
365 udi_gfx_range_engine_ack(cb);
369 engine_t *engine = &rdata->engines[cb->subsystem];
370 const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
372 switch(cb->attribute)
374 case UDI_GFX_PROP_ENABLE:
375 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1);
377 case UDI_GFX_PROP_INPUT:
378 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1);
381 case UDI_GFX_PROP_OPERATOR_INDEX:
382 gfxhelpers_return_range_simple(udi_gfx_range_engine_ack, cb, 0, engine->op_idx-1, 1);
384 case UDI_GFX_PROP_OPERATOR_OPCODE:
385 case UDI_GFX_PROP_OPERATOR_ARG_1:
386 case UDI_GFX_PROP_OPERATOR_ARG_2:
387 case UDI_GFX_PROP_OPERATOR_ARG_3:
388 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb,
389 gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
392 CONTIN(bochsga_gfx_range_engine_req, udi_log_write,
393 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
394 (udi_status_t status)
396 udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
397 udi_gfx_range_engine_ack( cb );
399 void bochsga_gfx_command_req(udi_gfx_command_cb_t *cb)
401 // Need to parse the GLX stream
404 // ====================================================================
406 udi_mgmt_ops_t bochsga_mgmt_ops = {
408 bochsga_enumerate_req,
410 bochsga_final_cleanup_req
412 udi_ubit8_t bochsga_mgmt_op_flags[4] = {0,0,0,0};
414 udi_bus_device_ops_t bochsga_bus_dev_ops = {
415 bochsga_bus_dev_channel_event_ind,
416 bochsga_bus_dev_bus_bind_ack,
417 bochsga_bus_dev_bus_unbind_ack,
418 bochsga_bus_dev_intr_attach_ack,
419 bochsga_bus_dev_intr_detach_ack
421 udi_ubit8_t bochsga_bus_dev_ops_flags[5] = {0};
422 // - GFX provider ops
423 udi_gfx_provider_ops_t bochsga_gfx_ops = {
424 bochsga_gfx_channel_event_ind,
425 bochsga_gfx_bind_req,
426 bochsga_gfx_unbind_req,
427 bochsga_gfx_set_connector_req,
428 bochsga_gfx_set_engine_req,
429 bochsga_gfx_get_connector_req,
430 bochsga_gfx_get_engine_req,
431 bochsga_gfx_range_connector_req,
432 bochsga_gfx_range_engine_req,
433 bochsga_gfx_command_req
435 udi_ubit8_t bochsga_gfx_ops_flags[10] = {0};
437 udi_primary_init_t bochsga_pri_init = {
438 .mgmt_ops = &bochsga_mgmt_ops,
439 .mgmt_op_flags = bochsga_mgmt_op_flags,
440 .mgmt_scratch_requirement = 0,
441 .enumeration_attr_list_length = 0,
442 .rdata_size = sizeof(rdata_t),
443 .child_data_size = 0,
444 .per_parent_paths = 0
446 udi_ops_init_t bochsga_ops_list[] = {
448 BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
450 (udi_ops_vector_t*)&bochsga_bus_dev_ops,
451 bochsga_bus_dev_ops_flags
454 BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM,
456 (udi_ops_vector_t*)&bochsga_gfx_ops,
457 bochsga_gfx_ops_flags
461 udi_cb_init_t bochsga_cb_init_list[] = {
462 {BOCHSGA_CB_BUS_BIND, BOCHSGA_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL},
463 {BOCHSGA_CB_GFX_BIND, BOCHSGA_META_GFX, UDI_GFX_BIND_CB_NUM, 0, 0,NULL},
464 {BOCHSGA_CB_GFX_STATE, BOCHSGA_META_GFX, UDI_GFX_STATE_CB_NUM, 0, 0,NULL},
465 {BOCHSGA_CB_GFX_RANGE, BOCHSGA_META_GFX, UDI_GFX_RANGE_CB_NUM, 0, 0,NULL},
466 {BOCHSGA_CB_GFX_COMMAND, BOCHSGA_META_GFX, UDI_GFX_COMMAND_CB_NUM, 0, 0,NULL},
469 const udi_init_t udi_init_info = {
470 .primary_init_info = &bochsga_pri_init,
471 .ops_init_list = bochsga_ops_list,
472 .cb_init_list = bochsga_cb_init_list,