2 Copyright © 1995-2015, The AROS Development Team. All rights reserved.
5 Desc: Class for VGA and compatible cards.
9 #include <aros/asmcall.h>
10 #include <proto/exec.h>
11 #include <proto/utility.h>
12 #include <proto/oop.h>
15 #include <exec/alerts.h>
16 #include <exec/memory.h>
18 #include <hidd/hidd.h>
19 #include <hidd/graphics.h>
21 #include <aros/symbolsets.h>
23 #include <hardware/custom.h>
25 #include <devices/inputevent.h>
32 #include LC_LIBDEFS_FILE
35 #include <aros/debug.h>
37 static AROS_INTH1(ResetHandler
, struct vga_staticdata
*, xsd
)
41 struct bitmap_data
*data
= NULL
;
43 /* On my machine this fills the screen with colorful vertical stripes
44 instead of blanking. So for now we use software method.
49 data
= OOP_INST_DATA(xsd
->bmclass
, xsd
->visible
);
53 struct Box box
= {0, 0, data
->width
- 1, data
->height
- 1};
55 vgaEraseArea(data
, &box
);
63 /* Default graphics modes */
66 vgaDefMode
[NUM_MODES
]={
67 {"640x480x4 @ 60Hz", // h: 31.5 kHz v: 60Hz
73 ,{"768x576x4 @ 54Hz", // h: 32.5 kHz v: 54Hz
78 {"800x600x4 @ 52Hz", // h: 31.5 kHz v: 52Hz
81 800,826,838,900,0, // 900
82 600,601,603,617} // 617
86 /*********************
88 *********************/
90 #define NUM_SYNC_TAGS 11
91 #define SET_SYNC_TAG(taglist, idx, tag, val) \
92 taglist[idx].ti_Tag = aHidd_Sync_ ## tag; \
93 taglist[idx].ti_Data = val
95 VOID
init_sync_tags(struct TagItem
*tags
, struct vgaModeDesc
*md
, STRPTR name
)
97 ULONG clock
= (md
->clock
== 1) ? 28322000 : 25175000;
99 SET_SYNC_TAG(tags
, 0, PixelClock
, clock
);
100 SET_SYNC_TAG(tags
, 1, HDisp
, md
->HDisplay
);
101 SET_SYNC_TAG(tags
, 2, VDisp
, md
->VDisplay
);
102 SET_SYNC_TAG(tags
, 3, HSyncStart
, md
->HSyncStart
);
103 SET_SYNC_TAG(tags
, 4, HSyncEnd
, md
->HSyncEnd
);
104 SET_SYNC_TAG(tags
, 5, HTotal
, md
->HTotal
);
105 SET_SYNC_TAG(tags
, 6, VSyncStart
, md
->VSyncStart
);
106 SET_SYNC_TAG(tags
, 7, VSyncEnd
, md
->VSyncEnd
);
107 SET_SYNC_TAG(tags
, 8, VTotal
, md
->VTotal
);
108 SET_SYNC_TAG(tags
, 9, Description
, (IPTR
)name
);
109 tags
[10].ti_Tag
= TAG_DONE
;
112 OOP_Object
*PCVGA__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
114 struct TagItem pftags
[] = {
115 { aHidd_PixFmt_RedShift
, 0 }, /* 0 */
116 { aHidd_PixFmt_GreenShift
, 0 }, /* 1 */
117 { aHidd_PixFmt_BlueShift
, 0 }, /* 2 */
118 { aHidd_PixFmt_AlphaShift
, 0 }, /* 3 */
119 { aHidd_PixFmt_RedMask
, 0x000000FC }, /* 4 */
120 { aHidd_PixFmt_GreenMask
, 0x0000FC00 }, /* 5 */
121 { aHidd_PixFmt_BlueMask
, 0x00FC0000 }, /* 6 */
122 { aHidd_PixFmt_AlphaMask
, 0x00000000 }, /* 7 */
123 { aHidd_PixFmt_ColorModel
, vHidd_ColorModel_Palette
}, /* 8 */
124 { aHidd_PixFmt_Depth
, 4 }, /* 9 */
125 { aHidd_PixFmt_BytesPerPixel
, 1 }, /* 10 */
126 { aHidd_PixFmt_BitsPerPixel
, 4 }, /* 11 */
127 { aHidd_PixFmt_StdPixFmt
, vHidd_StdPixFmt_LUT8
}, /* 12 */
128 { aHidd_PixFmt_CLUTShift
, 0 }, /* 13 */
129 { aHidd_PixFmt_CLUTMask
, 0x0f }, /* 14 */
130 { aHidd_PixFmt_BitMapType
, vHidd_BitMapType_Chunky
}, /* 15 */
134 struct TagItem sync_640_480
[NUM_SYNC_TAGS
];
136 struct TagItem sync_758_576
[NUM_SYNC_TAGS
];
137 struct TagItem sync_800_600
[NUM_SYNC_TAGS
];
140 struct TagItem modetags
[] = {
141 { aHidd_Sync_HMax
, 16384 },
142 { aHidd_Sync_VMax
, 16384 },
143 { aHidd_Gfx_PixFmtTags
, (IPTR
)pftags
},
144 { aHidd_Gfx_SyncTags
, (IPTR
)sync_640_480
},
146 { aHidd_Gfx_SyncTags
, (IPTR
)sync_758_576
},
147 { aHidd_Gfx_SyncTags
, (IPTR
)sync_800_600
},
152 struct TagItem mytags
[] = {
153 { aHidd_Gfx_ModeTags
, (IPTR
)modetags
},
156 struct pRoot_New mymsg
;
158 /* Do not allow to create more than one object */
159 if (XSD(cl
)->vgahidd
)
162 /* First init the sync tags */
163 init_sync_tags(sync_640_480
, &vgaDefMode
[0], "VGA:640x480");
165 init_sync_tags(sync_758_576
, &vgaDefMode
[1], "VGA:758x576");
166 init_sync_tags(sync_800_600
, &vgaDefMode
[2], "VGA:800x600");
169 /* init mytags. We use TAG_MORE to attach our own tags before we send them
171 mytags
[1].ti_Tag
= TAG_MORE
;
172 mytags
[1].ti_Data
= (IPTR
)msg
->attrList
;
174 /* Init mymsg. We have to use our own message struct because
175 one should not alter the one passed to this method.
176 message structs passed to a method are always read-only.
177 (The user who called us might want to reuse the same msg struct
178 for several calls, but that will break if some method changes the
181 mymsg
.mID
= msg
->mID
; /* We got New() method and we are sending
182 the same method to the superclass */
183 mymsg
.attrList
= mytags
;
186 EnterFunc(bug("VGAGfx::New()\n"));
188 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
189 XSD(cl
)->vgahidd
= o
;
191 struct Vga_Data
*data
= OOP_INST_DATA(cl
, o
);
193 data
->ResetInterrupt
.is_Node
.ln_Name
= cl
->ClassNode
.ln_Name
;
194 data
->ResetInterrupt
.is_Code
= (VOID_FUNC
)ResetHandler
;
195 data
->ResetInterrupt
.is_Data
= XSD(cl
);
196 AddResetCallback(&data
->ResetInterrupt
);
198 ReturnPtr("VGAGfx::New", OOP_Object
*, o
);
201 VOID
PCVGA__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
203 struct Vga_Data
*data
= OOP_INST_DATA(cl
, o
);
205 RemResetCallback(&data
->ResetInterrupt
);
206 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
207 XSD(cl
)->vgahidd
= NULL
;
210 VOID
PCVGA__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
214 if (IS_GFX_ATTR(msg
->attrID
, idx
)) {
216 case aoHidd_Gfx_SupportsHWCursor
:
217 case aoHidd_Gfx_NoFrameBuffer
:
218 *msg
->storage
= (IPTR
)TRUE
;
225 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
230 /********** GfxHidd::CreateObject() ****************************/
231 OOP_Object
*PCVGA__Hidd_Gfx__CreateObject(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_CreateObject
*msg
)
233 OOP_Object
*object
= NULL
;
235 EnterFunc(bug("VGAGfx::CreateObject()\n"));
237 if (msg
->cl
== XSD(cl
)->basebm
)
239 struct TagItem mytags
[] =
241 { TAG_IGNORE
, TAG_IGNORE
}, /* Placeholder for aHidd_BitMap_ClassPtr */
242 { TAG_MORE
, (IPTR
)msg
->attrList
}
245 struct pHidd_Gfx_CreateObject mymsg
;
248 modeid
= (HIDDT_ModeID
)GetTagData(aHidd_BitMap_ModeID
, vHidd_ModeID_Invalid
, msg
->attrList
);
249 if (vHidd_ModeID_Invalid
!= modeid
) {
250 /* User supplied a valid modeid. We can use our class */
251 mytags
[0].ti_Tag
= aHidd_BitMap_ClassPtr
;
252 mytags
[0].ti_Data
= (IPTR
)XSD(cl
)->bmclass
;
254 /* Like in Gfx::New() we init a new message struct */
255 mymsg
.mID
= msg
->mID
;
257 mymsg
.attrList
= mytags
;
259 object
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)&mymsg
);
262 object
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
264 ReturnPtr("VGAGfx::CreateObject", OOP_Object
*, object
);
267 /********* GfxHidd::Show() ***************************/
269 OOP_Object
*PCVGA__Hidd_Gfx__Show(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_Show
*msg
)
271 /* We currently use class static data instead of
272 object data. In addition we directly access
273 bitmap's private data. This is horribly wrong
274 and needs further refactoring */
275 struct vga_staticdata
*data
= XSD(cl
);
278 D(bug("[VGAGfx] Show(0x%p)\n", msg
->bitMap
));
279 ObtainSemaphore(&data
->sema
);
281 /* Remove old bitmap from the screen */
283 IPTR tags
[] = {aHidd_BitMap_Visible
, FALSE
, TAG_DONE
};
285 D(bug("[VGAGfx] Old displayed bitmap: 0x%p\n", data
->visible
));
286 OOP_SetAttrs(data
->visible
, (struct TagItem
*)tags
);
290 /* If we have a bitmap to show, set it as visible */
291 IPTR tags
[] = {aHidd_BitMap_Visible
, TRUE
, TAG_DONE
};
295 OOP_GetAttr(msg
->bitMap
, aHidd_BitMap_PixFmt
, (IPTR
*)&pixfmt
);
296 OOP_GetAttr(pixfmt
, aHidd_PixFmt_Depth
, &depth
);
297 /* TODO: this should be brought in from SpriteBase of the colormap */
298 data
->mouseBase
= (depth
> 4) ? 16 : (1 << depth
) - 8;
300 OOP_SetAttrs(msg
->bitMap
, (struct TagItem
*)tags
);
301 data
->visible
= msg
->bitMap
;
303 /* Otherwise simply clear the framebuffer */
308 ObtainSemaphore(&data
->HW_acc
);
309 /* We use old visible bitmap pointer here since this bitmap
310 contains data about the current video mode */
311 vgaEraseArea(OOP_INST_DATA(data
->bmclass
, data
->visible
), &box
);
313 ReleaseSemaphore(&data
->HW_acc
);
315 data
->visible
= NULL
;
317 D(bug("[VGAGfx] New displayed bitmap: 0x%p\n", data
->visible
));
318 D(bug("[VGAGfx] Mouse pointer base color: %u\n", data
->mouseBase
));
320 ReleaseSemaphore(&data
->sema
);
324 /********* GfxHidd::CopyBox() ***************************/
326 VOID
PCVGA__Hidd_Gfx__CopyBox(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_CopyBox
*msg
)
329 unsigned char *src
= 0, *dest
= 0;
331 mode
= GC_DRMD(msg
->gc
);
333 EnterFunc(bug("VGAGfx.BitMap::CopyBox (%d,%d) to (%d,%d) of dim %d,%d\n",
334 msg
->srcX
, msg
->srcY
, msg
->destX
, msg
->destY
, msg
->width
, msg
->height
));
335 D(bug("[VGAGfx] Src: 0x%p, dest: 0x%p\n", msg
->src
, msg
->dest
));
336 OOP_GetAttr(msg
->src
, aHidd_VGABitMap_Drawable
, (IPTR
*)&src
);
337 OOP_GetAttr(msg
->dest
, aHidd_VGABitMap_Drawable
, (IPTR
*)&dest
);
340 ((mode
!= vHidd_GC_DrawMode_Copy
) &&
341 (mode
!= vHidd_GC_DrawMode_And
) &&
342 (mode
!= vHidd_GC_DrawMode_Xor
) &&
343 (mode
!= vHidd_GC_DrawMode_Clear
) &&
344 (mode
!= vHidd_GC_DrawMode_Invert
)))
346 /* The source and/or destination object is no VGA bitmap, onscreen nor offscreen.
347 Or drawmode is not one of those we accelerate. Let the superclass do the
348 copying in a more general way
350 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
356 struct bitmap_data
*data
= OOP_INST_DATA(OOP_OCLASS(msg
->src
), msg
->src
);
357 struct bitmap_data
*ddata
= OOP_INST_DATA(OOP_OCLASS(msg
->dest
), msg
->dest
);
358 int i
, width
, phase
, j
;
361 // start of Source data
362 unsigned char *s_start
= data
->VideoData
+
363 msg
->srcX
+ (msg
->srcY
* data
->bpr
);
364 // adder for each line
365 ULONG s_add
= data
->bpr
- msg
->width
;
366 ULONG cnt
= msg
->height
;
368 unsigned char *d_start
= ddata
->VideoData
+
369 msg
->destX
+ (msg
->destY
* ddata
->bpr
);
370 ULONG d_add
= ddata
->bpr
- msg
->width
;
374 if ((msg
->srcY
> msg
->destY
) || ((msg
->srcY
== msg
->destY
) && (msg
->srcX
>= msg
->destX
)))
376 if ((phase
= ((IPTR
)s_start
& 3L)))
379 if (phase
> width
) phase
= width
;
386 s_start
+= (cnt
- 1) * data
->bpr
+ width
;
387 d_start
+= (cnt
- 1) * ddata
->bpr
+ width
;
389 phase
= ((IPTR
)s_start
& 3L);
390 if (phase
> width
) phase
= width
;
398 case vHidd_GC_DrawMode_Copy
:
399 HIDD_BM_CopyMemBox8(msg
->dest
,
412 case vHidd_GC_DrawMode_And
:
421 *d_start
++ &= *s_start
++;
425 *((ULONG
*)d_start
) &= *((ULONG
*)s_start
);
432 *d_start
++ &= *s_start
++;
446 *--d_start
&= *--s_start
;
452 *((ULONG
*)d_start
) &= *((ULONG
*)s_start
);
457 *--d_start
&= *--s_start
;
466 case vHidd_GC_DrawMode_Xor
:
475 *d_start
++ ^= *s_start
++;
479 *((ULONG
*)d_start
) ^= *((ULONG
*)s_start
);
486 *d_start
++ ^= *s_start
++;
500 *--d_start
^= *--s_start
;
506 *((ULONG
*)d_start
) ^= *((ULONG
*)s_start
);
511 *--d_start
^= *--s_start
;
519 case vHidd_GC_DrawMode_Clear
:
532 *((ULONG
*)d_start
) = 0;
556 *((ULONG
*)d_start
) = 0;
568 case vHidd_GC_DrawMode_Invert
:
577 *d_start
= ~*d_start
;
582 *((ULONG
*)d_start
) = ~*((ULONG
*)d_start
);
588 *d_start
= ~*d_start
;
602 *d_start
= ~*d_start
;
608 *((ULONG
*)d_start
) = ~*((ULONG
*)d_start
);
613 *d_start
= ~*d_start
;
624 ReturnVoid("VGAGfx.BitMap::CopyBox");
627 /********** GfxHidd::SetCursorShape() ****************************/
629 BOOL
PCVGA__Hidd_Gfx__SetCursorShape(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorShape
*msg
)
631 struct vga_staticdata
*data
= XSD(cl
);
632 IPTR curs_width
, curs_height
;
633 UBYTE
*new_curs_pixels
;
635 OOP_GetAttr(msg
->shape
, aHidd_BitMap_Width
, &curs_width
);
636 OOP_GetAttr(msg
->shape
, aHidd_BitMap_Height
, &curs_height
);
638 new_curs_pixels
= AllocMem(curs_width
* curs_height
, MEMF_ANY
);
639 if (!new_curs_pixels
)
642 HIDD_BM_GetImage(msg
->shape
, new_curs_pixels
, curs_width
, 0, 0, curs_width
, curs_height
, vHidd_StdPixFmt_LUT8
);
644 ObtainSemaphore(&data
->HW_acc
);
646 if (data
->mouseShape
)
647 FreeMem(data
->mouseShape
, data
->mouseW
* data
->mouseH
);
649 data
->mouseW
= curs_width
;
650 data
->mouseH
= curs_height
;
651 data
->mouseShape
= new_curs_pixels
;
654 ReleaseSemaphore(&data
->HW_acc
);
658 /********** GfxHidd::SetCursorPos() ****************************/
660 BOOL
PCVGA__Hidd_Gfx__SetCursorPos(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorPos
*msg
)
662 ObtainSemaphore(&XSD(cl
)->HW_acc
);
664 erase_mouse(XSD(cl
));
666 XSD(cl
)->mouseX
= (short)msg
->x
;
667 XSD(cl
)->mouseY
= (short)msg
->y
;
669 if (XSD(cl
)->visible
)
671 struct bitmap_data
*bm_data
=
672 OOP_INST_DATA(XSD(cl
)->bmclass
, XSD(cl
)->visible
);
674 if (XSD(cl
)->mouseX
< 0) XSD(cl
)->mouseX
= 0;
675 if (XSD(cl
)->mouseY
< 0) XSD(cl
)->mouseY
= 0;
676 if (XSD(cl
)->mouseX
>= bm_data
->width
) XSD(cl
)->mouseX
=
678 if (XSD(cl
)->mouseY
>= bm_data
->height
) XSD(cl
)->mouseY
=
684 ReleaseSemaphore(&XSD(cl
)->HW_acc
);
689 /********** GfxHidd::SetCursorVisible() ****************************/
691 VOID
PCVGA__Hidd_Gfx__SetCursorVisible(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorVisible
*msg
)
693 XSD(cl
)->mouseVisible
= msg
->visible
;
695 ObtainSemaphore(&XSD(cl
)->HW_acc
);
696 erase_mouse(XSD(cl
));
698 ReleaseSemaphore(&XSD(cl
)->HW_acc
);
701 /* end of stuff added by stegerg */
702 /*******************************************************************/
704 void draw_mouse(struct vga_staticdata
*xsd
)
707 unsigned char *ptr
, *data
;
708 int x
, y
, width
, fg
, x_i
, y_i
;
710 if (!xsd
->mouseShape
)
713 if (xsd
->mouseVisible
)
717 struct bitmap_data
*bm_data
=
718 OOP_INST_DATA(xsd
->bmclass
, xsd
->visible
);
720 /* Get display width */
721 width
= bm_data
->disp_width
;
723 /* And pointer data */
724 data
= xsd
->mouseShape
;
726 ObtainSemaphore(&xsd
->HW_acc
);
733 for (y_i
= 0, y
= xsd
->mouseY
; y_i
< xsd
->mouseH
; y_i
++, y
++)
735 for (x_i
= 0, x
= xsd
->mouseX
; x_i
< xsd
->mouseW
; x_i
++, x
++)
737 ptr
= (char *)(IPTR
)(0xa0000 + (x
+ (y
* width
)) / 8);
738 pix
= 0x8000 >> (x
% 8);
742 if (fg
&& (x
< width
))
744 fg
+= xsd
->mouseBase
;
746 outw(0x3ce,(fg
<< 8));
748 *ptr
|= 1; // This or'ed value isn't important
753 ReleaseSemaphore(&xsd
->HW_acc
);
758 void erase_mouse(struct vga_staticdata
*data
)
761 struct Box box
= {0, 0, 0, 0};
763 box
.x1
= data
->mouseX
;
764 box
.y1
= data
->mouseY
;
765 box
.x2
= box
.x1
+ data
->mouseW
;
766 box
.y2
= box
.y1
+ data
->mouseH
;
768 vgaRefreshArea(OOP_INST_DATA(data
->bmclass
, data
->visible
), &box
);