Handle vga_init() error and output error message.
[mplayer/glamo.git] / drivers / tdfx_vid.c
blob18451ab6ffd1961aec6e696bc58221a6d31542d8
1 /*
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>
27 #include <linux/mm.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>
33 #else
34 #include <linux/slab.h>
35 #endif
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>
44 #include <asm/io.h>
46 #include "tdfx_vid.h"
47 #include "3dfx.h"
50 #define TDFX_VID_MAJOR 178
52 MODULE_AUTHOR("Albeu");
53 MODULE_DESCRIPTION("A driver for Banshee targeted for video app");
55 #ifdef MODULE_LICENSE
56 MODULE_LICENSE("GPL");
57 #endif
59 #ifndef min
60 #define min(x,y) (((x)<(y))?(x):(y))
61 #endif
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) {
101 int i = 0;
103 banshee_make_room(1);
104 tdfx_outl(COMMAND_3D, COMMAND_3D_NOP);
106 while(1) {
107 i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1;
108 if(i == 3) break;
112 static unsigned long get_lfb_size(void) {
113 u32 draminit0 = 0;
114 u32 draminit1 = 0;
115 // u32 miscinit1 = 0;
116 u32 lfbsize = 0;
117 int sgram_p = 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;
126 lfbsize = sgram_p ?
127 (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) *
128 ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) :
129 16 * 1024 * 1024;
130 } else {
131 /* Voodoo4/5 */
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;
138 lfbsize <<= 20;
141 #if 0
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);
149 #endif
151 return lfbsize;
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");
163 else
164 return 0;
167 pci_dev = dev;
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;
173 #else
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;
177 #endif
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);
185 #if 0
187 int temp;
188 printk("List resources -----------\n");
189 for(temp=0;temp<DEVICE_COUNT_RESOURCE;temp++){
190 struct resource *res=&pci_dev->resource[temp];
191 if(res->flags){
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;
200 #endif
203 return 1;
206 static int agp_init(void) {
208 drm_agp = (drm_agp_t*)inter_module_get("drm_agp");
210 if(!drm_agp) {
211 printk(KERN_ERR "tdfx_vid: Unable to get drm_agp pointer\n");
212 return 0;
215 if(drm_agp->acquire()) {
216 printk(KERN_ERR "tdfx_vid: Unable to acquire the agp backend\n");
217 drm_agp = NULL;
218 return 0;
221 drm_agp->copy_info(&agp_info);
222 #if 0
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"
226 "Page mask = %#X\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",
231 agp_info.page_mask);
232 #endif
233 drm_agp->enable(agp_info.mode);
236 printk(KERN_INFO "AGP Enabled\n");
238 return 1;
241 static void agp_close(void) {
243 if(!drm_agp) return;
245 if(agp_mem) {
246 drm_agp->unbind_memory(agp_mem);
247 drm_agp->free_memory(agp_mem);
248 agp_mem = NULL;
252 drm_agp->release();
253 inter_module_put("drm_agp");
256 static int agp_move(tdfx_vid_agp_move_t* m) {
257 u32 src = 0;
258 u32 src_h,src_l;
260 if(!(agp_mem||map_start))
261 return (-EAGAIN);
263 if(m->move2 > 3) {
264 printk(KERN_DEBUG "tdfx_vid: AGP move invalid destination %d\n",
265 m->move2);
266 return (-EAGAIN);
269 if(map_start)
270 src = map_start + m->src;
271 else
272 src = agp_info.aper_base + m->src;
274 src_l = (u32)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);
287 banshee_wait_idle();
289 return 0;
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
296 banshee_wait_idle();
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);
307 banshee_wait_idle();
311 static int bump_fifo(u16 size) {
313 banshee_wait_idle();
314 tdfx_outl(CMDBUMP0 , size);
315 banshee_wait_idle();
317 return 0;
320 static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) {
321 u32 in;
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;
330 switch(in) {
331 case 0:
332 cfg->screen_format = TDFX_VID_FORMAT_BGR8;
333 break;
334 case 1:
335 cfg->screen_format = TDFX_VID_FORMAT_BGR16;
336 break;
337 case 2:
338 cfg->screen_format = TDFX_VID_FORMAT_BGR24;
339 break;
340 case 3:
341 cfg->screen_format = TDFX_VID_FORMAT_BGR32;
342 break;
343 default:
344 printk(KERN_INFO "tdfx_vid: unknown screen format %d\n",in);
345 cfg->screen_format = 0;
346 break;
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;
354 u32 tdfx_fmt = 0;
356 // src and dest formats
357 switch(fmt) {
358 case TDFX_VID_FORMAT_BGR8:
359 tdfx_fmt = 1;
360 break;
361 case TDFX_VID_FORMAT_BGR16:
362 tdfx_fmt = 3;
363 break;
364 case TDFX_VID_FORMAT_BGR24:
365 tdfx_fmt = 4;
366 break;
367 case TDFX_VID_FORMAT_BGR32:
368 tdfx_fmt = 5;
369 break;
372 if(!src && !tdfx_fmt) {
373 printk(KERN_INFO "tdfx_vid: Invalid destination format %#X\n",fmt);
374 return 0;
377 if(src && !tdfx_fmt) {
378 // src only format
379 switch(fmt){
380 case TDFX_VID_FORMAT_BGR1:
381 tdfx_fmt = 0;
382 break;
383 case TDFX_VID_FORMAT_BGR15: // To check
384 tdfx_fmt = 2;
385 break;
386 case TDFX_VID_FORMAT_YUY2:
387 tdfx_fmt = 8;
388 break;
389 case TDFX_VID_FORMAT_UYVY:
390 tdfx_fmt = 9;
391 break;
392 default:
393 printk(KERN_INFO "tdfx_vid: Invalid source format %#X\n",fmt);
394 return 0;
398 r |= tdfx_fmt << 16;
400 return r;
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);
411 if(!src_fmt)
412 return 0;
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);
415 if(!dst_fmt)
416 return 0;
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)))
426 cmd = 2;
428 // Save the regs otherwise fb get crazy
429 // we can perhaps avoid some ...
430 banshee_wait_idle();
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);
440 if(cmd == 2)
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]);
454 if(blit->colorkey) {
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);
465 // Setup the src
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));
471 // Setup the dst
472 tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF);
473 tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y));
474 tdfx_outl(DSTFORMAT,dst_fmt);
475 if(cmd == 2)
476 tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h));
478 // Send the command
479 tdfx_outl(COMMAND_2D,cmd | 0x100 | (blit->rop[0] << 24));
480 banshee_wait_idle();
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);
492 if(cmd == 2)
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]);
502 if(blit->colorkey) {
503 tdfx_outl(COMMANDEXTRA_2D,cmd_extra);
504 tdfx_outl(ROP123,rop123);
506 return 1;
509 static int tdfx_vid_set_yuv(unsigned long arg) {
510 tdfx_vid_yuv_t yuv;
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");
514 return(-EFAULT);
516 banshee_make_room(2);
517 tdfx_outl(YUVBASEADDRESS,yuv.base & 0x01FFFFFF);
518 tdfx_outl(YUVSTRIDE, yuv.stride & 0x3FFF);
520 banshee_wait_idle();
522 return 0;
525 static int tdfx_vid_get_yuv(unsigned long arg) {
526 tdfx_vid_yuv_t yuv;
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");
533 return(-EFAULT);
536 return 0;
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;
543 int disp_w,disp_h;
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");
547 return(-EFAULT);
550 if(ov.dst_y < 0) {
551 int shift;
552 if(-ov.dst_y >= ov.src_height) {
553 printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
554 return(-EFAULT);
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;
560 ov.dst_y = 0;
563 if(ov.dst_x < 0) {
564 int shift;
565 if(-ov.dst_x >= ov.src_width) {
566 printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n");
567 return(-EFAULT);
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;
574 ov.dst_x = 0;
577 vidcfg = tdfx_inl(VIDPROCCFG);
578 // clear the overlay fmt
579 vidcfg &= ~(7 << 21);
580 switch(ov.format) {
581 case TDFX_VID_FORMAT_BGR15:
582 vidcfg |= (1 << 21);
583 break;
584 case TDFX_VID_FORMAT_BGR16:
585 vidcfg |= (7 << 21);
586 break;
587 case TDFX_VID_FORMAT_YUY2:
588 vidcfg |= (5 << 21);
589 break;
590 case TDFX_VID_FORMAT_UYVY:
591 vidcfg |= (6 << 21);
592 break;
593 default:
594 printk(KERN_DEBUG "tdfx_vid: Invalid overlay fmt 0x%x\n",ov.format);
595 return (-EFAULT);
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);
603 return(-EFAULT);
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]);
607 return(-EFAULT);
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;
616 screen_w &= 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");
625 return (-EFAULT);
627 // Setup the vidproc
628 // H scaling
629 if(ov.src_width < ov.dst_width)
630 vidcfg |= (1<<14);
631 else
632 vidcfg &= ~(1<<14);
633 // V scaling
634 if(ov.src_height < ov.dst_height)
635 vidcfg |= (1<<15);
636 else
637 vidcfg &= ~(1<<15);
638 // Filtering can only be used in 1x mode
639 if(!(vidcfg | (1<<26)))
640 vidcfg |= (3<<16);
641 else
642 vidcfg &= ~(3<<16);
643 // disable overlay stereo mode
644 vidcfg &= ~(1<<2);
645 // Colorkey on/off
646 if(ov.use_colorkey) {
647 // Colorkey inversion
648 if(ov.invert_colorkey)
649 vidcfg |= (1<<6);
650 else
651 vidcfg &= ~(1<<6);
652 vidcfg |= (1<<5);
653 } else
654 vidcfg &= ~(1<<5);
655 // Overlay isn't VidIn
656 vidcfg &= ~(1<<9);
657 // vidcfg |= (1<<8);
658 tdfx_outl(VIDPROCCFG,vidcfg);
660 // Start coord
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));
663 // End coord
664 tdfx_outl(VIDOVRENDCRD, ((ov.dst_x + disp_w-1) & 0xFFF)|
665 (((ov.dst_y + disp_h-1) & 0xFFF)<<12));
666 // H Scaling
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);
670 // V Scaling
671 tdfx_outl(VIDOVRDVDY, ( ((u32)ov.src_height) << 20) / ov.dst_height);
672 //else
673 // tdfx_outl(VIDOVRDVDY,0);
674 // V Offset
675 tdfx_outl(VIDOVRDVDYOFF,0);
676 // Overlay stride
677 stride = tdfx_inl(VIDDESKSTRIDE) & 0xFFFF;
678 tdfx_outl(VIDDESKSTRIDE,stride | (((u32)ov.src_stride) << 16));
679 // Buffers address
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));
691 // Colorkey
692 if(ov.use_colorkey) {
693 tdfx_outl(VIDCHRMIN,ov.colorkey[0]);
694 tdfx_outl(VIDCHRMAX,ov.colorkey[1]);
697 return 0;
700 static int tdfx_vid_overlay_on(void) {
701 uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
702 //return 0;
703 if(vidcfg & (1<<8)) { // Overlay is already on
704 //printk(KERN_DEBUG "tdfx_vid: Overlay is already on.\n");
705 return (-EFAULT);
707 vidcfg |= (1<<8);
708 tdfx_outl(VIDPROCCFG,vidcfg);
709 return 0;
712 static int tdfx_vid_overlay_off(void) {
713 uint32_t vidcfg = tdfx_inl(VIDPROCCFG);
715 if(vidcfg & (1<<8)) {
716 vidcfg &= ~(1<<8);
717 tdfx_outl(VIDPROCCFG,vidcfg);
718 return 0;
721 printk(KERN_DEBUG "tdfx_vid: Overlay is already off.\n");
722 return (-EFAULT);
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;
731 u16 int16;
733 switch(cmd) {
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");
737 return(-EFAULT);
739 return agp_move(&move);
740 case TDFX_VID_BUMP0:
741 if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) {
742 printk(KERN_INFO "tdfx_vid:failed copy from userspace\n");
743 return(-EFAULT);
745 return bump_fifo(int16);
746 case TDFX_VID_BLIT:
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");
749 return(-EFAULT);
751 if(!tdfx_vid_blit(&blit)) {
752 printk(KERN_INFO "tdfx_vid: Blit failed\n");
753 return(-EFAULT);
755 return 0;
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");
759 return(-EFAULT);
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");
764 return(-EFAULT);
766 return 0;
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();
777 default:
778 printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd);
779 return (-EINVAL);
781 return 0;
786 static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos)
788 return 0;
791 static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
794 return 0;
797 static void tdfx_vid_mopen(struct vm_area_struct *vma) {
798 int i;
799 struct page *page;
800 unsigned long phys;
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));
807 if(!page) {
808 printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
809 return;
811 get_page(page);
813 MOD_INC_USE_COUNT;
816 static void tdfx_vid_mclose(struct vm_area_struct *vma) {
817 int i;
818 struct page *page;
819 unsigned long phys;
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));
826 if(!page) {
827 printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count);
828 return;
830 put_page(page);
833 MOD_DEC_USE_COUNT;
836 static struct page *tdfx_vid_nopage(struct vm_area_struct *vma,
837 unsigned long address,
838 int write_access) {
839 unsigned long off;
840 uint32_t n;
841 struct page *page;
842 unsigned long phys;
844 off = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT);
845 n = off / PAGE_SIZE;
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));
853 if(!page) {
854 printk(KERN_DEBUG "tdfx_vid: Can't get the page\n");
855 return ((struct page *)0UL);
857 return page;
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)
870 size_t size;
871 #ifdef MP_DEBUG
872 printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n");
873 #endif
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");
880 return(-EAGAIN);
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))
885 #else
886 if(remap_page_range(vma->vm_start, (unsigned long)map_start,
887 vma->vm_end - vma->vm_start, vma->vm_page_prot))
888 #endif
890 printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
891 return(-EAGAIN);
893 printk(KERN_INFO "Physical mem 0x%lx mapped in userspace\n",map_start);
894 return 0;
897 if(agp_mem)
898 return(-EAGAIN);
900 agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY);
901 if(!agp_mem) {
902 printk(KERN_ERR "Failed to allocate AGP memory\n");
903 return(-ENOMEM);
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);
909 agp_mem = NULL;
910 return(-ENOMEM);
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);
917 if(tdfx_map_io) {
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))
921 #else
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))
924 #endif
926 printk(KERN_ERR "tdfx_vid: error mapping video memory\n");
927 return(-EAGAIN);
929 } else {
930 // Never swap it out
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");
937 return 0;
941 static int tdfx_vid_release(struct inode *inode, struct file *file)
943 #ifdef MP_DEBUG
944 printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n");
945 #endif
947 // Release the agp mem
948 if(agp_mem) {
949 drm_agp->unbind_memory(agp_mem);
950 drm_agp->free_memory(agp_mem);
951 agp_mem = NULL;
954 tdfx_vid_in_use = 0;
956 MOD_DEC_USE_COUNT;
957 return 0;
960 static long long tdfx_vid_lseek(struct file *file, long long offset, int origin)
962 return -ESPIPE;
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);
969 #else
970 int minor = MINOR(inode->i_rdev);
971 #endif
973 if(minor != 0)
974 return(-ENXIO);
976 if(tdfx_vid_in_use == 1)
977 return(-EBUSY);
979 tdfx_vid_in_use = 1;
980 MOD_INC_USE_COUNT;
981 return(0);
984 #if LINUX_VERSION_CODE >= 0x020400
985 static struct file_operations tdfx_vid_fops =
987 llseek: tdfx_vid_lseek,
988 read: tdfx_vid_read,
989 write: tdfx_vid_write,
990 ioctl: tdfx_vid_ioctl,
991 mmap: tdfx_vid_mmap,
992 open: tdfx_vid_open,
993 release: tdfx_vid_release
995 #else
996 static struct file_operations tdfx_vid_fops =
998 tdfx_vid_lseek,
999 tdfx_vid_read,
1000 tdfx_vid_write,
1001 NULL,
1002 NULL,
1003 tdfx_vid_ioctl,
1004 tdfx_vid_mmap,
1005 tdfx_vid_open,
1006 NULL,
1007 tdfx_vid_release
1009 #endif
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);
1018 return -EIO;
1021 if(!agp_init()) {
1022 printk(KERN_ERR "tdfx_vid: AGP init failed\n");
1023 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
1024 return -EINVAL;
1027 if (!tdfx_vid_find_card()) {
1028 printk(KERN_ERR "tdfx_vid: no supported devices found\n");
1029 agp_close();
1030 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");
1031 return -EINVAL;
1036 return (0);
1040 void cleanup_module(void)
1042 if(tdfx_mmio_base)
1043 iounmap(tdfx_mmio_base);
1044 agp_close();
1045 printk(KERN_INFO "tdfx_vid: Cleaning up module\n");
1046 unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");