2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
5 Desc: Class for VGA and compatible cards.
9 #define __OOP_NOATTRBASES__
11 #include <proto/exec.h>
12 #include <proto/utility.h>
13 #include <proto/oop.h>
16 #include <exec/alerts.h>
17 #include <exec/memory.h>
19 #include <hidd/hidd.h>
20 #include <hidd/graphics.h>
22 #include <aros/symbolsets.h>
24 #include <hardware/custom.h>
26 #include <devices/inputevent.h>
33 #include LC_LIBDEFS_FILE
36 #include <aros/debug.h>
40 /* Some attrbases needed as global vars.
41 These are write-once read-many */
43 /* Don't initialize them with "= 0", otherwise they end up in the DATA segment! */
45 static OOP_AttrBase HiddBitMapAttrBase
;
46 static OOP_AttrBase HiddPixFmtAttrBase
;
47 static OOP_AttrBase HiddGfxAttrBase
;
48 static OOP_AttrBase HiddSyncAttrBase
;
49 static OOP_AttrBase HiddVGAAB
;
50 static OOP_AttrBase HiddVGABitMapAB
;
52 static struct OOP_ABDescr attrbases
[] =
54 { IID_Hidd_BitMap
, &HiddBitMapAttrBase
},
55 { IID_Hidd_VGABitMap
, &HiddVGABitMapAB
},
56 { IID_Hidd_VGAgfx
, &HiddVGAAB
},
57 { IID_Hidd_PixFmt
, &HiddPixFmtAttrBase
},
58 { IID_Hidd_Sync
, &HiddSyncAttrBase
},
59 { IID_Hidd_Gfx
, &HiddGfxAttrBase
},
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 /* Default mouse shape */
90 9,11,00,00,00,00,00,00,00,00,00,
91 10, 9,11,11,00,00,00,00,00,00,00,
92 00,10, 9, 9,11,11,00,00,00,00,00,
93 00,10, 9, 9, 9, 9,11,11,00,00,00,
94 00,00,10, 9, 9, 9, 9, 9,11,11,00,
95 00,00,10, 9, 9, 9, 9, 9, 9, 9,00,
96 00,00,00,10, 9, 9, 9,11,00,00,00,
97 00,00,00,10, 9, 9,10, 9,11,00,00,
98 00,00,00,00,10, 9,00,10, 9,11,00,
99 00,00,00,00,10, 9,00,00,10, 9,11,
100 00,00,00,00,00,00,00,00,00,10,11
103 /*********************
105 *********************/
107 #define NUM_SYNC_TAGS 11
108 #define SET_SYNC_TAG(taglist, idx, tag, val) \
109 taglist[idx].ti_Tag = aHidd_Sync_ ## tag; \
110 taglist[idx].ti_Data = val
112 VOID
init_sync_tags(struct TagItem
*tags
, struct vgaModeDesc
*md
, STRPTR name
)
114 ULONG clock
= (md
->clock
== 1) ? 28322000 : 25175000;
115 SET_SYNC_TAG(tags
, 0, PixelClock
, clock
);
116 SET_SYNC_TAG(tags
, 1, HDisp
, md
->HDisplay
);
117 SET_SYNC_TAG(tags
, 2, VDisp
, md
->VDisplay
);
118 SET_SYNC_TAG(tags
, 3, HSyncStart
, md
->HSyncStart
);
119 SET_SYNC_TAG(tags
, 4, HSyncEnd
, md
->HSyncEnd
);
120 SET_SYNC_TAG(tags
, 5, HTotal
, md
->HTotal
);
121 SET_SYNC_TAG(tags
, 6, VSyncStart
, md
->VSyncStart
);
122 SET_SYNC_TAG(tags
, 7, VSyncEnd
, md
->VSyncEnd
);
123 SET_SYNC_TAG(tags
, 8, VTotal
, md
->VTotal
);
124 SET_SYNC_TAG(tags
, 9, Description
, (IPTR
)name
);
125 tags
[10].ti_Tag
= TAG_DONE
;
128 OOP_Object
*PCVGA__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
130 struct TagItem pftags
[] = {
131 { aHidd_PixFmt_RedShift
, 0 }, /* 0 */
132 { aHidd_PixFmt_GreenShift
, 0 }, /* 1 */
133 { aHidd_PixFmt_BlueShift
, 0 }, /* 2 */
134 { aHidd_PixFmt_AlphaShift
, 0 }, /* 3 */
135 { aHidd_PixFmt_RedMask
, 0 }, /* 4 */
136 { aHidd_PixFmt_GreenMask
, 0 }, /* 5 */
137 { aHidd_PixFmt_BlueMask
, 0 }, /* 6 */
138 { aHidd_PixFmt_AlphaMask
, 0 }, /* 7 */
139 { aHidd_PixFmt_ColorModel
, 0 }, /* 8 */
140 { aHidd_PixFmt_Depth
, 0 }, /* 9 */
141 { aHidd_PixFmt_BytesPerPixel
, 0 }, /* 10 */
142 { aHidd_PixFmt_BitsPerPixel
, 0 }, /* 11 */
143 { aHidd_PixFmt_StdPixFmt
, 0 }, /* 12 */
144 { aHidd_PixFmt_CLUTShift
, 0 }, /* 13 */
145 { aHidd_PixFmt_CLUTMask
, 0x0f }, /* 14 */
146 { aHidd_PixFmt_BitMapType
, 0 }, /* 15 */
150 struct TagItem sync_640_480
[NUM_SYNC_TAGS
];
152 struct TagItem sync_758_576
[NUM_SYNC_TAGS
];
153 struct TagItem sync_800_600
[NUM_SYNC_TAGS
];
156 struct TagItem modetags
[] = {
157 { aHidd_Gfx_PixFmtTags
, (IPTR
)pftags
},
158 { aHidd_Gfx_SyncTags
, (IPTR
)sync_640_480
},
160 { aHidd_Gfx_SyncTags
, (IPTR
)sync_758_576
},
161 { aHidd_Gfx_SyncTags
, (IPTR
)sync_800_600
},
166 struct TagItem mytags
[] = {
167 { aHidd_Gfx_ModeTags
, (IPTR
)modetags
},
170 struct pRoot_New mymsg
;
172 /* Init the pixel format */
173 pftags
[0].ti_Data
= 0;
174 pftags
[1].ti_Data
= 0;
175 pftags
[2].ti_Data
= 0;
176 pftags
[3].ti_Data
= 0;
178 pftags
[4].ti_Data
= 0x00003f;
179 pftags
[5].ti_Data
= 0x003f00;
180 pftags
[6].ti_Data
= 0x3f0000;
181 pftags
[7].ti_Data
= 0;
183 pftags
[8].ti_Data
= vHidd_ColorModel_Palette
;
184 pftags
[9].ti_Data
= 4;
185 pftags
[10].ti_Data
= 1;
186 pftags
[11].ti_Data
= 4;
187 pftags
[12].ti_Data
= vHidd_StdPixFmt_Native
;
189 #warning Is this true in all cases ?
190 pftags
[15].ti_Data
= vHidd_BitMapType_Chunky
;
193 /* First init the sync tags */
194 init_sync_tags(sync_640_480
, &vgaDefMode
[0], "VGA:640x480");
196 init_sync_tags(sync_758_576
, &vgaDefMode
[1], "VGA:758x576");
197 init_sync_tags(sync_800_600
, &vgaDefMode
[2], "VGA:800x600");
200 /* init mytags. We use TAG_MORE to attach our own tags before we send them
202 mytags
[1].ti_Tag
= TAG_MORE
;
203 mytags
[1].ti_Data
= (IPTR
)msg
->attrList
;
205 /* Init mymsg. We have to use our own message struct because
206 one should not alter the one passed to this method.
207 message structs passed to a method are allways read-only.
208 (The user who called us might want to reuse the same msg struct
209 for several calls, but that will break if som method changes the
212 mymsg
.mID
= msg
->mID
; /* We got New() method and we are sending
213 the same method to the superclass */
214 mymsg
.attrList
= mytags
;
219 EnterFunc(bug("VGAGfx::New()\n"));
222 o
= (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
225 D(bug("Got object from super\n"));
228 XSD(cl
)->mouseW
= 11;
229 XSD(cl
)->mouseH
= 11;
230 XSD(cl
)->mouseShape
= shape
;
231 XSD(cl
)->mouseVisible
= 1;
233 XSD(cl
)->vgahidd
= o
;
235 ReturnPtr("VGAGfx::New", OOP_Object
*, o
);
238 ReturnPtr("VGAGfx::New", OOP_Object
*, NULL
);
241 VOID
PCVGA__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
243 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
247 VOID
PCVGA__Root__Get(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_Get
*msg
)
251 if (IS_GFX_ATTR(msg
->attrID
, idx
)) {
253 case aoHidd_Gfx_SupportsHWCursor
:
254 *msg
->storage
= (IPTR
)TRUE
;
261 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
266 /********** GfxHidd::NewBitMap() ****************************/
267 OOP_Object
*PCVGA__Hidd_Gfx__NewBitMap(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_NewBitMap
*msg
)
270 BOOL displayable
, framebuffer
;
271 struct vga_data
*data
;
272 OOP_Class
*classptr
= NULL
;
273 struct TagItem mytags
[2];
274 struct pHidd_Gfx_NewBitMap mymsg
;
276 EnterFunc(bug("VGAGfx::NewBitMap()\n"));
278 data
= OOP_INST_DATA(cl
, o
);
280 /* Displayable bitmap ? */
281 displayable
= GetTagData(aHidd_BitMap_Displayable
, FALSE
, msg
->attrList
);
282 framebuffer
= GetTagData(aHidd_BitMap_FrameBuffer
, FALSE
, msg
->attrList
);
285 /* If the user asks for a framebuffer map we must ALLWAYS supply a class */
286 classptr
= XSD(cl
)->onbmclass
;
288 } else if (displayable
) {
289 classptr
= XSD(cl
)->offbmclass
;
293 For the non-displayable case we can either supply a class ourselves
294 if we can optimize a certain type of non-displayable bitmaps. Or we
295 can let the superclass create on for us.
297 The attributes that might come from the user deciding the bitmap
299 - aHidd_BitMap_ModeID: a modeid. create a nondisplayable
300 bitmap with the size and pixelformat of a gfxmode.
301 - aHidd_BitMap_StdPixFmt: a standard pixelformat as described in
303 - aHidd_BitMap_Friend: if this is supplied and none of the two above
304 are supplied, then the pixel format of the created bitmap
305 will be the same as the one of the friend bitmap.
307 These tags are listed in prioritized order, so if
308 the user supplied a ModeID tag, then you should not care about StdPixFmt
309 or Friend. If there is no ModeID, but a StdPixFmt tag supplied,
310 then you should not care about Friend because you have to
311 create the correct pixelformat. And as said above, if only Friend
312 is supplied, you can create a bitmap with same pixelformat as Frien
316 modeid
= (HIDDT_ModeID
)GetTagData(aHidd_BitMap_ModeID
, vHidd_ModeID_Invalid
, msg
->attrList
);
317 if (vHidd_ModeID_Invalid
!= modeid
) {
318 /* User supplied a valid modeid. We can use our offscreen class */
319 classptr
= XSD(cl
)->offbmclass
;
321 /* We may create an offscreen bitmap if the user supplied a friend
322 bitmap. But we need to check that he did not supplied a StdPixFmt
324 HIDDT_StdPixFmt stdpf
;
325 stdpf
= (HIDDT_StdPixFmt
)GetTagData(aHidd_BitMap_StdPixFmt
, vHidd_StdPixFmt_Unknown
, msg
->attrList
);
326 if (vHidd_StdPixFmt_Unknown
== stdpf
) {
327 /* No std pixfmt supplied */
330 /* Did the user supply a friend bitmap ? */
331 friend = (OOP_Object
*)GetTagData(aHidd_BitMap_Friend
, 0, msg
->attrList
);
332 if (NULL
!= friend) {
333 OOP_Object
* gfxhidd
;
334 /* User supplied friend bitmap. Is the friend bitmap a
335 VGA Gfx hidd bitmap ? */
336 OOP_GetAttr(friend, aHidd_BitMap_GfxHidd
, &gfxhidd
);
338 /* Friend was VGA hidd bitmap. Now we can supply our own class */
339 classptr
= XSD(cl
)->offbmclass
;
346 /* Do we supply our own class ? */
347 if (NULL
!= classptr
) {
348 /* Yes. We must let the superclass not that we do this. This is
349 done through adding a tag in the frot of the taglist */
350 mytags
[0].ti_Tag
= aHidd_BitMap_ClassPtr
;
351 mytags
[0].ti_Data
= (IPTR
)classptr
;
352 mytags
[1].ti_Tag
= TAG_MORE
;
353 mytags
[1].ti_Data
= (IPTR
)msg
->attrList
;
355 /* Like in Gfx::New() we init a new message struct */
356 mymsg
.mID
= msg
->mID
;
357 mymsg
.attrList
= mytags
;
359 /* Pass the new message to the superclass */
363 ReturnPtr("VGAGfx::NewBitMap", OOP_Object
*, (OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
));
366 /********* GfxHidd::CopyBox() ***************************/
368 VOID
PCVGA__Hidd_Gfx__CopyBox(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_CopyBox
*msg
)
371 unsigned char *src
= 0, *dest
= 0;
372 struct Box box
= {0, 0, 0, 0};
374 mode
= GC_DRMD(msg
->gc
);
376 EnterFunc(bug("VGAGfx.BitMap::CopyBox( %d,%d to %d,%d of dim %d,%d\n",
377 msg
->srcX
, msg
->srcY
, msg
->destX
, msg
->destY
, msg
->width
, msg
->height
));
379 OOP_GetAttr(msg
->src
, aHidd_VGABitMap_Drawable
, &src
);
380 OOP_GetAttr(msg
->dest
, aHidd_VGABitMap_Drawable
, &dest
);
383 ((mode
!= vHidd_GC_DrawMode_Copy
) &&
384 (mode
!= vHidd_GC_DrawMode_And
) &&
385 (mode
!= vHidd_GC_DrawMode_Xor
) &&
386 (mode
!= vHidd_GC_DrawMode_Clear
) &&
387 (mode
!= vHidd_GC_DrawMode_Invert
)))
389 /* The source and/or destination object is no VGA bitmap, onscreen nor offscreen.
390 Or drawmode is not one of those we accelerate. Let the superclass do the
391 copying in a more general way
393 OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
399 struct bitmap_data
*data
= OOP_INST_DATA(OOP_OCLASS(msg
->src
), msg
->src
);
400 struct bitmap_data
*ddata
= OOP_INST_DATA(OOP_OCLASS(msg
->dest
), msg
->dest
);
401 int i
, width
, phase
, j
;
404 // start of Source data
405 unsigned char *s_start
= data
->VideoData
+
406 msg
->srcX
+ (msg
->srcY
* data
->width
);
407 // adder for each line
408 ULONG s_add
= data
->width
- msg
->width
;
409 ULONG cnt
= msg
->height
;
411 unsigned char *d_start
= ddata
->VideoData
+
412 msg
->destX
+ (msg
->destY
* ddata
->width
);
413 ULONG d_add
= ddata
->width
- msg
->width
;
417 if ((msg
->srcY
> msg
->destY
) || ((msg
->srcY
== msg
->destY
) && (msg
->srcX
>= msg
->destX
)))
419 if ((phase
= ((LONG
)s_start
& 3L)))
422 if (phase
> width
) phase
= width
;
429 s_start
+= (cnt
- 1) * data
->width
+ width
;
430 d_start
+= (cnt
- 1) * ddata
->width
+ width
;
432 phase
= ((LONG
)s_start
& 3L);
433 if (phase
> width
) phase
= width
;
441 case vHidd_GC_DrawMode_Copy
:
442 HIDD_BM_CopyMemBox8(msg
->dest
,
455 case vHidd_GC_DrawMode_And
:
464 *d_start
++ &= *s_start
++;
468 *((ULONG
*)d_start
) &= *((ULONG
*)s_start
);
475 *d_start
++ &= *s_start
++;
489 *--d_start
&= *--s_start
;
495 *((ULONG
*)d_start
) &= *((ULONG
*)s_start
);
500 *--d_start
&= *--s_start
;
509 case vHidd_GC_DrawMode_Xor
:
518 *d_start
++ ^= *s_start
++;
522 *((ULONG
*)d_start
) ^= *((ULONG
*)s_start
);
529 *d_start
++ ^= *s_start
++;
543 *--d_start
^= *--s_start
;
549 *((ULONG
*)d_start
) ^= *((ULONG
*)s_start
);
554 *--d_start
^= *--s_start
;
562 case vHidd_GC_DrawMode_Clear
:
575 *((ULONG
*)d_start
) = 0;
599 *((ULONG
*)d_start
) = 0;
611 case vHidd_GC_DrawMode_Invert
:
620 *d_start
= ~*d_start
;
625 *((ULONG
*)d_start
) = ~*((ULONG
*)d_start
);
631 *d_start
= ~*d_start
;
645 *d_start
= ~*d_start
;
651 *((ULONG
*)d_start
) = ~*((ULONG
*)d_start
);
656 *d_start
= ~*d_start
;
671 box
.x2
= box
.x1
+ msg
->width
;
672 box
.y2
= box
.y1
+ msg
->height
;
674 ObtainSemaphore(&XSD(cl
)->HW_acc
);
676 vgaRefreshArea(ddata
, 1, &box
);
677 if ( ( (XSD(cl
)->mouseX
+ XSD(cl
)->mouseW
>= box
.x1
) &&
678 (XSD(cl
)->mouseX
<= box
.x2
) ) ||
679 ( (XSD(cl
)->mouseY
+ XSD(cl
)->mouseH
>= box
.y1
) &&
680 (XSD(cl
)->mouseY
<= box
.y2
) ) )
683 ReleaseSemaphore(&XSD(cl
)->HW_acc
);
687 ReturnVoid("VGAGfx.BitMap::CopyBox");
690 VOID
PCVGA__Hidd_Gfx__ShowImminentReset(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
692 struct bitmap_data
*data
;
695 data
= XSD(cl
)->visible
;
698 struct Box box
= {0, 0, data
->width
- 1, data
->height
- 1};
700 memset(data
->VideoData
, 0, data
->width
* data
->height
);
702 vgaRefreshArea(data
, 1, &box
);
709 /* stuff added by stegerg */
711 /********** GfxHidd::SetCursorShape() ****************************/
713 BOOL
PCVGA__Hidd_Gfx__SetCursorShape(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorShape
*msg
)
715 /* hmm ... moHidd_Gfx_SetCursorShape seems to have a HIDD bitmap in msg->shape, while
716 the old (obsolete?) native moHidd_Gfx_SetMouseShape seems to expect a simple
717 chunky array. So don't do anything for now (it would have to be done similiar as
718 in config/hidd/fakegfxhidd.c I guess */
723 /********** GfxHidd::SetCursorPos() ****************************/
725 BOOL
PCVGA__Hidd_Gfx__SetCursorPos(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorPos
*msg
)
727 struct Box box
= {0, 0, 0, 0};
729 box
.x1
= XSD(cl
)->mouseX
;
730 box
.y1
= XSD(cl
)->mouseY
;
731 box
.x2
= box
.x1
+ XSD(cl
)->mouseW
;
732 box
.y2
= box
.y1
+ XSD(cl
)->mouseH
;
734 ObtainSemaphore(&XSD(cl
)->HW_acc
);
736 if (XSD(cl
)->visible
)
737 vgaRefreshArea(XSD(cl
)->visible
, 1, &box
);
739 XSD(cl
)->mouseX
= (short)msg
->x
;
740 XSD(cl
)->mouseY
= (short)msg
->y
;
742 if (XSD(cl
)->visible
)
744 if (XSD(cl
)->mouseX
< 0) XSD(cl
)->mouseX
= 0;
745 if (XSD(cl
)->mouseY
< 0) XSD(cl
)->mouseY
= 0;
746 if (XSD(cl
)->mouseX
>= XSD(cl
)->visible
->width
) XSD(cl
)->mouseX
= XSD(cl
)->visible
->width
- 1;
747 if (XSD(cl
)->mouseY
>= XSD(cl
)->visible
->height
) XSD(cl
)->mouseY
= XSD(cl
)->visible
->height
- 1;
752 ReleaseSemaphore(&XSD(cl
)->HW_acc
);
757 /********** GfxHidd::SetCursorVisible() ****************************/
759 VOID
PCVGA__Hidd_Gfx__SetCursorVisible(OOP_Class
*cl
, OOP_Object
*o
, struct pHidd_Gfx_SetCursorVisible
*msg
)
761 XSD(cl
)->mouseVisible
= msg
->visible
;
763 ObtainSemaphore(&XSD(cl
)->HW_acc
);
765 ReleaseSemaphore(&XSD(cl
)->HW_acc
);
768 /* end of stuff added by stegerg */
770 /******************** init_vgaclass() *********************************/
772 static int PCVGA_InitAttrs(LIBBASETYPEPTR LIBBASE
)
774 EnterFunc(bug("PCVGA_Init\n"));
776 ReturnInt("PCVGA_Init", ULONG
, OOP_ObtainAttrBases(attrbases
));
779 /*************** free_vgaclass() **********************************/
780 static int PCVGA_ExpungeAttrs(LIBBASETYPEPTR LIBBASE
)
782 EnterFunc(bug("PCVGA_Expunge\n"));
784 OOP_ReleaseAttrBases(attrbases
);
786 ReturnInt("PCVGA_Expunge", int, TRUE
);
789 /*******************************************************************/
791 ADD2INITLIB(PCVGA_InitAttrs
, 0)
792 ADD2EXPUNGELIB(PCVGA_ExpungeAttrs
, 0)
794 /*******************************************************************/
799 void draw_mouse(struct vga_staticdata
*xsd
)
802 unsigned char *ptr
, *data
;
803 int x
, y
, width
, fg
, x_i
, y_i
;
805 if (xsd
->mouseVisible
)
809 /* Get display width */
810 width
= xsd
->visible
->width
;
812 /* And pointer data */
813 data
= xsd
->mouseShape
;
815 ObtainSemaphore(&xsd
->HW_acc
);
822 for (y_i
= 0, y
= xsd
->mouseY
; y_i
< xsd
->mouseH
; y_i
++, y
++)
824 for (x_i
= 0, x
= xsd
->mouseX
; x_i
< xsd
->mouseW
; x_i
++, x
++)
826 ptr
= (char *)(0xa0000 + (x
+ (y
* width
)) / 8);
827 pix
= 0x8000 >> (x
% 8);
831 if (fg
&& (x
< width
))
834 outw(0x3ce,(fg
<< 8));
836 *ptr
|= 1; // This or'ed value isn't important
841 ReleaseSemaphore(&xsd
->HW_acc
);