2 * UDI Bochs Graphics Driver
3 * By John Hodge (thePowersGang)
8 #define UDI_VERSION 0x101
9 #define UDI_GFX_VERSION 0x101
11 #include <udi_physio.h>
13 #define DEBUG_ENABLED 1
14 #include "../helpers.h"
15 #include "../helpers_gfx.h"
16 #include "bochsga_common.h"
18 // --- Management Metalang
19 void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
21 rdata_t *rdata = UDI_GCB(cb)->context;
22 //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
24 // TODO: Set up region data
29 void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
31 rdata_t *rdata = UDI_GCB(cb)->context;
32 udi_instance_attr_list_t *attr_list = cb->attr_list;
34 switch(enumeration_level)
36 case UDI_ENUMERATE_START:
37 case UDI_ENUMERATE_START_RESCAN:
38 cb->attr_valid_length = attr_list - cb->attr_list;
39 udi_enumerate_ack(cb, UDI_ENUMERATE_OK, BOCHSGA_OPS_GFX);
41 case UDI_ENUMERATE_NEXT:
42 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
46 void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
49 void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb)
53 void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb);
54 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);
55 void bochsga_bus_dev_bind__pio_map(udi_cb_t *cb, udi_pio_handle_t new_pio_handle);
56 void bochsga_bus_dev_bind__intr_chanel(udi_cb_t *gcb, udi_channel_t new_channel);
57 void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb);
59 void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
61 udi_cb_t *gcb = UDI_GCB(cb);
62 rdata_t *rdata = gcb->context;
66 case UDI_CHANNEL_CLOSED:
68 case UDI_CHANNEL_BOUND: {
69 rdata->active_cb = gcb;
70 udi_bus_bind_cb_t *bus_bind_cb = UDI_MCB(cb->params.parent_bound.bind_cb, udi_bus_bind_cb_t);
71 udi_bus_bind_req( bus_bind_cb );
72 // continue at bochsga_bus_dev_bus_bind_ack
76 void bochsga_bus_dev_bus_bind_ack(udi_bus_bind_cb_t *cb,
77 udi_dma_constraints_t dma_constraints, udi_ubit8_t perferred_endianness, udi_status_t status)
79 udi_cb_t *gcb = UDI_GCB(cb);
80 rdata_t *rdata = gcb->context;
83 rdata->init.pio_index = -1;
84 bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
87 void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
89 rdata_t *rdata = gcb->context;
90 if( rdata->init.pio_index != -1 )
92 rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
95 rdata->init.pio_index ++;
96 if( rdata->init.pio_index < N_PIO )
98 const struct s_pio_ops *ops = &bochsga_pio_ops[rdata->init.pio_index];
99 udi_pio_map(bochsga_bus_dev_bind__pio_map, gcb,
100 ops->regset_idx, ops->base_offset, ops->length,
101 ops->trans_list, ops->list_length,
102 UDI_PIO_LITTLE_ENDIAN, 0, 0
107 udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK);
110 void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
113 void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
116 void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
121 void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb)
125 void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb)
127 // TODO: ACK bind if nothing already bound
129 void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb)
131 // TODO: Release internal state?
133 void bochsga_gfx_set_connector_req$pio(udi_cb_t *gcb, udi_buf_t *new_buf, udi_status_t status, udi_ubit16_t result)
135 udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t);
136 udi_gfx_set_connector_ack(cb);
138 void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
140 udi_cb_t *gcb = UDI_GCB(cb);
141 rdata_t *rdata = gcb->context;
143 switch(cb->attribute)
145 case UDI_GFX_PROP_ENABLE:
146 if( rdata->output_enable != !!value )
148 rdata->output_enable = !!value;
149 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
150 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
153 udi_gfx_set_connector_ack(cb);
155 // Change input engine
157 case UDI_GFX_PROP_INPUT:
158 if( rdata->outputstate.engine != value )
161 if( !(0 <= value && value <= N_ENGINES) ) {
162 udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
166 // Change saved bitdepth (requires cycling enable)
167 rdata->outputstate.engine = value;
168 rdata->outputstate.bitdepth = bochsga_engine_defs[value].bitdepth;
170 udi_gfx_set_connector_ack(cb);
172 // Alter output dimensions
173 case UDI_GFX_PROP_WIDTH:
174 if( value % 8 != 0 ) {
175 // Qemu doesn't like resolutions not a multiple of 8
178 if( !(320 <= value && value <= rdata->limits.max_width) ) {
181 rdata->outputstate.width = value;
182 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
183 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
185 case UDI_GFX_PROP_HEIGHT:
186 if( !(240 <= value && value <= rdata->limits.max_height) ) {
189 rdata->outputstate.height = value;
190 udi_pio_trans(bochsga_gfx_set_connector_req$pio, gcb,
191 rdata->pio_handles[BOCHSGA_PIO_ENABLE], rdata->output_enable, NULL, &rdata->outputstate);
194 CONTIN(bochsga_gfx_set_connector_req, udi_log_write,
195 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
196 (udi_status_t status)
198 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
199 udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
201 void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb)
203 udi_cb_t *gcb = UDI_GCB(cb);
204 rdata_t *rdata = gcb->context;
206 switch(cb->attribute)
208 case UDI_GFX_PROP_ENABLE:
209 udi_gfx_get_connector_ack(cb, !!rdata->output_enable);
211 case UDI_GFX_PROP_INPUT:
212 udi_gfx_get_connector_ack(cb, rdata->outputstate.bitdepth/8-1);
214 case UDI_GFX_PROP_WIDTH:
215 udi_gfx_get_connector_ack(cb, rdata->outputstate.width);
217 case UDI_GFX_PROP_HEIGHT:
218 udi_gfx_get_connector_ack(cb, rdata->outputstate.height);
220 case UDI_GFX_PROP_CONNECTOR_TYPE:
221 udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN);
223 case UDI_GFX_PROP_SIGNAL:
224 udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED);
227 CONTIN(bochsga_gfx_get_connector_req, udi_log_write,
228 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
229 (udi_status_t status)
231 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
232 udi_gfx_get_connector_ack(cb, 0);
234 void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb)
236 udi_cb_t *gcb = UDI_GCB(cb);
237 rdata_t *rdata = gcb->context;
239 switch(cb->attribute)
241 case UDI_GFX_PROP_ENABLE:
243 gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1);
245 case UDI_GFX_PROP_INPUT:
246 // 0--3 with a step of 1
247 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb, 0, 3, 1);
249 case UDI_GFX_PROP_WIDTH:
250 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
251 BOCHSGA_MIN_WIDTH, rdata->limits.max_width, 8); // qemu restricts to 8 step
253 case UDI_GFX_PROP_HEIGHT:
254 gfxhelpers_return_range_simple(udi_gfx_range_connector_ack, cb,
255 BOCHSGA_MIN_HEIGHT, rdata->limits.max_height, 8); // step of 8 for neatness
257 case UDI_GFX_PROP_CONNECTOR_TYPE:
258 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN);
260 case UDI_GFX_PROP_SIGNAL:
261 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED);
264 CONTIN(bochsga_gfx_range_connector_req, udi_log_write,
265 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
266 (udi_status_t status)
268 udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
269 udi_gfx_range_connector_ack(cb);
271 // --- Engine Manipulation ---
272 void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
274 udi_cb_t *gcb = UDI_GCB(cb);
275 rdata_t *rdata = gcb->context;
277 if( cb->subsystem >= N_ENGINES ) {
278 udi_gfx_get_engine_ack(cb, 0);
282 engine_t *engine = &rdata->engines[cb->subsystem];
284 switch(cb->attribute)
286 case UDI_GFX_PROP_WIDTH:
287 engine->width = value;
288 udi_gfx_set_engine_ack(cb);
290 case UDI_GFX_PROP_HEIGHT:
291 engine->height = value;
292 udi_gfx_set_engine_ack(cb);
294 case UDI_GFX_PROP_OPERATOR_INDEX:
295 if( value >= bochsga_engine_defs[cb->subsystem].op_map.op_count ) {
297 udi_gfx_set_engine_ack(cb);
300 engine->op_idx = value;
301 udi_gfx_set_engine_ack(cb);
304 CONTIN(bochsga_gfx_set_engine_req, udi_log_write,
305 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
306 (udi_status_t status)
308 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
309 udi_gfx_set_engine_ack(cb);
311 void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb)
313 udi_cb_t *gcb = UDI_GCB(cb);
314 rdata_t *rdata = gcb->context;
316 if( cb->subsystem >= N_ENGINES ) {
317 udi_gfx_get_engine_ack(cb, 0);
321 const engine_t *engine = &rdata->engines[cb->subsystem];
322 const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
324 switch(cb->attribute)
326 case UDI_GFX_PROP_ENABLE:
327 udi_gfx_get_engine_ack(cb, 1);
330 case UDI_GFX_PROP_INPUT:
331 udi_gfx_get_engine_ack(cb, -1);
334 case UDI_GFX_PROP_WIDTH:
335 udi_gfx_get_engine_ack(cb, engine->width);
337 case UDI_GFX_PROP_HEIGHT:
338 udi_gfx_get_engine_ack(cb, engine->height);
341 case UDI_GFX_PROP_OPERATOR_INDEX:
342 udi_gfx_get_engine_ack(cb, engine->op_idx);
344 case UDI_GFX_PROP_OPERATOR_OPCODE:
345 case UDI_GFX_PROP_OPERATOR_ARG_1:
346 case UDI_GFX_PROP_OPERATOR_ARG_2:
347 case UDI_GFX_PROP_OPERATOR_ARG_3:
348 udi_gfx_get_engine_ack(cb, gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
351 CONTIN(bochsga_gfx_get_engine_req, udi_log_write,
352 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
353 (udi_status_t status)
355 udi_gfx_state_cb_t *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
356 udi_gfx_get_engine_ack(cb, 0);
358 void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb)
360 udi_cb_t *gcb = UDI_GCB(cb);
361 rdata_t *rdata = gcb->context;
363 if( cb->subsystem >= N_ENGINES ) {
364 udi_gfx_range_engine_ack(cb);
368 engine_t *engine = &rdata->engines[cb->subsystem];
369 const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
371 switch(cb->attribute)
373 case UDI_GFX_PROP_ENABLE:
374 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1);
376 case UDI_GFX_PROP_INPUT:
377 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1);
380 case UDI_GFX_PROP_OPERATOR_INDEX:
381 gfxhelpers_return_range_simple(udi_gfx_range_engine_ack, cb, 0, engine->op_idx-1, 1);
383 case UDI_GFX_PROP_OPERATOR_OPCODE:
384 case UDI_GFX_PROP_OPERATOR_ARG_1:
385 case UDI_GFX_PROP_OPERATOR_ARG_2:
386 case UDI_GFX_PROP_OPERATOR_ARG_3:
387 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb,
388 gfxhelpers_get_engine_op(&engine_def->op_map, engine->op_idx, cb->attribute));
391 CONTIN(bochsga_gfx_range_engine_req, udi_log_write,
392 (UDI_TREVENT_LOG, UDI_LOG_INFORMATION, BOCHSGA_OPS_GFX, 0, BOCHSGA_MSGNUM_PROPUNK, __func__, cb->attribute),
393 (udi_status_t status)
395 udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
396 udi_gfx_range_engine_ack( cb );
398 void bochsga_gfx_command_req(udi_gfx_command_cb_t *cb)
400 // Need to parse the GLX stream
403 // ====================================================================
405 udi_mgmt_ops_t bochsga_mgmt_ops = {
407 bochsga_enumerate_req,
409 bochsga_final_cleanup_req
411 udi_ubit8_t bochsga_mgmt_op_flags[4] = {0,0,0,0};
413 udi_bus_device_ops_t bochsga_bus_dev_ops = {
414 bochsga_bus_dev_channel_event_ind,
415 bochsga_bus_dev_bus_bind_ack,
416 bochsga_bus_dev_bus_unbind_ack,
417 bochsga_bus_dev_intr_attach_ack,
418 bochsga_bus_dev_intr_detach_ack
420 udi_ubit8_t bochsga_bus_dev_ops_flags[5] = {0};
421 // - GFX provider ops
422 udi_gfx_provider_ops_t bochsga_gfx_ops = {
423 bochsga_gfx_channel_event_ind,
424 bochsga_gfx_bind_req,
425 bochsga_gfx_unbind_req,
426 bochsga_gfx_set_connector_req,
427 bochsga_gfx_set_engine_req,
428 bochsga_gfx_get_connector_req,
429 bochsga_gfx_get_engine_req,
430 bochsga_gfx_range_connector_req,
431 bochsga_gfx_range_engine_req,
432 bochsga_gfx_command_req
434 udi_ubit8_t bochsga_gfx_ops_flags[10] = {0};
436 udi_primary_init_t bochsga_pri_init = {
437 .mgmt_ops = &bochsga_mgmt_ops,
438 .mgmt_op_flags = bochsga_mgmt_op_flags,
439 .mgmt_scratch_requirement = 0,
440 .enumeration_attr_list_length = 0,
441 .rdata_size = sizeof(rdata_t),
442 .child_data_size = 0,
443 .per_parent_paths = 0
445 udi_ops_init_t bochsga_ops_list[] = {
447 BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
449 (udi_ops_vector_t*)&bochsga_bus_dev_ops,
450 bochsga_bus_dev_ops_flags
453 BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM,
455 (udi_ops_vector_t*)&bochsga_gfx_ops,
456 bochsga_gfx_ops_flags
460 udi_cb_init_t bochsga_cb_init_list[] = {
461 {BOCHSGA_CB_BUS_BIND, BOCHSGA_META_BUS, UDI_BUS_BIND_CB_NUM, 0, 0,NULL},
462 {BOCHSGA_CB_GFX_BIND, BOCHSGA_META_GFX, UDI_GFX_BIND_CB_NUM, 0, 0,NULL},
463 {BOCHSGA_CB_GFX_STATE, BOCHSGA_META_GFX, UDI_GFX_STATE_CB_NUM, 0, 0,NULL},
464 {BOCHSGA_CB_GFX_RANGE, BOCHSGA_META_GFX, UDI_GFX_RANGE_CB_NUM, 0, 0,NULL},
465 {BOCHSGA_CB_GFX_COMMAND, BOCHSGA_META_GFX, UDI_GFX_COMMAND_CB_NUM, 0, 0,NULL},
468 const udi_init_t udi_init_info = {
469 .primary_init_info = &bochsga_pri_init,
470 .ops_init_list = bochsga_ops_list,
471 .cb_init_list = bochsga_cb_init_list,