2 * Copyright (C) 2003 Alban Bedel
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include <linux/config.h>
22 #include <linux/version.h>
23 #include <linux/module.h>
24 #include <linux/types.h>
25 #include <linux/kernel.h>
26 #include <linux/sched.h>
28 #include <linux/string.h>
29 #include <linux/errno.h>
31 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10)
32 #include <linux/malloc.h>
34 #include <linux/slab.h>
37 #include <linux/pci.h>
38 #include <linux/ioport.h>
39 #include <linux/init.h>
40 #include <linux/agp_backend.h>
42 #include <asm/uaccess.h>
43 #include <asm/system.h>
50 #define TDFX_VID_MAJOR 178
52 MODULE_AUTHOR("Albeu");
53 MODULE_DESCRIPTION("A driver for Banshee targeted for video app");
56 MODULE_LICENSE("GPL");
60 #define min(x,y) (((x)<(y))?(x):(y))
63 static struct pci_dev
*pci_dev
;
65 static uint8_t *tdfx_mmio_base
= 0;
66 static uint32_t tdfx_mem_base
= 0;
67 static uint32_t tdfx_io_base
= 0;
69 static int tdfx_ram_size
= 0;
71 static int tdfx_vid_in_use
= 0;
73 static drm_agp_t
*drm_agp
= NULL
;
74 static agp_kern_info agp_info
;
75 static agp_memory
*agp_mem
= NULL
;
77 static __initdata
int tdfx_map_io
= 1;
78 static __initdata
unsigned long map_start
= 0; //0x7300000;
79 static __initdata
unsigned long map_max
= (10*1024*1024);
81 MODULE_PARM(tdfx_map_io
,"i");
82 MODULE_PARM_DESC(tdfx_map_io
, "Set to 0 to use the page fault handler (you need to patch agpgart_be.c to allow the mapping in user space)\n");
83 MODULE_PARM(map_start
,"l");
84 MODULE_PARM_DESC(map_start
,"Use a block of physical mem instead of the agp arerture.");
85 MODULE_PARM(map_max
,"l");
86 MODULE_PARM_DESC(map_max
, "Maximum amout of physical memory (in bytes) that can be used\n");
88 static inline u32
tdfx_inl(unsigned int reg
) {
89 return readl(tdfx_mmio_base
+ reg
);
92 static inline void tdfx_outl(unsigned int reg
, u32 val
) {
93 writel(val
,tdfx_mmio_base
+ reg
);
96 static inline void banshee_make_room(int size
) {
97 while((tdfx_inl(STATUS
) & 0x1f) < size
);
100 static inline void banshee_wait_idle(void) {
103 banshee_make_room(1);
104 tdfx_outl(COMMAND_3D
, COMMAND_3D_NOP
);
107 i
= (tdfx_inl(STATUS
) & STATUS_BUSY
) ? 0 : i
+ 1;
112 static unsigned long get_lfb_size(void) {
115 // u32 miscinit1 = 0;
119 draminit0
= tdfx_inl(DRAMINIT0
);
120 draminit1
= tdfx_inl(DRAMINIT1
);
122 if ((pci_dev
->device
== PCI_DEVICE_ID_3DFX_BANSHEE
) ||
123 (pci_dev
->device
== PCI_DEVICE_ID_3DFX_VOODOO3
)) {
124 sgram_p
= (draminit1
& DRAMINIT1_MEM_SDRAM
) ? 0 : 1;
127 (((draminit0
& DRAMINIT0_SGRAM_NUM
) ? 2 : 1) *
128 ((draminit0
& DRAMINIT0_SGRAM_TYPE
) ? 8 : 4) * 1024 * 1024) :
132 u32 chips
, psize
, banks
;
134 chips
= ((draminit0
& (1 << 26)) == 0) ? 4 : 8;
135 psize
= 1 << ((draminit0
& 0x38000000) >> 28);
136 banks
= ((draminit0
& (1 << 30)) == 0) ? 2 : 4;
137 lfbsize
= chips
* psize
* banks
;
142 /* disable block writes for SDRAM (why?) */
143 miscinit1
= tdfx_inl(MISCINIT1
);
144 miscinit1
|= sgram_p
? 0 : MISCINIT1_2DBLOCK_DIS
;
145 miscinit1
|= MISCINIT1_CLUT_INV
;
147 banshee_make_room(1);
148 tdfx_outl(MISCINIT1
, miscinit1
);
154 static int tdfx_vid_find_card(void)
156 struct pci_dev
*dev
= NULL
;
157 // unsigned int card_option;
159 if((dev
= pci_find_device(PCI_VENDOR_ID_3DFX
, PCI_DEVICE_ID_3DFX_BANSHEE
, NULL
)))
160 printk(KERN_INFO
"tdfx_vid: Found VOODOO BANSHEE\n");
161 else if((dev
= pci_find_device(PCI_VENDOR_ID_3DFX
, PCI_DEVICE_ID_3DFX_VOODOO3
, NULL
)))
162 printk(KERN_INFO
"tdfx_vid: Found VOODOO 3 \n");
169 #if LINUX_VERSION_CODE >= 0x020300
170 tdfx_mmio_base
= ioremap_nocache(dev
->resource
[0].start
,1 << 24);
171 tdfx_mem_base
= dev
->resource
[1].start
;
172 tdfx_io_base
= dev
->resource
[2].start
;
174 tdfx_mmio_base
= ioremap_nocache(dev
->base_address
[1] & PCI_BASE_ADDRESS_MEM_MASK
,0x4000);
175 tdfx_mem_base
= dev
->base_address
[1] & PCI_BASE_ADDRESS_MEM_MASK
;
176 tdfx_io_base
= dev
->base_address
[2] & PCI_BASE_ADDRESS_MEM_MASK
;
178 printk(KERN_INFO
"tdfx_vid: MMIO at 0x%p\n", tdfx_mmio_base
);
179 tdfx_ram_size
= get_lfb_size();
181 printk(KERN_INFO
"tdfx_vid: Found %d MB (%d bytes) of memory\n",
182 tdfx_ram_size
/ 1024 / 1024,tdfx_ram_size
);
188 printk("List resources -----------\n");
189 for(temp
=0;temp
<DEVICE_COUNT_RESOURCE
;temp
++){
190 struct resource
*res
=&pci_dev
->resource
[temp
];
192 int size
=(1+res
->end
-res
->start
)>>20;
193 printk(KERN_DEBUG
"res %d: start: 0x%X end: 0x%X (%d MB) flags=0x%X\n",temp
,res
->start
,res
->end
,size
,res
->flags
);
194 if(res
->flags
&(IORESOURCE_MEM
|IORESOURCE_PREFETCH
)){
195 if(size
>tdfx_ram_size
&& size
<=64) tdfx_ram_size
=size
;
206 static int agp_init(void) {
208 drm_agp
= (drm_agp_t
*)inter_module_get("drm_agp");
211 printk(KERN_ERR
"tdfx_vid: Unable to get drm_agp pointer\n");
215 if(drm_agp
->acquire()) {
216 printk(KERN_ERR
"tdfx_vid: Unable to acquire the agp backend\n");
221 drm_agp
->copy_info(&agp_info
);
223 printk(KERN_DEBUG
"AGP Version : %d %d\n"
224 "AGP Mode: %#X\nAperture Base: %p\nAperture Size: %d\n"
225 "Max memory = %d\nCurrent mem = %d\nCan use perture : %s\n"
227 agp_info
.version
.major
,agp_info
.version
.minor
,
228 agp_info
.mode
,agp_info
.aper_base
,agp_info
.aper_size
,
229 agp_info
.max_memory
,agp_info
.current_memory
,
230 agp_info
.cant_use_aperture
? "no" : "yes",
233 drm_agp
->enable(agp_info
.mode
);
236 printk(KERN_INFO
"AGP Enabled\n");
241 static void agp_close(void) {
246 drm_agp
->unbind_memory(agp_mem
);
247 drm_agp
->free_memory(agp_mem
);
253 inter_module_put("drm_agp");
256 static int agp_move(tdfx_vid_agp_move_t
* m
) {
260 if(!(agp_mem
||map_start
))
264 printk(KERN_DEBUG
"tdfx_vid: AGP move invalid destination %d\n",
270 src
= map_start
+ m
->src
;
272 src
= agp_info
.aper_base
+ m
->src
;
275 src_h
= (m
->width
| (m
->src_stride
<< 14)) & 0x0FFFFFFF;
277 // banshee_wait_idle();
278 banshee_make_room(6);
279 tdfx_outl(AGPHOSTADDRESSHIGH
,src_h
);
280 tdfx_outl(AGPHOSTADDRESSLOW
,src_l
);
282 tdfx_outl(AGPGRAPHICSADDRESS
, m
->dst
);
283 tdfx_outl(AGPGRAPHICSSTRIDE
, m
->dst_stride
);
284 tdfx_outl(AGPREQSIZE
,m
->src_stride
*m
->height
);
286 tdfx_outl(AGPMOVECMD
,m
->move2
<< 3);
292 static void setup_fifo(u32 offset
,ssize_t pages
) {
293 long addr
= agp_info
.aper_base
+ offset
;
294 u32 size
= pages
| 0x700; // fifo on, in agp mem, disable hole cnt
298 tdfx_outl(CMDBASEADDR0
,addr
>> 4);
299 tdfx_outl(CMDRDPTRL0
, addr
<< 4);
300 tdfx_outl(CMDRDPTRH0
, addr
>> 28);
301 tdfx_outl(CMDAMIN0
, (addr
- 4) & 0xFFFFFF);
302 tdfx_outl(CMDAMAX0
, (addr
- 4) & 0xFFFFFF);
303 tdfx_outl(CMDFIFODEPTH0
, 0);
304 tdfx_outl(CMDHOLECNT0
, 0);
305 tdfx_outl(CMDBASESIZE0
,size
);
311 static int bump_fifo(u16 size
) {
314 tdfx_outl(CMDBUMP0
, size
);
320 static void tdfx_vid_get_config(tdfx_vid_config_t
* cfg
) {
323 cfg
->version
= TDFX_VID_VERSION
;
324 cfg
->ram_size
= tdfx_ram_size
;
326 in
= tdfx_inl(VIDSCREENSIZE
);
327 cfg
->screen_width
= in
& 0xFFF;
328 cfg
->screen_height
= (in
>> 12) & 0xFFF;
329 in
= (tdfx_inl(VIDPROCCFG
)>> 18)& 0x7;
332 cfg
->screen_format
= TDFX_VID_FORMAT_BGR8
;
335 cfg
->screen_format
= TDFX_VID_FORMAT_BGR16
;
338 cfg
->screen_format
= TDFX_VID_FORMAT_BGR24
;
341 cfg
->screen_format
= TDFX_VID_FORMAT_BGR32
;
344 printk(KERN_INFO
"tdfx_vid: unknown screen format %d\n",in
);
345 cfg
->screen_format
= 0;
348 cfg
->screen_stride
= tdfx_inl(VIDDESKSTRIDE
) & 0x7FFF;
349 cfg
->screen_start
= tdfx_inl(VIDDESKSTART
);
352 inline static u32
tdfx_vid_make_format(int src
,u16 stride
,u32 fmt
) {
353 u32 r
= stride
& 0xFFF3;
356 // src and dest formats
358 case TDFX_VID_FORMAT_BGR8
:
361 case TDFX_VID_FORMAT_BGR16
:
364 case TDFX_VID_FORMAT_BGR24
:
367 case TDFX_VID_FORMAT_BGR32
:
372 if(!src
&& !tdfx_fmt
) {
373 printk(KERN_INFO
"tdfx_vid: Invalid destination format %#X\n",fmt
);
377 if(src
&& !tdfx_fmt
) {
380 case TDFX_VID_FORMAT_BGR1
:
383 case TDFX_VID_FORMAT_BGR15
: // To check
386 case TDFX_VID_FORMAT_YUY2
:
389 case TDFX_VID_FORMAT_UYVY
:
393 printk(KERN_INFO
"tdfx_vid: Invalid source format %#X\n",fmt
);
403 static int tdfx_vid_blit(tdfx_vid_blit_t
* blit
) {
404 u32 src_fmt
,dst_fmt
,cmd
= 2;
405 u32 cmin
,cmax
,srcbase
,srcxy
,srcfmt
,srcsize
;
406 u32 dstbase
,dstxy
,dstfmt
,dstsize
= 0;
407 u32 cmd_extra
= 0,src_ck
[2],dst_ck
[2],rop123
=0;
409 //printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format);
410 src_fmt
= tdfx_vid_make_format(1,blit
->src_stride
,blit
->src_format
);
413 //printk(KERN_INFO "tdfx_vid: Make dst fmt 0x%x\n", blit->dst_format);
414 dst_fmt
= tdfx_vid_make_format(0,blit
->dst_stride
,blit
->dst_format
);
417 blit
->colorkey
&= 0x3;
418 // Be nice if user just want a simple blit
419 if((!blit
->colorkey
) && (!blit
->rop
[0]))
420 blit
->rop
[0] = TDFX_VID_ROP_COPY
;
421 // No stretch : fix me the cmd should be 1 but it
422 // doesn't work. Maybe some other regs need to be set
423 // as non-stretch blit have more options
424 if(((!blit
->dst_w
) && (!blit
->dst_h
)) ||
425 ((blit
->dst_w
== blit
->src_w
) && (blit
->dst_h
== blit
->src_h
)))
428 // Save the regs otherwise fb get crazy
429 // we can perhaps avoid some ...
431 cmin
= tdfx_inl(CLIP0MIN
);
432 cmax
= tdfx_inl(CLIP0MAX
);
433 srcbase
= tdfx_inl(SRCBASE
);
434 srcxy
= tdfx_inl(SRCXY
);
435 srcfmt
= tdfx_inl(SRCFORMAT
);
436 srcsize
= tdfx_inl(SRCSIZE
);
437 dstbase
= tdfx_inl(DSTBASE
);
438 dstxy
= tdfx_inl(DSTXY
);
439 dstfmt
= tdfx_inl(DSTFORMAT
);
441 dstsize
= tdfx_inl(DSTSIZE
);
442 if(blit
->colorkey
& TDFX_VID_SRC_COLORKEY
) {
443 src_ck
[0] = tdfx_inl(SRCCOLORKEYMIN
);
444 src_ck
[1] = tdfx_inl(SRCCOLORKEYMAX
);
445 tdfx_outl(SRCCOLORKEYMIN
,blit
->src_colorkey
[0]);
446 tdfx_outl(SRCCOLORKEYMAX
,blit
->src_colorkey
[1]);
448 if(blit
->colorkey
& TDFX_VID_DST_COLORKEY
) {
449 dst_ck
[0] = tdfx_inl(DSTCOLORKEYMIN
);
450 dst_ck
[1] = tdfx_inl(DSTCOLORKEYMAX
);
451 tdfx_outl(SRCCOLORKEYMIN
,blit
->dst_colorkey
[0]);
452 tdfx_outl(SRCCOLORKEYMAX
,blit
->dst_colorkey
[1]);
455 cmd_extra
= tdfx_inl(COMMANDEXTRA_2D
);
456 rop123
= tdfx_inl(ROP123
);
457 tdfx_outl(COMMANDEXTRA_2D
, blit
->colorkey
);
458 tdfx_outl(ROP123
,(blit
->rop
[1] | (blit
->rop
[2] << 8) | blit
->rop
[3] << 16));
461 // Get rid of the clipping at the moment
462 tdfx_outl(CLIP0MIN
,0);
463 tdfx_outl(CLIP0MAX
,0x0fff0fff);
466 tdfx_outl(SRCBASE
,blit
->src
& 0x00FFFFFF);
467 tdfx_outl(SRCXY
,XYREG(blit
->src_x
,blit
->src_y
));
468 tdfx_outl(SRCFORMAT
,src_fmt
);
469 tdfx_outl(SRCSIZE
,XYREG(blit
->src_w
,blit
->src_h
));
472 tdfx_outl(DSTBASE
,blit
->dst
& 0x00FFFFFF);
473 tdfx_outl(DSTXY
,XYREG(blit
->dst_x
,blit
->dst_y
));
474 tdfx_outl(DSTFORMAT
,dst_fmt
);
476 tdfx_outl(DSTSIZE
,XYREG(blit
->dst_w
,blit
->dst_h
));
479 tdfx_outl(COMMAND_2D
,cmd
| 0x100 | (blit
->rop
[0] << 24));
482 // Now restore the regs to make fb happy
483 tdfx_outl(CLIP0MIN
, cmin
);
484 tdfx_outl(CLIP0MAX
, cmax
);
485 tdfx_outl(SRCBASE
, srcbase
);
486 tdfx_outl(SRCXY
, srcxy
);
487 tdfx_outl(SRCFORMAT
, srcfmt
);
488 tdfx_outl(SRCSIZE
, srcsize
);
489 tdfx_outl(DSTBASE
, dstbase
);
490 tdfx_outl(DSTXY
, dstxy
);
491 tdfx_outl(DSTFORMAT
, dstfmt
);
493 tdfx_outl(DSTSIZE
, dstsize
);
494 if(blit
->colorkey
& TDFX_VID_SRC_COLORKEY
) {
495 tdfx_outl(SRCCOLORKEYMIN
,src_ck
[0]);
496 tdfx_outl(SRCCOLORKEYMAX
,src_ck
[1]);
498 if(blit
->colorkey
& TDFX_VID_DST_COLORKEY
) {
499 tdfx_outl(SRCCOLORKEYMIN
,dst_ck
[0]);
500 tdfx_outl(SRCCOLORKEYMAX
,dst_ck
[1]);
503 tdfx_outl(COMMANDEXTRA_2D
,cmd_extra
);
504 tdfx_outl(ROP123
,rop123
);
509 static int tdfx_vid_set_yuv(unsigned long arg
) {
512 if(copy_from_user(&yuv
,(tdfx_vid_yuv_t
*)arg
,sizeof(tdfx_vid_yuv_t
))) {
513 printk(KERN_DEBUG
"tdfx_vid:failed copy from userspace\n");
516 banshee_make_room(2);
517 tdfx_outl(YUVBASEADDRESS
,yuv
.base
& 0x01FFFFFF);
518 tdfx_outl(YUVSTRIDE
, yuv
.stride
& 0x3FFF);
525 static int tdfx_vid_get_yuv(unsigned long arg
) {
528 yuv
.base
= tdfx_inl(YUVBASEADDRESS
) & 0x01FFFFFF;
529 yuv
.stride
= tdfx_inl(YUVSTRIDE
) & 0x3FFF;
531 if(copy_to_user((tdfx_vid_yuv_t
*)arg
,&yuv
,sizeof(tdfx_vid_yuv_t
))) {
532 printk(KERN_INFO
"tdfx_vid:failed copy to userspace\n");
539 static int tdfx_vid_set_overlay(unsigned long arg
) {
540 tdfx_vid_overlay_t ov
;
541 uint32_t screen_w
,screen_h
;
542 uint32_t vidcfg
,stride
,vidbuf
;
545 if(copy_from_user(&ov
,(tdfx_vid_overlay_t
*)arg
,sizeof(tdfx_vid_overlay_t
))) {
546 printk(KERN_DEBUG
"tdfx_vid:failed copy from userspace\n");
552 if(-ov
.dst_y
>= ov
.src_height
) {
553 printk(KERN_DEBUG
"tdfx_vid: Overlay outside of the screen ????\n");
556 shift
= (-ov
.dst_y
)/(double)ov
.dst_height
*ov
.src_height
;
557 ov
.src
[0] += shift
*ov
.src_stride
;
558 ov
.src_height
-= shift
;
559 ov
.dst_height
+= ov
.dst_y
;
565 if(-ov
.dst_x
>= ov
.src_width
) {
566 printk(KERN_DEBUG
"tdfx_vid: Overlay outside of the screen ????\n");
569 shift
= (-ov
.dst_x
)/(double)ov
.dst_width
*ov
.src_width
;
570 shift
= ((shift
+3)/2)*2;
571 ov
.src
[0] += shift
*2;
572 ov
.src_width
-= shift
;
573 ov
.dst_width
+= ov
.dst_x
;
577 vidcfg
= tdfx_inl(VIDPROCCFG
);
578 // clear the overlay fmt
579 vidcfg
&= ~(7 << 21);
581 case TDFX_VID_FORMAT_BGR15
:
584 case TDFX_VID_FORMAT_BGR16
:
587 case TDFX_VID_FORMAT_YUY2
:
590 case TDFX_VID_FORMAT_UYVY
:
594 printk(KERN_DEBUG
"tdfx_vid: Invalid overlay fmt 0x%x\n",ov
.format
);
598 // YUV422 need 4 bytes aligned stride and address
599 if((ov
.format
== TDFX_VID_FORMAT_YUY2
||
600 ov
.format
== TDFX_VID_FORMAT_UYVY
)) {
601 if((ov
.src_stride
& ~0x3) != ov
.src_stride
) {
602 printk(KERN_DEBUG
"tdfx_vid: YUV need a 4 bytes aligned stride %d\n",ov
.src_stride
);
605 if((ov
.src
[0] & ~0x3) != ov
.src
[0] || (ov
.src
[1] & ~0x3) != ov
.src
[1]){
606 printk(KERN_DEBUG
"tdfx_vid: YUV need a 4 bytes aligned address 0x%x 0x%x\n",ov
.src
[0],ov
.src
[1]);
611 // Now we have a good input format
612 // but first get the screen size to check a bit
613 // if the size/position is valid
614 screen_w
= tdfx_inl(VIDSCREENSIZE
);
615 screen_h
= (screen_w
>> 12) & 0xFFF;
617 disp_w
= ov
.dst_x
+ ov
.dst_width
>= screen_w
?
618 screen_w
- ov
.dst_x
: ov
.dst_width
;
619 disp_h
= ov
.dst_y
+ ov
.dst_height
>= screen_h
?
620 screen_h
- ov
.dst_y
: ov
.dst_height
;
622 if(ov
.dst_x
>= screen_w
|| ov
.dst_y
>= screen_h
||
623 disp_h
<= 0 || disp_h
> screen_h
|| disp_w
<= 0 || disp_w
> screen_w
) {
624 printk(KERN_DEBUG
"tdfx_vid: Invalid overlay dimension and/or position\n");
629 if(ov
.src_width
< ov
.dst_width
)
634 if(ov
.src_height
< ov
.dst_height
)
638 // Filtering can only be used in 1x mode
639 if(!(vidcfg
| (1<<26)))
643 // disable overlay stereo mode
646 if(ov
.use_colorkey
) {
647 // Colorkey inversion
648 if(ov
.invert_colorkey
)
655 // Overlay isn't VidIn
658 tdfx_outl(VIDPROCCFG
,vidcfg
);
661 //printk(KERN_DEBUG "tdfx_vid: start %dx%d\n",ov.dst_x & 0xFFF,ov.dst_y & 0xFFF);
662 tdfx_outl(VIDOVRSTARTCRD
,(ov
.dst_x
& 0xFFF)|((ov
.dst_y
& 0xFFF)<<12));
664 tdfx_outl(VIDOVRENDCRD
, ((ov
.dst_x
+ disp_w
-1) & 0xFFF)|
665 (((ov
.dst_y
+ disp_h
-1) & 0xFFF)<<12));
667 tdfx_outl(VIDOVRDUDX
,( ((u32
)ov
.src_width
) << 20) / ov
.dst_width
);
668 // Src offset and width (in bytes)
669 tdfx_outl(VIDOVRDUDXOFF
,((ov
.src_width
<<1) & 0xFFF) << 19);
671 tdfx_outl(VIDOVRDVDY
, ( ((u32
)ov
.src_height
) << 20) / ov
.dst_height
);
673 // tdfx_outl(VIDOVRDVDY,0);
675 tdfx_outl(VIDOVRDVDYOFF
,0);
677 stride
= tdfx_inl(VIDDESKSTRIDE
) & 0xFFFF;
678 tdfx_outl(VIDDESKSTRIDE
,stride
| (((u32
)ov
.src_stride
) << 16));
680 tdfx_outl(LEFTOVBUF
, ov
.src
[0]);
681 tdfx_outl(RIGHTOVBUF
, ov
.src
[1]);
683 // Send a swap buffer cmd if we are not on one of the 2 buffers
684 vidbuf
= tdfx_inl(VIDCUROVRSTART
);
685 if(vidbuf
!= ov
.src
[0] && vidbuf
!= ov
.src
[1]) {
686 tdfx_outl(SWAPPENDING
,0);
687 tdfx_outl(SWAPBUFCMD
, 1);
689 //printk(KERN_DEBUG "tdfx_vid: Buf0=0x%x Buf1=0x%x Current=0x%x\n",
690 // ov.src[0],ov.src[1],tdfx_inl(VIDCUROVRSTART));
692 if(ov
.use_colorkey
) {
693 tdfx_outl(VIDCHRMIN
,ov
.colorkey
[0]);
694 tdfx_outl(VIDCHRMAX
,ov
.colorkey
[1]);
700 static int tdfx_vid_overlay_on(void) {
701 uint32_t vidcfg
= tdfx_inl(VIDPROCCFG
);
703 if(vidcfg
& (1<<8)) { // Overlay is already on
704 //printk(KERN_DEBUG "tdfx_vid: Overlay is already on.\n");
708 tdfx_outl(VIDPROCCFG
,vidcfg
);
712 static int tdfx_vid_overlay_off(void) {
713 uint32_t vidcfg
= tdfx_inl(VIDPROCCFG
);
715 if(vidcfg
& (1<<8)) {
717 tdfx_outl(VIDPROCCFG
,vidcfg
);
721 printk(KERN_DEBUG
"tdfx_vid: Overlay is already off.\n");
726 static int tdfx_vid_ioctl(struct inode
*inode
, struct file
*file
, unsigned int cmd
, unsigned long arg
)
728 tdfx_vid_agp_move_t move
;
729 tdfx_vid_config_t cfg
;
730 tdfx_vid_blit_t blit
;
734 case TDFX_VID_AGP_MOVE
:
735 if(copy_from_user(&move
,(tdfx_vid_agp_move_t
*)arg
,sizeof(tdfx_vid_agp_move_t
))) {
736 printk(KERN_INFO
"tdfx_vid:failed copy from userspace\n");
739 return agp_move(&move
);
741 if(copy_from_user(&int16
,(u16
*)arg
,sizeof(u16
))) {
742 printk(KERN_INFO
"tdfx_vid:failed copy from userspace\n");
745 return bump_fifo(int16
);
747 if(copy_from_user(&blit
,(tdfx_vid_blit_t
*)arg
,sizeof(tdfx_vid_blit_t
))) {
748 printk(KERN_INFO
"tdfx_vid:failed copy from userspace\n");
751 if(!tdfx_vid_blit(&blit
)) {
752 printk(KERN_INFO
"tdfx_vid: Blit failed\n");
756 case TDFX_VID_GET_CONFIG
:
757 if(copy_from_user(&cfg
,(tdfx_vid_config_t
*)arg
,sizeof(tdfx_vid_config_t
))) {
758 printk(KERN_INFO
"tdfx_vid:failed copy from userspace\n");
761 tdfx_vid_get_config(&cfg
);
762 if(copy_to_user((tdfx_vid_config_t
*)arg
,&cfg
,sizeof(tdfx_vid_config_t
))) {
763 printk(KERN_INFO
"tdfx_vid:failed copy to userspace\n");
767 case TDFX_VID_SET_YUV
:
768 return tdfx_vid_set_yuv(arg
);
769 case TDFX_VID_GET_YUV
:
770 return tdfx_vid_get_yuv(arg
);
771 case TDFX_VID_SET_OVERLAY
:
772 return tdfx_vid_set_overlay(arg
);
773 case TDFX_VID_OVERLAY_ON
:
774 return tdfx_vid_overlay_on();
775 case TDFX_VID_OVERLAY_OFF
:
776 return tdfx_vid_overlay_off();
778 printk(KERN_ERR
"tdfx_vid: Invalid ioctl %d\n",cmd
);
786 static ssize_t
tdfx_vid_read(struct file
*file
, char *buf
, size_t count
, loff_t
*ppos
)
791 static ssize_t
tdfx_vid_write(struct file
*file
, const char *buf
, size_t count
, loff_t
*ppos
)
797 static void tdfx_vid_mopen(struct vm_area_struct
*vma
) {
802 printk(KERN_DEBUG
"tdfx_vid: mopen\n");
804 for(i
= 0 ; i
< agp_mem
->page_count
; i
++) {
805 phys
= agp_mem
->memory
[i
] & ~(0x00000fff);
806 page
= virt_to_page(phys_to_virt(phys
));
808 printk(KERN_DEBUG
"tdfx_vid: Can't get the page %d\%d\n",i
,agp_mem
->page_count
);
816 static void tdfx_vid_mclose(struct vm_area_struct
*vma
) {
821 printk(KERN_DEBUG
"tdfx_vid: mclose\n");
823 for(i
= 0 ; i
< agp_mem
->page_count
; i
++) {
824 phys
= agp_mem
->memory
[i
] & ~(0x00000fff);
825 page
= virt_to_page(phys_to_virt(phys
));
827 printk(KERN_DEBUG
"tdfx_vid: Can't get the page %d\%d\n",i
,agp_mem
->page_count
);
836 static struct page
*tdfx_vid_nopage(struct vm_area_struct
*vma
,
837 unsigned long address
,
844 off
= address
- vma
->vm_start
+ (vma
->vm_pgoff
<<PAGE_SHIFT
);
847 if(n
>= agp_mem
->page_count
) {
848 printk(KERN_DEBUG
"tdfx_vid: Too far away\n");
849 return ((struct page
*)0UL);
851 phys
= agp_mem
->memory
[n
] & ~(0x00000fff);
852 page
= virt_to_page(phys_to_virt(phys
));
854 printk(KERN_DEBUG
"tdfx_vid: Can't get the page\n");
855 return ((struct page
*)0UL);
860 /* memory handler functions */
861 static struct vm_operations_struct tdfx_vid_vm_ops
= {
862 open
: tdfx_vid_mopen
, /* mmap-open */
863 close
: tdfx_vid_mclose
,/* mmap-close */
864 nopage
: tdfx_vid_nopage
, /* no-page fault handler */
868 static int tdfx_vid_mmap(struct file
*file
, struct vm_area_struct
*vma
)
872 printk(KERN_DEBUG
"tdfx_vid: mapping agp memory into userspace\n");
875 size
= (vma
->vm_end
-vma
->vm_start
+ PAGE_SIZE
- 1) / PAGE_SIZE
;
877 if(map_start
) { // Ok we map directly in the physcal ram
878 if(size
*PAGE_SIZE
> map_max
) {
879 printk(KERN_ERR
"tdfx_vid: Not enouth mem\n");
882 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
883 if(remap_page_range(vma
, vma
->vm_start
,map_start
,
884 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
886 if(remap_page_range(vma
->vm_start
, (unsigned long)map_start
,
887 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
890 printk(KERN_ERR
"tdfx_vid: error mapping video memory\n");
893 printk(KERN_INFO
"Physical mem 0x%lx mapped in userspace\n",map_start
);
900 agp_mem
= drm_agp
->allocate_memory(size
,AGP_NORMAL_MEMORY
);
902 printk(KERN_ERR
"Failed to allocate AGP memory\n");
906 if(drm_agp
->bind_memory(agp_mem
,0)) {
907 printk(KERN_ERR
"Failed to bind the AGP memory\n");
908 drm_agp
->free_memory(agp_mem
);
913 printk(KERN_INFO
"%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n",
914 size
,vma
->vm_end
-vma
->vm_start
,size
*PAGE_SIZE
);
918 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3)
919 if(remap_page_range(vma
, vma
->vm_start
,agp_info
.aper_base
,
920 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
922 if(remap_page_range(vma
->vm_start
, (unsigned long)agp_info
.aper_base
,
923 vma
->vm_end
- vma
->vm_start
, vma
->vm_page_prot
))
926 printk(KERN_ERR
"tdfx_vid: error mapping video memory\n");
931 vma
->vm_flags
|= VM_LOCKED
| VM_IO
;
932 vma
->vm_ops
= &tdfx_vid_vm_ops
;
933 vma
->vm_ops
->open(vma
);
934 printk(KERN_INFO
"Page fault handler ready !!!!!\n");
941 static int tdfx_vid_release(struct inode
*inode
, struct file
*file
)
944 printk(KERN_DEBUG
"tdfx_vid: Video OFF (release)\n");
947 // Release the agp mem
949 drm_agp
->unbind_memory(agp_mem
);
950 drm_agp
->free_memory(agp_mem
);
960 static long long tdfx_vid_lseek(struct file
*file
, long long offset
, int origin
)
965 static int tdfx_vid_open(struct inode
*inode
, struct file
*file
)
967 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2)
968 int minor
= MINOR(inode
->i_rdev
.value
);
970 int minor
= MINOR(inode
->i_rdev
);
976 if(tdfx_vid_in_use
== 1)
984 #if LINUX_VERSION_CODE >= 0x020400
985 static struct file_operations tdfx_vid_fops
=
987 llseek
: tdfx_vid_lseek
,
989 write
: tdfx_vid_write
,
990 ioctl
: tdfx_vid_ioctl
,
993 release
: tdfx_vid_release
996 static struct file_operations tdfx_vid_fops
=
1012 int init_module(void)
1014 tdfx_vid_in_use
= 0;
1016 if(register_chrdev(TDFX_VID_MAJOR
, "tdfx_vid", &tdfx_vid_fops
)) {
1017 printk(KERN_ERR
"tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR
);
1022 printk(KERN_ERR
"tdfx_vid: AGP init failed\n");
1023 unregister_chrdev(TDFX_VID_MAJOR
, "tdfx_vid");
1027 if (!tdfx_vid_find_card()) {
1028 printk(KERN_ERR
"tdfx_vid: no supported devices found\n");
1030 unregister_chrdev(TDFX_VID_MAJOR
, "tdfx_vid");
1040 void cleanup_module(void)
1043 iounmap(tdfx_mmio_base
);
1045 printk(KERN_INFO
"tdfx_vid: Cleaning up module\n");
1046 unregister_chrdev(TDFX_VID_MAJOR
, "tdfx_vid");