]> git.proxmox.com Git - mirror_ubuntu-zesty-kernel.git/blame - drivers/video/matrox/matroxfb_base.c
Fix common misspellings
[mirror_ubuntu-zesty-kernel.git] / drivers / video / matrox / matroxfb_base.c
CommitLineData
1da177e4
LT
1/*
2 *
3 * Hardware accelerated Matrox Millennium I, II, Mystique, G100, G200 and G400
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 * MTRR stuff: 1998 Tom Rini <trini@kernel.crashing.org>
12 *
13 * Contributors: "menion?" <menion@mindless.com>
14 * Betatesting, fixes, ideas
15 *
16 * "Kurt Garloff" <garloff@suse.de>
17 * Betatesting, fixes, ideas, videomodes, videomodes timmings
18 *
19 * "Tom Rini" <trini@kernel.crashing.org>
20 * MTRR stuff, PPC cleanups, betatesting, fixes, ideas
21 *
22 * "Bibek Sahu" <scorpio@dodds.net>
23 * Access device through readb|w|l and write b|w|l
24 * Extensive debugging stuff
25 *
26 * "Daniel Haun" <haund@usa.net>
27 * Testing, hardware cursor fixes
28 *
29 * "Scott Wood" <sawst46+@pitt.edu>
30 * Fixes
31 *
32 * "Gerd Knorr" <kraxel@goldbach.isdn.cs.tu-berlin.de>
33 * Betatesting
34 *
35 * "Kelly French" <targon@hazmat.com>
36 * "Fernando Herrera" <fherrera@eurielec.etsit.upm.es>
37 * Betatesting, bug reporting
38 *
39 * "Pablo Bianucci" <pbian@pccp.com.ar>
40 * Fixes, ideas, betatesting
41 *
42 * "Inaky Perez Gonzalez" <inaky@peloncho.fis.ucm.es>
43 * Fixes, enhandcements, ideas, betatesting
44 *
45 * "Ryuichi Oikawa" <roikawa@rr.iiij4u.or.jp>
46 * PPC betatesting, PPC support, backward compatibility
47 *
48 * "Paul Womar" <Paul@pwomar.demon.co.uk>
49 * "Owen Waller" <O.Waller@ee.qub.ac.uk>
50 * PPC betatesting
51 *
52 * "Thomas Pornin" <pornin@bolet.ens.fr>
53 * Alpha betatesting
54 *
55 * "Pieter van Leuven" <pvl@iae.nl>
56 * "Ulf Jaenicke-Roessler" <ujr@physik.phy.tu-dresden.de>
57 * G100 testing
58 *
59 * "H. Peter Arvin" <hpa@transmeta.com>
60 * Ideas
61 *
62 * "Cort Dougan" <cort@cs.nmt.edu>
63 * CHRP fixes and PReP cleanup
64 *
65 * "Mark Vojkovich" <mvojkovi@ucsd.edu>
66 * G400 support
67 *
68 * "Samuel Hocevar" <sam@via.ecp.fr>
69 * Fixes
70 *
71 * "Anton Altaparmakov" <AntonA@bigfoot.com>
72 * G400 MAX/non-MAX distinction
73 *
74 * "Ken Aaker" <kdaaker@rchland.vnet.ibm.com>
75 * memtype extension (needed for GXT130P RS/6000 adapter)
76 *
77 * "Uns Lider" <unslider@miranda.org>
78 * G100 PLNWT fixes
79 *
80 * "Denis Zaitsev" <zzz@cd-club.ru>
81 * Fixes
82 *
83 * "Mike Pieper" <mike@pieper-family.de>
84 * TVOut enhandcements, V4L2 control interface.
85 *
86 * "Diego Biurrun" <diego@biurrun.de>
87 * DFP testing
88 *
89 * (following author is not in any relation with this code, but his code
90 * is included in this driver)
91 *
92 * Based on framebuffer driver for VBE 2.0 compliant graphic boards
93 * (c) 1998 Gerd Knorr <kraxel@cs.tu-berlin.de>
94 *
95 * (following author is not in any relation with this code, but his ideas
beb7dd86 96 * were used when writing this driver)
1da177e4
LT
97 *
98 * FreeVBE/AF (Matrox), "Shawn Hargreaves" <shawn@talula.demon.co.uk>
99 *
100 */
101
1da177e4
LT
102#include <linux/version.h>
103
104#include "matroxfb_base.h"
105#include "matroxfb_misc.h"
106#include "matroxfb_accel.h"
107#include "matroxfb_DAC1064.h"
108#include "matroxfb_Ti3026.h"
109#include "matroxfb_maven.h"
110#include "matroxfb_crtc2.h"
111#include "matroxfb_g450.h"
112#include <linux/matroxfb.h>
113#include <linux/interrupt.h>
5a0e3ad6 114#include <linux/slab.h>
84902b7a 115#include <linux/uaccess.h>
1da177e4
LT
116
117#ifdef CONFIG_PPC_PMAC
e8222502 118#include <asm/machdep.h>
1da177e4
LT
119unsigned char nvram_read_byte(int);
120static int default_vmode = VMODE_NVRAM;
121static int default_cmode = CMODE_NVRAM;
122#endif
123
124static void matroxfb_unregister_device(struct matrox_fb_info* minfo);
125
126/* --------------------------------------------------------------------- */
127
128/*
129 * card parameters
130 */
131
132/* --------------------------------------------------------------------- */
133
134static struct fb_var_screeninfo vesafb_defined = {
135 640,480,640,480,/* W,H, W, H (virtual) load xres,xres_virtual*/
136 0,0, /* virtual -> visible no offset */
137 8, /* depth -> load bits_per_pixel */
138 0, /* greyscale ? */
139 {0,0,0}, /* R */
140 {0,0,0}, /* G */
141 {0,0,0}, /* B */
142 {0,0,0}, /* transparency */
143 0, /* standard pixel format */
144 FB_ACTIVATE_NOW,
145 -1,-1,
146 FB_ACCELF_TEXT, /* accel flags */
147 39721L,48L,16L,33L,10L,
148 96L,2L,~0, /* No sync info */
149 FB_VMODE_NONINTERLACED,
150 0, {0,0,0,0,0}
151};
152
153
154
155/* --------------------------------------------------------------------- */
316b4d64
JD
156static void update_crtc2(struct matrox_fb_info *minfo, unsigned int pos)
157{
fc2d10dd 158 struct matroxfb_dh_fb_info *info = minfo->crtc2.info;
1da177e4
LT
159
160 /* Make sure that displays are compatible */
fc2d10dd
JD
161 if (info && (info->fbcon.var.bits_per_pixel == minfo->fbcon.var.bits_per_pixel)
162 && (info->fbcon.var.xres_virtual == minfo->fbcon.var.xres_virtual)
163 && (info->fbcon.var.green.length == minfo->fbcon.var.green.length)
a50d913f 164 ) {
fc2d10dd 165 switch (minfo->fbcon.var.bits_per_pixel) {
1da177e4
LT
166 case 16:
167 case 32:
168 pos = pos * 8;
169 if (info->interlaced) {
170 mga_outl(0x3C2C, pos);
fc2d10dd 171 mga_outl(0x3C28, pos + minfo->fbcon.var.xres_virtual * minfo->fbcon.var.bits_per_pixel / 8);
1da177e4
LT
172 } else {
173 mga_outl(0x3C28, pos);
174 }
175 break;
176 }
177 }
178}
179
316b4d64
JD
180static void matroxfb_crtc1_panpos(struct matrox_fb_info *minfo)
181{
fc2d10dd 182 if (minfo->crtc1.panpos >= 0) {
1da177e4
LT
183 unsigned long flags;
184 int panpos;
185
186 matroxfb_DAC_lock_irqsave(flags);
fc2d10dd 187 panpos = minfo->crtc1.panpos;
1da177e4
LT
188 if (panpos >= 0) {
189 unsigned int extvga_reg;
190
fc2d10dd 191 minfo->crtc1.panpos = -1; /* No update pending anymore */
1da177e4
LT
192 extvga_reg = mga_inb(M_EXTVGA_INDEX);
193 mga_setr(M_EXTVGA_INDEX, 0x00, panpos);
194 if (extvga_reg != 0x00) {
195 mga_outb(M_EXTVGA_INDEX, extvga_reg);
196 }
197 }
198 matroxfb_DAC_unlock_irqrestore(flags);
199 }
200}
201
7d12e780 202static irqreturn_t matrox_irq(int irq, void *dev_id)
1da177e4
LT
203{
204 u_int32_t status;
205 int handled = 0;
ee5a2749 206 struct matrox_fb_info *minfo = dev_id;
1da177e4
LT
207
208 status = mga_inl(M_STATUS);
209
210 if (status & 0x20) {
211 mga_outl(M_ICLEAR, 0x20);
fc2d10dd 212 minfo->crtc1.vsync.cnt++;
316b4d64 213 matroxfb_crtc1_panpos(minfo);
fc2d10dd 214 wake_up_interruptible(&minfo->crtc1.vsync.wait);
1da177e4
LT
215 handled = 1;
216 }
217 if (status & 0x200) {
218 mga_outl(M_ICLEAR, 0x200);
fc2d10dd
JD
219 minfo->crtc2.vsync.cnt++;
220 wake_up_interruptible(&minfo->crtc2.vsync.wait);
1da177e4
LT
221 handled = 1;
222 }
223 return IRQ_RETVAL(handled);
224}
225
316b4d64
JD
226int matroxfb_enable_irq(struct matrox_fb_info *minfo, int reenable)
227{
1da177e4 228 u_int32_t bm;
a50d913f 229
fc2d10dd 230 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
1da177e4
LT
231 bm = 0x220;
232 else
233 bm = 0x020;
234
fc2d10dd
JD
235 if (!test_and_set_bit(0, &minfo->irq_flags)) {
236 if (request_irq(minfo->pcidev->irq, matrox_irq,
237 IRQF_SHARED, "matroxfb", minfo)) {
238 clear_bit(0, &minfo->irq_flags);
1da177e4
LT
239 return -EINVAL;
240 }
241 /* Clear any pending field interrupts */
242 mga_outl(M_ICLEAR, bm);
243 mga_outl(M_IEN, mga_inl(M_IEN) | bm);
244 } else if (reenable) {
245 u_int32_t ien;
a50d913f 246
1da177e4
LT
247 ien = mga_inl(M_IEN);
248 if ((ien & bm) != bm) {
249 printk(KERN_DEBUG "matroxfb: someone disabled IRQ [%08X]\n", ien);
250 mga_outl(M_IEN, ien | bm);
251 }
252 }
253 return 0;
254}
255
316b4d64
JD
256static void matroxfb_disable_irq(struct matrox_fb_info *minfo)
257{
fc2d10dd 258 if (test_and_clear_bit(0, &minfo->irq_flags)) {
1da177e4 259 /* Flush pending pan-at-vbl request... */
316b4d64 260 matroxfb_crtc1_panpos(minfo);
fc2d10dd 261 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
1da177e4
LT
262 mga_outl(M_IEN, mga_inl(M_IEN) & ~0x220);
263 else
264 mga_outl(M_IEN, mga_inl(M_IEN) & ~0x20);
fc2d10dd 265 free_irq(minfo->pcidev->irq, minfo);
1da177e4
LT
266 }
267}
268
316b4d64
JD
269int matroxfb_wait_for_sync(struct matrox_fb_info *minfo, u_int32_t crtc)
270{
1da177e4
LT
271 struct matrox_vsync *vs;
272 unsigned int cnt;
273 int ret;
274
275 switch (crtc) {
276 case 0:
fc2d10dd 277 vs = &minfo->crtc1.vsync;
1da177e4
LT
278 break;
279 case 1:
fc2d10dd 280 if (minfo->devflags.accelerator != FB_ACCEL_MATROX_MGAG400) {
1da177e4
LT
281 return -ENODEV;
282 }
fc2d10dd 283 vs = &minfo->crtc2.vsync;
1da177e4
LT
284 break;
285 default:
286 return -ENODEV;
287 }
316b4d64 288 ret = matroxfb_enable_irq(minfo, 0);
1da177e4
LT
289 if (ret) {
290 return ret;
291 }
1da177e4
LT
292
293 cnt = vs->cnt;
294 ret = wait_event_interruptible_timeout(vs->wait, cnt != vs->cnt, HZ/10);
295 if (ret < 0) {
296 return ret;
297 }
298 if (ret == 0) {
316b4d64 299 matroxfb_enable_irq(minfo, 1);
1da177e4
LT
300 return -ETIMEDOUT;
301 }
302 return 0;
303}
304
305/* --------------------------------------------------------------------- */
306
316b4d64
JD
307static void matrox_pan_var(struct matrox_fb_info *minfo,
308 struct fb_var_screeninfo *var)
309{
1da177e4
LT
310 unsigned int pos;
311 unsigned short p0, p1, p2;
1da177e4 312 unsigned int p3;
1da177e4
LT
313 int vbl;
314 unsigned long flags;
315
316 CRITFLAGS
317
5ae12170 318 DBG(__func__)
1da177e4 319
fc2d10dd 320 if (minfo->dead)
1da177e4
LT
321 return;
322
fc2d10dd
JD
323 minfo->fbcon.var.xoffset = var->xoffset;
324 minfo->fbcon.var.yoffset = var->yoffset;
325 pos = (minfo->fbcon.var.yoffset * minfo->fbcon.var.xres_virtual + minfo->fbcon.var.xoffset) * minfo->curr.final_bppShift / 32;
326 pos += minfo->curr.ydstorg.chunks;
327 p0 = minfo->hw.CRTC[0x0D] = pos & 0xFF;
328 p1 = minfo->hw.CRTC[0x0C] = (pos & 0xFF00) >> 8;
329 p2 = minfo->hw.CRTCEXT[0] = (minfo->hw.CRTCEXT[0] & 0xB0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
fc2d10dd 330 p3 = minfo->hw.CRTCEXT[8] = pos >> 21;
1da177e4
LT
331
332 /* FB_ACTIVATE_VBL and we can acquire interrupts? Honor FB_ACTIVATE_VBL then... */
316b4d64 333 vbl = (var->activate & FB_ACTIVATE_VBL) && (matroxfb_enable_irq(minfo, 0) == 0);
1da177e4
LT
334
335 CRITBEGIN
336
337 matroxfb_DAC_lock_irqsave(flags);
338 mga_setr(M_CRTC_INDEX, 0x0D, p0);
339 mga_setr(M_CRTC_INDEX, 0x0C, p1);
fc2d10dd 340 if (minfo->devflags.support32MB)
1da177e4 341 mga_setr(M_EXTVGA_INDEX, 0x08, p3);
1da177e4 342 if (vbl) {
fc2d10dd 343 minfo->crtc1.panpos = p2;
1da177e4
LT
344 } else {
345 /* Abort any pending change */
fc2d10dd 346 minfo->crtc1.panpos = -1;
1da177e4
LT
347 mga_setr(M_EXTVGA_INDEX, 0x00, p2);
348 }
349 matroxfb_DAC_unlock_irqrestore(flags);
a50d913f 350
316b4d64 351 update_crtc2(minfo, pos);
1da177e4
LT
352
353 CRITEND
354}
355
316b4d64
JD
356static void matroxfb_remove(struct matrox_fb_info *minfo, int dummy)
357{
1da177e4
LT
358 /* Currently we are holding big kernel lock on all dead & usecount updates.
359 * Destroy everything after all users release it. Especially do not unregister
360 * framebuffer and iounmap memory, neither fbmem nor fbcon-cfb* does not check
361 * for device unplugged when in use.
362 * In future we should point mmio.vbase & video.vbase somewhere where we can
363 * write data without causing too much damage...
364 */
365
fc2d10dd
JD
366 minfo->dead = 1;
367 if (minfo->usecount) {
1da177e4
LT
368 /* destroy it later */
369 return;
370 }
fc2d10dd
JD
371 matroxfb_unregister_device(minfo);
372 unregister_framebuffer(&minfo->fbcon);
316b4d64 373 matroxfb_g450_shutdown(minfo);
1da177e4 374#ifdef CONFIG_MTRR
fc2d10dd
JD
375 if (minfo->mtrr.vram_valid)
376 mtrr_del(minfo->mtrr.vram, minfo->video.base, minfo->video.len);
1da177e4 377#endif
fc2d10dd
JD
378 mga_iounmap(minfo->mmio.vbase);
379 mga_iounmap(minfo->video.vbase);
380 release_mem_region(minfo->video.base, minfo->video.len_maximum);
381 release_mem_region(minfo->mmio.base, 16384);
1da177e4 382 kfree(minfo);
1da177e4
LT
383}
384
385 /*
386 * Open/Release the frame buffer device
387 */
388
389static int matroxfb_open(struct fb_info *info, int user)
390{
ee5a2749 391 struct matrox_fb_info *minfo = info2minfo(info);
a50d913f 392
5ae12170 393 DBG_LOOP(__func__)
1da177e4 394
fc2d10dd 395 if (minfo->dead) {
1da177e4
LT
396 return -ENXIO;
397 }
fc2d10dd 398 minfo->usecount++;
1da177e4 399 if (user) {
fc2d10dd 400 minfo->userusecount++;
1da177e4
LT
401 }
402 return(0);
403}
404
405static int matroxfb_release(struct fb_info *info, int user)
406{
ee5a2749 407 struct matrox_fb_info *minfo = info2minfo(info);
a50d913f 408
5ae12170 409 DBG_LOOP(__func__)
1da177e4
LT
410
411 if (user) {
fc2d10dd 412 if (0 == --minfo->userusecount) {
316b4d64 413 matroxfb_disable_irq(minfo);
1da177e4
LT
414 }
415 }
fc2d10dd 416 if (!(--minfo->usecount) && minfo->dead) {
316b4d64 417 matroxfb_remove(minfo, 0);
1da177e4
LT
418 }
419 return(0);
420}
421
422static int matroxfb_pan_display(struct fb_var_screeninfo *var,
423 struct fb_info* info) {
ee5a2749 424 struct matrox_fb_info *minfo = info2minfo(info);
1da177e4 425
5ae12170 426 DBG(__func__)
1da177e4 427
316b4d64 428 matrox_pan_var(minfo, var);
1da177e4
LT
429 return 0;
430}
431
316b4d64
JD
432static int matroxfb_get_final_bppShift(const struct matrox_fb_info *minfo,
433 int bpp)
434{
1da177e4
LT
435 int bppshft2;
436
5ae12170 437 DBG(__func__)
1da177e4
LT
438
439 bppshft2 = bpp;
440 if (!bppshft2) {
441 return 8;
442 }
fc2d10dd 443 if (isInterleave(minfo))
1da177e4 444 bppshft2 >>= 1;
fc2d10dd 445 if (minfo->devflags.video64bits)
1da177e4
LT
446 bppshft2 >>= 1;
447 return bppshft2;
448}
449
316b4d64
JD
450static int matroxfb_test_and_set_rounding(const struct matrox_fb_info *minfo,
451 int xres, int bpp)
452{
1da177e4
LT
453 int over;
454 int rounding;
455
5ae12170 456 DBG(__func__)
1da177e4
LT
457
458 switch (bpp) {
459 case 0: return xres;
460 case 4: rounding = 128;
461 break;
462 case 8: rounding = 64; /* doc says 64; 32 is OK for G400 */
463 break;
464 case 16: rounding = 32;
465 break;
466 case 24: rounding = 64; /* doc says 64; 32 is OK for G400 */
467 break;
468 default: rounding = 16;
469 /* on G400, 16 really does not work */
fc2d10dd 470 if (minfo->devflags.accelerator == FB_ACCEL_MATROX_MGAG400)
1da177e4
LT
471 rounding = 32;
472 break;
473 }
fc2d10dd 474 if (isInterleave(minfo)) {
1da177e4
LT
475 rounding *= 2;
476 }
477 over = xres % rounding;
478 if (over)
479 xres += rounding-over;
480 return xres;
481}
482
316b4d64
JD
483static int matroxfb_pitch_adjust(const struct matrox_fb_info *minfo, int xres,
484 int bpp)
485{
1da177e4
LT
486 const int* width;
487 int xres_new;
488
5ae12170 489 DBG(__func__)
1da177e4
LT
490
491 if (!bpp) return xres;
492
fc2d10dd 493 width = minfo->capable.vxres;
1da177e4 494
fc2d10dd 495 if (minfo->devflags.precise_width) {
1da177e4 496 while (*width) {
316b4d64 497 if ((*width >= xres) && (matroxfb_test_and_set_rounding(minfo, *width, bpp) == *width)) {
1da177e4
LT
498 break;
499 }
500 width++;
501 }
502 xres_new = *width;
503 } else {
316b4d64 504 xres_new = matroxfb_test_and_set_rounding(minfo, xres, bpp);
1da177e4 505 }
1da177e4
LT
506 return xres_new;
507}
508
509static int matroxfb_get_cmap_len(struct fb_var_screeninfo *var) {
510
5ae12170 511 DBG(__func__)
1da177e4
LT
512
513 switch (var->bits_per_pixel) {
514 case 4:
515 return 16; /* pseudocolor... 16 entries HW palette */
516 case 8:
517 return 256; /* pseudocolor... 256 entries HW palette */
518 case 16:
519 return 16; /* directcolor... 16 entries SW palette */
520 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
521 case 24:
522 return 16; /* directcolor... 16 entries SW palette */
523 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
524 case 32:
525 return 16; /* directcolor... 16 entries SW palette */
526 /* Mystique: truecolor, 16 entries SW palette, HW palette hardwired into 1:1 mapping */
527 }
528 return 16; /* return something reasonable... or panic()? */
529}
530
316b4d64
JD
531static int matroxfb_decode_var(const struct matrox_fb_info *minfo,
532 struct fb_var_screeninfo *var, int *visual,
533 int *video_cmap_len, unsigned int* ydstorg)
534{
1da177e4
LT
535 struct RGBT {
536 unsigned char bpp;
537 struct {
538 unsigned char offset,
539 length;
540 } red,
541 green,
542 blue,
543 transp;
544 signed char visual;
545 };
546 static const struct RGBT table[]= {
547 { 8,{ 0,8},{0,8},{0,8},{ 0,0},MX_VISUAL_PSEUDOCOLOR},
548 {15,{10,5},{5,5},{0,5},{15,1},MX_VISUAL_DIRECTCOLOR},
549 {16,{11,5},{5,6},{0,5},{ 0,0},MX_VISUAL_DIRECTCOLOR},
550 {24,{16,8},{8,8},{0,8},{ 0,0},MX_VISUAL_DIRECTCOLOR},
551 {32,{16,8},{8,8},{0,8},{24,8},MX_VISUAL_DIRECTCOLOR}
552 };
553 struct RGBT const *rgbt;
554 unsigned int bpp = var->bits_per_pixel;
555 unsigned int vramlen;
556 unsigned int memlen;
557
5ae12170 558 DBG(__func__)
1da177e4
LT
559
560 switch (bpp) {
fc2d10dd 561 case 4: if (!minfo->capable.cfb4) return -EINVAL;
1da177e4
LT
562 break;
563 case 8: break;
564 case 16: break;
565 case 24: break;
566 case 32: break;
567 default: return -EINVAL;
568 }
569 *ydstorg = 0;
fc2d10dd 570 vramlen = minfo->video.len_usable;
1da177e4
LT
571 if (var->yres_virtual < var->yres)
572 var->yres_virtual = var->yres;
573 if (var->xres_virtual < var->xres)
574 var->xres_virtual = var->xres;
575
316b4d64 576 var->xres_virtual = matroxfb_pitch_adjust(minfo, var->xres_virtual, bpp);
1da177e4
LT
577 memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
578 if (memlen > vramlen) {
579 var->yres_virtual = vramlen * 8 / (var->xres_virtual * bpp);
580 memlen = var->xres_virtual * bpp * var->yres_virtual / 8;
581 }
582 /* There is hardware bug that no line can cross 4MB boundary */
583 /* give up for CFB24, it is impossible to easy workaround it */
584 /* for other try to do something */
fc2d10dd 585 if (!minfo->capable.cross4MB && (memlen > 0x400000)) {
1da177e4
LT
586 if (bpp == 24) {
587 /* sorry */
588 } else {
589 unsigned int linelen;
590 unsigned int m1 = linelen = var->xres_virtual * bpp / 8;
591 unsigned int m2 = PAGE_SIZE; /* or 128 if you do not need PAGE ALIGNED address */
592 unsigned int max_yres;
593
594 while (m1) {
595 int t;
596
597 while (m2 >= m1) m2 -= m1;
598 t = m1;
599 m1 = m2;
600 m2 = t;
601 }
602 m2 = linelen * PAGE_SIZE / m2;
603 *ydstorg = m2 = 0x400000 % m2;
604 max_yres = (vramlen - m2) / linelen;
605 if (var->yres_virtual > max_yres)
606 var->yres_virtual = max_yres;
607 }
608 }
609 /* YDSTLEN contains only signed 16bit value */
610 if (var->yres_virtual > 32767)
611 var->yres_virtual = 32767;
612 /* we must round yres/xres down, we already rounded y/xres_virtual up
613 if it was possible. We should return -EINVAL, but I disagree */
614 if (var->yres_virtual < var->yres)
615 var->yres = var->yres_virtual;
616 if (var->xres_virtual < var->xres)
617 var->xres = var->xres_virtual;
618 if (var->xoffset + var->xres > var->xres_virtual)
619 var->xoffset = var->xres_virtual - var->xres;
620 if (var->yoffset + var->yres > var->yres_virtual)
621 var->yoffset = var->yres_virtual - var->yres;
622
623 if (bpp == 16 && var->green.length == 5) {
25985edc 624 bpp--; /* an artificial value - 15 */
1da177e4
LT
625 }
626
627 for (rgbt = table; rgbt->bpp < bpp; rgbt++);
628#define SETCLR(clr)\
629 var->clr.offset = rgbt->clr.offset;\
630 var->clr.length = rgbt->clr.length
631 SETCLR(red);
632 SETCLR(green);
633 SETCLR(blue);
634 SETCLR(transp);
635#undef SETCLR
636 *visual = rgbt->visual;
637
638 if (bpp > 8)
639 dprintk("matroxfb: truecolor: "
640 "size=%d:%d:%d:%d, shift=%d:%d:%d:%d\n",
641 var->transp.length, var->red.length, var->green.length, var->blue.length,
642 var->transp.offset, var->red.offset, var->green.offset, var->blue.offset);
643
644 *video_cmap_len = matroxfb_get_cmap_len(var);
645 dprintk(KERN_INFO "requested %d*%d/%dbpp (%d*%d)\n", var->xres, var->yres, var->bits_per_pixel,
646 var->xres_virtual, var->yres_virtual);
647 return 0;
648}
649
650static int matroxfb_setcolreg(unsigned regno, unsigned red, unsigned green,
651 unsigned blue, unsigned transp,
652 struct fb_info *fb_info)
653{
1da177e4 654 struct matrox_fb_info* minfo = container_of(fb_info, struct matrox_fb_info, fbcon);
1da177e4 655
5ae12170 656 DBG(__func__)
1da177e4
LT
657
658 /*
659 * Set a single color register. The values supplied are
660 * already rounded down to the hardware's capabilities
661 * (according to the entries in the `var' structure). Return
662 * != 0 for invalid regno.
663 */
664
fc2d10dd 665 if (regno >= minfo->curr.cmap_len)
1da177e4
LT
666 return 1;
667
fc2d10dd 668 if (minfo->fbcon.var.grayscale) {
1da177e4
LT
669 /* gray = 0.30*R + 0.59*G + 0.11*B */
670 red = green = blue = (red * 77 + green * 151 + blue * 28) >> 8;
671 }
672
fc2d10dd
JD
673 red = CNVT_TOHW(red, minfo->fbcon.var.red.length);
674 green = CNVT_TOHW(green, minfo->fbcon.var.green.length);
675 blue = CNVT_TOHW(blue, minfo->fbcon.var.blue.length);
676 transp = CNVT_TOHW(transp, minfo->fbcon.var.transp.length);
1da177e4 677
fc2d10dd 678 switch (minfo->fbcon.var.bits_per_pixel) {
1da177e4
LT
679 case 4:
680 case 8:
681 mga_outb(M_DAC_REG, regno);
682 mga_outb(M_DAC_VAL, red);
683 mga_outb(M_DAC_VAL, green);
684 mga_outb(M_DAC_VAL, blue);
685 break;
686 case 16:
08a498de
AD
687 if (regno >= 16)
688 break;
1da177e4
LT
689 {
690 u_int16_t col =
fc2d10dd
JD
691 (red << minfo->fbcon.var.red.offset) |
692 (green << minfo->fbcon.var.green.offset) |
693 (blue << minfo->fbcon.var.blue.offset) |
694 (transp << minfo->fbcon.var.transp.offset); /* for 1:5:5:5 */
695 minfo->cmap[regno] = col | (col << 16);
1da177e4
LT
696 }
697 break;
698 case 24:
699 case 32:
08a498de
AD
700 if (regno >= 16)
701 break;
fc2d10dd
JD
702 minfo->cmap[regno] =
703 (red << minfo->fbcon.var.red.offset) |
704 (green << minfo->fbcon.var.green.offset) |
705 (blue << minfo->fbcon.var.blue.offset) |
706 (transp << minfo->fbcon.var.transp.offset); /* 8:8:8:8 */
1da177e4
LT
707 break;
708 }
709 return 0;
710}
711
316b4d64 712static void matroxfb_init_fix(struct matrox_fb_info *minfo)
1da177e4 713{
fc2d10dd 714 struct fb_fix_screeninfo *fix = &minfo->fbcon.fix;
5ae12170 715 DBG(__func__)
1da177e4
LT
716
717 strcpy(fix->id,"MATROX");
718
719 fix->xpanstep = 8; /* 8 for 8bpp, 4 for 16bpp, 2 for 32bpp */
720 fix->ypanstep = 1;
721 fix->ywrapstep = 0;
fc2d10dd
JD
722 fix->mmio_start = minfo->mmio.base;
723 fix->mmio_len = minfo->mmio.len;
724 fix->accel = minfo->devflags.accelerator;
1da177e4
LT
725}
726
316b4d64 727static void matroxfb_update_fix(struct matrox_fb_info *minfo)
1da177e4 728{
fc2d10dd 729 struct fb_fix_screeninfo *fix = &minfo->fbcon.fix;
5ae12170 730 DBG(__func__)
1da177e4 731
fc2d10dd
JD
732 mutex_lock(&minfo->fbcon.mm_lock);
733 fix->smem_start = minfo->video.base + minfo->curr.ydstorg.bytes;
734 fix->smem_len = minfo->video.len_usable - minfo->curr.ydstorg.bytes;
735 mutex_unlock(&minfo->fbcon.mm_lock);
1da177e4
LT
736}
737
738static int matroxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
739{
740 int err;
741 int visual;
742 int cmap_len;
743 unsigned int ydstorg;
ee5a2749 744 struct matrox_fb_info *minfo = info2minfo(info);
1da177e4 745
fc2d10dd 746 if (minfo->dead) {
1da177e4
LT
747 return -ENXIO;
748 }
316b4d64 749 if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0)
1da177e4
LT
750 return err;
751 return 0;
752}
753
754static int matroxfb_set_par(struct fb_info *info)
755{
756 int err;
757 int visual;
758 int cmap_len;
759 unsigned int ydstorg;
760 struct fb_var_screeninfo *var;
ee5a2749 761 struct matrox_fb_info *minfo = info2minfo(info);
1da177e4 762
5ae12170 763 DBG(__func__)
1da177e4 764
fc2d10dd 765 if (minfo->dead) {
1da177e4
LT
766 return -ENXIO;
767 }
768
769 var = &info->var;
316b4d64 770 if ((err = matroxfb_decode_var(minfo, var, &visual, &cmap_len, &ydstorg)) != 0)
1da177e4 771 return err;
fc2d10dd 772 minfo->fbcon.screen_base = vaddr_va(minfo->video.vbase) + ydstorg;
316b4d64 773 matroxfb_update_fix(minfo);
fc2d10dd
JD
774 minfo->fbcon.fix.visual = visual;
775 minfo->fbcon.fix.type = FB_TYPE_PACKED_PIXELS;
776 minfo->fbcon.fix.type_aux = 0;
777 minfo->fbcon.fix.line_length = (var->xres_virtual * var->bits_per_pixel) >> 3;
1da177e4
LT
778 {
779 unsigned int pos;
780
fc2d10dd
JD
781 minfo->curr.cmap_len = cmap_len;
782 ydstorg += minfo->devflags.ydstorg;
783 minfo->curr.ydstorg.bytes = ydstorg;
784 minfo->curr.ydstorg.chunks = ydstorg >> (isInterleave(minfo) ? 3 : 2);
1da177e4 785 if (var->bits_per_pixel == 4)
fc2d10dd 786 minfo->curr.ydstorg.pixels = ydstorg;
1da177e4 787 else
fc2d10dd 788 minfo->curr.ydstorg.pixels = (ydstorg * 8) / var->bits_per_pixel;
316b4d64 789 minfo->curr.final_bppShift = matroxfb_get_final_bppShift(minfo, var->bits_per_pixel);
1da177e4
LT
790 { struct my_timming mt;
791 struct matrox_hw_state* hw;
792 int out;
793
794 matroxfb_var2my(var, &mt);
795 mt.crtc = MATROXFB_SRC_CRTC1;
796 /* CRTC1 delays */
797 switch (var->bits_per_pixel) {
798 case 0: mt.delay = 31 + 0; break;
799 case 16: mt.delay = 21 + 8; break;
800 case 24: mt.delay = 17 + 8; break;
801 case 32: mt.delay = 16 + 8; break;
802 default: mt.delay = 31 + 8; break;
803 }
804
fc2d10dd 805 hw = &minfo->hw;
1da177e4 806
fc2d10dd 807 down_read(&minfo->altout.lock);
1da177e4 808 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
fc2d10dd
JD
809 if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
810 minfo->outputs[out].output->compute) {
811 minfo->outputs[out].output->compute(minfo->outputs[out].data, &mt);
1da177e4
LT
812 }
813 }
fc2d10dd
JD
814 up_read(&minfo->altout.lock);
815 minfo->crtc1.pixclock = mt.pixclock;
816 minfo->crtc1.mnp = mt.mnp;
316b4d64 817 minfo->hw_switch->init(minfo, &mt);
fc2d10dd
JD
818 pos = (var->yoffset * var->xres_virtual + var->xoffset) * minfo->curr.final_bppShift / 32;
819 pos += minfo->curr.ydstorg.chunks;
1da177e4
LT
820
821 hw->CRTC[0x0D] = pos & 0xFF;
822 hw->CRTC[0x0C] = (pos & 0xFF00) >> 8;
823 hw->CRTCEXT[0] = (hw->CRTCEXT[0] & 0xF0) | ((pos >> 16) & 0x0F) | ((pos >> 14) & 0x40);
824 hw->CRTCEXT[8] = pos >> 21;
316b4d64
JD
825 minfo->hw_switch->restore(minfo);
826 update_crtc2(minfo, pos);
fc2d10dd 827 down_read(&minfo->altout.lock);
1da177e4 828 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
fc2d10dd
JD
829 if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
830 minfo->outputs[out].output->program) {
831 minfo->outputs[out].output->program(minfo->outputs[out].data);
1da177e4
LT
832 }
833 }
834 for (out = 0; out < MATROXFB_MAX_OUTPUTS; out++) {
fc2d10dd
JD
835 if (minfo->outputs[out].src == MATROXFB_SRC_CRTC1 &&
836 minfo->outputs[out].output->start) {
837 minfo->outputs[out].output->start(minfo->outputs[out].data);
1da177e4
LT
838 }
839 }
fc2d10dd 840 up_read(&minfo->altout.lock);
316b4d64 841 matrox_cfbX_init(minfo);
1da177e4
LT
842 }
843 }
fc2d10dd 844 minfo->initialized = 1;
1da177e4
LT
845 return 0;
846}
847
316b4d64
JD
848static int matroxfb_get_vblank(struct matrox_fb_info *minfo,
849 struct fb_vblank *vblank)
1da177e4
LT
850{
851 unsigned int sts1;
852
316b4d64 853 matroxfb_enable_irq(minfo, 0);
1da177e4
LT
854 memset(vblank, 0, sizeof(*vblank));
855 vblank->flags = FB_VBLANK_HAVE_VCOUNT | FB_VBLANK_HAVE_VSYNC |
856 FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_HBLANK;
857 sts1 = mga_inb(M_INSTS1);
858 vblank->vcount = mga_inl(M_VCOUNT);
859 /* BTW, on my PIII/450 with G400, reading M_INSTS1
860 byte makes this call about 12% slower (1.70 vs. 2.05 us
861 per ioctl()) */
862 if (sts1 & 1)
863 vblank->flags |= FB_VBLANK_HBLANKING;
864 if (sts1 & 8)
865 vblank->flags |= FB_VBLANK_VSYNCING;
fc2d10dd 866 if (vblank->vcount >= minfo->fbcon.var.yres)
1da177e4 867 vblank->flags |= FB_VBLANK_VBLANKING;
fc2d10dd 868 if (test_bit(0, &minfo->irq_flags)) {
1da177e4 869 vblank->flags |= FB_VBLANK_HAVE_COUNT;
a50d913f 870 /* Only one writer, aligned int value...
1da177e4 871 it should work without lock and without atomic_t */
fc2d10dd 872 vblank->count = minfo->crtc1.vsync.cnt;
1da177e4
LT
873 }
874 return 0;
875}
876
877static struct matrox_altout panellink_output = {
878 .name = "Panellink output",
879};
880
67a6680d
CH
881static int matroxfb_ioctl(struct fb_info *info,
882 unsigned int cmd, unsigned long arg)
1da177e4
LT
883{
884 void __user *argp = (void __user *)arg;
ee5a2749 885 struct matrox_fb_info *minfo = info2minfo(info);
a50d913f 886
5ae12170 887 DBG(__func__)
1da177e4 888
fc2d10dd 889 if (minfo->dead) {
1da177e4
LT
890 return -ENXIO;
891 }
892
893 switch (cmd) {
894 case FBIOGET_VBLANK:
895 {
896 struct fb_vblank vblank;
897 int err;
898
316b4d64 899 err = matroxfb_get_vblank(minfo, &vblank);
1da177e4
LT
900 if (err)
901 return err;
902 if (copy_to_user(argp, &vblank, sizeof(vblank)))
903 return -EFAULT;
904 return 0;
905 }
906 case FBIO_WAITFORVSYNC:
907 {
908 u_int32_t crt;
909
910 if (get_user(crt, (u_int32_t __user *)arg))
911 return -EFAULT;
912
316b4d64 913 return matroxfb_wait_for_sync(minfo, crt);
1da177e4
LT
914 }
915 case MATROXFB_SET_OUTPUT_MODE:
916 {
917 struct matroxioc_output_mode mom;
918 struct matrox_altout *oproc;
919 int val;
920
921 if (copy_from_user(&mom, argp, sizeof(mom)))
922 return -EFAULT;
923 if (mom.output >= MATROXFB_MAX_OUTPUTS)
924 return -ENXIO;
fc2d10dd
JD
925 down_read(&minfo->altout.lock);
926 oproc = minfo->outputs[mom.output].output;
1da177e4
LT
927 if (!oproc) {
928 val = -ENXIO;
929 } else if (!oproc->verifymode) {
930 if (mom.mode == MATROXFB_OUTPUT_MODE_MONITOR) {
931 val = 0;
932 } else {
933 val = -EINVAL;
934 }
935 } else {
fc2d10dd 936 val = oproc->verifymode(minfo->outputs[mom.output].data, mom.mode);
1da177e4
LT
937 }
938 if (!val) {
fc2d10dd
JD
939 if (minfo->outputs[mom.output].mode != mom.mode) {
940 minfo->outputs[mom.output].mode = mom.mode;
1da177e4
LT
941 val = 1;
942 }
943 }
fc2d10dd 944 up_read(&minfo->altout.lock);
1da177e4
LT
945 if (val != 1)
946 return val;
fc2d10dd 947 switch (minfo->outputs[mom.output].src) {
1da177e4
LT
948 case MATROXFB_SRC_CRTC1:
949 matroxfb_set_par(info);
950 break;
951 case MATROXFB_SRC_CRTC2:
952 {
953 struct matroxfb_dh_fb_info* crtc2;
954
fc2d10dd
JD
955 down_read(&minfo->crtc2.lock);
956 crtc2 = minfo->crtc2.info;
1da177e4
LT
957 if (crtc2)
958 crtc2->fbcon.fbops->fb_set_par(&crtc2->fbcon);
fc2d10dd 959 up_read(&minfo->crtc2.lock);
1da177e4
LT
960 }
961 break;
962 }
963 return 0;
964 }
965 case MATROXFB_GET_OUTPUT_MODE:
966 {
967 struct matroxioc_output_mode mom;
968 struct matrox_altout *oproc;
969 int val;
970
971 if (copy_from_user(&mom, argp, sizeof(mom)))
972 return -EFAULT;
973 if (mom.output >= MATROXFB_MAX_OUTPUTS)
974 return -ENXIO;
fc2d10dd
JD
975 down_read(&minfo->altout.lock);
976 oproc = minfo->outputs[mom.output].output;
1da177e4
LT
977 if (!oproc) {
978 val = -ENXIO;
979 } else {
fc2d10dd 980 mom.mode = minfo->outputs[mom.output].mode;
1da177e4
LT
981 val = 0;
982 }
fc2d10dd 983 up_read(&minfo->altout.lock);
1da177e4
LT
984 if (val)
985 return val;
986 if (copy_to_user(argp, &mom, sizeof(mom)))
987 return -EFAULT;
988 return 0;
989 }
990 case MATROXFB_SET_OUTPUT_CONNECTION:
991 {
992 u_int32_t tmp;
993 int i;
994 int changes;
995
996 if (copy_from_user(&tmp, argp, sizeof(tmp)))
997 return -EFAULT;
998 for (i = 0; i < 32; i++) {
999 if (tmp & (1 << i)) {
1000 if (i >= MATROXFB_MAX_OUTPUTS)
1001 return -ENXIO;
fc2d10dd 1002 if (!minfo->outputs[i].output)
1da177e4 1003 return -ENXIO;
fc2d10dd 1004 switch (minfo->outputs[i].src) {
1da177e4
LT
1005 case MATROXFB_SRC_NONE:
1006 case MATROXFB_SRC_CRTC1:
1007 break;
1008 default:
1009 return -EBUSY;
1010 }
1011 }
1012 }
fc2d10dd 1013 if (minfo->devflags.panellink) {
1da177e4
LT
1014 if (tmp & MATROXFB_OUTPUT_CONN_DFP) {
1015 if (tmp & MATROXFB_OUTPUT_CONN_SECONDARY)
1016 return -EINVAL;
1017 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
fc2d10dd 1018 if (minfo->outputs[i].src == MATROXFB_SRC_CRTC2) {
1da177e4
LT
1019 return -EBUSY;
1020 }
1021 }
1022 }
1023 }
1024 changes = 0;
1025 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
1026 if (tmp & (1 << i)) {
fc2d10dd 1027 if (minfo->outputs[i].src != MATROXFB_SRC_CRTC1) {
1da177e4 1028 changes = 1;
fc2d10dd 1029 minfo->outputs[i].src = MATROXFB_SRC_CRTC1;
1da177e4 1030 }
fc2d10dd 1031 } else if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
1da177e4 1032 changes = 1;
fc2d10dd 1033 minfo->outputs[i].src = MATROXFB_SRC_NONE;
1da177e4
LT
1034 }
1035 }
1036 if (!changes)
1037 return 0;
1038 matroxfb_set_par(info);
1039 return 0;
1040 }
1041 case MATROXFB_GET_OUTPUT_CONNECTION:
1042 {
1043 u_int32_t conn = 0;
1044 int i;
1045
1046 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
fc2d10dd 1047 if (minfo->outputs[i].src == MATROXFB_SRC_CRTC1) {
1da177e4
LT
1048 conn |= 1 << i;
1049 }
1050 }
1051 if (put_user(conn, (u_int32_t __user *)arg))
1052 return -EFAULT;
1053 return 0;
1054 }
1055 case MATROXFB_GET_AVAILABLE_OUTPUTS:
1056 {
1057 u_int32_t conn = 0;
1058 int i;
1059
1060 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
fc2d10dd
JD
1061 if (minfo->outputs[i].output) {
1062 switch (minfo->outputs[i].src) {
1da177e4
LT
1063 case MATROXFB_SRC_NONE:
1064 case MATROXFB_SRC_CRTC1:
1065 conn |= 1 << i;
1066 break;
1067 }
1068 }
1069 }
fc2d10dd 1070 if (minfo->devflags.panellink) {
1da177e4
LT
1071 if (conn & MATROXFB_OUTPUT_CONN_DFP)
1072 conn &= ~MATROXFB_OUTPUT_CONN_SECONDARY;
1073 if (conn & MATROXFB_OUTPUT_CONN_SECONDARY)
1074 conn &= ~MATROXFB_OUTPUT_CONN_DFP;
1075 }
1076 if (put_user(conn, (u_int32_t __user *)arg))
1077 return -EFAULT;
1078 return 0;
1079 }
1080 case MATROXFB_GET_ALL_OUTPUTS:
1081 {
1082 u_int32_t conn = 0;
1083 int i;
1084
1085 for (i = 0; i < MATROXFB_MAX_OUTPUTS; i++) {
fc2d10dd 1086 if (minfo->outputs[i].output) {
1da177e4
LT
1087 conn |= 1 << i;
1088 }
1089 }
1090 if (put_user(conn, (u_int32_t __user *)arg))
1091 return -EFAULT;
1092 return 0;
1093 }
1094 case VIDIOC_QUERYCAP:
1095 {
1096 struct v4l2_capability r;
a50d913f 1097
1da177e4
LT
1098 memset(&r, 0, sizeof(r));
1099 strcpy(r.driver, "matroxfb");
1100 strcpy(r.card, "Matrox");
fc2d10dd 1101 sprintf(r.bus_info, "PCI:%s", pci_name(minfo->pcidev));
1da177e4
LT
1102 r.version = KERNEL_VERSION(1,0,0);
1103 r.capabilities = V4L2_CAP_VIDEO_OUTPUT;
1104 if (copy_to_user(argp, &r, sizeof(r)))
1105 return -EFAULT;
1106 return 0;
a50d913f 1107
1da177e4
LT
1108 }
1109 case VIDIOC_QUERYCTRL:
1110 {
1111 struct v4l2_queryctrl qctrl;
1112 int err;
1113
1114 if (copy_from_user(&qctrl, argp, sizeof(qctrl)))
1115 return -EFAULT;
1116
fc2d10dd
JD
1117 down_read(&minfo->altout.lock);
1118 if (!minfo->outputs[1].output) {
1da177e4 1119 err = -ENXIO;
fc2d10dd
JD
1120 } else if (minfo->outputs[1].output->getqueryctrl) {
1121 err = minfo->outputs[1].output->getqueryctrl(minfo->outputs[1].data, &qctrl);
1da177e4
LT
1122 } else {
1123 err = -EINVAL;
1124 }
fc2d10dd 1125 up_read(&minfo->altout.lock);
1da177e4
LT
1126 if (err >= 0 &&
1127 copy_to_user(argp, &qctrl, sizeof(qctrl)))
1128 return -EFAULT;
1129 return err;
1130 }
1131 case VIDIOC_G_CTRL:
1132 {
1133 struct v4l2_control ctrl;
1134 int err;
1135
1136 if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
1137 return -EFAULT;
1138
fc2d10dd
JD
1139 down_read(&minfo->altout.lock);
1140 if (!minfo->outputs[1].output) {
1da177e4 1141 err = -ENXIO;
fc2d10dd
JD
1142 } else if (minfo->outputs[1].output->getctrl) {
1143 err = minfo->outputs[1].output->getctrl(minfo->outputs[1].data, &ctrl);
1da177e4
LT
1144 } else {
1145 err = -EINVAL;
1146 }
fc2d10dd 1147 up_read(&minfo->altout.lock);
1da177e4
LT
1148 if (err >= 0 &&
1149 copy_to_user(argp, &ctrl, sizeof(ctrl)))
1150 return -EFAULT;
1151 return err;
1152 }
1da177e4
LT
1153 case VIDIOC_S_CTRL:
1154 {
1155 struct v4l2_control ctrl;
1156 int err;
1157
1158 if (copy_from_user(&ctrl, argp, sizeof(ctrl)))
1159 return -EFAULT;
1160
fc2d10dd
JD
1161 down_read(&minfo->altout.lock);
1162 if (!minfo->outputs[1].output) {
1da177e4 1163 err = -ENXIO;
fc2d10dd
JD
1164 } else if (minfo->outputs[1].output->setctrl) {
1165 err = minfo->outputs[1].output->setctrl(minfo->outputs[1].data, &ctrl);
1da177e4
LT
1166 } else {
1167 err = -EINVAL;
1168 }
fc2d10dd 1169 up_read(&minfo->altout.lock);
1da177e4
LT
1170 return err;
1171 }
1172 }
1173 return -ENOTTY;
1174}
1175
1176/* 0 unblank, 1 blank, 2 no vsync, 3 no hsync, 4 off */
1177
1178static int matroxfb_blank(int blank, struct fb_info *info)
1179{
1180 int seq;
1181 int crtc;
1182 CRITFLAGS
ee5a2749 1183 struct matrox_fb_info *minfo = info2minfo(info);
1da177e4 1184
5ae12170 1185 DBG(__func__)
1da177e4 1186
fc2d10dd 1187 if (minfo->dead)
1da177e4
LT
1188 return 1;
1189
1190 switch (blank) {
1191 case FB_BLANK_NORMAL: seq = 0x20; crtc = 0x00; break; /* works ??? */
1192 case FB_BLANK_VSYNC_SUSPEND: seq = 0x20; crtc = 0x10; break;
1193 case FB_BLANK_HSYNC_SUSPEND: seq = 0x20; crtc = 0x20; break;
1194 case FB_BLANK_POWERDOWN: seq = 0x20; crtc = 0x30; break;
1195 default: seq = 0x00; crtc = 0x00; break;
1196 }
1197
1198 CRITBEGIN
1199
1200 mga_outb(M_SEQ_INDEX, 1);
1201 mga_outb(M_SEQ_DATA, (mga_inb(M_SEQ_DATA) & ~0x20) | seq);
1202 mga_outb(M_EXTVGA_INDEX, 1);
1203 mga_outb(M_EXTVGA_DATA, (mga_inb(M_EXTVGA_DATA) & ~0x30) | crtc);
1204
1205 CRITEND
1206 return 0;
1207}
1208
1209static struct fb_ops matroxfb_ops = {
1210 .owner = THIS_MODULE,
1211 .fb_open = matroxfb_open,
1212 .fb_release = matroxfb_release,
1213 .fb_check_var = matroxfb_check_var,
1214 .fb_set_par = matroxfb_set_par,
1215 .fb_setcolreg = matroxfb_setcolreg,
1216 .fb_pan_display =matroxfb_pan_display,
1217 .fb_blank = matroxfb_blank,
1218 .fb_ioctl = matroxfb_ioctl,
1219/* .fb_fillrect = <set by matrox_cfbX_init>, */
1220/* .fb_copyarea = <set by matrox_cfbX_init>, */
1221/* .fb_imageblit = <set by matrox_cfbX_init>, */
1222/* .fb_cursor = <set by matrox_cfbX_init>, */
1223};
1224
1225#define RSDepth(X) (((X) >> 8) & 0x0F)
1226#define RS8bpp 0x1
1227#define RS15bpp 0x2
1228#define RS16bpp 0x3
1229#define RS32bpp 0x4
1230#define RS4bpp 0x5
1231#define RS24bpp 0x6
1232#define RSText 0x7
1233#define RSText8 0x8
1234/* 9-F */
1235static struct { struct fb_bitfield red, green, blue, transp; int bits_per_pixel; } colors[] = {
1236 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 8 },
1237 { { 10, 5, 0}, { 5, 5, 0}, { 0, 5, 0}, { 15, 1, 0}, 16 },
1238 { { 11, 5, 0}, { 5, 6, 0}, { 0, 5, 0}, { 0, 0, 0}, 16 },
1239 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 24, 8, 0}, 32 },
1240 { { 0, 8, 0}, { 0, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 4 },
1241 { { 16, 8, 0}, { 8, 8, 0}, { 0, 8, 0}, { 0, 0, 0}, 24 },
1242 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode with (default) VGA8x16 */
1243 { { 0, 6, 0}, { 0, 6, 0}, { 0, 6, 0}, { 0, 0, 0}, 0 }, /* textmode hardwired to VGA8x8 */
1244};
1245
1246/* initialized by setup, see explanation at end of file (search for MODULE_PARM_DESC) */
90a48151 1247static unsigned int mem; /* "matroxfb:mem:xxxxxM" */
1da177e4 1248static int option_precise_width = 1; /* cannot be changed, option_precise_width==0 must imply noaccel */
90a48151
VJ
1249static int inv24; /* "matroxfb:inv24" */
1250static int cross4MB = -1; /* "matroxfb:cross4MB" */
1251static int disabled; /* "matroxfb:disabled" */
1252static int noaccel; /* "matroxfb:noaccel" */
1253static int nopan; /* "matroxfb:nopan" */
1254static int no_pci_retry; /* "matroxfb:nopciretry" */
1255static int novga; /* "matroxfb:novga" */
1256static int nobios; /* "matroxfb:nobios" */
1257static int noinit = 1; /* "matroxfb:init" */
1258static int inverse; /* "matroxfb:inverse" */
1259static int sgram; /* "matroxfb:sgram" */
1da177e4 1260#ifdef CONFIG_MTRR
90a48151 1261static int mtrr = 1; /* "matroxfb:nomtrr" */
1da177e4 1262#endif
90a48151
VJ
1263static int grayscale; /* "matroxfb:grayscale" */
1264static int dev = -1; /* "matroxfb:dev:xxxxx" */
1265static unsigned int vesa = ~0; /* "matroxfb:vesa:xxxxx" */
1266static int depth = -1; /* "matroxfb:depth:xxxxx" */
1267static unsigned int xres; /* "matroxfb:xres:xxxxx" */
1268static unsigned int yres; /* "matroxfb:yres:xxxxx" */
1269static unsigned int upper = ~0; /* "matroxfb:upper:xxxxx" */
1270static unsigned int lower = ~0; /* "matroxfb:lower:xxxxx" */
1271static unsigned int vslen; /* "matroxfb:vslen:xxxxx" */
1272static unsigned int left = ~0; /* "matroxfb:left:xxxxx" */
1273static unsigned int right = ~0; /* "matroxfb:right:xxxxx" */
1274static unsigned int hslen; /* "matroxfb:hslen:xxxxx" */
1275static unsigned int pixclock; /* "matroxfb:pixclock:xxxxx" */
1276static int sync = -1; /* "matroxfb:sync:xxxxx" */
1277static unsigned int fv; /* "matroxfb:fv:xxxxx" */
1278static unsigned int fh; /* "matroxfb:fh:xxxxxk" */
1279static unsigned int maxclk; /* "matroxfb:maxclk:xxxxM" */
1280static int dfp; /* "matroxfb:dfp */
1281static int dfp_type = -1; /* "matroxfb:dfp:xxx */
1282static int memtype = -1; /* "matroxfb:memtype:xxx" */
1283static char outputs[8]; /* "matroxfb:outputs:xxx" */
1da177e4
LT
1284
1285#ifndef MODULE
90a48151 1286static char videomode[64]; /* "matroxfb:mode:xxxxx" or "matroxfb:xxxxx" */
1da177e4
LT
1287#endif
1288
316b4d64
JD
1289static int matroxfb_getmemory(struct matrox_fb_info *minfo,
1290 unsigned int maxSize, unsigned int *realSize)
1291{
1da177e4
LT
1292 vaddr_t vm;
1293 unsigned int offs;
1294 unsigned int offs2;