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