]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/vgabt485.c
kernel: cleanup the software mouse cursor mess
[plan9front.git] / sys / src / 9 / pc / vgabt485.c
1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "io.h"
7 #include "../port/error.h"
8
9 #define Image   IMAGE
10 #include <draw.h>
11 #include <memdraw.h>
12 #include <cursor.h>
13 #include "screen.h"
14
15 /*
16  * Hardware graphics cursor support for
17  * Brooktree Bt485 Monolithic True-Color RAMDAC.
18  * Assumes hooked up to an S3 86C928.
19  *
20  * BUGS:
21  *      64x64x2 cursor always used;
22  *      no support for interlaced mode.
23  */
24 enum {
25         AddrW           = 0x00,         /* Address register; palette/cursor RAM write */
26         Palette         = 0x01,         /* 6/8-bit color palette data */
27         Pmask           = 0x02,         /* Pixel mask register */
28         AddrR           = 0x03,         /* Address register; palette/cursor RAM read */
29         ColorW          = 0x04,         /* Address register; cursor/overscan color write */
30         Color           = 0x05,         /* Cursor/overscan color data */
31         Cmd0            = 0x06,         /* Command register 0 */
32         ColorR          = 0x07,         /* Address register; cursor/overscan color read */
33         Cmd1            = 0x08,         /* Command register 1 */
34         Cmd2            = 0x09,         /* Command register 2 */
35         Status          = 0x0A,         /* Status */
36         Cmd3            = 0x1A,         /* Command register 3 */
37         Cram            = 0x0B,         /* Cursor RAM array data */
38         Cxlr            = 0x0C,         /* Cursor x-low register */
39         Cxhr            = 0x0D,         /* Cursor x-high register */
40         Cylr            = 0x0E,         /* Cursor y-low register */
41         Cyhr            = 0x0F,         /* Cursor y-high register */
42
43         Nreg            = 0x10,
44 };
45
46 /*
47  * Lower 2-bits of indirect DAC register
48  * addressing.
49  */
50 static ushort dacxreg[4] = {
51         PaddrW, Pdata, Pixmask, PaddrR
52 };
53
54 static uchar
55 bt485io(uchar reg)
56 {
57         uchar crt55, cr0;
58
59         crt55 = vgaxi(Crtx, 0x55) & 0xFC;
60         if((reg & 0x0F) == Status){
61                 /*
62                  * 1,2: Set indirect addressing for Status or
63                  *      Cmd3 - set bit7 of Cr0.
64                  */
65                 vgaxo(Crtx, 0x55, crt55|((Cmd0>>2) & 0x03));
66                 cr0 = vgai(dacxreg[Cmd0 & 0x03])|0x80;
67                 vgao(dacxreg[Cmd0 & 0x03], cr0);
68
69                 /*
70                  * 3,4: Set the index into the Write register,
71                  *      index == 0x00 for Status, 0x01 for Cmd3.
72                  */
73                 vgaxo(Crtx, 0x55, crt55|((AddrW>>2) & 0x03));
74                 vgao(dacxreg[AddrW & 0x03], (reg == Status) ? 0x00: 0x01);
75
76                 /*
77                  * 5,6: Get the contents of the appropriate
78                  *      register at 0x0A.
79                  */
80         }
81
82         return crt55;
83 }
84
85 static uchar
86 bt485i(uchar reg)
87 {
88         uchar crt55, r;
89
90         crt55 = bt485io(reg);
91         vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
92         r = vgai(dacxreg[reg & 0x03]);
93         vgaxo(Crtx, 0x55, crt55);
94
95         return r;
96 }
97
98 static void
99 bt485o(uchar reg, uchar data)
100 {
101         uchar crt55;
102
103         crt55 = bt485io(reg);
104         vgaxo(Crtx, 0x55, crt55|((reg>>2) & 0x03));
105         vgao(dacxreg[reg & 0x03], data);
106         vgaxo(Crtx, 0x55, crt55);
107 }
108
109 static void
110 bt485disable(VGAscr*)
111 {
112         uchar r;
113
114         /*
115          * Disable 
116          *      cursor mode 3;
117          *      cursor control enable for Bt485 DAC;
118          *      the hardware cursor external operation mode.
119          */
120         r = bt485i(Cmd2) & ~0x03;
121         bt485o(Cmd2, r);
122
123         r = vgaxi(Crtx, 0x45) & ~0x20;
124         vgaxo(Crtx, 0x45, r);
125
126         r = vgaxi(Crtx, 0x55) & ~0x20;
127         vgaxo(Crtx, 0x55, r);
128 }
129
130 static void
131 bt485enable(VGAscr*)
132 {
133         uchar r;
134
135         /*
136          * Turn cursor off.
137          */
138         r = bt485i(Cmd2) & 0xFC;
139         bt485o(Cmd2, r);
140
141         /*
142          * Overscan colour,
143          * cursor colour 1 (white),
144          * cursor colour 2, 3 (black).
145          */
146         bt485o(ColorW, 0x00);
147         bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);
148
149         bt485o(Color, Pwhite); bt485o(Color, Pwhite); bt485o(Color, Pwhite);
150
151         bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);
152         bt485o(Color, Pblack); bt485o(Color, Pblack); bt485o(Color, Pblack);
153
154         /*
155          * Finally, enable
156          *      the hardware cursor external operation mode;
157          *      cursor control enable for Bt485 DAC.
158          * The #9GXE cards seem to need the 86C928 Bt485 support
159          * enabled in order to work at all in enhanced mode.
160          */
161
162         r = vgaxi(Crtx, 0x55)|0x20;
163         vgaxo(Crtx, 0x55, r);
164
165         r = vgaxi(Crtx, 0x45)|0x20;
166         vgaxo(Crtx, 0x45, r);
167 }
168
169 static void
170 bt485load(VGAscr* scr, Cursor* curs)
171 {
172         uchar r;
173         int x, y;
174
175         /*
176          * Turn cursor off;
177          * put cursor into 64x64x2 mode and clear MSBs of address;
178          * clear LSBs of address;
179          */
180         r = bt485i(Cmd2) & 0xFC;
181         bt485o(Cmd2, r);
182
183         r = (bt485i(Cmd3) & 0xFC)|0x04;
184         bt485o(Cmd3, r);
185
186         bt485o(AddrW, 0x00);
187
188         /*
189          * Now load the cursor RAM array, both planes.
190          * The cursor is 16x16, the array 64x64; put
191          * the cursor in the top left. The 0,0 cursor
192          * point is bottom-right, so positioning will
193          * have to take that into account.
194          */
195         for(y = 0; y < 64; y++){
196                 for(x = 0; x < 64/8; x++){
197                         if(x < 16/8 && y < 16)
198                                 bt485o(Cram, curs->clr[x+y*2]);
199                         else
200                                 bt485o(Cram, 0x00);
201                 }
202         }
203         for(y = 0; y < 64; y++){
204                 for(x = 0; x < 64/8; x++){
205                         if(x < 16/8 && y < 16)
206                                 bt485o(Cram, curs->set[x+y*2]);
207                         else
208                                 bt485o(Cram, 0x00);
209                 }
210         }
211
212         /*
213          * Initialise the cursor hot-point
214          * and enable the cursor.
215          */
216         scr->offset.x = 64+curs->offset.x;
217         scr->offset.y = 64+curs->offset.y;
218
219         r = (bt485i(Cmd2) & 0xFC)|0x01;
220         bt485o(Cmd2, r);
221 }
222
223 static int
224 bt485move(VGAscr* scr, Point p)
225 {
226         int x, y;
227
228         x = p.x+scr->offset.x;
229         y = p.y+scr->offset.y;
230
231         bt485o(Cxlr, x & 0xFF);
232         bt485o(Cxhr, (x>>8) & 0x0F);
233         bt485o(Cylr, y & 0xFF);
234         bt485o(Cyhr, (y>>8) & 0x0F);
235
236         return 0;
237 }
238
239 VGAcur vgabt485cur = {
240         "bt485hwgc",
241
242         bt485enable,
243         bt485disable,
244         bt485load,
245         bt485move,
246 };