1 #include "matroxfb_maven.h"
2 #include "matroxfb_crtc2.h"
3 #include "matroxfb_misc.h"
4 #include "matroxfb_DAC1064.h"
5 #include <linux/matroxfb.h>
6 #include <asm/uaccess.h>
8 /* **************************************************** */
10 static int mem
= 8192;
12 MODULE_PARM(mem
, "i");
13 MODULE_PARM_DESC(mem
, "Memory size reserved for dualhead (default=8MB)");
15 /* **************************************************** */
17 static int matroxfb_dh_getcolreg(unsigned regno
, unsigned *red
, unsigned *green
,
18 unsigned *blue
, unsigned *transp
, struct fb_info
* info
) {
19 #define m2info ((struct matroxfb_dh_fb_info*)info)
22 *red
= m2info
->palette
[regno
].red
;
23 *blue
= m2info
->palette
[regno
].blue
;
24 *green
= m2info
->palette
[regno
].green
;
25 *transp
= m2info
->palette
[regno
].transp
;
30 static int matroxfb_dh_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
31 unsigned blue
, unsigned transp
, struct fb_info
* info
) {
32 #define m2info ((struct matroxfb_dh_fb_info*)info)
37 m2info
->palette
[regno
].red
= red
;
38 m2info
->palette
[regno
].blue
= blue
;
39 m2info
->palette
[regno
].green
= green
;
40 m2info
->palette
[regno
].transp
= transp
;
41 p
= m2info
->currcon_display
;
42 if (p
->var
.grayscale
) {
43 /* gray = 0.30*R + 0.59*G + 0.11*B */
44 red
= green
= blue
= (red
* 77 + green
* 151 + blue
* 28) >> 8;
46 red
= CNVT_TOHW(red
, p
->var
.red
.length
);
47 green
= CNVT_TOHW(green
, p
->var
.green
.length
);
48 blue
= CNVT_TOHW(blue
, p
->var
.blue
.length
);
49 transp
= CNVT_TOHW(transp
, p
->var
.transp
.length
);
51 switch (p
->var
.bits_per_pixel
) {
52 #ifdef FBCON_HAS_CFB16
54 m2info
->cmap
.cfb16
[regno
] =
55 (red
<< p
->var
.red
.offset
) |
56 (green
<< p
->var
.green
.offset
) |
57 (blue
<< p
->var
.blue
.offset
) |
58 (transp
<< p
->var
.transp
.offset
);
61 #ifdef FBCON_HAS_CFB32
63 m2info
->cmap
.cfb32
[regno
] =
64 (red
<< p
->var
.red
.offset
) |
65 (green
<< p
->var
.green
.offset
) |
66 (blue
<< p
->var
.blue
.offset
) |
67 (transp
<< p
->var
.transp
.offset
);
75 static void do_install_cmap(struct matroxfb_dh_fb_info
* m2info
, struct display
* p
) {
77 fb_set_cmap(&p
->cmap
, 1, matroxfb_dh_setcolreg
, &m2info
->fbcon
);
79 fb_set_cmap(fb_default_cmap(16), 1, matroxfb_dh_setcolreg
, &m2info
->fbcon
);
82 static void matroxfb_dh_restore(struct matroxfb_dh_fb_info
* m2info
,
83 struct my_timming
* mt
,
88 MINFO_FROM(m2info
->primary_dev
);
103 if (ACCESS_FBINFO(output
.sh
)) {
104 tmp
|= 0x00000001; /* enable CRTC2 */
106 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_SECONDARY
) {
107 tmp
|= 0x00000002; /* source from VDOCLK */
108 tmp
|= 0xC0000000; /* enable vvidrst & hvidrst */
109 /* MGA TVO is our clock source */
110 } else if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_PRIMARY
) {
111 tmp
|= 0x00000004; /* source from pixclock */
112 /* PIXPLL is our clock source */
115 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_PRIMARY
)
116 tmp
|= 0x00100000; /* connect CRTC2 to DAC */
118 mga_outl(0x3C10, tmp
| 0x10000000); /* depth and so on... 0x10000000 is VIDRST polarity */
119 mga_outl(0x3C14, ((mt
->HDisplay
- 8) << 16) | (mt
->HTotal
- 8));
120 mga_outl(0x3C18, ((mt
->HSyncEnd
- 8) << 16) | (mt
->HSyncStart
- 8));
121 mga_outl(0x3C1C, ((mt
->VDisplay
- 1) << 16) | (mt
->VTotal
- 1));
122 mga_outl(0x3C20, ((mt
->VSyncEnd
- 1) << 16) | (mt
->VSyncStart
- 1));
123 mga_outl(0x3C24, ((mt
->VSyncStart
) << 16) | (mt
->HSyncStart
)); /* preload */
124 mga_outl(0x3C28, pos
); /* vmemory start */
125 mga_outl(0x3C40, p
->var
.xres_virtual
* (p
->var
.bits_per_pixel
>> 3));
126 tmp
= 0x0FFF0000; /* line compare */
127 if (mt
->sync
& FB_SYNC_HOR_HIGH_ACT
)
129 if (mt
->sync
& FB_SYNC_VERT_HIGH_ACT
)
131 mga_outl(0x3C44, tmp
);
132 mga_outl(0x3C4C, 0); /* data control */
135 static void matroxfb_dh_cfbX_init(struct matroxfb_dh_fb_info
* m2info
,
137 /* no acceleration for secondary head... */
140 static void matroxfb_dh_pan_var(struct matroxfb_dh_fb_info
* m2info
,
141 struct fb_var_screeninfo
* var
) {
144 #define minfo (m2info->primary_dev)
145 pos
= (var
->yoffset
* var
->xres_virtual
+ var
->xoffset
) * var
->bits_per_pixel
>> 3;
146 pos
+= m2info
->video
.offbase
;
147 mga_outl(0x3C28, pos
);
151 static int matroxfb_dh_decode_var(struct matroxfb_dh_fb_info
* m2info
,
153 struct fb_var_screeninfo
* var
,
159 unsigned int vramlen
;
161 switch (var
->bits_per_pixel
) {
162 #ifdef FBCON_HAS_CFB16
163 case 16: mask
= 0x1F;
166 #ifdef FBCON_HAS_CFB32
167 case 32: mask
= 0x0F;
170 default: return -EINVAL
;
172 vramlen
= m2info
->video
.len_usable
;
173 if (var
->yres_virtual
< var
->yres
)
174 var
->yres_virtual
= var
->yres
;
175 if (var
->xres_virtual
< var
->xres
)
176 var
->xres_virtual
= var
->xres
;
177 var
->xres_virtual
= (var
->xres_virtual
+ mask
) & ~mask
;
178 if (var
->yres_virtual
> 32767)
180 memlen
= var
->xres_virtual
* var
->yres_virtual
* (var
->bits_per_pixel
>> 3);
181 if (memlen
> vramlen
)
183 if (var
->xoffset
+ var
->xres
> var
->xres_virtual
)
184 var
->xoffset
= var
->xres_virtual
- var
->xres
;
185 if (var
->yoffset
+ var
->yres
> var
->yres_virtual
)
186 var
->yoffset
= var
->yres_virtual
- var
->yres
;
189 var
->left_margin
&= ~7;
190 var
->right_margin
&= ~7;
191 var
->hsync_len
&= ~7;
193 *mode
= var
->bits_per_pixel
;
194 if (var
->bits_per_pixel
== 16) {
195 if (var
->green
.length
== 5) {
196 var
->red
.offset
= 10;
198 var
->green
.offset
= 5;
199 var
->green
.length
= 5;
200 var
->blue
.offset
= 0;
201 var
->blue
.length
= 5;
202 var
->transp
.offset
= 15;
203 var
->transp
.length
= 1;
206 var
->red
.offset
= 11;
208 var
->green
.offset
= 5;
209 var
->green
.length
= 6;
210 var
->blue
.offset
= 0;
211 var
->blue
.length
= 5;
212 var
->transp
.offset
= 0;
213 var
->transp
.length
= 0;
216 var
->red
.offset
= 16;
218 var
->green
.offset
= 8;
219 var
->green
.length
= 8;
220 var
->blue
.offset
= 0;
221 var
->blue
.length
= 8;
222 var
->transp
.offset
= 24;
223 var
->transp
.length
= 8;
225 *visual
= FB_VISUAL_TRUECOLOR
;
226 *video_cmap_len
= 16;
230 static void initMatroxDH(struct matroxfb_dh_fb_info
* m2info
, struct display
* p
) {
231 switch (p
->var
.bits_per_pixel
) {
232 #ifdef FBCON_HAS_CFB16
234 p
->dispsw_data
= m2info
->cmap
.cfb16
;
235 p
->dispsw
= &fbcon_cfb16
;
238 #ifdef FBCON_HAS_CFB32
240 p
->dispsw_data
= m2info
->cmap
.cfb32
;
241 p
->dispsw
= &fbcon_cfb32
;
245 p
->dispsw_data
= NULL
;
246 p
->dispsw
= &fbcon_dummy
;
251 static int matroxfb_dh_open(struct fb_info
* info
, int user
) {
252 #define m2info ((struct matroxfb_dh_fb_info*)info)
253 MINFO_FROM(m2info
->primary_dev
);
256 if (ACCESS_FBINFO(dead
)) {
264 static int matroxfb_dh_release(struct fb_info
* info
, int user
) {
265 #define m2info ((struct matroxfb_dh_fb_info*)info)
266 MINFO_FROM(m2info
->primary_dev
);
274 static int matroxfb_dh_get_fix(struct fb_fix_screeninfo
* fix
, int con
,
275 struct fb_info
* info
) {
276 #define m2info ((struct matroxfb_dh_fb_info*)info)
280 p
= fb_display
+ con
;
282 p
= m2info
->fbcon
.disp
;
284 memset(fix
, 0, sizeof(*fix
));
285 strcpy(fix
->id
, "MATROX DH");
287 fix
->smem_start
= m2info
->video
.base
;
288 fix
->smem_len
= m2info
->video
.len_usable
;
290 fix
->type_aux
= p
->type_aux
;
291 fix
->visual
= p
->visual
;
292 fix
->xpanstep
= 8; /* TBD */
295 fix
->line_length
= p
->line_length
;
296 fix
->mmio_start
= m2info
->mmio
.base
;
297 fix
->mmio_len
= m2info
->mmio
.len
;
298 fix
->accel
= 0; /* no accel... */
303 static int matroxfb_dh_get_var(struct fb_var_screeninfo
* var
, int con
,
304 struct fb_info
* info
) {
305 #define m2info ((struct matroxfb_dh_fb_info*)info)
307 *var
= m2info
->fbcon
.disp
->var
;
309 *var
= fb_display
[con
].var
;
314 static int matroxfb_dh_set_var(struct fb_var_screeninfo
* var
, int con
,
315 struct fb_info
* info
) {
316 #define m2info ((struct matroxfb_dh_fb_info*)info)
323 MINFO_FROM(m2info
->primary_dev
);
326 p
= m2info
->fbcon
.disp
;
328 p
= fb_display
+ con
;
329 if ((err
= matroxfb_dh_decode_var(m2info
, p
, var
, &visual
, &cmap_len
, &mode
)) != 0)
331 switch (var
->activate
& FB_ACTIVATE_MASK
) {
332 case FB_ACTIVATE_TEST
: return 0;
333 case FB_ACTIVATE_NXTOPEN
:
334 case FB_ACTIVATE_NOW
: break;
335 default: return -EINVAL
;
338 chgvar
= (p
->var
.xres
!= var
->xres
) ||
339 (p
->var
.yres
!= var
->yres
) ||
340 (p
->var
.xres_virtual
!= var
->xres_virtual
) ||
341 (p
->var
.yres_virtual
!= var
->yres_virtual
) ||
342 (p
->var
.bits_per_pixel
!= var
->bits_per_pixel
) ||
343 memcmp(&p
->var
.red
, &var
->red
, sizeof(var
->red
)) ||
344 memcmp(&p
->var
.green
, &var
->green
, sizeof(var
->green
)) ||
345 memcmp(&p
->var
.blue
, &var
->blue
, sizeof(var
->blue
));
350 p
->screen_base
= vaddr_va(m2info
->video
.vbase
);
354 p
->type
= FB_TYPE_PACKED_PIXELS
;
356 p
->next_line
= p
->line_length
= (var
->xres_virtual
* var
->bits_per_pixel
) >> 3;
357 p
->can_soft_blank
= 0;
358 p
->inverse
= 0; /* TBD */
359 initMatroxDH(m2info
, p
);
360 if (chgvar
&& info
&& info
->changevar
)
361 info
->changevar(con
);
362 if (con
== m2info
->currcon
) {
363 struct my_timming mt
;
364 struct matrox_hw_state
* hw
;
365 struct matrox_hw_state
* ohw
;
368 matroxfb_var2my(var
, &mt
);
372 hw
= ACCESS_FBINFO(newhw
);
373 ohw
= ACCESS_FBINFO(currenthw
);
375 /* copy last setting... */
376 memcpy(hw
, ohw
, sizeof(*hw
));
378 pos
= (var
->yoffset
* var
->xres_virtual
+ var
->xoffset
) * var
->bits_per_pixel
>> 3;
379 pos
+= m2info
->video
.offbase
;
380 DAC1064_global_init(PMINFO hw
);
381 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_PRIMARY
) {
382 if (ACCESS_FBINFO(primout
))
383 ACCESS_FBINFO(primout
)->compute(MINFO
, &mt
, hw
);
385 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_SECONDARY
) {
386 down_read(&ACCESS_FBINFO(altout
.lock
));
387 if (ACCESS_FBINFO(altout
.output
))
388 ACCESS_FBINFO(altout
.output
)->compute(ACCESS_FBINFO(altout
.device
), &mt
, hw
);
389 up_read(&ACCESS_FBINFO(altout
.lock
));
391 matroxfb_dh_restore(m2info
, &mt
, p
, mode
, pos
);
392 DAC1064_global_restore(PMINFO hw
);
393 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_PRIMARY
) {
394 if (ACCESS_FBINFO(primout
))
395 ACCESS_FBINFO(primout
)->program(MINFO
, hw
);
397 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_SECONDARY
) {
398 down_read(&ACCESS_FBINFO(altout
.lock
));
399 if (ACCESS_FBINFO(altout
.output
))
400 ACCESS_FBINFO(altout
.output
)->program(ACCESS_FBINFO(altout
.device
), hw
);
401 up_read(&ACCESS_FBINFO(altout
.lock
));
403 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_PRIMARY
) {
404 if (ACCESS_FBINFO(primout
))
405 ACCESS_FBINFO(primout
)->start(MINFO
);
407 if (ACCESS_FBINFO(output
.sh
) & MATROXFB_OUTPUT_CONN_SECONDARY
) {
408 down_read(&ACCESS_FBINFO(altout
.lock
));
409 if (ACCESS_FBINFO(altout
.output
))
410 ACCESS_FBINFO(altout
.output
)->start(ACCESS_FBINFO(altout
.device
));
411 up_read(&ACCESS_FBINFO(altout
.lock
));
413 matroxfb_dh_cfbX_init(m2info
, p
);
414 do_install_cmap(m2info
, p
);
420 static int matroxfb_dh_get_cmap(struct fb_cmap
* cmap
, int kspc
, int con
,
421 struct fb_info
* info
) {
422 #define m2info ((struct matroxfb_dh_fb_info*)info)
426 dsp
= m2info
->fbcon
.disp
;
428 dsp
= fb_display
+ con
;
429 if (con
== m2info
->currcon
)
430 return fb_get_cmap(cmap
, kspc
, matroxfb_dh_getcolreg
, info
);
431 else if (dsp
->cmap
.len
)
432 fb_copy_cmap(&dsp
->cmap
, cmap
, kspc
? 0 : 2);
434 fb_copy_cmap(fb_default_cmap(16), cmap
, kspc
? 0 : 2);
439 static int matroxfb_dh_set_cmap(struct fb_cmap
* cmap
, int kspc
, int con
,
440 struct fb_info
* info
) {
441 #define m2info ((struct matroxfb_dh_fb_info*)info)
445 dsp
= m2info
->fbcon
.disp
;
447 dsp
= fb_display
+ con
;
448 if (dsp
->cmap
.len
!= 16) {
451 err
= fb_alloc_cmap(&dsp
->cmap
, 16, 0);
455 if (con
== m2info
->currcon
)
456 return fb_set_cmap(cmap
, kspc
, matroxfb_dh_setcolreg
, info
);
458 fb_copy_cmap(cmap
, &dsp
->cmap
, kspc
? 0 : 1);
463 static int matroxfb_dh_pan_display(struct fb_var_screeninfo
* var
, int con
,
464 struct fb_info
* info
) {
465 #define m2info ((struct matroxfb_dh_fb_info*)info)
466 if (var
->xoffset
+ fb_display
[con
].var
.xres
> fb_display
[con
].var
.xres_virtual
||
467 var
->yoffset
+ fb_display
[con
].var
.yres
> fb_display
[con
].var
.yres_virtual
)
469 if (con
== m2info
->currcon
)
470 matroxfb_dh_pan_var(m2info
, var
);
471 fb_display
[con
].var
.xoffset
= var
->xoffset
;
472 fb_display
[con
].var
.yoffset
= var
->yoffset
;
477 static int matroxfb_dh_switch(int con
, struct fb_info
* info
);
479 static int matroxfb_dh_get_vblank(const struct matroxfb_dh_fb_info
* m2info
, struct fb_vblank
* vblank
) {
480 MINFO_FROM(m2info
->primary_dev
);
482 memset(vblank
, 0, sizeof(*vblank
));
483 vblank
->flags
= FB_VBLANK_HAVE_VCOUNT
| FB_VBLANK_HAVE_VBLANK
;
484 /* mask out reserved bits + field number (odd/even) */
485 vblank
->vcount
= mga_inl(0x3C48) & 0x000007FF;
486 /* compatibility stuff */
487 if (vblank
->vcount
>= m2info
->currcon_display
->var
.yres
)
488 vblank
->flags
|= FB_VBLANK_VBLANKING
;
492 static int matroxfb_dh_ioctl(struct inode
* inode
,
497 struct fb_info
* info
) {
498 #define m2info ((struct matroxfb_dh_fb_info*)info)
499 MINFO_FROM(m2info
->primary_dev
);
501 DBG("matroxfb_crtc2_ioctl")
506 struct fb_vblank vblank
;
509 err
= matroxfb_dh_get_vblank(m2info
, &vblank
);
512 if (copy_to_user((struct fb_vblank
*)arg
, &vblank
, sizeof(vblank
)))
516 case MATROXFB_SET_OUTPUT_MODE
:
517 case MATROXFB_GET_OUTPUT_MODE
:
518 case MATROXFB_GET_ALL_OUTPUTS
:
520 return ACCESS_FBINFO(fbcon
.fbops
)->fb_ioctl(inode
, file
, cmd
, arg
, con
, &ACCESS_FBINFO(fbcon
));
522 case MATROXFB_SET_OUTPUT_CONNECTION
:
526 if (get_user(tmp
, (u_int32_t
*)arg
))
528 if (tmp
& ~ACCESS_FBINFO(output
.all
))
530 if (tmp
& ACCESS_FBINFO(output
.ph
))
532 if (tmp
& MATROXFB_OUTPUT_CONN_DFP
)
534 if ((ACCESS_FBINFO(output
.ph
) & MATROXFB_OUTPUT_CONN_DFP
) && tmp
)
536 if (tmp
== ACCESS_FBINFO(output
.sh
))
538 ACCESS_FBINFO(output
.sh
) = tmp
;
539 matroxfb_dh_switch(m2info
->currcon
, info
);
542 case MATROXFB_GET_OUTPUT_CONNECTION
:
544 if (put_user(ACCESS_FBINFO(output
.sh
), (u_int32_t
*)arg
))
548 case MATROXFB_GET_AVAILABLE_OUTPUTS
:
552 /* we do not support DFP from CRTC2 */
553 tmp
= ACCESS_FBINFO(output
.all
) & ~ACCESS_FBINFO(output
.ph
) & ~MATROXFB_OUTPUT_CONN_DFP
;
554 /* CRTC1 in DFP mode disables CRTC2 at all (I know, I'm lazy) */
555 if (ACCESS_FBINFO(output
.ph
) & MATROXFB_OUTPUT_CONN_DFP
)
557 if (put_user(tmp
, (u_int32_t
*)arg
))
566 static struct fb_ops matroxfb_dh_ops
= {
568 fb_open
: matroxfb_dh_open
,
569 fb_release
: matroxfb_dh_release
,
570 fb_get_fix
: matroxfb_dh_get_fix
,
571 fb_get_var
: matroxfb_dh_get_var
,
572 fb_set_var
: matroxfb_dh_set_var
,
573 fb_get_cmap
: matroxfb_dh_get_cmap
,
574 fb_set_cmap
: matroxfb_dh_set_cmap
,
575 fb_pan_display
: matroxfb_dh_pan_display
,
576 fb_ioctl
: matroxfb_dh_ioctl
,
579 static int matroxfb_dh_switch(int con
, struct fb_info
* info
) {
580 #define m2info ((struct matroxfb_dh_fb_info*)info)
581 struct fb_cmap
* cmap
;
584 if (m2info
->currcon
>= 0) {
585 cmap
= &m2info
->currcon_display
->cmap
;
587 fb_get_cmap(cmap
, 1, matroxfb_dh_getcolreg
, info
);
590 m2info
->currcon
= con
;
592 p
= m2info
->fbcon
.disp
;
594 p
= fb_display
+ con
;
595 m2info
->currcon_display
= p
;
596 p
->var
.activate
= FB_ACTIVATE_NOW
;
597 matroxfb_dh_set_var(&p
->var
, con
, info
);
602 static int matroxfb_dh_updatevar(int con
, struct fb_info
* info
) {
603 #define m2info ((struct matroxfb_dh_fb_info*)info)
604 matroxfb_dh_pan_var(m2info
, &fb_display
[con
].var
);
609 static void matroxfb_dh_blank(int blank
, struct fb_info
* info
) {
610 #define m2info ((struct matroxfb_dh_fb_info*)info)
618 /* do something... */
622 static struct fb_var_screeninfo matroxfb_dh_defined
= {
623 640,480,640,480,/* W,H, virtual W,H */
633 -1,-1, /* display size */
635 39721L,48L,16L,33L,10L,
636 96L,2,0, /* no sync info */
637 FB_VMODE_NONINTERLACED
,
641 static int matroxfb_dh_regit(CPMINFO
struct matroxfb_dh_fb_info
* m2info
) {
642 #define minfo (m2info->primary_dev)
646 d
= kmalloc(sizeof(*d
), GFP_KERNEL
);
648 memset(d
, 0, sizeof(*d
));
650 strcpy(m2info
->fbcon
.modename
, "MATROX CRTC2");
651 m2info
->fbcon
.changevar
= NULL
;
652 m2info
->fbcon
.node
= -1;
653 m2info
->fbcon
.fbops
= &matroxfb_dh_ops
;
654 m2info
->fbcon
.disp
= d
;
655 m2info
->fbcon
.switch_con
= &matroxfb_dh_switch
;
656 m2info
->fbcon
.updatevar
= &matroxfb_dh_updatevar
;
657 m2info
->fbcon
.blank
= &matroxfb_dh_blank
;
658 m2info
->fbcon
.flags
= FBINFO_FLAG_DEFAULT
;
659 m2info
->currcon
= -1;
660 m2info
->currcon_display
= d
;
666 mem
&= ~0x00000FFF; /* PAGE_MASK? */
667 if (ACCESS_FBINFO(video
.len_usable
) + mem
<= ACCESS_FBINFO(video
.len
))
668 m2info
->video
.offbase
= ACCESS_FBINFO(video
.len
) - mem
;
669 else if (ACCESS_FBINFO(video
.len
) < mem
) {
672 } else { /* check yres on first head... */
673 m2info
->video
.borrowed
= mem
;
674 ACCESS_FBINFO(video
.len_usable
) -= mem
;
675 m2info
->video
.offbase
= ACCESS_FBINFO(video
.len_usable
);
677 m2info
->video
.base
= ACCESS_FBINFO(video
.base
) + m2info
->video
.offbase
;
678 m2info
->video
.len
= m2info
->video
.len_usable
= m2info
->video
.len_maximum
= mem
;
679 m2info
->video
.vbase
.vaddr
= vaddr_va(ACCESS_FBINFO(video
.vbase
)) + m2info
->video
.offbase
;
680 m2info
->mmio
.base
= ACCESS_FBINFO(mmio
.base
);
681 m2info
->mmio
.vbase
= ACCESS_FBINFO(mmio
.vbase
);
682 m2info
->mmio
.len
= ACCESS_FBINFO(mmio
.len
);
685 * If we have two outputs, connect CRTC2 to it...
687 if (ACCESS_FBINFO(output
.all
) & MATROXFB_OUTPUT_CONN_SECONDARY
) {
688 ACCESS_FBINFO(output
.sh
) |= MATROXFB_OUTPUT_CONN_SECONDARY
;
689 ACCESS_FBINFO(output
.ph
) &= ~MATROXFB_OUTPUT_CONN_SECONDARY
;
690 if (ACCESS_FBINFO(output
.all
) & MATROXFB_OUTPUT_CONN_DFP
) {
691 ACCESS_FBINFO(output
.sh
) &= ~MATROXFB_OUTPUT_CONN_DFP
;
692 ACCESS_FBINFO(output
.ph
) &= ~MATROXFB_OUTPUT_CONN_DFP
;
696 matroxfb_dh_set_var(&matroxfb_dh_defined
, -2, &m2info
->fbcon
);
697 if (register_framebuffer(&m2info
->fbcon
)) {
701 if (m2info
->currcon
< 0) {
702 matroxfb_dh_set_var(&matroxfb_dh_defined
, -1, &m2info
->fbcon
);
704 down_write(&ACCESS_FBINFO(crtc2
.lock
));
705 oldcrtc2
= ACCESS_FBINFO(crtc2
.info
);
706 ACCESS_FBINFO(crtc2
.info
) = &m2info
->fbcon
;
707 up_write(&ACCESS_FBINFO(crtc2
.lock
));
709 printk(KERN_ERR
"matroxfb_crtc2: Internal consistency check failed: crtc2 already present: %p\n",
716 /* ************************** */
718 static int matroxfb_dh_registerfb(struct matroxfb_dh_fb_info
* m2info
) {
719 #define minfo (m2info->primary_dev)
720 if (matroxfb_dh_regit(PMINFO m2info
)) {
721 printk(KERN_ERR
"matroxfb_crtc2: secondary head failed to register\n");
724 printk(KERN_INFO
"matroxfb_crtc2: secondary head of fb%u was registered as fb%u\n",
725 GET_FB_IDX(ACCESS_FBINFO(fbcon
.node
)), GET_FB_IDX(m2info
->fbcon
.node
));
726 m2info
->fbcon_registered
= 1;
731 static void matroxfb_dh_deregisterfb(struct matroxfb_dh_fb_info
* m2info
) {
732 #define minfo (m2info->primary_dev)
733 if (m2info
->fbcon_registered
) {
735 struct fb_info
* crtc2
;
737 down_write(&ACCESS_FBINFO(crtc2
.lock
));
738 crtc2
= ACCESS_FBINFO(crtc2
.info
);
739 if (crtc2
== &m2info
->fbcon
)
740 ACCESS_FBINFO(crtc2
.info
) = NULL
;
741 up_write(&ACCESS_FBINFO(crtc2
.lock
));
742 if (crtc2
!= &m2info
->fbcon
) {
743 printk(KERN_ERR
"matroxfb_crtc2: Internal consistency check failed: crtc2 mismatch at unload: %p != %p\n",
744 crtc2
, &m2info
->fbcon
);
745 printk(KERN_ERR
"matroxfb_crtc2: Expect kernel crash after module unload.\n");
748 id
= GET_FB_IDX(m2info
->fbcon
.node
);
749 unregister_framebuffer(&m2info
->fbcon
);
750 kfree(m2info
->fbcon
.disp
);
751 /* return memory back to primary head */
752 ACCESS_FBINFO(video
.len_usable
) += m2info
->video
.borrowed
;
753 printk(KERN_INFO
"matroxfb_crtc2: fb%u unregistered\n", id
);
754 m2info
->fbcon_registered
= 0;
759 static void* matroxfb_crtc2_probe(struct matrox_fb_info
* minfo
) {
760 struct matroxfb_dh_fb_info
* m2info
;
762 /* hardware is CRTC2 incapable... */
763 if (!ACCESS_FBINFO(devflags
.crtc2
))
765 m2info
= (struct matroxfb_dh_fb_info
*)kmalloc(sizeof(*m2info
), GFP_KERNEL
);
767 printk(KERN_ERR
"matroxfb_crtc2: Not enough memory for CRTC2 control structs\n");
770 memset(m2info
, 0, sizeof(*m2info
));
771 m2info
->primary_dev
= MINFO
;
772 if (matroxfb_dh_registerfb(m2info
)) {
774 printk(KERN_ERR
"matroxfb_crtc2: CRTC2 framebuffer failed to register\n");
780 static void matroxfb_crtc2_remove(struct matrox_fb_info
* minfo
, void* crtc2
) {
781 matroxfb_dh_deregisterfb(crtc2
);
784 static struct matroxfb_driver crtc2
= {
785 name
: "Matrox G400 CRTC2",
786 probe
: matroxfb_crtc2_probe
,
787 remove
: matroxfb_crtc2_remove
};
789 static int matroxfb_crtc2_init(void) {
790 matroxfb_register_driver(&crtc2
);
794 static void matroxfb_crtc2_exit(void) {
795 matroxfb_unregister_driver(&crtc2
);
798 MODULE_AUTHOR("(c) 1999,2000 Petr Vandrovec <vandrove@vc.cvut.cz>");
799 MODULE_DESCRIPTION("Matrox G400 CRTC2 driver");
800 module_init(matroxfb_crtc2_init
);
801 module_exit(matroxfb_crtc2_exit
);
802 /* we do not have __setup() yet */