UDI - Adding an attempt at a BochsGA UDI GFX driver
[tpg/acess2.git] / UDI / drivers / gfx_bochs / bochsga_core.c
1 /*
2  * UDI Bochs Graphics Driver
3  * By John Hodge (thePowersGang)
4  *
5  * bochsga_core.c
6  * - Core Code
7  */
8 #define UDI_VERSION     0x101
9 #define UDI_GFX_VERSION 0x101
10 #include <udi.h>
11 #include <udi_physio.h>
12 #include <udi_gfx.h>
13 #define DEBUG_ENABLED   1
14 #include "../helpers.h"
15 #include "../helpers_gfx.h"
16 #include "bochsga_common.h"
17
18 // --- Management Metalang
19 void bochsga_usage_ind(udi_usage_cb_t *cb, udi_ubit8_t resource_level)
20 {
21         rdata_t *rdata = UDI_GCB(cb)->context;
22         //udi_trace_write(rdata->init_context, UDI_TREVENT_LOCAL_PROC_ENTRY, 0, );
23
24         // TODO: Set up region data     
25
26         udi_usage_res(cb);
27 }
28
29 void bochsga_enumerate_req(udi_enumerate_cb_t *cb, udi_ubit8_t enumeration_level)
30 {
31         rdata_t *rdata = UDI_GCB(cb)->context;
32         udi_instance_attr_list_t *attr_list = cb->attr_list;
33         
34         switch(enumeration_level)
35         {
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);
40                 break;
41         case UDI_ENUMERATE_NEXT:
42                 udi_enumerate_ack(cb, UDI_ENUMERATE_DONE, 0);
43                 break;
44         }
45 }
46 void bochsga_devmgmt_req(udi_mgmt_cb_t *cb, udi_ubit8_t mgmt_op, udi_ubit8_t parent_ID)
47 {
48 }
49 void bochsga_final_cleanup_req(udi_mgmt_cb_t *cb)
50 {
51 }
52 // ---
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);
58
59 void bochsga_bus_dev_channel_event_ind(udi_channel_event_cb_t *cb)
60 {
61         udi_cb_t        *gcb = UDI_GCB(cb);
62         rdata_t *rdata = gcb->context;
63         
64         switch(cb->event)
65         {
66         case UDI_CHANNEL_CLOSED:
67                 break;
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
73                 return; }
74         }
75 }
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)
78 {
79         udi_cb_t        *gcb = UDI_GCB(cb);
80         rdata_t *rdata = gcb->context;
81         
82         // Set up PIO handles
83         rdata->init.pio_index = -1;
84         bochsga_bus_dev_bind__pio_map(gcb, UDI_NULL_PIO_HANDLE);
85         // V V V V
86 }
87 void bochsga_bus_dev_bind__pio_map(udi_cb_t *gcb, udi_pio_handle_t new_pio_handle)
88 {
89         rdata_t *rdata = gcb->context;
90         if( rdata->init.pio_index != -1 )
91         {
92                 rdata->pio_handles[rdata->init.pio_index] = new_pio_handle;
93         }
94         
95         rdata->init.pio_index ++;
96         if( rdata->init.pio_index < N_PIO )
97         {
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
103                         );
104                 return ;
105         }
106         
107         udi_channel_event_complete( UDI_MCB(rdata->active_cb, udi_channel_event_cb_t), UDI_OK);
108         // = = = = =
109 }
110 void bochsga_bus_dev_bus_unbind_ack(udi_bus_bind_cb_t *cb)
111 {
112 }
113 void bochsga_bus_dev_intr_attach_ack(udi_intr_attach_cb_t *intr_attach_cb, udi_status_t status)
114 {
115 }
116 void bochsga_bus_dev_intr_detach_ack(udi_intr_detach_cb_t *intr_detach_cb)
117 {
118 }
119 // ---
120 // GFX Provider ops
121 void bochsga_gfx_channel_event_ind(udi_channel_event_cb_t *cb)
122 {
123         // No operation
124 }
125 void bochsga_gfx_bind_req(udi_gfx_bind_cb_t *cb)
126 {
127         // TODO: ACK bind if nothing already bound
128 }
129 void bochsga_gfx_unbind_req(udi_gfx_bind_cb_t *cb)
130 {
131         // TODO: Release internal state?
132 }
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)
134 {
135         udi_gfx_state_cb_t *cb = UDI_MCB(gcb, udi_gfx_state_cb_t);
136         udi_gfx_set_connector_ack(cb);
137 }
138 void bochsga_gfx_set_connector_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
139 {
140         udi_cb_t        *gcb = UDI_GCB(cb);
141         rdata_t *rdata = gcb->context;
142         
143         switch(cb->attribute)
144         {
145         case UDI_GFX_PROP_ENABLE:
146                 if( rdata->output_enable != !!value )
147                 {
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);
151                         return ;
152                 }
153                 udi_gfx_set_connector_ack(cb);
154                 return;
155         // Change input engine
156         // - 
157         case UDI_GFX_PROP_INPUT:
158                 if( rdata->outputstate.engine != value )
159                 {
160                         // Validate
161                         if( !(0 <= value && value <= N_ENGINES) ) {
162                                 udi_gfx_set_connector_ack(cb /*, UDI_STAT_NOT_SUPPORTED*/);
163                                 return ;
164                         }
165                         
166                         // Change saved bitdepth (requires cycling enable)
167                         rdata->outputstate.engine = value;
168                         rdata->outputstate.bitdepth = bochsga_engine_defs[value].bitdepth;
169                 }
170                 udi_gfx_set_connector_ack(cb);
171                 return;
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
176                         return ;
177                 }
178                 if( !(320 <= value && value <= rdata->limits.max_width) ) {
179                         return ;
180                 } 
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);
184                 return;
185         case UDI_GFX_PROP_HEIGHT:
186                 if( !(240 <= value && value <= rdata->limits.max_height) ) {
187                         return ;
188                 } 
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);
192                 return;
193         }
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)
197                 );
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*/);
200 }
201 void bochsga_gfx_get_connector_req(udi_gfx_state_cb_t *cb)
202 {
203         udi_cb_t        *gcb = UDI_GCB(cb);
204         rdata_t *rdata = gcb->context;
205         
206         switch(cb->attribute)
207         {
208         case UDI_GFX_PROP_ENABLE:
209                 udi_gfx_get_connector_ack(cb, !!rdata->output_enable);
210                 return;
211         case UDI_GFX_PROP_INPUT:
212                 udi_gfx_get_connector_ack(cb, rdata->outputstate.bitdepth/8-1);
213                 return;
214         case UDI_GFX_PROP_WIDTH:
215                 udi_gfx_get_connector_ack(cb, rdata->outputstate.width);
216                 return;
217         case UDI_GFX_PROP_HEIGHT:
218                 udi_gfx_get_connector_ack(cb, rdata->outputstate.height);
219                 return;
220         case UDI_GFX_PROP_CONNECTOR_TYPE:
221                 udi_gfx_get_connector_ack(cb, UDI_GFX_CONNECTOR_HIDDEN);
222                 return;
223         case UDI_GFX_PROP_SIGNAL:
224                 udi_gfx_get_connector_ack(cb, UDI_GFX_SIGNAL_INTEGRATED);
225                 return;
226         }
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)
230                 );
231         udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
232         udi_gfx_get_connector_ack(cb, 0);
233 }
234 void bochsga_gfx_range_connector_req(udi_gfx_range_cb_t *cb)
235 {
236         udi_cb_t        *gcb = UDI_GCB(cb);
237         rdata_t *rdata = gcb->context;
238         
239         switch(cb->attribute)
240         {
241         case UDI_GFX_PROP_ENABLE:
242                 // 2 values: 0 and 1
243                 gfxhelpers_return_range_set(udi_gfx_range_connector_ack, cb, 2, 0, 1);
244                 return;
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);
248                 return;
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
252                 return;
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
256                 return;
257         case UDI_GFX_PROP_CONNECTOR_TYPE:
258                 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_CONNECTOR_HIDDEN);
259                 return;
260         case UDI_GFX_PROP_SIGNAL:
261                 gfxhelpers_return_range_fixed(udi_gfx_range_connector_ack, cb, UDI_GFX_SIGNAL_INTEGRATED);
262                 return;
263         }
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)
267                 );
268         udi_gfx_range_cb_t      *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
269         udi_gfx_range_connector_ack(cb);
270 }
271 // --- Engine Manipulation ---
272 void bochsga_gfx_set_engine_req(udi_gfx_state_cb_t *cb, udi_ubit32_t value)
273 {
274         udi_cb_t        *gcb = UDI_GCB(cb);
275         rdata_t *rdata = gcb->context;
276         
277         if( cb->subsystem >= N_ENGINES ) {
278                 udi_gfx_get_engine_ack(cb, 0);
279                 return;
280         }
281         
282         engine_t *engine = &rdata->engines[cb->subsystem];
283         
284         switch(cb->attribute)
285         {
286         case UDI_GFX_PROP_WIDTH:
287                 engine->width = value;
288                 udi_gfx_set_engine_ack(cb);
289                 return;
290         case UDI_GFX_PROP_HEIGHT:
291                 engine->height = value;
292                 udi_gfx_set_engine_ack(cb);
293                 return;
294         case UDI_GFX_PROP_OPERATOR_INDEX:
295                 if( value >= bochsga_engine_defs[cb->subsystem].op_map.op_count ) {
296                         // Bad value
297                         udi_gfx_set_engine_ack(cb);
298                         return;
299                 }
300                 engine->op_idx = value;
301                 udi_gfx_set_engine_ack(cb);
302                 return;
303         }
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)
307                 );
308         udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
309         udi_gfx_set_engine_ack(cb);
310 }
311 void bochsga_gfx_get_engine_req(udi_gfx_state_cb_t *cb)
312 {
313         udi_cb_t        *gcb = UDI_GCB(cb);
314         rdata_t *rdata = gcb->context;
315         
316         if( cb->subsystem >= N_ENGINES ) {
317                 udi_gfx_get_engine_ack(cb, 0);
318                 return;
319         }
320         
321         const engine_t *engine = &rdata->engines[cb->subsystem];
322         const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
323         
324         switch(cb->attribute)
325         {
326         case UDI_GFX_PROP_ENABLE:
327                 udi_gfx_get_engine_ack(cb, 1);
328                 return;
329         
330         case UDI_GFX_PROP_INPUT:
331                 udi_gfx_get_engine_ack(cb, -1);
332                 return;
333         
334         case UDI_GFX_PROP_WIDTH:
335                 udi_gfx_get_engine_ack(cb, engine->width);
336                 return;
337         case UDI_GFX_PROP_HEIGHT:
338                 udi_gfx_get_engine_ack(cb, engine->height);
339                 return;
340         
341         case UDI_GFX_PROP_OPERATOR_INDEX:
342                 udi_gfx_get_engine_ack(cb, engine->op_idx);
343                 return;
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));
349                 return;
350         }
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)
354                 );
355         udi_gfx_state_cb_t      *cb = UDI_MCB(cb, udi_gfx_state_cb_t);
356         udi_gfx_get_engine_ack(cb, 0);
357 }
358 void bochsga_gfx_range_engine_req(udi_gfx_range_cb_t *cb)
359 {
360         udi_cb_t        *gcb = UDI_GCB(cb);
361         rdata_t *rdata = gcb->context;
362         
363         if( cb->subsystem >= N_ENGINES ) {
364                 udi_gfx_range_engine_ack(cb);
365                 return;
366         }
367         
368         engine_t *engine = &rdata->engines[cb->subsystem];
369         const engine_static_t *engine_def = &bochsga_engine_defs[cb->subsystem];
370         
371         switch(cb->attribute)
372         {
373         case UDI_GFX_PROP_ENABLE:
374                 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, 1);
375                 return;
376         case UDI_GFX_PROP_INPUT:
377                 gfxhelpers_return_range_fixed(udi_gfx_range_engine_ack, cb, -1);
378                 return;
379         
380         case UDI_GFX_PROP_OPERATOR_INDEX:
381                 gfxhelpers_return_range_simple(udi_gfx_range_engine_ack, cb, 0, engine->op_idx-1, 1);
382                 return;
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));
389                 return;
390         }
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)
394                 );
395         udi_gfx_range_cb_t *cb = UDI_MCB(cb, udi_gfx_range_cb_t);
396         udi_gfx_range_engine_ack( cb );
397 }
398 void bochsga_gfx_command_req(udi_gfx_command_cb_t *cb)
399 {
400         // Need to parse the GLX stream
401 }
402
403 // ====================================================================
404 // - Management ops
405 udi_mgmt_ops_t  bochsga_mgmt_ops = {
406         bochsga_usage_ind,
407         bochsga_enumerate_req,
408         bochsga_devmgmt_req,
409         bochsga_final_cleanup_req
410 };
411 udi_ubit8_t     bochsga_mgmt_op_flags[4] = {0,0,0,0};
412 // - Bus Ops
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
419 };
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
433 };
434 udi_ubit8_t     bochsga_gfx_ops_flags[10] = {0};
435 // --
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
444 };
445 udi_ops_init_t  bochsga_ops_list[] = {
446         {
447                 BOCHSGA_OPS_DEV, BOCHSGA_META_BUS, UDI_BUS_DEVICE_OPS_NUM,
448                 0,
449                 (udi_ops_vector_t*)&bochsga_bus_dev_ops,
450                 bochsga_bus_dev_ops_flags
451         },
452         {
453                 BOCHSGA_OPS_GFX, BOCHSGA_META_GFX, UDI_GFX_PROVIDER_OPS_NUM,
454                 0,
455                 (udi_ops_vector_t*)&bochsga_gfx_ops,
456                 bochsga_gfx_ops_flags
457         },
458         {0}
459 };
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},
466         {0}
467 };
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,
472 };

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