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