diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/video/matrox/matroxfb_maven.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/video/matrox/matroxfb_maven.c')
-rw-r--r-- | drivers/video/matrox/matroxfb_maven.c | 1328 |
1 files changed, 1328 insertions, 0 deletions
diff --git a/drivers/video/matrox/matroxfb_maven.c b/drivers/video/matrox/matroxfb_maven.c new file mode 100644 index 000000000000..e529841cd83d --- /dev/null +++ b/drivers/video/matrox/matroxfb_maven.c | |||
@@ -0,0 +1,1328 @@ | |||
1 | /* | ||
2 | * | ||
3 | * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200, G400 and G450. | ||
4 | * | ||
5 | * (c) 1998-2002 Petr Vandrovec <vandrove@vc.cvut.cz> | ||
6 | * | ||
7 | * Portions Copyright (c) 2001 Matrox Graphics Inc. | ||
8 | * | ||
9 | * Version: 1.65 2002/08/14 | ||
10 | * | ||
11 | * See matroxfb_base.c for contributors. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include "matroxfb_maven.h" | ||
16 | #include "matroxfb_misc.h" | ||
17 | #include "matroxfb_DAC1064.h" | ||
18 | #include <linux/i2c.h> | ||
19 | #include <linux/matroxfb.h> | ||
20 | #include <asm/div64.h> | ||
21 | #include <asm/uaccess.h> | ||
22 | |||
23 | #define MAVEN_I2CID (0x1B) | ||
24 | |||
25 | #define MGATVO_B 1 | ||
26 | #define MGATVO_C 2 | ||
27 | |||
28 | static const struct maven_gamma { | ||
29 | unsigned char reg83; | ||
30 | unsigned char reg84; | ||
31 | unsigned char reg85; | ||
32 | unsigned char reg86; | ||
33 | unsigned char reg87; | ||
34 | unsigned char reg88; | ||
35 | unsigned char reg89; | ||
36 | unsigned char reg8a; | ||
37 | unsigned char reg8b; | ||
38 | } maven_gamma[] = { | ||
39 | { 131, 57, 223, 15, 117, 212, 251, 91, 156}, | ||
40 | { 133, 61, 128, 63, 180, 147, 195, 100, 180}, | ||
41 | { 131, 19, 63, 31, 50, 66, 171, 64, 176}, | ||
42 | { 0, 0, 0, 31, 16, 16, 16, 100, 200}, | ||
43 | { 8, 23, 47, 73, 147, 244, 220, 80, 195}, | ||
44 | { 22, 43, 64, 80, 147, 115, 58, 85, 168}, | ||
45 | { 34, 60, 80, 214, 147, 212, 188, 85, 167}, | ||
46 | { 45, 77, 96, 216, 147, 99, 91, 85, 159}, | ||
47 | { 56, 76, 112, 107, 147, 212, 148, 64, 144}, | ||
48 | { 65, 91, 128, 137, 147, 196, 17, 69, 148}, | ||
49 | { 72, 104, 136, 138, 147, 180, 245, 73, 147}, | ||
50 | { 87, 116, 143, 126, 16, 83, 229, 77, 144}, | ||
51 | { 95, 119, 152, 254, 244, 83, 221, 77, 151}, | ||
52 | { 100, 129, 159, 156, 244, 148, 197, 77, 160}, | ||
53 | { 105, 141, 167, 247, 244, 132, 181, 84, 166}, | ||
54 | { 105, 147, 168, 247, 244, 245, 181, 90, 170}, | ||
55 | { 120, 153, 175, 248, 212, 229, 165, 90, 180}, | ||
56 | { 119, 156, 176, 248, 244, 229, 84, 74, 160}, | ||
57 | { 119, 158, 183, 248, 244, 229, 149, 78, 165} | ||
58 | }; | ||
59 | |||
60 | /* Definition of the various controls */ | ||
61 | struct mctl { | ||
62 | struct v4l2_queryctrl desc; | ||
63 | size_t control; | ||
64 | }; | ||
65 | |||
66 | #define BLMIN 0x0FF | ||
67 | #define WLMAX 0x3FF | ||
68 | |||
69 | static const struct mctl maven_controls[] = | ||
70 | { { { V4L2_CID_BRIGHTNESS, V4L2_CTRL_TYPE_INTEGER, | ||
71 | "brightness", | ||
72 | 0, WLMAX - BLMIN, 1, 379 - BLMIN, | ||
73 | 0, | ||
74 | }, offsetof(struct matrox_fb_info, altout.tvo_params.brightness) }, | ||
75 | { { V4L2_CID_CONTRAST, V4L2_CTRL_TYPE_INTEGER, | ||
76 | "contrast", | ||
77 | 0, 1023, 1, 127, | ||
78 | 0, | ||
79 | }, offsetof(struct matrox_fb_info, altout.tvo_params.contrast) }, | ||
80 | { { V4L2_CID_SATURATION, V4L2_CTRL_TYPE_INTEGER, | ||
81 | "saturation", | ||
82 | 0, 255, 1, 155, | ||
83 | 0, | ||
84 | }, offsetof(struct matrox_fb_info, altout.tvo_params.saturation) }, | ||
85 | { { V4L2_CID_HUE, V4L2_CTRL_TYPE_INTEGER, | ||
86 | "hue", | ||
87 | 0, 255, 1, 0, | ||
88 | 0, | ||
89 | }, offsetof(struct matrox_fb_info, altout.tvo_params.hue) }, | ||
90 | { { V4L2_CID_GAMMA, V4L2_CTRL_TYPE_INTEGER, | ||
91 | "gamma", | ||
92 | 0, sizeof(maven_gamma)/sizeof(maven_gamma[0])-1, 1, 3, | ||
93 | 0, | ||
94 | }, offsetof(struct matrox_fb_info, altout.tvo_params.gamma) }, | ||
95 | { { MATROXFB_CID_TESTOUT, V4L2_CTRL_TYPE_BOOLEAN, | ||
96 | "test output", | ||
97 | 0, 1, 1, 0, | ||
98 | 0, | ||
99 | }, offsetof(struct matrox_fb_info, altout.tvo_params.testout) }, | ||
100 | { { MATROXFB_CID_DEFLICKER, V4L2_CTRL_TYPE_INTEGER, | ||
101 | "deflicker mode", | ||
102 | 0, 2, 1, 0, | ||
103 | 0, | ||
104 | }, offsetof(struct matrox_fb_info, altout.tvo_params.deflicker) }, | ||
105 | |||
106 | }; | ||
107 | |||
108 | #define MAVCTRLS (sizeof(maven_controls)/sizeof(maven_controls[0])) | ||
109 | |||
110 | /* Return: positive number: id found | ||
111 | -EINVAL: id not found, return failure | ||
112 | -ENOENT: id not found, create fake disabled control */ | ||
113 | static int get_ctrl_id(__u32 v4l2_id) { | ||
114 | int i; | ||
115 | |||
116 | for (i = 0; i < MAVCTRLS; i++) { | ||
117 | if (v4l2_id < maven_controls[i].desc.id) { | ||
118 | if (maven_controls[i].desc.id == 0x08000000) { | ||
119 | return -EINVAL; | ||
120 | } | ||
121 | return -ENOENT; | ||
122 | } | ||
123 | if (v4l2_id == maven_controls[i].desc.id) { | ||
124 | return i; | ||
125 | } | ||
126 | } | ||
127 | return -EINVAL; | ||
128 | } | ||
129 | |||
130 | struct maven_data { | ||
131 | struct matrox_fb_info* primary_head; | ||
132 | struct i2c_client* client; | ||
133 | int version; | ||
134 | }; | ||
135 | |||
136 | static int* get_ctrl_ptr(struct maven_data* md, int idx) { | ||
137 | return (int*)((char*)(md->primary_head) + maven_controls[idx].control); | ||
138 | } | ||
139 | |||
140 | static int maven_get_reg(struct i2c_client* c, char reg) { | ||
141 | char dst; | ||
142 | struct i2c_msg msgs[] = {{ c->addr, I2C_M_REV_DIR_ADDR, sizeof(reg), ® }, | ||
143 | { c->addr, I2C_M_RD | I2C_M_NOSTART, sizeof(dst), &dst }}; | ||
144 | s32 err; | ||
145 | |||
146 | err = i2c_transfer(c->adapter, msgs, 2); | ||
147 | if (err < 0) | ||
148 | printk(KERN_INFO "ReadReg(%d) failed\n", reg); | ||
149 | return dst & 0xFF; | ||
150 | } | ||
151 | |||
152 | static int maven_set_reg(struct i2c_client* c, int reg, int val) { | ||
153 | s32 err; | ||
154 | |||
155 | err = i2c_smbus_write_byte_data(c, reg, val); | ||
156 | if (err) | ||
157 | printk(KERN_INFO "WriteReg(%d) failed\n", reg); | ||
158 | return err; | ||
159 | } | ||
160 | |||
161 | static int maven_set_reg_pair(struct i2c_client* c, int reg, int val) { | ||
162 | s32 err; | ||
163 | |||
164 | err = i2c_smbus_write_word_data(c, reg, val); | ||
165 | if (err) | ||
166 | printk(KERN_INFO "WriteRegPair(%d) failed\n", reg); | ||
167 | return err; | ||
168 | } | ||
169 | |||
170 | static const struct matrox_pll_features maven_pll = { | ||
171 | 50000, | ||
172 | 27000, | ||
173 | 4, 127, | ||
174 | 2, 31, | ||
175 | 3 | ||
176 | }; | ||
177 | |||
178 | struct matrox_pll_features2 { | ||
179 | unsigned int vco_freq_min; | ||
180 | unsigned int vco_freq_max; | ||
181 | unsigned int feed_div_min; | ||
182 | unsigned int feed_div_max; | ||
183 | unsigned int in_div_min; | ||
184 | unsigned int in_div_max; | ||
185 | unsigned int post_shift_max; | ||
186 | }; | ||
187 | |||
188 | struct matrox_pll_ctl { | ||
189 | unsigned int ref_freq; | ||
190 | unsigned int den; | ||
191 | }; | ||
192 | |||
193 | static const struct matrox_pll_features2 maven1000_pll = { | ||
194 | 50000000, | ||
195 | 300000000, | ||
196 | 5, 128, | ||
197 | 3, 32, | ||
198 | 3 | ||
199 | }; | ||
200 | |||
201 | static const struct matrox_pll_ctl maven_PAL = { | ||
202 | 540000, | ||
203 | 50 | ||
204 | }; | ||
205 | |||
206 | static const struct matrox_pll_ctl maven_NTSC = { | ||
207 | 450450, /* 27027000/60 == 27000000/59.94005994 */ | ||
208 | 60 | ||
209 | }; | ||
210 | |||
211 | static int matroxfb_PLL_mavenclock(const struct matrox_pll_features2* pll, | ||
212 | const struct matrox_pll_ctl* ctl, | ||
213 | unsigned int htotal, unsigned int vtotal, | ||
214 | unsigned int* in, unsigned int* feed, unsigned int* post, | ||
215 | unsigned int* h2) { | ||
216 | unsigned int besth2 = 0; | ||
217 | unsigned int fxtal = ctl->ref_freq; | ||
218 | unsigned int fmin = pll->vco_freq_min / ctl->den; | ||
219 | unsigned int fwant; | ||
220 | unsigned int p; | ||
221 | unsigned int scrlen; | ||
222 | unsigned int fmax; | ||
223 | |||
224 | DBG(__FUNCTION__) | ||
225 | |||
226 | scrlen = htotal * (vtotal - 1); | ||
227 | fwant = htotal * vtotal; | ||
228 | fmax = pll->vco_freq_max / ctl->den; | ||
229 | |||
230 | dprintk(KERN_DEBUG "want: %u, xtal: %u, h: %u, v: %u, fmax: %u\n", | ||
231 | fwant, fxtal, htotal, vtotal, fmax); | ||
232 | for (p = 1; p <= pll->post_shift_max; p++) { | ||
233 | if (fwant * 2 > fmax) | ||
234 | break; | ||
235 | fwant *= 2; | ||
236 | } | ||
237 | if (fwant > fmax) | ||
238 | return 0; | ||
239 | for (; p-- > 0; fwant >>= 1) { | ||
240 | unsigned int m; | ||
241 | |||
242 | if (fwant < fmin) break; | ||
243 | for (m = pll->in_div_min; m <= pll->in_div_max; m++) { | ||
244 | unsigned int n; | ||
245 | unsigned int dvd; | ||
246 | unsigned int ln; | ||
247 | |||
248 | n = (fwant * m) / fxtal; | ||
249 | if (n < pll->feed_div_min) | ||
250 | continue; | ||
251 | if (n > pll->feed_div_max) | ||
252 | break; | ||
253 | |||
254 | ln = fxtal * n; | ||
255 | dvd = m << p; | ||
256 | |||
257 | if (ln % dvd) | ||
258 | continue; | ||
259 | ln = ln / dvd; | ||
260 | |||
261 | if (ln < scrlen + 2) | ||
262 | continue; | ||
263 | ln = ln - scrlen; | ||
264 | if (ln > htotal) | ||
265 | continue; | ||
266 | dprintk(KERN_DEBUG "Match: %u / %u / %u / %u\n", n, m, p, ln); | ||
267 | if (ln > besth2) { | ||
268 | dprintk(KERN_DEBUG "Better...\n"); | ||
269 | *h2 = besth2 = ln; | ||
270 | *post = p; | ||
271 | *in = m; | ||
272 | *feed = n; | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | if (besth2 < 2) | ||
277 | return 0; | ||
278 | dprintk(KERN_ERR "clk: %02X %02X %02X %d %d\n", *in, *feed, *post, fxtal, fwant); | ||
279 | return fxtal * (*feed) / (*in) * ctl->den; | ||
280 | } | ||
281 | |||
282 | static unsigned int matroxfb_mavenclock(const struct matrox_pll_ctl* ctl, | ||
283 | unsigned int htotal, unsigned int vtotal, | ||
284 | unsigned int* in, unsigned int* feed, unsigned int* post, | ||
285 | unsigned int* htotal2) { | ||
286 | unsigned int fvco; | ||
287 | unsigned int p; | ||
288 | |||
289 | fvco = matroxfb_PLL_mavenclock(&maven1000_pll, ctl, htotal, vtotal, in, feed, &p, htotal2); | ||
290 | if (!fvco) | ||
291 | return -EINVAL; | ||
292 | p = (1 << p) - 1; | ||
293 | if (fvco <= 100000000) | ||
294 | ; | ||
295 | else if (fvco <= 140000000) | ||
296 | p |= 0x08; | ||
297 | else if (fvco <= 180000000) | ||
298 | p |= 0x10; | ||
299 | else | ||
300 | p |= 0x18; | ||
301 | *post = p; | ||
302 | return 0; | ||
303 | } | ||
304 | |||
305 | static void DAC1064_calcclock(unsigned int freq, unsigned int fmax, | ||
306 | unsigned int* in, unsigned int* feed, unsigned int* post) { | ||
307 | unsigned int fvco; | ||
308 | unsigned int p; | ||
309 | |||
310 | fvco = matroxfb_PLL_calcclock(&maven_pll, freq, fmax, in, feed, &p); | ||
311 | p = (1 << p) - 1; | ||
312 | if (fvco <= 100000) | ||
313 | ; | ||
314 | else if (fvco <= 140000) | ||
315 | p |= 0x08; | ||
316 | else if (fvco <= 180000) | ||
317 | p |= 0x10; | ||
318 | else | ||
319 | p |= 0x18; | ||
320 | *post = p; | ||
321 | return; | ||
322 | } | ||
323 | |||
324 | static unsigned char maven_compute_deflicker (const struct maven_data* md) { | ||
325 | unsigned char df; | ||
326 | |||
327 | df = (md->version == MGATVO_B?0x40:0x00); | ||
328 | switch (md->primary_head->altout.tvo_params.deflicker) { | ||
329 | case 0: | ||
330 | /* df |= 0x00; */ | ||
331 | break; | ||
332 | case 1: | ||
333 | df |= 0xB1; | ||
334 | break; | ||
335 | case 2: | ||
336 | df |= 0xA2; | ||
337 | break; | ||
338 | } | ||
339 | return df; | ||
340 | } | ||
341 | |||
342 | static void maven_compute_bwlevel (const struct maven_data* md, | ||
343 | int *bl, int *wl) { | ||
344 | const int b = md->primary_head->altout.tvo_params.brightness + BLMIN; | ||
345 | const int c = md->primary_head->altout.tvo_params.contrast; | ||
346 | |||
347 | *bl = max(b - c, BLMIN); | ||
348 | *wl = min(b + c, WLMAX); | ||
349 | } | ||
350 | |||
351 | static const struct maven_gamma* maven_compute_gamma (const struct maven_data* md) { | ||
352 | return maven_gamma + md->primary_head->altout.tvo_params.gamma; | ||
353 | } | ||
354 | |||
355 | |||
356 | static void maven_init_TVdata(const struct maven_data* md, struct mavenregs* data) { | ||
357 | static struct mavenregs palregs = { { | ||
358 | 0x2A, 0x09, 0x8A, 0xCB, /* 00: chroma subcarrier */ | ||
359 | 0x00, | ||
360 | 0x00, /* ? not written */ | ||
361 | 0x00, /* modified by code (F9 written...) */ | ||
362 | 0x00, /* ? not written */ | ||
363 | 0x7E, /* 08 */ | ||
364 | 0x44, /* 09 */ | ||
365 | 0x9C, /* 0A */ | ||
366 | 0x2E, /* 0B */ | ||
367 | 0x21, /* 0C */ | ||
368 | 0x00, /* ? not written */ | ||
369 | 0x3F, 0x03, /* 0E-0F */ | ||
370 | 0x3F, 0x03, /* 10-11 */ | ||
371 | 0x1A, /* 12 */ | ||
372 | 0x2A, /* 13 */ | ||
373 | 0x1C, 0x3D, 0x14, /* 14-16 */ | ||
374 | 0x9C, 0x01, /* 17-18 */ | ||
375 | 0x00, /* 19 */ | ||
376 | 0xFE, /* 1A */ | ||
377 | 0x7E, /* 1B */ | ||
378 | 0x60, /* 1C */ | ||
379 | 0x05, /* 1D */ | ||
380 | 0x89, 0x03, /* 1E-1F */ | ||
381 | 0x72, /* 20 */ | ||
382 | 0x07, /* 21 */ | ||
383 | 0x72, /* 22 */ | ||
384 | 0x00, /* 23 */ | ||
385 | 0x00, /* 24 */ | ||
386 | 0x00, /* 25 */ | ||
387 | 0x08, /* 26 */ | ||
388 | 0x04, /* 27 */ | ||
389 | 0x00, /* 28 */ | ||
390 | 0x1A, /* 29 */ | ||
391 | 0x55, 0x01, /* 2A-2B */ | ||
392 | 0x26, /* 2C */ | ||
393 | 0x07, 0x7E, /* 2D-2E */ | ||
394 | 0x02, 0x54, /* 2F-30 */ | ||
395 | 0xB0, 0x00, /* 31-32 */ | ||
396 | 0x14, /* 33 */ | ||
397 | 0x49, /* 34 */ | ||
398 | 0x00, /* 35 written multiple times */ | ||
399 | 0x00, /* 36 not written */ | ||
400 | 0xA3, /* 37 */ | ||
401 | 0xC8, /* 38 */ | ||
402 | 0x22, /* 39 */ | ||
403 | 0x02, /* 3A */ | ||
404 | 0x22, /* 3B */ | ||
405 | 0x3F, 0x03, /* 3C-3D */ | ||
406 | 0x00, /* 3E written multiple times */ | ||
407 | 0x00, /* 3F not written */ | ||
408 | }, MATROXFB_OUTPUT_MODE_PAL, 625, 50 }; | ||
409 | static struct mavenregs ntscregs = { { | ||
410 | 0x21, 0xF0, 0x7C, 0x1F, /* 00: chroma subcarrier */ | ||
411 | 0x00, | ||
412 | 0x00, /* ? not written */ | ||
413 | 0x00, /* modified by code (F9 written...) */ | ||
414 | 0x00, /* ? not written */ | ||
415 | 0x7E, /* 08 */ | ||
416 | 0x43, /* 09 */ | ||
417 | 0x7E, /* 0A */ | ||
418 | 0x3D, /* 0B */ | ||
419 | 0x00, /* 0C */ | ||
420 | 0x00, /* ? not written */ | ||
421 | 0x41, 0x00, /* 0E-0F */ | ||
422 | 0x3C, 0x00, /* 10-11 */ | ||
423 | 0x17, /* 12 */ | ||
424 | 0x21, /* 13 */ | ||
425 | 0x1B, 0x1B, 0x24, /* 14-16 */ | ||
426 | 0x83, 0x01, /* 17-18 */ | ||
427 | 0x00, /* 19 */ | ||
428 | 0x0F, /* 1A */ | ||
429 | 0x0F, /* 1B */ | ||
430 | 0x60, /* 1C */ | ||
431 | 0x05, /* 1D */ | ||
432 | 0x89, 0x02, /* 1E-1F */ | ||
433 | 0x5F, /* 20 */ | ||
434 | 0x04, /* 21 */ | ||
435 | 0x5F, /* 22 */ | ||
436 | 0x01, /* 23 */ | ||
437 | 0x02, /* 24 */ | ||
438 | 0x00, /* 25 */ | ||
439 | 0x0A, /* 26 */ | ||
440 | 0x05, /* 27 */ | ||
441 | 0x00, /* 28 */ | ||
442 | 0x10, /* 29 */ | ||
443 | 0xFF, 0x03, /* 2A-2B */ | ||
444 | 0x24, /* 2C */ | ||
445 | 0x0F, 0x78, /* 2D-2E */ | ||
446 | 0x00, 0x00, /* 2F-30 */ | ||
447 | 0xB2, 0x04, /* 31-32 */ | ||
448 | 0x14, /* 33 */ | ||
449 | 0x02, /* 34 */ | ||
450 | 0x00, /* 35 written multiple times */ | ||
451 | 0x00, /* 36 not written */ | ||
452 | 0xA3, /* 37 */ | ||
453 | 0xC8, /* 38 */ | ||
454 | 0x15, /* 39 */ | ||
455 | 0x05, /* 3A */ | ||
456 | 0x3B, /* 3B */ | ||
457 | 0x3C, 0x00, /* 3C-3D */ | ||
458 | 0x00, /* 3E written multiple times */ | ||
459 | 0x00, /* never written */ | ||
460 | }, MATROXFB_OUTPUT_MODE_NTSC, 525, 60 }; | ||
461 | MINFO_FROM(md->primary_head); | ||
462 | |||
463 | if (ACCESS_FBINFO(outputs[1]).mode == MATROXFB_OUTPUT_MODE_PAL) | ||
464 | *data = palregs; | ||
465 | else | ||
466 | *data = ntscregs; | ||
467 | |||
468 | /* Set deflicker */ | ||
469 | data->regs[0x93] = maven_compute_deflicker(md); | ||
470 | |||
471 | /* set gamma */ | ||
472 | { | ||
473 | const struct maven_gamma* g; | ||
474 | g = maven_compute_gamma(md); | ||
475 | data->regs[0x83] = g->reg83; | ||
476 | data->regs[0x84] = g->reg84; | ||
477 | data->regs[0x85] = g->reg85; | ||
478 | data->regs[0x86] = g->reg86; | ||
479 | data->regs[0x87] = g->reg87; | ||
480 | data->regs[0x88] = g->reg88; | ||
481 | data->regs[0x89] = g->reg89; | ||
482 | data->regs[0x8A] = g->reg8a; | ||
483 | data->regs[0x8B] = g->reg8b; | ||
484 | } | ||
485 | |||
486 | /* Set contrast / brightness */ | ||
487 | { | ||
488 | int bl, wl; | ||
489 | maven_compute_bwlevel (md, &bl, &wl); | ||
490 | data->regs[0x0e] = bl >> 2; | ||
491 | data->regs[0x0f] = bl & 3; | ||
492 | data->regs[0x1e] = wl >> 2; | ||
493 | data->regs[0x1f] = wl & 3; | ||
494 | } | ||
495 | |||
496 | /* Set saturation */ | ||
497 | { | ||
498 | data->regs[0x20] = | ||
499 | data->regs[0x22] = ACCESS_FBINFO(altout.tvo_params.saturation); | ||
500 | } | ||
501 | |||
502 | /* Set HUE */ | ||
503 | data->regs[0x25] = ACCESS_FBINFO(altout.tvo_params.hue); | ||
504 | return; | ||
505 | } | ||
506 | |||
507 | #define LR(x) maven_set_reg(c, (x), m->regs[(x)]) | ||
508 | #define LRP(x) maven_set_reg_pair(c, (x), m->regs[(x)] | (m->regs[(x)+1] << 8)) | ||
509 | static void maven_init_TV(struct i2c_client* c, const struct mavenregs* m) { | ||
510 | int val; | ||
511 | |||
512 | |||
513 | maven_set_reg(c, 0x3E, 0x01); | ||
514 | maven_get_reg(c, 0x82); /* fetch oscillator state? */ | ||
515 | maven_set_reg(c, 0x8C, 0x00); | ||
516 | maven_get_reg(c, 0x94); /* get 0x82 */ | ||
517 | maven_set_reg(c, 0x94, 0xA2); | ||
518 | /* xmiscctrl */ | ||
519 | |||
520 | maven_set_reg_pair(c, 0x8E, 0x1EFF); | ||
521 | maven_set_reg(c, 0xC6, 0x01); | ||
522 | |||
523 | /* removed code... */ | ||
524 | |||
525 | maven_get_reg(c, 0x06); | ||
526 | maven_set_reg(c, 0x06, 0xF9); /* or read |= 0xF0 ? */ | ||
527 | |||
528 | /* removed code here... */ | ||
529 | |||
530 | /* real code begins here? */ | ||
531 | /* chroma subcarrier */ | ||
532 | LR(0x00); LR(0x01); LR(0x02); LR(0x03); | ||
533 | |||
534 | LR(0x04); | ||
535 | |||
536 | LR(0x2C); | ||
537 | LR(0x08); | ||
538 | LR(0x0A); | ||
539 | LR(0x09); | ||
540 | LR(0x29); | ||
541 | LRP(0x31); | ||
542 | LRP(0x17); | ||
543 | LR(0x0B); | ||
544 | LR(0x0C); | ||
545 | if (m->mode == MATROXFB_OUTPUT_MODE_PAL) { | ||
546 | maven_set_reg(c, 0x35, 0x10); /* ... */ | ||
547 | } else { | ||
548 | maven_set_reg(c, 0x35, 0x0F); /* ... */ | ||
549 | } | ||
550 | |||
551 | LRP(0x10); | ||
552 | |||
553 | LRP(0x0E); | ||
554 | LRP(0x1E); | ||
555 | |||
556 | LR(0x20); /* saturation #1 */ | ||
557 | LR(0x22); /* saturation #2 */ | ||
558 | LR(0x25); /* hue */ | ||
559 | LR(0x34); | ||
560 | LR(0x33); | ||
561 | LR(0x19); | ||
562 | LR(0x12); | ||
563 | LR(0x3B); | ||
564 | LR(0x13); | ||
565 | LR(0x39); | ||
566 | LR(0x1D); | ||
567 | LR(0x3A); | ||
568 | LR(0x24); | ||
569 | LR(0x14); | ||
570 | LR(0x15); | ||
571 | LR(0x16); | ||
572 | LRP(0x2D); | ||
573 | LRP(0x2F); | ||
574 | LR(0x1A); | ||
575 | LR(0x1B); | ||
576 | LR(0x1C); | ||
577 | LR(0x23); | ||
578 | LR(0x26); | ||
579 | LR(0x28); | ||
580 | LR(0x27); | ||
581 | LR(0x21); | ||
582 | LRP(0x2A); | ||
583 | if (m->mode == MATROXFB_OUTPUT_MODE_PAL) | ||
584 | maven_set_reg(c, 0x35, 0x1D); /* ... */ | ||
585 | else | ||
586 | maven_set_reg(c, 0x35, 0x1C); | ||
587 | |||
588 | LRP(0x3C); | ||
589 | LR(0x37); | ||
590 | LR(0x38); | ||
591 | maven_set_reg(c, 0xB3, 0x01); | ||
592 | |||
593 | maven_get_reg(c, 0xB0); /* read 0x80 */ | ||
594 | maven_set_reg(c, 0xB0, 0x08); /* ugh... */ | ||
595 | maven_get_reg(c, 0xB9); /* read 0x7C */ | ||
596 | maven_set_reg(c, 0xB9, 0x78); | ||
597 | maven_get_reg(c, 0xBF); /* read 0x00 */ | ||
598 | maven_set_reg(c, 0xBF, 0x02); | ||
599 | maven_get_reg(c, 0x94); /* read 0x82 */ | ||
600 | maven_set_reg(c, 0x94, 0xB3); | ||
601 | |||
602 | LR(0x80); /* 04 1A 91 or 05 21 91 */ | ||
603 | LR(0x81); | ||
604 | LR(0x82); | ||
605 | |||
606 | maven_set_reg(c, 0x8C, 0x20); | ||
607 | maven_get_reg(c, 0x8D); | ||
608 | maven_set_reg(c, 0x8D, 0x10); | ||
609 | |||
610 | LR(0x90); /* 4D 50 52 or 4E 05 45 */ | ||
611 | LR(0x91); | ||
612 | LR(0x92); | ||
613 | |||
614 | LRP(0x9A); /* 0049 or 004F */ | ||
615 | LRP(0x9C); /* 0004 or 0004 */ | ||
616 | LRP(0x9E); /* 0458 or 045E */ | ||
617 | LRP(0xA0); /* 05DA or 051B */ | ||
618 | LRP(0xA2); /* 00CC or 00CF */ | ||
619 | LRP(0xA4); /* 007D or 007F */ | ||
620 | LRP(0xA6); /* 007C or 007E */ | ||
621 | LRP(0xA8); /* 03CB or 03CE */ | ||
622 | LRP(0x98); /* 0000 or 0000 */ | ||
623 | LRP(0xAE); /* 0044 or 003A */ | ||
624 | LRP(0x96); /* 05DA or 051B */ | ||
625 | LRP(0xAA); /* 04BC or 046A */ | ||
626 | LRP(0xAC); /* 004D or 004E */ | ||
627 | |||
628 | LR(0xBE); | ||
629 | LR(0xC2); | ||
630 | |||
631 | maven_get_reg(c, 0x8D); | ||
632 | maven_set_reg(c, 0x8D, 0x04); | ||
633 | |||
634 | LR(0x20); /* saturation #1 */ | ||
635 | LR(0x22); /* saturation #2 */ | ||
636 | LR(0x93); /* whoops */ | ||
637 | LR(0x20); /* oh, saturation #1 again */ | ||
638 | LR(0x22); /* oh, saturation #2 again */ | ||
639 | LR(0x25); /* hue */ | ||
640 | LRP(0x0E); | ||
641 | LRP(0x1E); | ||
642 | LRP(0x0E); /* problems with memory? */ | ||
643 | LRP(0x1E); /* yes, matrox must have problems in memory area... */ | ||
644 | |||
645 | /* load gamma correction stuff */ | ||
646 | LR(0x83); | ||
647 | LR(0x84); | ||
648 | LR(0x85); | ||
649 | LR(0x86); | ||
650 | LR(0x87); | ||
651 | LR(0x88); | ||
652 | LR(0x89); | ||
653 | LR(0x8A); | ||
654 | LR(0x8B); | ||
655 | |||
656 | val = maven_get_reg(c, 0x8D); | ||
657 | val &= 0x14; /* 0x10 or anything ored with it */ | ||
658 | maven_set_reg(c, 0x8D, val); | ||
659 | |||
660 | LR(0x33); | ||
661 | LR(0x19); | ||
662 | LR(0x12); | ||
663 | LR(0x3B); | ||
664 | LR(0x13); | ||
665 | LR(0x39); | ||
666 | LR(0x1D); | ||
667 | LR(0x3A); | ||
668 | LR(0x24); | ||
669 | LR(0x14); | ||
670 | LR(0x15); | ||
671 | LR(0x16); | ||
672 | LRP(0x2D); | ||
673 | LRP(0x2F); | ||
674 | LR(0x1A); | ||
675 | LR(0x1B); | ||
676 | LR(0x1C); | ||
677 | LR(0x23); | ||
678 | LR(0x26); | ||
679 | LR(0x28); | ||
680 | LR(0x27); | ||
681 | LR(0x21); | ||
682 | LRP(0x2A); | ||
683 | if (m->mode == MATROXFB_OUTPUT_MODE_PAL) | ||
684 | maven_set_reg(c, 0x35, 0x1D); | ||
685 | else | ||
686 | maven_set_reg(c, 0x35, 0x1C); | ||
687 | LRP(0x3C); | ||
688 | LR(0x37); | ||
689 | LR(0x38); | ||
690 | |||
691 | maven_get_reg(c, 0xB0); | ||
692 | LR(0xB0); /* output mode */ | ||
693 | LR(0x90); | ||
694 | LR(0xBE); | ||
695 | LR(0xC2); | ||
696 | |||
697 | LRP(0x9A); | ||
698 | LRP(0xA2); | ||
699 | LRP(0x9E); | ||
700 | LRP(0xA6); | ||
701 | LRP(0xAA); | ||
702 | LRP(0xAC); | ||
703 | maven_set_reg(c, 0x3E, 0x00); | ||
704 | maven_set_reg(c, 0x95, 0x20); | ||
705 | } | ||
706 | |||
707 | static int maven_find_exact_clocks(unsigned int ht, unsigned int vt, | ||
708 | struct mavenregs* m) { | ||
709 | unsigned int x; | ||
710 | unsigned int err = ~0; | ||
711 | |||
712 | /* 1:1 */ | ||
713 | m->regs[0x80] = 0x0F; | ||
714 | m->regs[0x81] = 0x07; | ||
715 | m->regs[0x82] = 0x81; | ||
716 | |||
717 | for (x = 0; x < 8; x++) { | ||
718 | unsigned int a, b, c, h2; | ||
719 | unsigned int h = ht + 2 + x; | ||
720 | |||
721 | if (!matroxfb_mavenclock((m->mode == MATROXFB_OUTPUT_MODE_PAL) ? &maven_PAL : &maven_NTSC, h, vt, &a, &b, &c, &h2)) { | ||
722 | unsigned int diff = h - h2; | ||
723 | |||
724 | if (diff < err) { | ||
725 | err = diff; | ||
726 | m->regs[0x80] = a - 1; | ||
727 | m->regs[0x81] = b - 1; | ||
728 | m->regs[0x82] = c | 0x80; | ||
729 | m->hcorr = h2 - 2; | ||
730 | m->htotal = h - 2; | ||
731 | } | ||
732 | } | ||
733 | } | ||
734 | return err != ~0U; | ||
735 | } | ||
736 | |||
737 | static inline int maven_compute_timming(struct maven_data* md, | ||
738 | struct my_timming* mt, | ||
739 | struct mavenregs* m) { | ||
740 | unsigned int tmpi; | ||
741 | unsigned int a, bv, c; | ||
742 | MINFO_FROM(md->primary_head); | ||
743 | |||
744 | m->mode = ACCESS_FBINFO(outputs[1]).mode; | ||
745 | if (m->mode != MATROXFB_OUTPUT_MODE_MONITOR) { | ||
746 | unsigned int lmargin; | ||
747 | unsigned int umargin; | ||
748 | unsigned int vslen; | ||
749 | unsigned int hcrt; | ||
750 | unsigned int slen; | ||
751 | |||
752 | maven_init_TVdata(md, m); | ||
753 | |||
754 | if (maven_find_exact_clocks(mt->HTotal, mt->VTotal, m) == 0) | ||
755 | return -EINVAL; | ||
756 | |||
757 | lmargin = mt->HTotal - mt->HSyncEnd; | ||
758 | slen = mt->HSyncEnd - mt->HSyncStart; | ||
759 | hcrt = mt->HTotal - slen - mt->delay; | ||
760 | umargin = mt->VTotal - mt->VSyncEnd; | ||
761 | vslen = mt->VSyncEnd - mt->VSyncStart; | ||
762 | |||
763 | if (m->hcorr < mt->HTotal) | ||
764 | hcrt += m->hcorr; | ||
765 | if (hcrt > mt->HTotal) | ||
766 | hcrt -= mt->HTotal; | ||
767 | if (hcrt + 2 > mt->HTotal) | ||
768 | hcrt = 0; /* or issue warning? */ | ||
769 | |||
770 | /* last (first? middle?) line in picture can have different length */ | ||
771 | /* hlen - 2 */ | ||
772 | m->regs[0x96] = m->hcorr; | ||
773 | m->regs[0x97] = m->hcorr >> 8; | ||
774 | /* ... */ | ||
775 | m->regs[0x98] = 0x00; m->regs[0x99] = 0x00; | ||
776 | /* hblanking end */ | ||
777 | m->regs[0x9A] = lmargin; /* 100% */ | ||
778 | m->regs[0x9B] = lmargin >> 8; /* 100% */ | ||
779 | /* who knows */ | ||
780 | m->regs[0x9C] = 0x04; | ||
781 | m->regs[0x9D] = 0x00; | ||
782 | /* htotal - 2 */ | ||
783 | m->regs[0xA0] = m->htotal; | ||
784 | m->regs[0xA1] = m->htotal >> 8; | ||
785 | /* vblanking end */ | ||
786 | m->regs[0xA2] = mt->VTotal - mt->VSyncStart - 1; /* stop vblanking */ | ||
787 | m->regs[0xA3] = (mt->VTotal - mt->VSyncStart - 1) >> 8; | ||
788 | /* something end... [A6]+1..[A8] */ | ||
789 | if (md->version == MGATVO_B) { | ||
790 | m->regs[0xA4] = 0x04; | ||
791 | m->regs[0xA5] = 0x00; | ||
792 | } else { | ||
793 | m->regs[0xA4] = 0x01; | ||
794 | m->regs[0xA5] = 0x00; | ||
795 | } | ||
796 | /* something start... 0..[A4]-1 */ | ||
797 | m->regs[0xA6] = 0x00; | ||
798 | m->regs[0xA7] = 0x00; | ||
799 | /* vertical line count - 1 */ | ||
800 | m->regs[0xA8] = mt->VTotal - 1; | ||
801 | m->regs[0xA9] = (mt->VTotal - 1) >> 8; | ||
802 | /* horizontal vidrst pos */ | ||
803 | m->regs[0xAA] = hcrt; /* 0 <= hcrt <= htotal - 2 */ | ||
804 | m->regs[0xAB] = hcrt >> 8; | ||
805 | /* vertical vidrst pos */ | ||
806 | m->regs[0xAC] = mt->VTotal - 2; | ||
807 | m->regs[0xAD] = (mt->VTotal - 2) >> 8; | ||
808 | /* moves picture up/down and so on... */ | ||
809 | m->regs[0xAE] = 0x01; /* Fix this... 0..VTotal */ | ||
810 | m->regs[0xAF] = 0x00; | ||
811 | { | ||
812 | int hdec; | ||
813 | int hlen; | ||
814 | unsigned int ibmin = 4 + lmargin + mt->HDisplay; | ||
815 | unsigned int ib; | ||
816 | int i; | ||
817 | |||
818 | /* Verify! */ | ||
819 | /* Where 94208 came from? */ | ||
820 | if (mt->HTotal) | ||
821 | hdec = 94208 / (mt->HTotal); | ||
822 | else | ||
823 | hdec = 0x81; | ||
824 | if (hdec > 0x81) | ||
825 | hdec = 0x81; | ||
826 | if (hdec < 0x41) | ||
827 | hdec = 0x41; | ||
828 | hdec--; | ||
829 | hlen = 98304 - 128 - ((lmargin + mt->HDisplay - 8) * hdec); | ||
830 | if (hlen < 0) | ||
831 | hlen = 0; | ||
832 | hlen = hlen >> 8; | ||
833 | if (hlen > 0xFF) | ||
834 | hlen = 0xFF; | ||
835 | /* Now we have to compute input buffer length. | ||
836 | If you want any picture, it must be between | ||
837 | 4 + lmargin + xres | ||
838 | and | ||
839 | 94208 / hdec | ||
840 | If you want perfect picture even on the top | ||
841 | of screen, it must be also | ||
842 | 0x3C0000 * i / hdec + Q - R / hdec | ||
843 | where | ||
844 | R Qmin Qmax | ||
845 | 0x07000 0x5AE 0x5BF | ||
846 | 0x08000 0x5CF 0x5FF | ||
847 | 0x0C000 0x653 0x67F | ||
848 | 0x10000 0x6F8 0x6FF | ||
849 | */ | ||
850 | i = 1; | ||
851 | do { | ||
852 | ib = ((0x3C0000 * i - 0x8000)/ hdec + 0x05E7) >> 8; | ||
853 | i++; | ||
854 | } while (ib < ibmin); | ||
855 | if (ib >= m->htotal + 2) { | ||
856 | ib = ibmin; | ||
857 | } | ||
858 | |||
859 | m->regs[0x90] = hdec; /* < 0x40 || > 0x80 is bad... 0x80 is questionable */ | ||
860 | m->regs[0xC2] = hlen; | ||
861 | /* 'valid' input line length */ | ||
862 | m->regs[0x9E] = ib; | ||
863 | m->regs[0x9F] = ib >> 8; | ||
864 | } | ||
865 | { | ||
866 | int vdec; | ||
867 | int vlen; | ||
868 | |||
869 | #define MATROX_USE64BIT_DIVIDE | ||
870 | if (mt->VTotal) { | ||
871 | #ifdef MATROX_USE64BIT_DIVIDE | ||
872 | u64 f1; | ||
873 | u32 a; | ||
874 | u32 b; | ||
875 | |||
876 | a = m->vlines * (m->htotal + 2); | ||
877 | b = (mt->VTotal - 1) * (m->htotal + 2) + m->hcorr + 2; | ||
878 | |||
879 | f1 = ((u64)a) << 15; /* *32768 */ | ||
880 | do_div(f1, b); | ||
881 | vdec = f1; | ||
882 | #else | ||
883 | vdec = m->vlines * 32768 / mt->VTotal; | ||
884 | #endif | ||
885 | } else | ||
886 | vdec = 0x8000; | ||
887 | if (vdec > 0x8000) | ||
888 | vdec = 0x8000; | ||
889 | vlen = (vslen + umargin + mt->VDisplay) * vdec; | ||
890 | vlen = (vlen >> 16) - 146; /* FIXME: 146?! */ | ||
891 | if (vlen < 0) | ||
892 | vlen = 0; | ||
893 | if (vlen > 0xFF) | ||
894 | vlen = 0xFF; | ||
895 | vdec--; | ||
896 | m->regs[0x91] = vdec; | ||
897 | m->regs[0x92] = vdec >> 8; | ||
898 | m->regs[0xBE] = vlen; | ||
899 | } | ||
900 | m->regs[0xB0] = 0x08; /* output: SVideo/Composite */ | ||
901 | return 0; | ||
902 | } | ||
903 | |||
904 | DAC1064_calcclock(mt->pixclock, 450000, &a, &bv, &c); | ||
905 | m->regs[0x80] = a; | ||
906 | m->regs[0x81] = bv; | ||
907 | m->regs[0x82] = c | 0x80; | ||
908 | |||
909 | m->regs[0xB3] = 0x01; | ||
910 | m->regs[0x94] = 0xB2; | ||
911 | |||
912 | /* htotal... */ | ||
913 | m->regs[0x96] = mt->HTotal; | ||
914 | m->regs[0x97] = mt->HTotal >> 8; | ||
915 | /* ?? */ | ||
916 | m->regs[0x98] = 0x00; | ||
917 | m->regs[0x99] = 0x00; | ||
918 | /* hsync len */ | ||
919 | tmpi = mt->HSyncEnd - mt->HSyncStart; | ||
920 | m->regs[0x9A] = tmpi; | ||
921 | m->regs[0x9B] = tmpi >> 8; | ||
922 | /* hblank end */ | ||
923 | tmpi = mt->HTotal - mt->HSyncStart; | ||
924 | m->regs[0x9C] = tmpi; | ||
925 | m->regs[0x9D] = tmpi >> 8; | ||
926 | /* hblank start */ | ||
927 | tmpi += mt->HDisplay; | ||
928 | m->regs[0x9E] = tmpi; | ||
929 | m->regs[0x9F] = tmpi >> 8; | ||
930 | /* htotal + 1 */ | ||
931 | tmpi = mt->HTotal + 1; | ||
932 | m->regs[0xA0] = tmpi; | ||
933 | m->regs[0xA1] = tmpi >> 8; | ||
934 | /* vsync?! */ | ||
935 | tmpi = mt->VSyncEnd - mt->VSyncStart - 1; | ||
936 | m->regs[0xA2] = tmpi; | ||
937 | m->regs[0xA3] = tmpi >> 8; | ||
938 | /* ignored? */ | ||
939 | tmpi = mt->VTotal - mt->VSyncStart; | ||
940 | m->regs[0xA4] = tmpi; | ||
941 | m->regs[0xA5] = tmpi >> 8; | ||
942 | /* ignored? */ | ||
943 | tmpi = mt->VTotal - 1; | ||
944 | m->regs[0xA6] = tmpi; | ||
945 | m->regs[0xA7] = tmpi >> 8; | ||
946 | /* vtotal - 1 */ | ||
947 | m->regs[0xA8] = tmpi; | ||
948 | m->regs[0xA9] = tmpi >> 8; | ||
949 | /* hor vidrst */ | ||
950 | tmpi = mt->HTotal - mt->delay; | ||
951 | m->regs[0xAA] = tmpi; | ||
952 | m->regs[0xAB] = tmpi >> 8; | ||
953 | /* vert vidrst */ | ||
954 | tmpi = mt->VTotal - 2; | ||
955 | m->regs[0xAC] = tmpi; | ||
956 | m->regs[0xAD] = tmpi >> 8; | ||
957 | /* ignored? */ | ||
958 | m->regs[0xAE] = 0x00; | ||
959 | m->regs[0xAF] = 0x00; | ||
960 | |||
961 | m->regs[0xB0] = 0x03; /* output: monitor */ | ||
962 | m->regs[0xB1] = 0xA0; /* ??? */ | ||
963 | m->regs[0x8C] = 0x20; /* must be set... */ | ||
964 | m->regs[0x8D] = 0x04; /* defaults to 0x10: test signal */ | ||
965 | m->regs[0xB9] = 0x1A; /* defaults to 0x2C: too bright */ | ||
966 | m->regs[0xBF] = 0x22; /* makes picture stable */ | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static inline int maven_program_timming(struct maven_data* md, | ||
972 | const struct mavenregs* m) { | ||
973 | struct i2c_client* c = md->client; | ||
974 | |||
975 | if (m->mode == MATROXFB_OUTPUT_MODE_MONITOR) { | ||
976 | LR(0x80); | ||
977 | LR(0x81); | ||
978 | LR(0x82); | ||
979 | |||
980 | LR(0xB3); | ||
981 | LR(0x94); | ||
982 | |||
983 | LRP(0x96); | ||
984 | LRP(0x98); | ||
985 | LRP(0x9A); | ||
986 | LRP(0x9C); | ||
987 | LRP(0x9E); | ||
988 | LRP(0xA0); | ||
989 | LRP(0xA2); | ||
990 | LRP(0xA4); | ||
991 | LRP(0xA6); | ||
992 | LRP(0xA8); | ||
993 | LRP(0xAA); | ||
994 | LRP(0xAC); | ||
995 | LRP(0xAE); | ||
996 | |||
997 | LR(0xB0); /* output: monitor */ | ||
998 | LR(0xB1); /* ??? */ | ||
999 | LR(0x8C); /* must be set... */ | ||
1000 | LR(0x8D); /* defaults to 0x10: test signal */ | ||
1001 | LR(0xB9); /* defaults to 0x2C: too bright */ | ||
1002 | LR(0xBF); /* makes picture stable */ | ||
1003 | } else { | ||
1004 | maven_init_TV(c, m); | ||
1005 | } | ||
1006 | return 0; | ||
1007 | } | ||
1008 | |||
1009 | static inline int maven_resync(struct maven_data* md) { | ||
1010 | struct i2c_client* c = md->client; | ||
1011 | maven_set_reg(c, 0x95, 0x20); /* start whole thing */ | ||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static int maven_get_queryctrl (struct maven_data* md, | ||
1016 | struct v4l2_queryctrl *p) { | ||
1017 | int i; | ||
1018 | |||
1019 | i = get_ctrl_id(p->id); | ||
1020 | if (i >= 0) { | ||
1021 | *p = maven_controls[i].desc; | ||
1022 | return 0; | ||
1023 | } | ||
1024 | if (i == -ENOENT) { | ||
1025 | static const struct v4l2_queryctrl disctrl = | ||
1026 | { .flags = V4L2_CTRL_FLAG_DISABLED }; | ||
1027 | |||
1028 | i = p->id; | ||
1029 | *p = disctrl; | ||
1030 | p->id = i; | ||
1031 | sprintf(p->name, "Ctrl #%08X", i); | ||
1032 | return 0; | ||
1033 | } | ||
1034 | return -EINVAL; | ||
1035 | } | ||
1036 | |||
1037 | static int maven_set_control (struct maven_data* md, | ||
1038 | struct v4l2_control *p) { | ||
1039 | int i; | ||
1040 | |||
1041 | i = get_ctrl_id(p->id); | ||
1042 | if (i < 0) return -EINVAL; | ||
1043 | |||
1044 | /* | ||
1045 | * Check if changed. | ||
1046 | */ | ||
1047 | if (p->value == *get_ctrl_ptr(md, i)) return 0; | ||
1048 | |||
1049 | /* | ||
1050 | * Check limits. | ||
1051 | */ | ||
1052 | if (p->value > maven_controls[i].desc.maximum) return -EINVAL; | ||
1053 | if (p->value < maven_controls[i].desc.minimum) return -EINVAL; | ||
1054 | |||
1055 | /* | ||
1056 | * Store new value. | ||
1057 | */ | ||
1058 | *get_ctrl_ptr(md, i) = p->value; | ||
1059 | |||
1060 | switch (p->id) { | ||
1061 | case V4L2_CID_BRIGHTNESS: | ||
1062 | case V4L2_CID_CONTRAST: | ||
1063 | { | ||
1064 | int blacklevel, whitelevel; | ||
1065 | maven_compute_bwlevel(md, &blacklevel, &whitelevel); | ||
1066 | blacklevel = (blacklevel >> 2) | ((blacklevel & 3) << 8); | ||
1067 | whitelevel = (whitelevel >> 2) | ((whitelevel & 3) << 8); | ||
1068 | maven_set_reg_pair(md->client, 0x0e, blacklevel); | ||
1069 | maven_set_reg_pair(md->client, 0x1e, whitelevel); | ||
1070 | } | ||
1071 | break; | ||
1072 | case V4L2_CID_SATURATION: | ||
1073 | { | ||
1074 | maven_set_reg(md->client, 0x20, p->value); | ||
1075 | maven_set_reg(md->client, 0x22, p->value); | ||
1076 | } | ||
1077 | break; | ||
1078 | case V4L2_CID_HUE: | ||
1079 | { | ||
1080 | maven_set_reg(md->client, 0x25, p->value); | ||
1081 | } | ||
1082 | break; | ||
1083 | case V4L2_CID_GAMMA: | ||
1084 | { | ||
1085 | const struct maven_gamma* g; | ||
1086 | g = maven_compute_gamma(md); | ||
1087 | maven_set_reg(md->client, 0x83, g->reg83); | ||
1088 | maven_set_reg(md->client, 0x84, g->reg84); | ||
1089 | maven_set_reg(md->client, 0x85, g->reg85); | ||
1090 | maven_set_reg(md->client, 0x86, g->reg86); | ||
1091 | maven_set_reg(md->client, 0x87, g->reg87); | ||
1092 | maven_set_reg(md->client, 0x88, g->reg88); | ||
1093 | maven_set_reg(md->client, 0x89, g->reg89); | ||
1094 | maven_set_reg(md->client, 0x8a, g->reg8a); | ||
1095 | maven_set_reg(md->client, 0x8b, g->reg8b); | ||
1096 | } | ||
1097 | break; | ||
1098 | case MATROXFB_CID_TESTOUT: | ||
1099 | { | ||
1100 | unsigned char val | ||
1101 | = maven_get_reg (md->client,0x8d); | ||
1102 | if (p->value) val |= 0x10; | ||
1103 | else val &= ~0x10; | ||
1104 | maven_set_reg (md->client, 0x8d, val); | ||
1105 | } | ||
1106 | break; | ||
1107 | case MATROXFB_CID_DEFLICKER: | ||
1108 | { | ||
1109 | maven_set_reg(md->client, 0x93, maven_compute_deflicker(md)); | ||
1110 | } | ||
1111 | break; | ||
1112 | } | ||
1113 | |||
1114 | |||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int maven_get_control (struct maven_data* md, | ||
1119 | struct v4l2_control *p) { | ||
1120 | int i; | ||
1121 | |||
1122 | i = get_ctrl_id(p->id); | ||
1123 | if (i < 0) return -EINVAL; | ||
1124 | p->value = *get_ctrl_ptr(md, i); | ||
1125 | return 0; | ||
1126 | } | ||
1127 | |||
1128 | /******************************************************/ | ||
1129 | |||
1130 | static int maven_out_compute(void* md, struct my_timming* mt) { | ||
1131 | #define mdinfo ((struct maven_data*)md) | ||
1132 | #define minfo (mdinfo->primary_head) | ||
1133 | return maven_compute_timming(md, mt, &ACCESS_FBINFO(hw).maven); | ||
1134 | #undef minfo | ||
1135 | #undef mdinfo | ||
1136 | } | ||
1137 | |||
1138 | static int maven_out_program(void* md) { | ||
1139 | #define mdinfo ((struct maven_data*)md) | ||
1140 | #define minfo (mdinfo->primary_head) | ||
1141 | return maven_program_timming(md, &ACCESS_FBINFO(hw).maven); | ||
1142 | #undef minfo | ||
1143 | #undef mdinfo | ||
1144 | } | ||
1145 | |||
1146 | static int maven_out_start(void* md) { | ||
1147 | return maven_resync(md); | ||
1148 | } | ||
1149 | |||
1150 | static int maven_out_verify_mode(void* md, u_int32_t arg) { | ||
1151 | switch (arg) { | ||
1152 | case MATROXFB_OUTPUT_MODE_PAL: | ||
1153 | case MATROXFB_OUTPUT_MODE_NTSC: | ||
1154 | case MATROXFB_OUTPUT_MODE_MONITOR: | ||
1155 | return 0; | ||
1156 | } | ||
1157 | return -EINVAL; | ||
1158 | } | ||
1159 | |||
1160 | static int maven_out_get_queryctrl(void* md, struct v4l2_queryctrl* p) { | ||
1161 | return maven_get_queryctrl(md, p); | ||
1162 | } | ||
1163 | |||
1164 | static int maven_out_get_ctrl(void* md, struct v4l2_control* p) { | ||
1165 | return maven_get_control(md, p); | ||
1166 | } | ||
1167 | |||
1168 | static int maven_out_set_ctrl(void* md, struct v4l2_control* p) { | ||
1169 | return maven_set_control(md, p); | ||
1170 | } | ||
1171 | |||
1172 | static struct matrox_altout maven_altout = { | ||
1173 | .name = "Secondary output", | ||
1174 | .compute = maven_out_compute, | ||
1175 | .program = maven_out_program, | ||
1176 | .start = maven_out_start, | ||
1177 | .verifymode = maven_out_verify_mode, | ||
1178 | .getqueryctrl = maven_out_get_queryctrl, | ||
1179 | .getctrl = maven_out_get_ctrl, | ||
1180 | .setctrl = maven_out_set_ctrl, | ||
1181 | }; | ||
1182 | |||
1183 | static int maven_init_client(struct i2c_client* clnt) { | ||
1184 | struct maven_data* md = i2c_get_clientdata(clnt); | ||
1185 | MINFO_FROM(container_of(clnt->adapter, struct i2c_bit_adapter, adapter)->minfo); | ||
1186 | |||
1187 | md->primary_head = MINFO; | ||
1188 | md->client = clnt; | ||
1189 | down_write(&ACCESS_FBINFO(altout.lock)); | ||
1190 | ACCESS_FBINFO(outputs[1]).output = &maven_altout; | ||
1191 | ACCESS_FBINFO(outputs[1]).src = ACCESS_FBINFO(outputs[1]).default_src; | ||
1192 | ACCESS_FBINFO(outputs[1]).data = md; | ||
1193 | ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; | ||
1194 | up_write(&ACCESS_FBINFO(altout.lock)); | ||
1195 | if (maven_get_reg(clnt, 0xB2) < 0x14) { | ||
1196 | md->version = MGATVO_B; | ||
1197 | /* Tweak some things for this old chip */ | ||
1198 | } else { | ||
1199 | md->version = MGATVO_C; | ||
1200 | } | ||
1201 | /* | ||
1202 | * Set all parameters to its initial values. | ||
1203 | */ | ||
1204 | { | ||
1205 | unsigned int i; | ||
1206 | |||
1207 | for (i = 0; i < MAVCTRLS; ++i) { | ||
1208 | *get_ctrl_ptr(md, i) = maven_controls[i].desc.default_value; | ||
1209 | } | ||
1210 | } | ||
1211 | |||
1212 | return 0; | ||
1213 | } | ||
1214 | |||
1215 | static int maven_shutdown_client(struct i2c_client* clnt) { | ||
1216 | struct maven_data* md = i2c_get_clientdata(clnt); | ||
1217 | |||
1218 | if (md->primary_head) { | ||
1219 | MINFO_FROM(md->primary_head); | ||
1220 | |||
1221 | down_write(&ACCESS_FBINFO(altout.lock)); | ||
1222 | ACCESS_FBINFO(outputs[1]).src = MATROXFB_SRC_NONE; | ||
1223 | ACCESS_FBINFO(outputs[1]).output = NULL; | ||
1224 | ACCESS_FBINFO(outputs[1]).data = NULL; | ||
1225 | ACCESS_FBINFO(outputs[1]).mode = MATROXFB_OUTPUT_MODE_MONITOR; | ||
1226 | up_write(&ACCESS_FBINFO(altout.lock)); | ||
1227 | md->primary_head = NULL; | ||
1228 | } | ||
1229 | return 0; | ||
1230 | } | ||
1231 | |||
1232 | static unsigned short normal_i2c[] = { MAVEN_I2CID, I2C_CLIENT_END }; | ||
1233 | static unsigned short normal_i2c_range[] = { MAVEN_I2CID, MAVEN_I2CID, I2C_CLIENT_END }; | ||
1234 | I2C_CLIENT_INSMOD; | ||
1235 | |||
1236 | static struct i2c_driver maven_driver; | ||
1237 | |||
1238 | static int maven_detect_client(struct i2c_adapter* adapter, int address, int kind) { | ||
1239 | int err = 0; | ||
1240 | struct i2c_client* new_client; | ||
1241 | struct maven_data* data; | ||
1242 | |||
1243 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WRITE_WORD_DATA | | ||
1244 | I2C_FUNC_SMBUS_BYTE_DATA | | ||
1245 | I2C_FUNC_PROTOCOL_MANGLING)) | ||
1246 | goto ERROR0; | ||
1247 | if (!(new_client = (struct i2c_client*)kmalloc(sizeof(*new_client) + sizeof(*data), | ||
1248 | GFP_KERNEL))) { | ||
1249 | err = -ENOMEM; | ||
1250 | goto ERROR0; | ||
1251 | } | ||
1252 | memset(new_client, 0, sizeof(*new_client) + sizeof(*data)); | ||
1253 | data = (struct maven_data*)(new_client + 1); | ||
1254 | i2c_set_clientdata(new_client, data); | ||
1255 | new_client->addr = address; | ||
1256 | new_client->adapter = adapter; | ||
1257 | new_client->driver = &maven_driver; | ||
1258 | new_client->flags = 0; | ||
1259 | strcpy(new_client->name, "maven client"); | ||
1260 | if ((err = i2c_attach_client(new_client))) | ||
1261 | goto ERROR3; | ||
1262 | err = maven_init_client(new_client); | ||
1263 | if (err) | ||
1264 | goto ERROR4; | ||
1265 | return 0; | ||
1266 | ERROR4:; | ||
1267 | i2c_detach_client(new_client); | ||
1268 | ERROR3:; | ||
1269 | kfree(new_client); | ||
1270 | ERROR0:; | ||
1271 | return err; | ||
1272 | } | ||
1273 | |||
1274 | static int maven_attach_adapter(struct i2c_adapter* adapter) { | ||
1275 | if (adapter->id == (I2C_ALGO_BIT | I2C_HW_B_G400)) | ||
1276 | return i2c_probe(adapter, &addr_data, &maven_detect_client); | ||
1277 | return 0; | ||
1278 | } | ||
1279 | |||
1280 | static int maven_detach_client(struct i2c_client* client) { | ||
1281 | int err; | ||
1282 | |||
1283 | if ((err = i2c_detach_client(client))) { | ||
1284 | printk(KERN_ERR "maven: Cannot deregister client\n"); | ||
1285 | return err; | ||
1286 | } | ||
1287 | maven_shutdown_client(client); | ||
1288 | kfree(client); | ||
1289 | return 0; | ||
1290 | } | ||
1291 | |||
1292 | static int maven_command(struct i2c_client* client, unsigned int cmd, void* arg) { | ||
1293 | return -ENOIOCTLCMD; /* or -EINVAL, depends on who will call this */ | ||
1294 | } | ||
1295 | |||
1296 | static struct i2c_driver maven_driver={ | ||
1297 | .owner = THIS_MODULE, | ||
1298 | .name = "maven", | ||
1299 | .id = I2C_DRIVERID_MGATVO, | ||
1300 | .flags = I2C_DF_NOTIFY, | ||
1301 | .attach_adapter = maven_attach_adapter, | ||
1302 | .detach_client = maven_detach_client, | ||
1303 | .command = maven_command, | ||
1304 | }; | ||
1305 | |||
1306 | /* ************************** */ | ||
1307 | |||
1308 | static int matroxfb_maven_init(void) { | ||
1309 | int err; | ||
1310 | |||
1311 | err = i2c_add_driver(&maven_driver); | ||
1312 | if (err) { | ||
1313 | printk(KERN_ERR "maven: Maven driver failed to register (%d).\n", err); | ||
1314 | return err; | ||
1315 | } | ||
1316 | return 0; | ||
1317 | } | ||
1318 | |||
1319 | static void matroxfb_maven_exit(void) { | ||
1320 | i2c_del_driver(&maven_driver); | ||
1321 | } | ||
1322 | |||
1323 | MODULE_AUTHOR("(c) 1999-2002 Petr Vandrovec <vandrove@vc.cvut.cz>"); | ||
1324 | MODULE_DESCRIPTION("Matrox G200/G400 Matrox MGA-TVO driver"); | ||
1325 | MODULE_LICENSE("GPL"); | ||
1326 | module_init(matroxfb_maven_init); | ||
1327 | module_exit(matroxfb_maven_exit); | ||
1328 | /* we do not have __setup() yet */ | ||