2 * This file is part of the Palacios Virtual Machine Monitor developed
3 * by the V3VEE Project with funding from the United States National
4 * Science Foundation and the Department of Energy.
6 * The V3VEE Project is a joint project between Northwestern University
7 * and the University of New Mexico. You can find out more at
10 * Copyright (c) 2011, Peter Dinda <pdinda@northwestern.edu>
11 * Copyright (c) 2011, The V3VEE Project <http://www.v3vee.org>
12 * All rights reserved.
14 * Author: Peter Dinda <pdinda@northwestern.edu>
16 * This is free software. You are permitted to use,
17 * redistribute, and modify it as specified in the file "V3VEE_LICENSE".
20 #include <palacios/vmm.h>
21 #include <palacios/vmm_dev_mgr.h>
22 #include <palacios/vmm_types.h>
23 #include <palacios/vm_guest_mem.h>
24 #include <palacios/vmm_io.h>
25 #include <interfaces/vmm_graphics_console.h>
29 #define MEM_REGION_START 0xa0000
30 #define MEM_REGION_END 0xc0000
31 #define MEM_REGION_NUM_PAGES (((MEM_REGION_END)-(MEM_REGION_START))/4096)
33 #define MAP_SIZE 65536
36 #define UPDATES_PER_RENDER 100
38 typedef uint8_t *vga_map; // points to MAP_SIZE data
44 #define VGA_MISC_OUT_READ 0x3cc
45 #define VGA_MISC_OUT_WRITE 0x3c2
47 #define VGA_INPUT_STAT0_READ 0x3c2
49 #define VGA_INPUT_STAT1_READ_MONO 0x3ba
50 #define VGA_INPUT_STAT1_READ_COLOR 0x3da
52 #define VGA_FEATURE_CONTROL_READ 0x3ca
53 #define VGA_FEATURE_CONTROL_WRITE_MONO 0x3ba
54 #define VGA_FEATURE_CONTROL_WRITE_COLOR 0x3da
56 #define VGA_VIDEO_SUBSYS_ENABLE 0x3c3
58 #define VGA_SEQUENCER_ADDRESS 0x3c4
59 #define VGA_SEQUENCER_DATA 0x3c5
60 #define VGA_SEQUENCER_NUM 5
63 #define VGA_CRT_CONTROLLER_ADDRESS_MONO 0x3b4
64 #define VGA_CRT_CONTROLLER_ADDRESS_COLOR 0x3d4
65 #define VGA_CRT_CONTROLLER_DATA_MONO 0x3b5
66 #define VGA_CRT_CONTROLLER_DATA_COLOR 0x3d5
67 #define VGA_CRT_CONTROLLER_NUM 25
70 #define VGA_GRAPHICS_CONTROLLER_ADDRESS 0x3ce
71 #define VGA_GRAPHICS_CONTROLLER_DATA 0x3cf
72 #define VGA_GRAPHICS_CONTROLLER_NUM 9
74 #define VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE 0x3c0
75 #define VGA_ATTRIBUTE_CONTROLLER_READ 0x3c1
76 #define VGA_ATTRIBUTE_CONTROLLER_NUM 21
78 #define VGA_DAC_WRITE_ADDR 0x3c8
79 #define VGA_DAC_READ_ADDR 0x3c7
80 #define VGA_DAC_DATA 0x3c9
81 #define VGA_DAC_PIXEL_MASK 0x3c6
83 #define VGA_DAC_NUM_ENTRIES 256
86 #define VGA_FONT_WIDTH 8
87 #define VGA_MAX_FONT_HEIGHT 32
89 struct vga_misc_regs {
90 /* Read: 0x3cc; Write: 0x3c2 */
91 struct vga_misc_out_reg vga_misc_out;
93 struct vga_input_stat0_reg vga_input_stat0;
94 /* Read: 0x3?a 3ba for mono; 3da for cga set by misc.io_addr_sel */
95 struct vga_input_stat1_reg vga_input_stat1;
96 /* Read: 0x3ca; Write: 0x3?a 3ba for mono 3da for color - set by misc.io_addr_sel*/
97 struct vga_feature_control_reg vga_feature_control;
98 /* Read: 0x3c3; Write: 0x3c3 */
99 struct vga_video_subsys_enable_reg vga_video_subsys_enable;
100 } __attribute__((packed));
102 struct vga_sequencer_regs {
103 /* Address register is 0x3c4, data register is 0x3c5 */
105 struct vga_sequencer_addr_reg vga_sequencer_addr;
107 /* these can be accessed via the index, offset on start
108 or via the specific regs. For this reason, it is essential
109 that this is all packed and that the order does not change */
111 uint8_t vga_sequencer_regs[0];
114 struct vga_reset_reg vga_reset;
116 struct vga_clocking_mode_reg vga_clocking_mode;
118 struct vga_map_mask_reg vga_map_mask;
120 struct vga_char_map_select_reg vga_char_map_select;
122 struct vga_mem_mode_reg vga_mem_mode;
123 } __attribute__((packed));
125 struct vga_crt_controller_regs {
126 /* Address Register is 0x3b4 or 0x3d4 */
127 /* Data register is 0x3b5 or 0x3d5 based on mono versus color */
128 struct vga_crt_addr_reg vga_crt_addr;
130 /* these can be accessed via the index, offset on start
131 or via the specific regs. For this reason, it is essential
132 that this is all packed and that the order does not change */
134 uint8_t vga_crt_controller_regs[0];
137 vga_horizontal_total_reg vga_horizontal_total;
139 vga_horizontal_display_enable_end_reg vga_horizontal_display_enable_end;
141 vga_start_horizontal_blanking_reg vga_start_horizontal_blanking;
143 struct vga_end_horizontal_blanking_reg vga_end_horizontal_blanking;
145 vga_start_horizontal_retrace_pulse_reg vga_start_horizontal_retrace_pulse;
147 struct vga_end_horizontal_retrace_reg vga_end_horizontal_retrace;
149 vga_vertical_total_reg vga_vertical_total;
151 struct vga_overflow_reg vga_overflow;
153 struct vga_preset_row_scan_reg vga_preset_row_scan;
155 struct vga_max_row_scan_reg vga_max_row_scan;
157 struct vga_cursor_start_reg vga_cursor_start;
159 struct vga_cursor_end_reg vga_cursor_end;
161 vga_start_address_high_reg vga_start_address_high;
163 vga_start_address_low_reg vga_start_address_low;
165 vga_cursor_location_high_reg vga_cursor_location_high;
167 vga_cursor_location_low_reg vga_cursor_location_low;
169 vga_vertical_retrace_start_reg vga_vertical_retrace_start;
171 struct vga_vertical_retrace_end_reg vga_vertical_retrace_end;
173 vga_vertical_display_enable_end_reg vga_vertical_display_enable_end;
175 vga_offset_reg vga_offset;
177 struct vga_underline_location_reg vga_underline_location;
179 vga_start_vertical_blanking_reg vga_start_vertical_blanking;
181 vga_end_vertical_blanking_reg vga_end_vertical_blanking;
183 struct vga_crt_mode_control_reg vga_crt_mode_control;
185 vga_line_compare_reg vga_line_compare;
186 } __attribute__((packed));
188 struct vga_graphics_controller_regs {
189 /* Address: 0x3ce Data: 0x3cf */
192 struct vga_graphics_ctrl_addr_reg vga_graphics_ctrl_addr;
194 /* these can be accessed via the index, offset on start
195 or via the specific regs. For this reason, it is essential
196 that this is all packed and that the order does not change */
198 uint8_t vga_graphics_controller_regs[0];
201 struct vga_set_reset_reg vga_set_reset;
203 struct vga_enable_set_reset_reg vga_enable_set_reset;
205 struct vga_color_compare_reg vga_color_compare;
207 struct vga_data_rotate_reg vga_data_rotate;
209 struct vga_read_map_select_reg vga_read_map_select;
211 struct vga_graphics_mode_reg vga_graphics_mode;
213 struct vga_misc_reg vga_misc;
215 struct vga_color_dont_care_reg vga_color_dont_care;
217 vga_bit_mask_reg vga_bit_mask;
218 } __attribute__((packed));
221 struct vga_attribute_contoller_regs {
223 Address AND WRITE: 0x3c0
226 The write protocol is to write the index to 0x3c0 followed by
227 the data. The read protocol is to write the index to 0x3c0
228 and then read from 0x3c1
230 IMPORTANT: write address, write data flips state back to write address
231 write address, read data DOES NOT
233 To reset to write address state, read input status register 1
235 enum { ATTR_ADDR, ATTR_DATA } state; //state of the flip flop
238 struct vga_attribute_controller_address_reg vga_attribute_controller_addr;
242 /* these can be accessed via the index, offset on start
243 or via the specific regs. For this reason, it is essential
244 that this is all packed and that the order does not change */
246 uint8_t vga_attribute_controller_regs[0];
249 vga_internal_palette_regs vga_internal_palette;
251 struct vga_attribute_mode_control_reg vga_attribute_mode_control;
253 vga_overscan_color_reg vga_overscan_color;
255 struct vga_color_plane_enable_reg vga_color_plane_enable;
257 struct vga_horizontal_pixel_pan_reg vga_horizontal_pixel_pan;
259 struct vga_color_select_reg vga_color_select;
260 } __attribute__((packed));
262 struct vga_dac_regs {
263 enum {DAC_READ=0, DAC_WRITE} state;
264 enum {RED=0,GREEN,BLUE} channel;
265 vga_dac_pixel_mask_reg vga_pixel_mask;
266 vga_dac_write_addr_reg vga_dac_write_addr;
267 vga_dac_read_addr_reg vga_dac_read_addr;
268 // the dac_data register is used only to access the registers
269 // and thus has no representation here
270 vga_palette_reg vga_dac_palette[VGA_DAC_NUM_ENTRIES];
271 } __attribute__((packed));
274 struct vga_internal {
275 struct vm_device *dev;
278 bool skip_next_passthrough_out; // for word access
280 struct v3_frame_buffer_spec target_spec;
281 v3_graphics_console_t host_cons;
283 uint32_t updates_since_render;
285 struct frame_buf *framebuf; // we render to this
287 // void *mem_store; // This is the region where the memory hooks will go
289 vga_map map[MAP_NUM]; // the maps that the host writes to
291 uint8_t latch[MAP_NUM]; // written to in any read, used during writes
293 /* Range of I/O ports here for backward compat with MDA and CGA */
294 struct vga_misc_regs vga_misc;
296 /* Address Register is 0x3b4 or 0x3d4 */
297 /* Data register is 0x3b5 or 0x3d5 based on MDA/CGA/VGA (backward compat) */
298 struct vga_crt_controller_regs vga_crt_controller;
300 /* Address register is 0x3c4, data register is 0x3c5 */
301 struct vga_sequencer_regs vga_sequencer;
303 /* Address: 0x3ce Data: 0x3cf */
304 struct vga_graphics_controller_regs vga_graphics_controller;
307 Address AND WRITE: 0x3c0
311 struct vga_attribute_contoller_regs vga_attribute_controller;
314 address for reads: 0x3c7 (also resets state machine for access to 18 bit regs
315 address for writes: 0x3c8 ("")
317 pixel mask: 0x3c6 - do not write (init to 0xff)
319 struct vga_dac_regs vga_dac;
323 typedef enum {PLANAR_SHIFT, PACKED_SHIFT, C256_SHIFT} shift_mode_t;
326 static void find_text_char_dim(struct vga_internal *vga, uint32_t *w, uint32_t *h)
328 *w = (vga->vga_sequencer.vga_clocking_mode.dot8 ? 8 : 9);
330 *h = vga->vga_crt_controller.vga_max_row_scan.max_scan_line+1;
334 static void find_text_res(struct vga_internal *vga, uint32_t *width, uint32_t *height)
336 uint32_t vert_lsb, vert_msb;
340 *width = (vga->vga_crt_controller.vga_horizontal_display_enable_end + 1)
341 - vga->vga_crt_controller.vga_end_horizontal_blanking.display_enable_skew;
343 vert_lsb = vga->vga_crt_controller.vga_vertical_display_enable_end; // 8 bits here
344 vert_msb = (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end9 << 1) // 2 bits here
345 + (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end8);
347 ph = ( (vert_msb << 8) + vert_lsb + 1) ; // pixels high (scanlines)
349 find_text_char_dim(vga,&cw, &ch);
356 static void find_text_data_start(struct vga_internal *vga, void **data)
360 offset = vga->vga_crt_controller.vga_start_address_high;
362 offset += vga->vga_crt_controller.vga_start_address_low;
364 *data = vga->map[0]+offset;
368 static void find_text_attr_start(struct vga_internal *vga, void **data)
372 offset = vga->vga_crt_controller.vga_start_address_high;
374 offset += vga->vga_crt_controller.vga_start_address_low;
376 *data = vga->map[1]+offset;
380 static void find_text_cursor_pos(struct vga_internal *vga, uint32_t *x, uint32_t *y, void **data)
387 find_text_res(vga,&w,&h);
389 find_text_data_start(vga,&buf);
391 offset = vga->vga_crt_controller.vga_cursor_location_high;
393 offset += vga->vga_crt_controller.vga_cursor_location_low;
395 *data = vga->map[0]+offset;
397 charsin = (uint32_t)(*data - buf);
405 static void find_text_font_start(struct vga_internal *vga, void **data, uint8_t char_map)
407 uint32_t mapa_offset, mapb_offset;
412 mapa_offset = (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_lsb << 1)
413 + vga->vga_sequencer.vga_char_map_select.char_map_a_sel_msb ;
414 *data = vga->map[2] + mapa_offset;
418 mapb_offset = (vga->vga_sequencer.vga_char_map_select.char_map_b_sel_lsb << 1)
419 + vga->vga_sequencer.vga_char_map_select.char_map_b_sel_msb ;
420 *data = vga->map[2] + mapb_offset;
423 PrintError("vga: unknown char_map given to find_text_font_start\n");
429 static int extended_fontset(struct vga_internal *vga)
431 if (vga->vga_sequencer.vga_mem_mode.extended_memory &&
432 ! ( (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_lsb
433 == vga->vga_sequencer.vga_char_map_select.char_map_b_sel_lsb) &&
434 (vga->vga_sequencer.vga_char_map_select.char_map_a_sel_msb
435 == vga->vga_sequencer.vga_char_map_select.char_map_b_sel_msb))) {
443 static int blinking(struct vga_internal *vga)
445 return vga->vga_attribute_controller.vga_attribute_mode_control.enable_blink;
449 static void find_graphics_res(struct vga_internal *vga, uint32_t *width, uint32_t *height)
451 uint32_t vert_lsb, vert_msb;
453 *width = ((vga->vga_crt_controller.vga_horizontal_display_enable_end + 1)
454 - vga->vga_crt_controller.vga_end_horizontal_blanking.display_enable_skew);
456 *width *= (vga->vga_sequencer.vga_clocking_mode.dot8 ? 8 : 9);
458 vert_lsb = vga->vga_crt_controller.vga_vertical_display_enable_end; // 8 bits here
459 vert_msb = (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end9 << 1) // 2 bits here
460 + (vga->vga_crt_controller.vga_overflow.vertical_disp_enable_end8);
462 *height = ( (vert_msb << 8) + vert_lsb + 1) ; // pixels high (scanlines)
467 static void find_graphics_cursor_pos(struct vga_internal *vga, uint32_t *x, uint32_t *y)
474 static void find_shift_mode(struct vga_internal *vga, shift_mode_t *mode)
476 if (vga->vga_graphics_controller.vga_graphics_mode.c256) {
479 if (vga->vga_graphics_controller.vga_graphics_mode.shift_reg_mode) {
487 static void dac_lookup_24bit_color(struct vga_internal *vga,
493 // use internal or external palette?
495 vga_palette_reg *r = &(vga->vga_dac.vga_dac_palette[entry]);
497 // converting from 6 bits to 8 bits so << 2
498 *red = (*r & 0x3f) << 2;
499 *green = ((*r >> 8) & 0x3f) << 2;
500 *blue = ((*r >> 16) & 0x3f) << 2;
506 Colors work like this:
508 4 bit modes: index is to the internal palette on the attribute controller
509 that supplies 6 bits, but we need 8 to index the dac
510 2 more (the msbs) are supplied from the color select register
511 we can optionally overwrite bits 5 and 4 from the color
512 select register as well, depending on a selection bit
513 in the mode control register. The result of all this is
514 8 bit index for the dac
516 8 bit modes: the attribute controller passes the index straight through
520 The DAC translates from the 8 bit index into 6 bits per color channel
521 (18 bit color). We mulitply by 4 to get 24 bit color.
524 static void find_24bit_color(struct vga_internal *vga,
530 uint8_t di; // ultimate dac index
532 if (vga->vga_attribute_controller.vga_attribute_mode_control.pixel_width) {
533 // 8 bit mode does right to the DAC
536 struct vga_internal_palette_reg pr = vga->vga_attribute_controller.vga_internal_palette[val%16];
537 di = pr.palette_data;
539 // Fix bits 5-4 if needed
540 if (vga->vga_attribute_controller.vga_attribute_mode_control.p54_select) {
541 di &= ~0x30; // clear 5-4
542 di |= vga->vga_attribute_controller.vga_color_select.sc4 << 4;
543 di |= vga->vga_attribute_controller.vga_color_select.sc5 << 5;
546 // We must always produce bits 6 and 7
547 di &= ~0xc0; // clear 7-6
548 di |= vga->vga_attribute_controller.vga_color_select.sc6 << 6;
549 di |= vga->vga_attribute_controller.vga_color_select.sc7 << 7;
552 dac_lookup_24bit_color(vga,di,red,green,blue);
555 static void render_graphics(struct vga_internal *vga, void *fb)
558 struct v3_frame_buffer_spec *spec = &(vga->target_spec);
560 uint32_t gw, gh; // graphics w/h
561 uint32_t fw, fh; // fb w/h
562 uint32_t rgw, rgh; // region we can actually show on the frame buffer
565 uint32_t fx, fy; // pixel position within the frame buffer
567 uint32_t offset; // offset into the maps
569 uint8_t p; // pixel in the current map byte (0..7)
571 uint8_t r,g,b; // looked up colors for entry
573 void *pixel; // current pixel in the fb
574 uint8_t *red; // and the channels in the pixel
578 uint8_t db[4]; // 4 bytes read at a time
579 uint8_t pb[8]; // 8 pixels assembled at a time
581 shift_mode_t sm; // shift mode
583 uint32_t cur_x, cur_y;
586 find_graphics_res(vga,&gw,&gh);
588 find_shift_mode(vga,&sm);
590 find_graphics_cursor_pos(vga,&cur_x,&cur_y);
596 PrintDebug("vga: attempting graphics render (%s): graphics_res=(%u,%u), fb_res=(%u,%u), "
597 "fb=0x%p (16 color mode)\n",
598 sm == PLANAR_SHIFT ? "planar shift" :
599 sm == PACKED_SHIFT ? "packed shift" :
600 sm == C256_SHIFT ? "color256 shift" : "UNKNOWN",
603 // First we need to clip to what we can actually show
604 rgw = gw < fw ? gw : fw;
605 rgh = gh < fh ? gh : gw;
608 PrintError("vga: warning: graphics width is not a multiple of 8\n");
611 offset=0; // do we always start at zero in the map?
613 // Now we scan across by row
614 for (fy=0;fy<gh;fy++) {
617 fx += (sm==C256_SHIFT ? 4 : 8) , offset++ ) {
619 // if any of these pixels are in the renger region
620 if (fy < rgh && fx < rgw) {
621 // assemble all 4 or 8 pixels
623 // fetch the data bytes
625 db[m]=*((uint8_t*)(vga->map[m]+offset));
645 // first 4 pixels use planes 0 and 2
655 // next 4 pixels use planes 1 and 3
666 // this one is either very bizarre or as simple as this
674 for (p=0;p< (sm==C256_SHIFT ? 4 : 8);p++) {
677 find_24bit_color(vga,db[p],&r,&g,&b);
679 // find its position in the framebuffer;
680 pixel = fb + (((fx + p) + (fy*spec->width)) * spec->bytes_per_pixel);
681 red = pixel + spec->red_offset;
682 green = pixel + spec->green_offset;
683 blue = pixel + spec->blue_offset;
694 PrintDebug("vga: render done\n");
698 static void render_text_cursor(struct vga_internal *vga, void *fb)
706 // A variant of this function could render to
707 // a text console interface as well
709 static void render_text(struct vga_internal *vga, void *fb)
711 // line graphics enable bit means to dupe column 8 to 9 when
712 // in 9 dot wide mode
713 // otherwise 9th dot is background
715 struct v3_frame_buffer_spec *spec = &(vga->target_spec);
717 uint32_t gw, gh; // graphics w/h
718 uint32_t tw, th; // text w/h
719 uint32_t rtw, rth; // rendered text w/h
720 uint32_t cw, ch; // char font w/h including 8/9
721 uint32_t fw, fh; // fb w/h
723 uint32_t px, py; // cursor position
725 uint32_t x, y, l, p; // text location, line and pixel within the char
726 uint32_t fx, fy; // pixel position within the frame buffer
729 uint8_t *text; // points to current char
730 uint8_t *attr; // and its matching attribute
731 uint8_t *curs; // to where the cursor is
732 uint8_t *font; // to where the current font is
734 uint8_t fg_entry; // foreground color entry
735 uint8_t bg_entry; // background color entry
736 uint8_t fgr,fgg,fgb; // looked up foreground colors
737 uint8_t bgr,bgg,bgb; // looked up bg colors
739 uint8_t ct, ca; // the current char and attribute
740 struct vga_attribute_byte a; // decoded attribute
742 void *pixel; // current pixel in the fb
743 uint8_t *red; // and the channels in the pixel
749 find_graphics_res(vga,&gw,&gh);
750 find_text_res(vga,&tw,&th);
751 find_text_char_dim(vga,&cw,&ch);
755 find_text_cursor_pos(vga,&px,&py,(void**)&curs);
756 find_text_data_start(vga,(void**)&text);
757 find_text_attr_start(vga,(void**)&attr);
759 find_text_font_start(vga,(void**)&font,0); // will need to switch this as we go since it is part of attr
761 PrintDebug("vga: attempting text render: graphics_res=(%u,%u), fb_res=(%u,%u), text_res=(%u,%u), "
762 "char_res=(%u,%u), cursor=(%u,%u) font=0x%p, text=0x%p, attr=0x%p, curs=0x%p, fb=0x%p"
763 "graphics extension=%u, extended_fontset=%d, blinking=%d\n",
764 gw,gh,fw,fh,tw,th,cw,ch,px,py,font,text,attr,curs,fb,
765 vga->vga_attribute_controller.vga_attribute_mode_control.enable_line_graphics_char_code,
766 extended_fontset(vga), blinking(vga));
770 // First we need to clip to what we can actually show
771 rtw = tw < fw/cw ? tw : fw/cw;
772 rth = th < fh/ch ? th : fh/ch;
776 // Now let's scan by char across the whole thing
778 for (x=0;x<tw;x++, text++, attr++) {
779 if (x < rtw && y < rth) {
780 // grab the character and attribute for the position
785 // find the character's font bitmap (one byte per row)
786 find_text_font_start(vga,(void**)&font,
787 extended_fontset(vga) ? a.foreground_intensity_or_font_select : 0 );
789 font += ct * ((VGA_MAX_FONT_HEIGHT * VGA_FONT_WIDTH)/8);
791 // Now let's find out what colors we will be using
794 if (!extended_fontset(vga)) {
795 fg_entry = a.foreground_intensity_or_font_select << 3;
801 find_24bit_color(vga,fg_entry,&fgr,&fgg,&fgb);
803 if (!blinking(vga)) {
804 bg_entry = a.blinking_or_bg_intensity << 3;
810 find_24bit_color(vga,bg_entry,&bgr,&bgg,&bgb);
812 // Draw the character
813 for (l=0; l<ch; l++, font++) {
814 uint8_t frow = *font; // this is the row of of the font map
818 // a char can be 9 bits wide, but the font map
819 // is only 8 bits wide, which means we need to know where to
822 // We get it from the font map if
823 // its line line graphics mode and its a graphics char
824 // otherwise it's the background color
825 if (vga->vga_attribute_controller.vga_attribute_mode_control.enable_line_graphics_char_code
826 && ct>=0xc0 && ct<=0xdf ) {
832 fbit= (frow >> (7-p) ) & 0x1;
835 // We are now at the pixel level, with fbit being the pixel we draw (color+attr or bg+attr)
836 // For now, we will draw it as black/white
838 // find its position in the framebuffer;
841 pixel = fb + ((fx + (fy*spec->width)) * spec->bytes_per_pixel);
842 red = pixel + spec->red_offset;
843 green = pixel + spec->green_offset;
844 blue = pixel + spec->blue_offset;
846 // Are we on the cursor?
847 // if so, let's negate this pixel to invert the cell
851 // update the framebuffer
874 static void render_test(struct vga_internal *vga, void *fb)
876 struct v3_frame_buffer_spec *s;
878 s=&(vga->target_spec);
880 if (fb && s->height>=480 && s->width>=640 ) {
881 uint8_t color = (uint8_t)(vga->updates_since_render);
885 for (y=0;y<480;y++) {
886 for (x=0;x<640;x++) {
887 void *pixel = fb + ((x + (y*s->width)) * s->bytes_per_pixel);
888 uint8_t *red = pixel + s->red_offset;
889 uint8_t *green = pixel + s->green_offset;
890 uint8_t *blue = pixel + s->blue_offset;
896 } else if (y<(480/2)) {
900 } else if (y<(3*(480/4))) {
905 *red=*green=*blue=color+x;
912 static void render_maps(struct vga_internal *vga, void *fb)
915 struct v3_frame_buffer_spec *s;
918 s=&(vga->target_spec);
920 if (fb && s->height>=768 && s->width>=1024 && !(vga->updates_since_render % 100)) {
921 // we draw the maps next, each being a 256x256 block appearing 32 pixels below the display block
928 for (y=480+32;y<768;y++) {
929 for (x=m*256;x<(m+1)*256;x++,b++) {
930 void *pixel = fb + ((x + (y*s->width)) * s->bytes_per_pixel);
931 uint8_t *red = pixel + s->red_offset;
932 uint8_t *green = pixel + s->green_offset;
933 uint8_t *blue = pixel + s->blue_offset;
935 *red=*green=*blue=*b;
943 static int render(struct vga_internal *vga)
948 vga->updates_since_render++;
950 if (vga->updates_since_render%100) {
955 if (vga->host_cons && v3_graphics_console_inform_update(vga->host_cons)>0) {
957 fb = v3_graphics_console_get_frame_buffer_data_rw(vga->host_cons,&(vga->target_spec));
959 if (vga->vga_graphics_controller.vga_misc.graphics_mode) {
960 render_graphics(vga,fb);
963 render_text_cursor(vga,fb);
966 if (0) { render_test(vga,fb); }
970 v3_graphics_console_release_frame_buffer_data_rw(vga->host_cons);
977 static void get_mem_region(struct vga_internal *vga, uint64_t *mem_start, uint64_t *mem_end)
979 switch (vga->vga_graphics_controller.vga_misc.memory_map) {
999 static uint64_t find_offset_write(struct vga_internal *vga, addr_t guest_addr)
1001 uint64_t mem_start, mem_end;
1004 mem_start=mem_end=0;
1006 get_mem_region(vga, &mem_start, &mem_end);
1008 size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start));
1010 if (vga->vga_sequencer.vga_mem_mode.odd_even) {
1011 return (guest_addr-mem_start) % size;
1014 return ((guest_addr-mem_start) >> 1 ) % size;
1021 // Determines which maps should be enabled for this single byte write
1022 // and what the increment (actually 1/increment for the copy loop
1024 // memory_mode.odd_even == 0 => even address = maps 0 and 2 enabled; 1,3 otherwise
1026 static uint8_t find_map_write(struct vga_internal *vga, addr_t guest_addr)
1028 uint8_t mm = vga->vga_sequencer.vga_map_mask.val;
1030 if (vga->vga_sequencer.vga_mem_mode.odd_even) {
1033 if (guest_addr & 0x1) {
1034 return mm & 0xa; // 0x1010
1036 return mm & 0x5; // 0x0101
1041 static uint8_t find_increment_write(struct vga_internal *vga, addr_t new_guest_addr)
1043 if (vga->vga_sequencer.vga_mem_mode.odd_even) {
1046 return !(new_guest_addr & 0x1);
1052 static int vga_write(struct guest_info * core,
1058 struct vm_device *dev = (struct vm_device *)priv_data;
1059 struct vga_internal *vga = (struct vga_internal *) dev->private_data;
1061 PrintDebug("vga: memory write: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
1063 if (vga->passthrough) {
1064 PrintDebug("vga: passthrough write to 0x%p\n", V3_VAddr((void*)guest_addr));
1065 memcpy(V3_VAddr((void*)guest_addr),src,length);
1070 PrintDebug("vga: data written was 0x");
1071 for (i=0;i<length;i++) {
1072 uint8_t c= ((char*)src)[i];
1073 PrintDebug("%.2x", c);
1076 for (i=0;i<length;i++) {
1077 char c= ((char*)src)[i];
1078 PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c==' ') ? c : '.');
1083 /* Write mode determine by Graphics Mode Register (Index 05h).writemode */
1086 switch (vga->vga_graphics_controller.vga_graphics_mode.write_mode) {
1090 00b -- Write Mode 0: In this mode, the host data is first rotated
1091 as per the Rotate Count field, then the Enable Set/Reset mechanism
1092 selects data from this or the Set/Reset field. Then the selected
1093 Logical Operation is performed on the resulting data and the data
1094 in the latch register. Then the Bit Mask field is used to select
1095 which bits come from the resulting data and which come
1096 from the latch register. Finally, only the bit planes enabled by
1097 the Memory Plane Write Enable field are written to memory.
1105 uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
1106 uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
1108 offset = find_offset_write(vga, guest_addr);
1110 PrintDebug("vga: mode 0 write, offset=0x%llx, ror=%u, func=%u\n", offset,ror,func);
1112 for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) {
1114 uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
1115 uint8_t esr = vga->vga_graphics_controller.vga_enable_set_reset.val &0xf;
1116 uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
1117 uint8_t mm = find_map_write(vga,guest_addr+i);
1119 //PrintDebug("vga: write i=%u, mm=0x%x, offset=0x%x\n",i,(unsigned int)mm,(unsigned int)offset);
1121 for (mapnum=0;mapnum<4;mapnum++, sr>>=1, esr>>=1, bm>>=1, mm>>=1) {
1122 vga_map map = vga->map[mapnum];
1123 uint8_t data = ((uint8_t *)src)[i];
1124 uint8_t latchval = vga->latch[mapnum];
1126 // rotate data right
1127 data = (data>>ror) | data<<(8-ror);
1129 // use SR bit if ESR is on for this map
1131 data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7); // expand sr bit
1149 // mux between latch and alu output
1151 // use alu output, which is in data
1159 // write to this map
1160 //PrintDebug("vga: write map %u offset 0x%p map=0x%p pointer=0x%p\n",mapnum,(void*)offset,map,&(map[offset]));
1174 01b -- Write Mode 1: In this mode, data is transferred directly
1175 from the 32 bit latch register to display memory, affected only by
1176 the Memory Plane Write Enable field. The host data is not used in this mode.
1181 uint64_t offset = find_offset_write(vga,guest_addr);
1183 PrintDebug("vga: mode 1 write, offset=0x%llx\n", offset);
1185 for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) {
1188 uint8_t mm = find_map_write(vga,guest_addr+i);
1190 for (mapnum=0;mapnum<4;mapnum++, mm>>=1) {
1191 vga_map map = vga->map[mapnum];
1192 uint8_t latchval = vga->latch[mapnum];
1196 // write to this map
1197 map[offset] = latchval;
1208 10b -- Write Mode 2: In this mode, the bits 3-0 of the host data
1209 are replicated across all 8 bits of their respective planes.
1210 Then the selected Logical Operation is performed on the resulting
1211 data and the data in the latch register. Then the Bit Mask field is used to
1212 select which bits come from the resulting data and which come from
1213 the latch register. Finally, only the bit planes enabled by the
1214 Memory Plane Write Enable field are written to memory.
1220 uint8_t func = vga->vga_graphics_controller.vga_data_rotate.function;
1222 offset = find_offset_write(vga, guest_addr);
1224 PrintDebug("vga: mode 2 write, offset=0x%llx, func=%u\n", offset,func);
1226 for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) {
1228 uint8_t bm = vga->vga_graphics_controller.vga_bit_mask;
1229 uint8_t mm = find_map_write(vga,guest_addr+i);
1231 for (mapnum=0;mapnum<4;mapnum++, bm>>=1, mm>>=1) {
1232 vga_map map = vga->map[mapnum];
1233 uint8_t data = ((uint8_t *)src)[i];
1234 uint8_t latchval = vga->latch[mapnum];
1236 // expand relevant bit to 8 bit
1237 // it's basically esr=1, sr=bit from write
1238 data = (uint8_t)(((sint8_t)(((data>>mapnum)&0x1)<<7))>>7);
1255 // mux between latch and alu output
1257 // use alu output, which is in data
1265 // write to this map
1276 /* 11b -- Write Mode 3: In this mode, the data in the Set/Reset field is used
1277 as if the Enable Set/Reset field were set to 1111b. Then the host data is
1278 first rotated as per the Rotate Count field, then logical ANDed with the
1279 value of the Bit Mask field. The resulting value is used on the data
1280 obtained from the Set/Reset field in the same way that the Bit Mask field
1281 would ordinarily be used. to select which bits come from the expansion
1282 of the Set/Reset field and which come from the latch register. Finally,
1283 only the bit planes enabled by the Memory Plane Write Enable field
1284 are written to memory.
1291 uint8_t ror = vga->vga_graphics_controller.vga_data_rotate.rotate_count;
1293 offset = find_offset_write(vga, guest_addr);
1295 PrintDebug("vga: mode 3 write, offset=0x%llx, ror=%u\n", offset,ror);
1297 for (i=0;i<length;i++,offset+=find_increment_write(vga,guest_addr+i)) {
1299 uint8_t data = ((uint8_t *)src)[i];
1301 data = (data>>ror) | data<<(8-ror);
1303 uint8_t bm = vga->vga_graphics_controller.vga_bit_mask & data;
1304 uint8_t sr = vga->vga_graphics_controller.vga_set_reset.val & 0xf;
1305 uint8_t mm = find_map_write(vga,guest_addr+i);
1307 for (mapnum=0;mapnum<4;mapnum++, sr>>=1, bm>>=1, mm>>=1) {
1308 vga_map map = vga->map[mapnum];
1309 uint8_t latchval = vga->latch[mapnum];
1311 data = (uint8_t)((((sint8_t)(sr&0x1))<<7)>>7); // expand sr bit
1314 // mux between latch and alu output
1316 // use alu output, which is in data
1324 // write to this map
1335 // There is no default
1345 static uint64_t find_offset_read(struct vga_internal *vga, addr_t guest_addr)
1347 uint64_t mem_start, mem_end;
1350 mem_start=mem_end=0;
1352 get_mem_region(vga, &mem_start, &mem_end);
1354 size=(mem_end-mem_start > 65536 ? 65536 : (mem_end-mem_start));
1356 if (!vga->vga_sequencer.vga_mem_mode.chain4) {
1357 return (guest_addr-mem_start) % size;
1360 return ((guest_addr - mem_start) >> 2) % size;
1364 static uint8_t find_increment_read(struct vga_internal *vga, addr_t new_guest_addr)
1367 if (vga->vga_sequencer.vga_mem_mode.chain4) {
1368 return !(new_guest_addr & 0x3);
1375 static int vga_read(struct guest_info * core,
1381 struct vm_device *dev = (struct vm_device *)priv_data;
1382 struct vga_internal *vga = (struct vga_internal *) dev->private_data;
1385 PrintDebug("vga: memory read: guest_addr=0x%p len=%u\n",(void*)guest_addr, length);
1390 Reading, 2 modes, set via Graphics Mode Register (index 05h).Read Mode:
1392 switch (vga->vga_graphics_controller.vga_graphics_mode.read_mode) {
1394 /* 0 - a byte from ONE of the 4 planes is returned;
1395 which plane is determined by Read Map Select (Read Map Select Register (Index 04h)) */
1400 if (vga->vga_sequencer.vga_mem_mode.chain4) {
1402 offset = find_offset_read(vga,guest_addr);
1403 // address bytes select the map
1404 for (i=0;i<length;i++,offset+=find_increment_read(vga,guest_addr+i)) {
1405 mapnum = (guest_addr+i) % 4;
1406 ((uint8_t*)dst)[i] = vga->latch[mapnum] = *(vga->map[mapnum]+offset);
1409 mapnum = vga->vga_graphics_controller.vga_read_map_select.map_select;
1410 offset = find_offset_read(vga,guest_addr);
1412 if (offset>=65536) {
1413 PrintError("vga: read to offset=%llu map=%u (%u bytes)\n",offset,mapnum,length);
1416 memcpy(dst,(vga->map[mapnum])+offset,length);
1418 // load the latches with the last item read
1419 for (mapnum=0;mapnum<4;mapnum++) {
1420 vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
1427 /* 1 - Compare video memory and reference color
1428 (in Color Compare, except those not set in Color Don't Care),
1429 each bit in returned result is one comparison between the reference color
1431 Ref color is *4* bits, and thus a one byte read returns a comparison
1437 uint8_t cc=vga->vga_graphics_controller.vga_color_compare.val & 0xf ;
1438 uint8_t dc=vga->vga_graphics_controller.vga_color_dont_care.val & 0xf;
1445 offset = find_offset_read(vga,guest_addr);
1447 for (i=0;i<length;i++,offset++) {
1450 for (mapnum=0;mapnum<4;mapnum++) {
1451 map = vga->map[mapnum];
1452 if ( (dc>>mapnum)&0x1 ) { // don't care
1456 bits = (map[offset]&0xf) == cc;
1459 bits |= (((map[offset]>>4))&0xf) == cc;
1461 // not clear whether it is 0..k or k..0
1467 // load the latches with the last item read
1468 for (mapnum=0;mapnum<4;mapnum++) {
1469 vga->latch[mapnum] = vga->map[mapnum][offset+length-1];
1474 // there is no default
1477 if (vga->passthrough) {
1478 PrintDebug("vga: passthrough read from 0x%p\n",V3_VAddr((void*)guest_addr));
1479 memcpy(dst,V3_VAddr((void*)guest_addr),length);
1485 PrintDebug("vga: data read is 0x");
1486 for (i=0;i<length;i++) {
1487 uint8_t c= ((char*)dst)[i];
1488 PrintDebug("%.2x", c);
1491 for (i=0;i<length;i++) {
1492 char c= ((char*)dst)[i];
1493 PrintDebug("%c", (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || (c==' ') ? c : '.');
1506 #define ERR_WRONG_SIZE(op,reg,len,min,max) \
1507 if (((len)<(min)) || ((len)>(max))) { \
1508 PrintError("vga: %s of %s wrong size (%d bytes, but only %d to %d allowed)\n",(op),(reg),(len),(min),(max)); \
1512 static inline void passthrough_io_in(uint16_t port, void * dest, uint_t length) {
1515 *(uint8_t *)dest = v3_inb(port);
1518 *(uint16_t *)dest = v3_inw(port);
1521 *(uint32_t *)dest = v3_indw(port);
1524 PrintError("vga: unsupported passthrough io in size %u\n",length);
1530 static inline void passthrough_io_out(uint16_t port, const void * src, uint_t length) {
1533 v3_outb(port, *(uint8_t *)src);
1536 v3_outw(port, *(uint16_t *)src);
1539 v3_outdw(port, *(uint32_t *)src);
1542 PrintError("vga: unsupported passthrough io out size %u\n",length);
1547 #define PASSTHROUGH_IO_IN(vga,port,dest,len) \
1548 do { if ((vga)->passthrough) { passthrough_io_in(port,dest,len); } } while (0)
1550 #define PASSTHROUGH_IO_OUT(vga,port,src,len) \
1551 do { if ((vga)->passthrough && (!(vga)->skip_next_passthrough_out)) { passthrough_io_out(port,src,len); } (vga)->skip_next_passthrough_out=false; } while (0)
1553 #define PASSTHROUGH_IO_SKIP_NEXT_OUT(vga) \
1554 do { if ((vga)->passthrough) { (vga)->skip_next_passthrough_out=true; } } while (0)
1556 #define PASSTHROUGH_READ_CHECK(vga,inter,pass) \
1557 do { if ((vga)->passthrough) { if ((inter)!=(pass)) { PrintError("vga: passthrough error: passthrough value read is 0x%x, but internal value read is 0x%x\n",(pass),(inter)); } } } while (0)
1559 static int misc_out_read(struct guest_info *core,
1565 struct vga_internal *vga = (struct vga_internal *) priv_data;
1567 PrintDebug("vga: misc out read data=0x%x\n", vga->vga_misc.vga_misc_out.val);
1569 ERR_WRONG_SIZE("read","misc out",len,1,1);
1571 *((uint8_t*)dest) = vga->vga_misc.vga_misc_out.val;
1573 PASSTHROUGH_IO_IN(vga,port,dest,len);
1575 PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_misc_out.val,*((uint8_t*)dest));
1580 static int misc_out_write(struct guest_info *core,
1586 struct vga_internal *vga = (struct vga_internal *) priv_data;
1588 PrintDebug("vga: misc out write data=0x%x\n", *((uint8_t*)src));
1590 ERR_WRONG_SIZE("write","misc out",len,1,1);
1592 PASSTHROUGH_IO_OUT(vga,port,src,len);
1594 vga->vga_misc.vga_misc_out.val = *((uint8_t*)src) ;
1603 static int input_stat0_read(struct guest_info *core,
1609 struct vga_internal *vga = (struct vga_internal *) priv_data;
1611 PrintDebug("vga: input stat0 read data=0x%x\n", vga->vga_misc.vga_input_stat0.val);
1613 ERR_WRONG_SIZE("read","input stat0",len,1,1);
1615 *((uint8_t*)dest) = vga->vga_misc.vga_input_stat0.val;
1617 PASSTHROUGH_IO_IN(vga,port,dest,len);
1619 PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat0.val,*(uint8_t*)dest);
1625 static int input_stat1_read(struct guest_info *core,
1631 struct vga_internal *vga = (struct vga_internal *) priv_data;
1633 PrintDebug("vga: input stat0 (%s) read data=0x%x\n",
1634 port==0x3ba ? "mono" : "color",
1635 vga->vga_misc.vga_input_stat1.val);
1637 ERR_WRONG_SIZE("read","input stat1",len,1,1);
1640 *((uint8_t*)dest) = vga->vga_misc.vga_input_stat1.val;
1642 // Stunningly, reading stat1 is also a way to reset
1643 // the state of attribute controller address/data flipflop
1644 // That is some mighty fine crack the designers were smoking.
1646 vga->vga_attribute_controller.state=ATTR_ADDR;
1648 PASSTHROUGH_IO_IN(vga,port,dest,len);
1650 PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_input_stat1.val,*(uint8_t*)dest);
1656 static int feature_control_read(struct guest_info *core,
1662 struct vga_internal *vga = (struct vga_internal *) priv_data;
1664 PrintDebug("vga: feature control read data=0x%x\n",
1665 vga->vga_misc.vga_feature_control.val);
1667 ERR_WRONG_SIZE("read","feature control",len,1,1);
1670 *((uint8_t*)dest) = vga->vga_misc.vga_feature_control.val;
1672 PASSTHROUGH_IO_IN(vga,port,dest,len);
1674 PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_feature_control.val,*(uint8_t*)dest);
1679 static int feature_control_write(struct guest_info *core,
1685 struct vga_internal *vga = (struct vga_internal *) priv_data;
1687 PrintDebug("vga: feature control (%s) write data=0x%x\n",
1688 port==0x3ba ? "mono" : "color",
1691 ERR_WRONG_SIZE("write","feature control",len,1,1);
1693 PASSTHROUGH_IO_OUT(vga,port,src,len);
1695 vga->vga_misc.vga_feature_control.val = *((uint8_t*)src) ;
1703 static int video_subsys_enable_read(struct guest_info *core,
1709 struct vga_internal *vga = (struct vga_internal *) priv_data;
1711 PrintDebug("vga: video subsys enable read data=0x%x\n",
1712 vga->vga_misc.vga_video_subsys_enable.val);
1714 ERR_WRONG_SIZE("read","video subsys enable",len,1,1);
1716 *((uint8_t*)dest) = vga->vga_misc.vga_video_subsys_enable.val;
1718 PASSTHROUGH_IO_IN(vga,port,dest,len);
1720 PASSTHROUGH_READ_CHECK(vga,vga->vga_misc.vga_video_subsys_enable.val,*(uint8_t*)dest);
1725 static int video_subsys_enable_write(struct guest_info *core,
1731 struct vga_internal *vga = (struct vga_internal *) priv_data;
1733 PrintDebug("vga: video subsys enable write data=0x%x\n", *((uint8_t*)src));
1735 ERR_WRONG_SIZE("write","video subsys enable",len,1,1);
1737 PASSTHROUGH_IO_OUT(vga,port,src,len);
1739 vga->vga_misc.vga_video_subsys_enable.val = *((uint8_t*)src) ;
1746 static int sequencer_address_read(struct guest_info *core,
1752 struct vga_internal *vga = (struct vga_internal *) priv_data;
1754 PrintDebug("vga: sequencer address read data=0x%x\n",
1755 vga->vga_sequencer.vga_sequencer_addr.val);
1757 ERR_WRONG_SIZE("read","vga sequencer addr",len,1,1);
1759 *((uint8_t*)dest) = vga->vga_sequencer.vga_sequencer_addr.val;
1761 PASSTHROUGH_IO_IN(vga,port,dest,len);
1763 PASSTHROUGH_READ_CHECK(vga,vga->vga_sequencer.vga_sequencer_addr.val,*(uint8_t*)dest);
1768 static int sequencer_data_write(struct guest_info *core,
1774 struct vga_internal *vga = (struct vga_internal *) priv_data;
1778 data=*((uint8_t*)src);
1779 index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
1781 PrintDebug("vga: sequencer write data (index=%d) with 0x%x\n",
1784 ERR_WRONG_SIZE("write","vga sequencer data",len,1,1);
1786 PASSTHROUGH_IO_OUT(vga,port,src,len);
1789 if (index>=VGA_SEQUENCER_NUM) {
1790 PrintError("vga: sequencer data write is for invalid index %d, ignoring\n",index);
1792 vga->vga_sequencer.vga_sequencer_regs[index] = data;
1800 static int sequencer_address_write(struct guest_info *core,
1806 struct vga_internal *vga = (struct vga_internal *) priv_data;
1809 new_addr=*((uint8_t*)src);
1811 PrintDebug("vga: sequencer address write data=0x%x len=%u\n", len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
1813 ERR_WRONG_SIZE("write","vga sequencer addr",len,1,2);
1815 PASSTHROUGH_IO_OUT(vga,port,src,len);
1817 vga->vga_sequencer.vga_sequencer_addr.val = *((uint8_t*)src) ;
1820 PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
1821 // second byte is the data
1822 if (sequencer_data_write(core,port,src+1,1,vga)!=1) {
1823 PrintError("vga: write of data failed\n");
1831 static int sequencer_data_read(struct guest_info *core,
1837 struct vga_internal *vga = (struct vga_internal *) priv_data;
1841 index=vga->vga_sequencer.vga_sequencer_addr.val; // should mask probably
1843 if (index>=VGA_SEQUENCER_NUM) {
1845 PrintError("vga: sequencer data read at invalid index %d, returning zero\n",index);
1847 data=vga->vga_sequencer.vga_sequencer_regs[index];
1850 PrintDebug("vga: sequencer data read data (index=%d) = 0x%x\n",
1853 ERR_WRONG_SIZE("read","vga sequencer data",len,1,1);
1855 *((uint8_t*)dest) = data;
1857 PASSTHROUGH_IO_IN(vga,port,dest,len);
1859 PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
1868 static int crt_controller_address_read(struct guest_info *core,
1874 struct vga_internal *vga = (struct vga_internal *) priv_data;
1876 PrintDebug("vga: crt controller (%s) address read data=0x%x\n",
1877 port==0x3b4 ? "mono" : "color",
1878 vga->vga_crt_controller.vga_crt_addr.val);
1880 ERR_WRONG_SIZE("read","vga crt controller addr",len,1,1);
1882 *((uint8_t*)dest) = vga->vga_crt_controller.vga_crt_addr.val;
1884 PASSTHROUGH_IO_IN(vga,port,dest,len);
1886 PASSTHROUGH_READ_CHECK(vga,vga->vga_crt_controller.vga_crt_addr.val,*(uint8_t*)dest);
1891 static int crt_controller_data_write(struct guest_info *core,
1897 struct vga_internal *vga = (struct vga_internal *) priv_data;
1901 data=*((uint8_t*)src);
1903 index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
1905 PrintDebug("vga: crt controller (%s) write data (index=%d) with 0x%x\n",
1906 port==0x3b5 ? "mono" : "color",
1909 ERR_WRONG_SIZE("write","vga crt controller data",len,1,1);
1911 PASSTHROUGH_IO_OUT(vga,port,src,len);
1913 if (index>=VGA_CRT_CONTROLLER_NUM) {
1914 PrintError("vga; crt controller write is for illegal index %d, ignoring\n",index);
1916 vga->vga_crt_controller.vga_crt_controller_regs[index] = data;
1924 static int crt_controller_address_write(struct guest_info *core,
1930 struct vga_internal *vga = (struct vga_internal *) priv_data;
1933 new_addr=*((uint8_t*)src);
1935 PrintDebug("vga: crt controller (%s) address write data=0x%x len=%u\n",
1936 port==0x3b4 ? "mono" : "color",
1937 len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
1939 ERR_WRONG_SIZE("write","vga crt controller addr",len,1,2);
1941 PASSTHROUGH_IO_OUT(vga,port,src,len);
1943 vga->vga_crt_controller.vga_crt_addr.val = *((uint8_t*)src) ;
1946 PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
1947 // second byte is the data
1948 if (crt_controller_data_write(core,port,src+1,1,vga)!=1) {
1949 PrintError("vga: write of data failed\n");
1957 static int crt_controller_data_read(struct guest_info *core,
1963 struct vga_internal *vga = (struct vga_internal *) priv_data;
1967 index=vga->vga_crt_controller.vga_crt_addr.val; // should mask probably
1969 if (index>=VGA_CRT_CONTROLLER_NUM) {
1971 PrintError("vga: crt controller data read for illegal index %d, returning zero\n",index);
1973 data=vga->vga_crt_controller.vga_crt_controller_regs[index];
1976 PrintDebug("vga: crt controller data (index=%d) = 0x%x\n",index,data);
1978 ERR_WRONG_SIZE("read","vga crt controller data",len,1,1);
1980 *((uint8_t*)dest) = data;
1982 PASSTHROUGH_IO_IN(vga,port,dest,len);
1984 PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t *)dest);
1991 static int graphics_controller_address_read(struct guest_info *core,
1997 struct vga_internal *vga = (struct vga_internal *) priv_data;
1999 PrintDebug("vga: graphics controller address read data=0x%x\n",
2000 vga->vga_graphics_controller.vga_graphics_ctrl_addr.val);
2002 ERR_WRONG_SIZE("read","vga graphics controller addr",len,1,1);
2004 *((uint8_t*)dest) = vga->vga_graphics_controller.vga_graphics_ctrl_addr.val;
2006 PASSTHROUGH_IO_IN(vga,port,dest,len);
2008 PASSTHROUGH_READ_CHECK(vga,vga->vga_graphics_controller.vga_graphics_ctrl_addr.val,*(uint8_t*)dest);
2013 static int graphics_controller_data_write(struct guest_info *core,
2019 struct vga_internal *vga = (struct vga_internal *) priv_data;
2023 data=*((uint8_t*)src);
2024 index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
2027 PrintDebug("vga: graphics_controller write data (index=%d) with 0x%x\n",
2030 ERR_WRONG_SIZE("write","vga graphics controller data",len,1,1);
2032 PASSTHROUGH_IO_OUT(vga,port,src,len);
2034 if (index>=VGA_GRAPHICS_CONTROLLER_NUM) {
2035 PrintError("vga: graphics controller write for illegal index %d ignored\n",index);
2037 vga->vga_graphics_controller.vga_graphics_controller_regs[index] = data;
2045 static int graphics_controller_address_write(struct guest_info *core,
2051 struct vga_internal *vga = (struct vga_internal *) priv_data;
2054 new_addr=*((uint8_t*)src);
2056 PrintDebug("vga: graphics controller address write data=0x%x len=%u\n",
2057 len==1 ? *((uint8_t*)src) : len==2 ? *((uint16_t*)src) : *((uint32_t*)src), len);
2059 ERR_WRONG_SIZE("write","vga graphics controller addr",len,1,2);
2061 PASSTHROUGH_IO_OUT(vga,port,src,len);
2063 vga->vga_graphics_controller.vga_graphics_ctrl_addr.val = *((uint8_t*)src) ;
2066 PASSTHROUGH_IO_SKIP_NEXT_OUT(vga);
2067 // second byte is the data
2068 if (graphics_controller_data_write(core,port,src+1,1,vga)!=1) {
2069 PrintError("vga: write of data failed\n");
2077 static int graphics_controller_data_read(struct guest_info *core,
2083 struct vga_internal *vga = (struct vga_internal *) priv_data;
2087 index=vga->vga_graphics_controller.vga_graphics_ctrl_addr.val; // should mask probably
2090 if (index>=VGA_GRAPHICS_CONTROLLER_NUM) {
2092 PrintError("vga: graphics controller data read from illegal index %d, returning zero\n",index);
2094 data=vga->vga_graphics_controller.vga_graphics_controller_regs[index];
2097 PrintDebug("vga: graphics controller data read data (index=%d) = 0x%x\n",
2100 ERR_WRONG_SIZE("read","vga graphics controller data",len,1,1);
2102 *((uint8_t*)dest) = data;
2104 PASSTHROUGH_IO_IN(vga,port,dest,len);
2106 PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
2114 /* Note that these guys have a bizarre protocol*/
2116 static int attribute_controller_address_read(struct guest_info *core,
2122 struct vga_internal *vga = (struct vga_internal *) priv_data;
2124 PrintDebug("vga: attribute controller address read data=0x%x\n",
2125 vga->vga_attribute_controller.vga_attribute_controller_addr.val);
2127 ERR_WRONG_SIZE("read","vga attribute controller addr",len,1,1);
2129 *((uint8_t*)dest) = vga->vga_attribute_controller.vga_attribute_controller_addr.val;
2131 PASSTHROUGH_IO_IN(vga,port,dest,len);
2133 PASSTHROUGH_READ_CHECK(vga,vga->vga_attribute_controller.vga_attribute_controller_addr.val,*(uint8_t*)dest);
2135 // Reading the attribute controller does not change the state
2140 static int attribute_controller_address_and_data_write(struct guest_info *core,
2146 struct vga_internal *vga = (struct vga_internal *) priv_data;
2149 if (vga->vga_attribute_controller.state==ATTR_ADDR) {
2150 uint8_t new_addr = *((uint8_t*)src);
2151 // We are to treat this as an address write, and flip state
2152 // to expect data ON THIS SAME PORT
2153 PrintDebug("vga: attribute controller address write data=0x%x\n", new_addr);
2155 ERR_WRONG_SIZE("write","vga attribute controller addr",len,1,1);
2157 PASSTHROUGH_IO_OUT(vga,port,src,len);
2159 vga->vga_attribute_controller.vga_attribute_controller_addr.val = new_addr;
2161 vga->vga_attribute_controller.state=ATTR_DATA;
2164 } else if (vga->vga_attribute_controller.state==ATTR_DATA) {
2166 uint8_t data = *((uint8_t*)src);
2167 uint8_t index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
2169 PrintDebug("vga: attribute controller data write index %d with data=0x%x\n", index,data);
2171 ERR_WRONG_SIZE("write","vga attribute controller data",len,1,1);
2173 PASSTHROUGH_IO_OUT(vga,port,src,len);
2175 if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) {
2176 PrintError("vga: attribute controller write to illegal index %d ignored\n",index);
2178 vga->vga_attribute_controller.vga_attribute_controller_regs[index] = data;
2181 vga->vga_attribute_controller.state=ATTR_ADDR;
2190 static int attribute_controller_data_read(struct guest_info *core,
2196 struct vga_internal *vga = (struct vga_internal *) priv_data;
2200 index=vga->vga_attribute_controller.vga_attribute_controller_addr.val; // should mask probably
2202 if (index>=VGA_ATTRIBUTE_CONTROLLER_NUM) {
2204 PrintError("vga: attribute controller read of illegal index %d, returning zero\n",index);
2206 data=vga->vga_attribute_controller.vga_attribute_controller_regs[index];
2209 PrintDebug("vga: attribute controller data read data (index=%d) = 0x%x\n",
2212 ERR_WRONG_SIZE("read","vga attribute controller data",len,1,1);
2214 *((uint8_t*)dest) = data;
2216 PASSTHROUGH_IO_IN(vga,port,dest,len);
2218 PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
2225 Note that these guys also have a strange protocol
2226 since they need to squeeze 18 bits of data through
2229 static int dac_write_address_read(struct guest_info *core,
2235 struct vga_internal *vga = (struct vga_internal *) priv_data;
2237 PrintDebug("vga: dac write address read data=0x%x\n",
2238 vga->vga_dac.vga_dac_write_addr);
2240 ERR_WRONG_SIZE("read","vga dac write addr",len,1,1);
2243 *((uint8_t*)dest) = vga->vga_dac.vga_dac_write_addr;
2245 PASSTHROUGH_IO_IN(vga,port,dest,len);
2247 PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_write_addr,*(uint8_t*)dest);
2249 // This read does not reset the state machine
2254 static int dac_write_address_write(struct guest_info *core,
2260 struct vga_internal *vga = (struct vga_internal *) priv_data;
2263 new_addr=*((uint8_t*)src);
2265 PrintDebug("vga: dac write address write data=0x%x\n", new_addr);
2267 ERR_WRONG_SIZE("write","vga dac write addr",len,1,1);
2269 PASSTHROUGH_IO_OUT(vga,port,src,len);
2271 // cannot be out of bounds since there are 256 regs
2273 vga->vga_dac.vga_dac_write_addr = *((uint8_t*)src) ;
2275 // Now we also need to reset the state machine
2277 vga->vga_dac.state=DAC_WRITE;
2278 vga->vga_dac.channel=RED;
2284 static int dac_read_address_read(struct guest_info *core,
2290 struct vga_internal *vga = (struct vga_internal *) priv_data;
2292 PrintDebug("vga: dac read address read data=0x%x\n",
2293 vga->vga_dac.vga_dac_read_addr);
2295 ERR_WRONG_SIZE("read","vga dac read addr",len,1,1);
2297 *((uint8_t*)dest) = vga->vga_dac.vga_dac_read_addr;
2299 PASSTHROUGH_IO_IN(vga,port,dest,len);
2301 PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_dac_read_addr,*(uint8_t*)dest);
2303 // This read does not reset the state machine
2308 static int dac_read_address_write(struct guest_info *core,
2314 struct vga_internal *vga = (struct vga_internal *) priv_data;
2317 new_addr=*((uint8_t*)src);
2319 PrintDebug("vga: dac read address write data=0x%x\n", new_addr);
2321 ERR_WRONG_SIZE("write","vga dac read addr",len,1,1);
2323 PASSTHROUGH_IO_OUT(vga,port,src,len);
2325 // cannot be out of bounds since there are 256 regs
2327 vga->vga_dac.vga_dac_read_addr = *((uint8_t*)src) ;
2329 // Now we also need to reset the state machine
2331 vga->vga_dac.state=DAC_READ;
2332 vga->vga_dac.channel=RED;
2338 static int dac_data_read(struct guest_info *core,
2344 struct vga_internal *vga = (struct vga_internal *) priv_data;
2349 if (vga->vga_dac.state!=DAC_READ) {
2350 PrintError("vga: dac data read while in other state\n");
2351 // results undefined, so we continue
2354 ERR_WRONG_SIZE("read","vga dac read data",len,1,1);
2356 curreg = vga->vga_dac.vga_dac_read_addr;
2357 curchannel = vga->vga_dac.channel;
2358 data = (vga->vga_dac.vga_dac_palette[curreg] >> curchannel*8) & 0x3f;
2360 PrintDebug("vga: dac reg %u [%s] = 0x%x\n",
2362 curchannel == 0 ? "RED" : curchannel == 1 ? "GREEN"
2363 : curchannel==2 ? "BLUE" : "BAD CHANNEL",
2366 *((uint8_t*)dest) = data;
2368 PASSTHROUGH_IO_IN(vga,port,dest,len);
2370 PASSTHROUGH_READ_CHECK(vga,data,*(uint8_t*)dest);
2372 curchannel = (curchannel+1)%3;
2373 vga->vga_dac.channel=curchannel;
2374 if (curchannel==0) {
2375 curreg = (curreg + 1) % VGA_DAC_NUM_ENTRIES;
2377 vga->vga_dac.vga_dac_read_addr = curreg;
2378 vga->vga_dac.state=DAC_READ;
2385 static int dac_data_write(struct guest_info *core,
2391 struct vga_internal *vga = (struct vga_internal *) priv_data;
2395 vga_palette_reg data32;
2396 vga_palette_reg mask32;
2398 if (vga->vga_dac.state!=DAC_WRITE) {
2399 PrintError("vga: dac data write while in other state\n");
2400 // results undefined, so we continue
2403 ERR_WRONG_SIZE("read","vga dac write data",len,1,1);
2405 PASSTHROUGH_IO_OUT(vga,port,src,len);
2407 curreg = vga->vga_dac.vga_dac_write_addr;
2408 curchannel = vga->vga_dac.channel;
2409 data = *((uint8_t *)src);
2411 PrintDebug("vga: dac reg %u [%s] write with 0x%x\n",
2413 curchannel == 0 ? "RED" : curchannel == 1 ? "GREEN"
2414 : curchannel==2 ? "BLUE" : "BAD CHANNEL",
2417 data32 = data & 0x3f ;
2418 data32 <<= curchannel*8;
2419 mask32 = ~(0xff << (curchannel * 8));
2421 vga->vga_dac.vga_dac_palette[curreg] &= mask32;
2422 vga->vga_dac.vga_dac_palette[curreg] |= data32;
2424 curchannel = (curchannel+1)%3;
2425 vga->vga_dac.channel=curchannel;
2426 if (curchannel==0) {
2427 curreg = (curreg + 1) % VGA_DAC_NUM_ENTRIES;
2429 vga->vga_dac.vga_dac_write_addr = curreg;
2430 vga->vga_dac.state=DAC_WRITE;
2439 static int dac_pixel_mask_read(struct guest_info *core,
2445 struct vga_internal *vga = (struct vga_internal *) priv_data;
2447 PrintDebug("vga: dac pixel mask read data=0x%x\n",
2448 vga->vga_dac.vga_pixel_mask);
2450 ERR_WRONG_SIZE("read","vga pixel mask",len,1,1);
2452 *((uint8_t*)dest) = vga->vga_dac.vga_pixel_mask;
2454 PASSTHROUGH_IO_IN(vga,port,dest,len);
2456 PASSTHROUGH_READ_CHECK(vga,vga->vga_dac.vga_pixel_mask,*(uint8_t*)dest);
2461 static int dac_pixel_mask_write(struct guest_info *core,
2467 struct vga_internal *vga = (struct vga_internal *) priv_data;
2470 new_data=*((uint8_t*)src);
2472 PrintDebug("vga: dac pixel mask write data=0x%x\n", new_data);
2474 ERR_WRONG_SIZE("write","pixel mask",len,1,1);
2476 PASSTHROUGH_IO_OUT(vga,port,src,len);
2478 vga->vga_dac.vga_pixel_mask = new_data;
2483 static int init_vga(struct vga_internal *vga)
2485 // TODO: startup spec of register contents, if any
2486 PrintError("vga: init_vga is UNIMPLEMTED\n");
2490 static int free_vga(struct vga_internal *vga)
2494 struct vm_device *dev = vga->dev;
2496 // Framebuffer deletion is user's responsibility
2498 // if (vga->mem_store) {
2499 // V3_FreePages(v3_hva_to_hpa(vga->mem_store),MEM_REGION_NUM_PAGES);
2500 // vga->mem_store=0;
2503 for (i=0;i<MAP_NUM;i++) {
2505 V3_FreePages(V3_PAddr(vga->map[i]),MAP_SIZE/4096);
2510 v3_unhook_mem(vga->dev->vm, V3_MEM_CORE_ANY, MEM_REGION_START);
2514 ret |= v3_dev_unhook_io(dev, VGA_MISC_OUT_READ);
2515 // The following also covers VGA_INPUT_STAT0_READ
2516 ret |= v3_dev_unhook_io(dev, VGA_MISC_OUT_WRITE);
2517 // The following also covers VGA_FEATURE_CTRL_WRITE_MONO
2518 ret |= v3_dev_unhook_io(dev, VGA_INPUT_STAT1_READ_MONO);
2519 // The folowinn also covers VGA FEATURE_CONTROL_WRITE_COLOR
2520 ret |= v3_dev_unhook_io(dev, VGA_INPUT_STAT1_READ_COLOR);
2521 ret |= v3_dev_unhook_io(dev, VGA_FEATURE_CONTROL_READ);
2523 ret |= v3_dev_unhook_io(dev, VGA_VIDEO_SUBSYS_ENABLE);
2525 /* Sequencer registers */
2526 ret |= v3_dev_unhook_io(dev, VGA_SEQUENCER_ADDRESS);
2527 ret |= v3_dev_unhook_io(dev, VGA_SEQUENCER_DATA);
2529 /* CRT controller registers */
2530 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_MONO);
2531 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_COLOR);
2532 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_DATA_MONO);
2533 ret |= v3_dev_unhook_io(dev, VGA_CRT_CONTROLLER_DATA_COLOR);
2535 /* graphics controller registers */
2536 ret |= v3_dev_unhook_io(dev, VGA_GRAPHICS_CONTROLLER_ADDRESS);
2537 ret |= v3_dev_unhook_io(dev, VGA_GRAPHICS_CONTROLLER_DATA);
2539 /* attribute controller registers */
2540 ret |= v3_dev_unhook_io(dev, VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE);
2541 ret |= v3_dev_unhook_io(dev, VGA_ATTRIBUTE_CONTROLLER_READ);
2543 /* video DAC palette registers */
2544 ret |= v3_dev_unhook_io(dev, VGA_DAC_WRITE_ADDR);
2545 ret |= v3_dev_unhook_io(dev, VGA_DAC_READ_ADDR);
2546 ret |= v3_dev_unhook_io(dev, VGA_DAC_DATA);
2547 ret |= v3_dev_unhook_io(dev, VGA_DAC_PIXEL_MASK);
2550 if (vga->host_cons) {
2551 v3_graphics_console_close(vga->host_cons);
2559 static struct v3_device_ops dev_ops = {
2560 .free = (int (*)(void *))free_vga,
2564 static int vga_init(struct v3_vm_info * vm, v3_cfg_tree_t * cfg) {
2565 struct vga_internal *vga;
2569 char * dev_id = v3_cfg_val(cfg, "ID");
2570 char * passthrough = v3_cfg_val(cfg, "passthrough");
2571 char * hostframebuf = v3_cfg_val(cfg, "hostframebuf");
2573 PrintDebug("vga: init_device\n");
2575 vga = (struct vga_internal *)V3_Malloc(sizeof(struct vga_internal));
2578 PrintError("vga: cannot allocate\n");
2582 memset(vga, 0, sizeof(struct vga_internal));
2584 if (passthrough && strcasecmp(passthrough,"enable")==0) {
2585 PrintDebug("vga: enabling passthrough\n");
2586 vga->passthrough=true;
2587 vga->skip_next_passthrough_out=false;
2591 if (hostframebuf && strcasecmp(hostframebuf,"enable")==0) {
2592 struct v3_frame_buffer_spec req;
2594 PrintDebug("vga: enabling host frame buffer console (GRAPHICS_CONSOLE)\n");
2596 memset(&req,0,sizeof(struct v3_frame_buffer_spec));
2597 memset(&(vga->target_spec),0,sizeof(struct v3_frame_buffer_spec));
2599 req.height=VGA_MAXY;
2601 req.bytes_per_pixel=4;
2602 req.bits_per_channel=8;
2608 vga->host_cons = v3_graphics_console_open(vm,&req,&(vga->target_spec));
2610 if (!vga->host_cons) {
2611 PrintError("vga: unable to open host OS's graphics console\n");
2616 if (memcmp(&req,&(vga->target_spec),sizeof(req))) {
2617 PrintDebug("vga: warning: target spec differs from requested spec\n");
2618 PrintDebug("vga: request: %u by %u by %u with %u bpc and r,g,b at %u, %u, %u\n", req.width, req.height, req.bytes_per_pixel, req.bits_per_channel, req.red_offset, req.green_offset, req.blue_offset);
2619 PrintDebug("vga: response: %u by %u by %u with %u bpc and r,g,b at %u, %u, %u\n", vga->target_spec.width, vga->target_spec.height, vga->target_spec.bytes_per_pixel, vga->target_spec.bits_per_channel, vga->target_spec.red_offset, vga->target_spec.green_offset, vga->target_spec.blue_offset);
2624 if (!vga->passthrough && !vga->host_cons) {
2625 V3_Print("vga: neither passthrough nor host console are enabled - no way to display anything!\n");
2629 // No memory store is allocated since we will use a full memory hook
2630 // The VGA maps can be read as well as written
2631 // Reads also affect writes, since they are how you fill the latches
2633 // Now allocate the maps
2634 for (i=0;i<MAP_NUM;i++) {
2635 vga->map[i] = (vga_map) V3_VAddr((void*)V3_AllocPages(MAP_SIZE/4096));
2636 if (!(vga->map[i])) {
2637 PrintError("vga: cannot allocate maps\n");
2641 memset(vga->map[i],0,MAP_SIZE);
2644 struct vm_device * dev = v3_add_device(vm, dev_id, &dev_ops, vga);
2647 PrintError("Could not attach device %s\n", dev_id);
2654 if (v3_hook_full_mem(vm, V3_MEM_CORE_ANY,
2655 MEM_REGION_START, MEM_REGION_END,
2659 PrintError("vga: memory book failed\n");
2660 v3_remove_device(dev);
2666 /* Miscelaneous registers */
2667 ret |= v3_dev_hook_io(dev, VGA_MISC_OUT_READ, &misc_out_read, NULL);
2668 // The following also covers VGA_INPUT_STAT0_READ
2669 ret |= v3_dev_hook_io(dev, VGA_MISC_OUT_WRITE, &input_stat0_read, &misc_out_write);
2670 // The following also covers VGA_FEATURE_CTRL_WRITE_MONO
2671 ret |= v3_dev_hook_io(dev, VGA_INPUT_STAT1_READ_MONO, &input_stat1_read, &feature_control_write);
2672 // The folowinn also covers VGA FEATURE_CONTROL_WRITE_COLOR
2673 ret |= v3_dev_hook_io(dev, VGA_INPUT_STAT1_READ_COLOR, &input_stat1_read, &feature_control_write);
2674 ret |= v3_dev_hook_io(dev, VGA_FEATURE_CONTROL_READ, &feature_control_read, NULL);
2676 ret |= v3_dev_hook_io(dev, VGA_VIDEO_SUBSYS_ENABLE, &video_subsys_enable_read, &video_subsys_enable_write);
2678 /* Sequencer registers */
2679 ret |= v3_dev_hook_io(dev, VGA_SEQUENCER_ADDRESS, &sequencer_address_read, &sequencer_address_write);
2680 ret |= v3_dev_hook_io(dev, VGA_SEQUENCER_DATA, &sequencer_data_read, &sequencer_data_write);
2682 /* CRT controller registers */
2683 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_MONO, &crt_controller_address_read,&crt_controller_address_write);
2684 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_ADDRESS_COLOR, &crt_controller_address_read,&crt_controller_address_write);
2685 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_DATA_MONO, &crt_controller_data_read,&crt_controller_data_write);
2686 ret |= v3_dev_hook_io(dev, VGA_CRT_CONTROLLER_DATA_COLOR, &crt_controller_data_read,&crt_controller_data_write);
2688 /* graphics controller registers */
2689 ret |= v3_dev_hook_io(dev, VGA_GRAPHICS_CONTROLLER_ADDRESS, &graphics_controller_address_read,&graphics_controller_address_write);
2690 ret |= v3_dev_hook_io(dev, VGA_GRAPHICS_CONTROLLER_DATA, &graphics_controller_data_read,&graphics_controller_data_write);
2692 /* attribute controller registers */
2693 ret |= v3_dev_hook_io(dev, VGA_ATTRIBUTE_CONTROLLER_ADDRESS_AND_WRITE, &attribute_controller_address_read,&attribute_controller_address_and_data_write);
2694 ret |= v3_dev_hook_io(dev, VGA_ATTRIBUTE_CONTROLLER_READ, &attribute_controller_data_read,NULL);
2696 /* video DAC palette registers */
2697 ret |= v3_dev_hook_io(dev, VGA_DAC_WRITE_ADDR, &dac_write_address_read,&dac_write_address_write);
2698 ret |= v3_dev_hook_io(dev, VGA_DAC_READ_ADDR, &dac_read_address_read,&dac_read_address_write);
2699 ret |= v3_dev_hook_io(dev, VGA_DAC_DATA, &dac_data_read, &dac_data_write);
2700 ret |= v3_dev_hook_io(dev, VGA_DAC_PIXEL_MASK, &dac_pixel_mask_read, &dac_pixel_mask_write);
2703 PrintError("vga: Error allocating VGA I/O ports\n");
2704 v3_remove_device(dev);
2710 PrintDebug("vga: successfully added and initialized.\n");
2716 device_register("VGA", vga_init);