vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / accelerants / s3 / trio64_mode.cpp
blobfb6de09e9f682faae2a5128f9d4a918a27e8978f
1 /*
2 Haiku S3 Trio64 driver adapted from the X.org S3 driver.
4 Copyright 2001 Ani Joshi <ajoshi@unixbox.com>
6 Copyright 2008 Haiku, Inc. All rights reserved.
7 Distributed under the terms of the MIT license.
9 Authors:
10 Gerald Zajac 2008
14 #include "accel.h"
15 #include "trio64.h"
18 #define BASE_FREQ 14.31818 // MHz
21 static void
22 Trio64_CalcClock(long freq, int min_m, int min_n1, int max_n1,
23 int min_n2, int max_n2, long freq_min, long freq_max,
24 uint8* mdiv, uint8* ndiv)
26 uint8 best_n1 = 18, best_n2 = 2, best_m = 127;
28 double ffreq = freq / 1000.0 / BASE_FREQ;
29 double ffreq_min = freq_min / 1000.0 / BASE_FREQ;
30 double ffreq_max = freq_max / 1000.0 / BASE_FREQ;
32 if (ffreq < ffreq_min / (1 << max_n2)) {
33 TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq >= %1.3f Mhz]\n",
34 ffreq*BASE_FREQ, ffreq_min*BASE_FREQ / (1 << max_n2));
35 ffreq = ffreq_min / (1 << max_n2);
37 if (ffreq > ffreq_max / (1 << min_n2)) {
38 TRACE("Trio64_CalcClock() invalid frequency %1.3f Mhz [freq <= %1.3f Mhz]\n",
39 ffreq*BASE_FREQ, ffreq_max*BASE_FREQ / (1 << min_n2));
40 ffreq = ffreq_max / (1 << min_n2);
43 double best_diff = ffreq;
45 for (uint8 n2 = min_n2; n2 <= max_n2; n2++) {
46 for (uint8 n1 = min_n1 + 2; n1 <= max_n1 + 2; n1++) {
47 int m = (int)(ffreq * n1 * (1 << n2) + 0.5);
48 if (m < min_m + 2 || m > 127 + 2)
49 continue;
51 double div = (double)(m) / (double)(n1);
52 if ((div >= ffreq_min) && (div <= ffreq_max)) {
53 double diff = ffreq - div / (1 << n2);
54 if (diff < 0.0)
55 diff = -diff;
56 if (diff < best_diff) {
57 best_diff = diff;
58 best_m = m;
59 best_n1 = n1;
60 best_n2 = n2;
66 if (max_n1 == 63)
67 *ndiv = (best_n1 - 2) | (best_n2 << 6);
68 else
69 *ndiv = (best_n1 - 2) | (best_n2 << 5);
70 *mdiv = best_m - 2;
75 static bool
76 Trio64_ModeInit(const DisplayModeEx& mode)
78 SharedInfo& si = *gInfo.sharedInfo;
80 TRACE("Trio64_ModeInit(%d x %d, %d KHz)\n",
81 mode.timing.h_display, mode.timing.v_display, mode.timing.pixel_clock);
83 uint32 videoRamMB = si.videoMemSize / (1024 * 1024); // MB's of video RAM
85 WriteCrtcReg(0x38, 0x48); // unlock sys regs
86 WriteCrtcReg(0x39, 0xa5); // unlock sys regs
87 WriteSeqReg(0x08, 0x06); // unlock extended sequencer regs
89 WriteCrtcReg(0x45, 0x00, 0x01); // turn off hardware cursor
91 uint8 sr12, sr13;
92 Trio64_CalcClock(mode.timing.pixel_clock, 1, 1, 31, 0, 3, 135000, 270000,
93 &sr13, &sr12);
95 // Set clock registers.
97 WriteSeqReg(0x12, sr12);
98 WriteSeqReg(0x13, sr13);
100 // Activate clock
102 uint8 tmp = ReadSeqReg(0x15) & ~0x21;
103 WriteSeqReg(0x15, tmp | 0x02);
104 WriteSeqReg(0x15, tmp | 0x22);
105 WriteSeqReg(0x15, tmp | 0x02);
107 uint8 cr33 = ReadCrtcReg(0x33) & ~0x28;
108 uint8 cr50 = 0;
109 uint8 pixmux = 0;
111 if (si.chipType == S3_TRIO64_V2)
112 cr33 |= 0x20;
114 switch (mode.bpp) {
115 case 8:
116 break;
117 case 15:
118 cr33 |= 0x08;
119 cr50 = 0x10;
120 pixmux = 0x30;
121 break;
122 case 16:
123 cr33 |= 0x08;
124 cr50 = 0x10;
125 pixmux = 0x50;
126 break;
127 case 32:
128 cr50 = 0x30;
129 pixmux = 0xd0;
130 break;
133 bool bDisableAccelFuncs = false;
135 switch (mode.timing.h_display) {
136 case 640:
137 cr50 |= 0x40;
138 break;
139 case 800:
140 cr50 |= 0x80;
141 break;
142 case 1024:
143 cr50 |= 0x00;
144 break;
145 case 1152:
146 cr50 |= 0x01;
147 break;
148 case 1280:
149 cr50 |= 0xc0;
150 break;
151 case 1600:
152 cr50 |= 0x81;
153 break;
154 default:
155 bDisableAccelFuncs = true; // use app_server default accel functions
156 break;
159 WriteCrtcReg(0x33, cr33);
160 WriteCrtcReg(0x50, cr50); // set number of bits per pixel & display width
161 WriteCrtcReg(0x67, pixmux); // set pixel format
163 WriteSeqReg(0x15, 0x00, 0x10); // turn off pixel multiplex
164 WriteSeqReg(0x18, 0x00, 0x80);
166 // Note that the 2D acceleration (drawing) functions in this accelerant work
167 // only with the display widths defined in the above switch statement. For
168 // the other widths, the default functions in the app_server will be used.
170 si.bDisableAccelDraw = bDisableAccelFuncs;
172 // Set the standard CRTC vga regs.
174 uint8 crtc[25], cr3b, cr3c, cr5d, cr5e;
176 InitCrtcTimingValues(mode, (mode.bpp > 8) ? 2 : 1, crtc, cr3b, cr3c, cr5d, cr5e);
177 crtc[0x17] = 0xe3;
179 WriteCrtcReg(0x11, 0x00, 0x80); // unlock CRTC reg's 0-7 by clearing bit 7 of cr11
181 for (int k = 0; k < (int)B_COUNT_OF(crtc); k++) {
182 WriteCrtcReg(k, crtc[k]);
185 WriteCrtcReg(0x3b, cr3b);
186 WriteCrtcReg(0x3c, cr3c);
187 WriteCrtcReg(0x5d, cr5d);
188 WriteCrtcReg(0x5e, cr5e);
190 uint8 miscOutReg = 0x2f;
192 if ( ! (mode.timing.flags & B_POSITIVE_HSYNC))
193 miscOutReg |= 0x40;
194 if ( ! (mode.timing.flags & B_POSITIVE_VSYNC))
195 miscOutReg |= 0x80;
197 WriteMiscOutReg(miscOutReg);
199 uint8 cr58;
200 if (videoRamMB <= 1)
201 cr58 = 0x01;
202 else if (videoRamMB <= 2)
203 cr58 = 0x02;
204 else
205 cr58 = 0x03;
207 WriteCrtcReg(0x58, cr58 | 0x10, 0x13); // enable linear addressing & set memory size
209 WriteCrtcReg(0x31, 0x08);
210 WriteCrtcReg(0x32, 0x00);
211 WriteCrtcReg(0x34, 0x10);
212 WriteCrtcReg(0x3a, 0x15);
214 WriteCrtcReg(0x51, mode.bytesPerRow >> 7, 0x30);
215 WriteCrtcReg(0x53, 0x18, 0x18);
217 int n = 255;
218 int clock2 = mode.timing.pixel_clock * (mode.bpp / 8);
219 if (videoRamMB < 2)
220 clock2 *= 2;
221 int m = (int)((gInfo.sharedInfo->mclk / 1000.0 * .72 + 16.867) * 89.736
222 / (clock2 / 1000.0 + 39) - 21.1543);
223 if (videoRamMB < 2)
224 m /= 2;
225 if (m > 31)
226 m = 31;
227 else if (m < 0) {
228 m = 0;
229 n = 16;
232 if (n < 0)
233 n = 0;
234 else if (n > 255)
235 n = 255;
237 WriteCrtcReg(0x54, m << 3);
238 WriteCrtcReg(0x60, n);
240 WriteCrtcReg(0x42, 0x00, 0x20); // disable interlace mode
241 WriteCrtcReg(0x66, 0x89, 0x8f);
243 WriteReg16(ADVFUNC_CNTL, 0x0001); // enable enhanced functions
245 WriteReg16(SUBSYS_CNTL, 0x8000); // reset graphics engine
246 WriteReg16(SUBSYS_CNTL, 0x4000); // enable graphics engine
247 ReadReg16(SUBSYS_STAT);
249 WriteReg16(MULTIFUNC_CNTL, 0x5000 | 0x0004 | 0x000c);
251 gInfo.WaitQueue(5);
252 WriteReg16(MULTIFUNC_CNTL, SCISSORS_L | 0);
253 WriteReg16(MULTIFUNC_CNTL, SCISSORS_T | 0);
254 WriteReg16(MULTIFUNC_CNTL, SCISSORS_R | (mode.timing.h_display - 1));
255 WriteReg16(MULTIFUNC_CNTL, SCISSORS_B | ((si.maxFrameBufferSize / mode.bytesPerRow) - 1));
257 WriteReg32(WRT_MASK, ~0); // enable all planes
259 TRACE("Trio64_ModeInit() exit\n");
260 return true;
264 bool
265 Trio64_SetDisplayMode(const DisplayModeEx& mode)
267 // The code to actually configure the display.
268 // All the error checking must be done in ProposeDisplayMode(),
269 // and assume that the mode values we get here are acceptable.
271 WriteSeqReg(0x01, 0x20, 0x20); // blank the screen
273 if ( ! Trio64_ModeInit(mode)) {
274 TRACE("Trio64_ModeInit() failed\n");
275 return false;
278 Trio64_AdjustFrame(mode);
280 WriteSeqReg(0x01, 0x00, 0x20); // unblank the screen
282 return true;
287 void
288 Trio64_AdjustFrame(const DisplayModeEx& mode)
290 // Adjust start address in frame buffer.
292 int base = (((mode.v_display_start * mode.virtual_width + mode.h_display_start)
293 * (mode.bpp / 8)) >> 2) & ~1;
294 base += gInfo.sharedInfo->frameBufferOffset;
296 WriteCrtcReg(0x0c, (base >> 8) & 0xff);
297 WriteCrtcReg(0x0d, base & 0xff);
298 WriteCrtcReg(0x31, base >> 12, 0x30); // put bits 16-17 in bits 4-5 of CR31
299 WriteCrtcReg(0x51, base >> 18, 0x03); // put bits 18-19 in bits 0-1 of CR51
303 void
304 Trio64_SetIndexedColors(uint count, uint8 first, uint8* colorData, uint32 flags)
306 // Set the indexed color palette for 8-bit color depth mode.
308 (void)flags; // avoid compiler warning for unused arg
310 if (gInfo.sharedInfo->displayMode.space != B_CMAP8)
311 return ;
313 while (count--) {
314 WriteIndexedColor(first++, // color index
315 colorData[0] >> 2, // red
316 colorData[1] >> 2, // green
317 colorData[2] >> 2); // blue
318 colorData += 3;