From 4db6d23cc2f55eddc4858d262de08e472edeee06 Mon Sep 17 00:00:00 2001 From: albeu Date: Fri, 7 Mar 2003 18:42:08 +0000 Subject: tdfx_vid a new kernel driver for tdfx wich let use agp move :) git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@9546 b3059339-0415-0410-9bf9-f77b7e298cf2 --- drivers/Makefile | 8 +- drivers/tdfx_vid.c | 698 +++++++++++++++++++++++++++++++++++++++++++++++++ drivers/tdfx_vid.h | 74 ++++++ drivers/tdfx_vid_tst.c | 98 +++++++ 4 files changed, 877 insertions(+), 1 deletion(-) create mode 100644 drivers/tdfx_vid.c create mode 100644 drivers/tdfx_vid.h create mode 100644 drivers/tdfx_vid_tst.c diff --git a/drivers/Makefile b/drivers/Makefile index 4c9c552893..53a2736b83 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -1,7 +1,7 @@ KERNEL_INCLUDES = /usr/src/linux/include INCLUDES = -I$(KERNEL_INCLUDES) -CFLAGS = -O2 -D__KERNEL__ -DMODULE -include $(KERNEL_INCLUDES)/linux/modversions.h +CFLAGS = -O2 -D__KERNEL__ -DMODULE -include $(KERNEL_INCLUDES)/linux/modversions.h -Wall VERSION = $(shell grep UTS_RELEASE $(KERNEL_INCLUDES)/linux/version.h | cut -d '"' -f2) MDIR = /lib/modules/$(VERSION)/misc @@ -17,6 +17,12 @@ sis_vid.o: sis_vid.c sis_vid.h mga_vid_test: mga_vid_test.c $(CC) -O $(INCLUDES) -o $@ $@.c +tdfx_vid.o: tdfx_vid.c 3dfx.h + $(CC) $(CFLAGS) $(INCLUDES) -c $(basename $@).c + +tdfx_vid_tst: tdfx_vid_tst.c + $(CC) -O $(INCLUDES) -o $@ $@.c + install: mga_vid.o if test ! -d $(MDIR) ; then mkdir -p $(MDIR) ; fi install -m 644 mga_vid.o $(MDIR)/mga_vid.o diff --git a/drivers/tdfx_vid.c b/drivers/tdfx_vid.c new file mode 100644 index 0000000000..80841a3b5a --- /dev/null +++ b/drivers/tdfx_vid.c @@ -0,0 +1,698 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,10) +#include +#else +#include +#endif + +#include +#include +#include +#include + +#include +#include +#include + +#include "tdfx_vid.h" +#include "3dfx.h" + + +#define TDFX_VID_MAJOR 178 + +MODULE_AUTHOR("Albeu"); + +#ifdef MODULE_LICENSE +MODULE_LICENSE("GPL"); +#endif + +#ifndef min +#define min(x,y) (((x)<(y))?(x):(y)) +#endif + +static struct pci_dev *pci_dev; + +static uint8_t *tdfx_mmio_base = 0; +static uint32_t tdfx_mem_base = 0; +static struct voodoo_2d_reg_t* tdfx_2d_regs = NULL; + +static int tdfx_ram_size = 0; + +static int tdfx_vid_in_use = 0; + +static drm_agp_t *drm_agp = NULL; +static agp_kern_info agp_info; +static agp_memory *agp_mem = NULL; + + + +static inline u32 tdfx_inl(unsigned int reg) { + return readl(tdfx_mmio_base + reg); +} + +static inline void tdfx_outl(unsigned int reg, u32 val) { + writel(val,tdfx_mmio_base + reg); +} + +static inline void banshee_make_room(int size) { + while((tdfx_inl(STATUS) & 0x1f) < size); +} + +static inline void banshee_wait_idle(void) { + int i = 0; + + banshee_make_room(1); + tdfx_outl(COMMAND_3D, COMMAND_3D_NOP); + + while(1) { + i = (tdfx_inl(STATUS) & STATUS_BUSY) ? 0 : i + 1; + if(i == 3) break; + } +} + +static unsigned long get_lfb_size(void) { + u32 draminit0 = 0; + u32 draminit1 = 0; + // u32 miscinit1 = 0; + u32 lfbsize = 0; + int sgram_p = 0; + + draminit0 = tdfx_inl(DRAMINIT0); + draminit1 = tdfx_inl(DRAMINIT1); + + if ((pci_dev->device == PCI_DEVICE_ID_3DFX_BANSHEE) || + (pci_dev->device == PCI_DEVICE_ID_3DFX_VOODOO3)) { + sgram_p = (draminit1 & DRAMINIT1_MEM_SDRAM) ? 0 : 1; + + lfbsize = sgram_p ? + (((draminit0 & DRAMINIT0_SGRAM_NUM) ? 2 : 1) * + ((draminit0 & DRAMINIT0_SGRAM_TYPE) ? 8 : 4) * 1024 * 1024) : + 16 * 1024 * 1024; + } else { + /* Voodoo4/5 */ + u32 chips, psize, banks; + + chips = ((draminit0 & (1 << 26)) == 0) ? 4 : 8; + psize = 1 << ((draminit0 & 0x38000000) >> 28); + banks = ((draminit0 & (1 << 30)) == 0) ? 2 : 4; + lfbsize = chips * psize * banks; + lfbsize <<= 20; + } + +#if 0 + /* disable block writes for SDRAM (why?) */ + miscinit1 = tdfx_inl(MISCINIT1); + miscinit1 |= sgram_p ? 0 : MISCINIT1_2DBLOCK_DIS; + miscinit1 |= MISCINIT1_CLUT_INV; + + banshee_make_room(1); + tdfx_outl(MISCINIT1, miscinit1); +#endif + + return lfbsize; +} + +static int tdfx_vid_find_card(void) +{ + struct pci_dev *dev = NULL; + // unsigned int card_option; + + if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_BANSHEE, NULL))) + printk(KERN_INFO "tdfx_vid: Found VOODOO BANSHEE\n"); + else if((dev = pci_find_device(PCI_VENDOR_ID_3DFX, PCI_DEVICE_ID_3DFX_VOODOO3, NULL))) + printk(KERN_INFO "tdfx_vid: Found VOODOO 3 \n"); + else + return 0; + + + pci_dev = dev; + +#if LINUX_VERSION_CODE >= 0x020300 + tdfx_mmio_base = ioremap_nocache(dev->resource[0].start,1 << 24); + tdfx_mem_base = dev->resource[1].start; +#else + tdfx_mmio_base = ioremap_nocache(dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK,0x4000); + tdfx_mem_base = dev->base_address[1] & PCI_BASE_ADDRESS_MEM_MASK; +#endif + printk(KERN_INFO "tdfx_vid: MMIO at 0x%p\n", tdfx_mmio_base); + tdfx_2d_regs = (struct voodoo_2d_reg_t*)tdfx_mmio_base; + tdfx_ram_size = get_lfb_size(); + + printk(KERN_INFO "tdfx_vid: Found %d MB (%d bytes) of memory\n", + tdfx_ram_size / 1024 / 1024,tdfx_ram_size); + + +#if 0 + { + int temp; + printk("List resources -----------\n"); + for(temp=0;tempresource[temp]; + if(res->flags){ + int size=(1+res->end-res->start)>>20; + 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); + if(res->flags&(IORESOURCE_MEM|IORESOURCE_PREFETCH)){ + if(size>tdfx_ram_size && size<=64) tdfx_ram_size=size; + } + } + } + } +#endif + + + return 1; +} + +static int agp_init(void) { + + drm_agp = (drm_agp_t*)inter_module_get("drm_agp"); + + if(!drm_agp) { + printk(KERN_ERR "tdfx_vid: Unable to get drm_agp pointer\n"); + return 0; + } + + if(drm_agp->acquire()) { + printk(KERN_ERR "tdfx_vid: Unable to acquire the agp backend\n"); + drm_agp = NULL; + return 0; + } + + drm_agp->copy_info(&agp_info); +#if 0 + printk(KERN_DEBUG "AGP Version : %d %d\n" + "AGP Mode: %#X\nAperture Base: %p\nAperture Size: %d\n" + "Max memory = %d\nCurrent mem = %d\nCan use perture : %s\n" + "Page mask = %#X\n", + agp_info.version.major,agp_info.version.minor, + agp_info.mode,agp_info.aper_base,agp_info.aper_size, + agp_info.max_memory,agp_info.current_memory, + agp_info.cant_use_aperture ? "no" : "yes", + agp_info.page_mask); +#endif + drm_agp->enable(agp_info.mode); + + + printk(KERN_INFO "AGP Enabled\n"); + + return 1; +} + +static void agp_close(void) { + + if(!drm_agp) return; + + if(agp_mem) { + drm_agp->unbind_memory(agp_mem); + drm_agp->free_memory(agp_mem); + agp_mem = NULL; + } + + + drm_agp->release(); + +} + +static int agp_move(tdfx_vid_agp_move_t* m) { + // u32 mov = 0; + u32 src = 0; + u32 src_h,src_l; + + if(!agp_mem) + return (-EAGAIN); + + if(m->move2 > 3) { + printk(KERN_DEBUG "tdfx_vid: AGP move invalid destination %d\n", + m->move2); + return (-EAGAIN); + } + + + src = agp_info.aper_base + m->src; + + src_l = (u32)src; + src_h = (m->width | (m->src_stride << 14)) & 0x0FFFFFFF; + + // banshee_wait_idle(); + banshee_make_room(6); + tdfx_outl(AGPHOSTADDRESSHIGH,src_h); + tdfx_outl(AGPHOSTADDRESSLOW,src_l); + + tdfx_outl(AGPGRAPHICSADDRESS, m->dst); + tdfx_outl(AGPGRAPHICSSTRIDE, m->dst_stride); + tdfx_outl(AGPREQSIZE,m->src_stride*m->height); + + tdfx_outl(AGPMOVECMD,m->move2 << 3); + banshee_wait_idle(); + + banshee_make_room(5); + tdfx_outl(AGPHOSTADDRESSHIGH,0); + tdfx_outl(AGPHOSTADDRESSLOW,0); + + tdfx_outl(AGPGRAPHICSADDRESS,0); + tdfx_outl(AGPGRAPHICSSTRIDE,0); + tdfx_outl(AGPREQSIZE,0); + banshee_wait_idle(); + + return 0; +} + +static void setup_fifo(u32 offset,ssize_t pages) { + long addr = agp_info.aper_base + offset; + u32 size = pages | 0x700; // fifo on, in agp mem, disable hole cnt + + banshee_wait_idle(); + + tdfx_outl(CMDBASEADDR0,addr >> 4); + tdfx_outl(CMDRDPTRL0, addr << 4); + tdfx_outl(CMDRDPTRH0, addr >> 28); + tdfx_outl(CMDAMIN0, (addr - 4) & 0xFFFFFF); + tdfx_outl(CMDAMAX0, (addr - 4) & 0xFFFFFF); + tdfx_outl(CMDFIFODEPTH0, 0); + tdfx_outl(CMDHOLECNT0, 0); + tdfx_outl(CMDBASESIZE0,size); + + banshee_wait_idle(); + +} + +static int bump_fifo(u16 size) { + + banshee_wait_idle(); + tdfx_outl(CMDBUMP0 , size); + banshee_wait_idle(); + + return 0; +} + +static void tdfx_vid_get_config(tdfx_vid_config_t* cfg) { + u32 in; + + cfg->version = TDFX_VID_VERSION; + cfg->ram_size = tdfx_ram_size; + + in = tdfx_inl(VIDSCREENSIZE); + cfg->screen_width = in & 0xFFF; + cfg->screen_height = (in >> 12) & 0xFFF; + in = (tdfx_inl(VIDPROCCFG)>> 18)& 0x7; + switch(in) { + case 0: + cfg->screen_format = TDFX_VID_FORMAT_BGR8; + break; + case 1: + cfg->screen_format = TDFX_VID_FORMAT_BGR16; + break; + case 2: + cfg->screen_format = TDFX_VID_FORMAT_BGR24; + break; + case 3: + cfg->screen_format = TDFX_VID_FORMAT_BGR32; + break; + default: + printk(KERN_INFO "tdfx_vid: unknow screen format %d\n",in); + cfg->screen_format = 0; + break; + } + cfg->screen_stride = tdfx_inl(VIDDESKSTRIDE); + cfg->screen_start = tdfx_inl(VIDDESKSTART); +} + +inline static u32 tdfx_vid_make_format(int src,u16 stride,u32 fmt) { + u32 r = stride & 0xFFF3; + u32 tdfx_fmt = 0; + + // src and dest formats + switch(fmt) { + case TDFX_VID_FORMAT_BGR8: + tdfx_fmt = 1; + break; + case TDFX_VID_FORMAT_BGR16: + tdfx_fmt = 3; + break; + case TDFX_VID_FORMAT_BGR24: + tdfx_fmt = 4; + break; + case TDFX_VID_FORMAT_BGR32: + tdfx_fmt = 5; + break; + } + + if(!src && !tdfx_fmt) { + printk(KERN_INFO "tdfx_vid: Invalid destination format %#X\n",fmt); + return 0; + } + + if(src && !tdfx_fmt) { + // src only format + switch(fmt){ + case TDFX_VID_FORMAT_BGR1: + tdfx_fmt = 0; + break; + case TDFX_VID_FORMAT_YUY2: + tdfx_fmt = 8; + break; + case TDFX_VID_FORMAT_UYVY: + tdfx_fmt = 9; + break; + default: + printk(KERN_INFO "tdfx_vid: Invalid source format %#X\n",fmt); + return 0; + } + } + + r |= tdfx_fmt << 16; + + return r; +} + +static int tdfx_vid_blit(tdfx_vid_blit_t* blit) { + u32 src_fmt,dst_fmt; + u32 cmin,cmax,srcbase,srcxy,srcfmt,srcsize; + u32 dstbase,dstxy,dstfmt,dstsize; + + //printk(KERN_INFO "tdfx_vid: Make src fmt 0x%x\n",blit->src_format); + src_fmt = tdfx_vid_make_format(1,blit->src_stride,blit->src_format); + if(!src_fmt) + return 0; + //printk(KERN_INFO "tdfx_vid: Make dst fmt 0x%x\n", blit->dst_format); + dst_fmt = tdfx_vid_make_format(0,blit->dst_stride,blit->dst_format); + if(!dst_fmt) + return 0; + + // Save the regs otherwise fb get crazy + // we can perhaps avoid some ... + cmin = tdfx_inl(CLIP0MIN); + cmax = tdfx_inl(CLIP0MAX); + srcbase = tdfx_inl(SRCBASE); + srcxy = tdfx_inl(SRCXY); + srcfmt = tdfx_inl(SRCFORMAT); + srcsize = tdfx_inl(SRCSIZE); + dstbase = tdfx_inl(DSTBASE); + dstxy = tdfx_inl(DSTXY); + dstfmt = tdfx_inl(DSTFORMAT); + dstsize = tdfx_inl(DSTSIZE); + + // Get rid of the clipping at the moment + banshee_make_room(11); + + tdfx_outl(CLIP0MIN,0); + tdfx_outl(CLIP0MAX,0x0fff0fff); + + // Setup the src + tdfx_outl(SRCBASE,blit->src & 0x00FFFFFF); + tdfx_outl(SRCXY,XYREG(blit->src_x,blit->src_y)); + tdfx_outl(SRCFORMAT,src_fmt); + tdfx_outl(SRCSIZE,XYREG(blit->src_w,blit->src_h)); + + // Setup the dst + tdfx_outl(DSTBASE,blit->dst & 0x00FFFFFF); + tdfx_outl(DSTXY,XYREG(blit->dst_x,blit->dst_y)); + tdfx_outl(DSTFORMAT,dst_fmt); + tdfx_outl(DSTSIZE,XYREG(blit->dst_w,blit->dst_h)); + + // Send the command + tdfx_outl(COMMAND_2D,0xcc000102); // | (ROP_COPY << 24)); + banshee_wait_idle(); + + // Now restore the regs to make fb happy + banshee_make_room(10); + tdfx_outl(CLIP0MIN, cmin); + tdfx_outl(CLIP0MAX, cmax); + tdfx_outl(SRCBASE, srcbase); + tdfx_outl(SRCXY, srcxy); + tdfx_outl(SRCFORMAT, srcfmt); + tdfx_outl(SRCSIZE, srcsize); + tdfx_outl(DSTBASE, dstbase); + tdfx_outl(DSTXY, dstxy); + tdfx_outl(DSTFORMAT, dstfmt); + tdfx_outl(DSTSIZE, dstsize); + banshee_wait_idle(); + + return 1; +} + +static int tdfx_vid_set_yuv(unsigned long arg) { + tdfx_vid_yuv_t yuv; + + if(copy_from_user(&yuv,(tdfx_vid_yuv_t*)arg,sizeof(tdfx_vid_yuv_t))) { + printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n"); + return(-EFAULT); + } + banshee_make_room(2); + tdfx_outl(YUVBASEADDRESS,yuv.base & 0x01FFFFFF); + tdfx_outl(YUVSTRIDE, yuv.stride & 0x3FFF); + + banshee_wait_idle(); + + return 0; +} + +static int tdfx_vid_get_yuv(unsigned long arg) { + tdfx_vid_yuv_t yuv; + + yuv.base = tdfx_inl(YUVBASEADDRESS) & 0x01FFFFFF; + yuv.stride = tdfx_inl(YUVSTRIDE) & 0x3FFF; + + if(copy_to_user((tdfx_vid_yuv_t*)arg,&yuv,sizeof(tdfx_vid_yuv_t))) { + printk(KERN_INFO "tdfx_vid:failed copy to userspace\n"); + return(-EFAULT); + } + + return 0; +} + +static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + tdfx_vid_agp_move_t move; + tdfx_vid_config_t cfg; + tdfx_vid_blit_t blit; + u16 int16; + + switch(cmd) { + case TDFX_VID_AGP_MOVE: + if(copy_from_user(&move,(tdfx_vid_agp_move_t*)arg,sizeof(tdfx_vid_agp_move_t))) { + printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); + return(-EFAULT); + } + return agp_move(&move); + case TDFX_VID_BUMP0: + if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) { + printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); + return(-EFAULT); + } + return bump_fifo(int16); + case TDFX_VID_BLIT: + if(copy_from_user(&blit,(tdfx_vid_blit_t*)arg,sizeof(tdfx_vid_blit_t))) { + printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); + return(-EFAULT); + } + if(!tdfx_vid_blit(&blit)) { + printk(KERN_INFO "tdfx_vid: Blit failed\n"); + return(-EFAULT); + } + return 0; + case TDFX_VID_GET_CONFIG: + if(copy_from_user(&cfg,(tdfx_vid_config_t*)arg,sizeof(tdfx_vid_config_t))) { + printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); + return(-EFAULT); + } + tdfx_vid_get_config(&cfg); + if(copy_to_user((tdfx_vid_config_t*)arg,&cfg,sizeof(tdfx_vid_config_t))) { + printk(KERN_INFO "tdfx_vid:failed copy to userspace\n"); + return(-EFAULT); + } + return 0; + case TDFX_VID_SET_YUV: + return tdfx_vid_set_yuv(arg); + case TDFX_VID_GET_YUV: + return tdfx_vid_get_yuv(arg); + default: + printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd); + return (-EINVAL); + } + return 0; +} + + + +static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + return 0; +} + +static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + + return 0; +} + + +static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma) +{ + size_t size; + //u32 pages; +#ifdef MP_DEBUG + printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n"); +#endif + + if(agp_mem) + return(-EAGAIN); + + size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE; + + agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY); + if(!agp_mem) { + printk(KERN_ERR "Failed to allocate AGP memory\n"); + return(-ENOMEM); + } + + if(drm_agp->bind_memory(agp_mem,0)) { + printk(KERN_ERR "Failed to bind the AGP memory\n"); + drm_agp->free_memory(agp_mem); + agp_mem = NULL; + return(-ENOMEM); + } + + printk(KERN_INFO "%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n", + size,vma->vm_end-vma->vm_start,size*PAGE_SIZE); + + //setup_fifo(0,size); + + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) + if(remap_page_range(vma, vma->vm_start,agp_info.aper_base, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) +#else + if(remap_page_range(vma->vm_start, (unsigned long)agp_info.aper_base, + vma->vm_end - vma->vm_start, vma->vm_page_prot)) +#endif + { + printk(KERN_ERR "tdfx_vid: error mapping video memory\n"); + return(-EAGAIN); + } + + + printk(KERN_INFO "AGP Mem mapped in user space !!!!!\n"); + + return 0; +} + + +static int tdfx_vid_release(struct inode *inode, struct file *file) +{ + //Close the window just in case +#ifdef MP_DEBUG + printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n"); +#endif + + // Release the agp mem + if(agp_mem) { + drm_agp->unbind_memory(agp_mem); + drm_agp->free_memory(agp_mem); + agp_mem = NULL; + } + + tdfx_vid_in_use = 0; + + MOD_DEC_USE_COUNT; + return 0; +} + +static long long tdfx_vid_lseek(struct file *file, long long offset, int origin) +{ + return -ESPIPE; +} + +static int tdfx_vid_open(struct inode *inode, struct file *file) +{ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2) + int minor = MINOR(inode->i_rdev.value); +#else + int minor = MINOR(inode->i_rdev); +#endif + + if(minor != 0) + return(-ENXIO); + + if(tdfx_vid_in_use == 1) + return(-EBUSY); + + tdfx_vid_in_use = 1; + MOD_INC_USE_COUNT; + return(0); +} + +#if LINUX_VERSION_CODE >= 0x020400 +static struct file_operations tdfx_vid_fops = +{ + llseek: tdfx_vid_lseek, + read: tdfx_vid_read, + write: tdfx_vid_write, + ioctl: tdfx_vid_ioctl, + mmap: tdfx_vid_mmap, + open: tdfx_vid_open, + release: tdfx_vid_release +}; +#else +static struct file_operations tdfx_vid_fops = +{ + tdfx_vid_lseek, + tdfx_vid_read, + tdfx_vid_write, + NULL, + NULL, + tdfx_vid_ioctl, + tdfx_vid_mmap, + tdfx_vid_open, + NULL, + tdfx_vid_release +}; +#endif + + +int init_module(void) +{ + tdfx_vid_in_use = 0; + + if(register_chrdev(TDFX_VID_MAJOR, "tdfx_vid", &tdfx_vid_fops)) { + printk(KERN_ERR "tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR); + return -EIO; + } + + if(!agp_init()) { + printk(KERN_ERR "tdfx_vid: AGP init failed\n"); + unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); + return -EINVAL; + } + + if (!tdfx_vid_find_card()) { + printk(KERN_ERR "tdfx_vid: no supported devices found\n"); + agp_close(); + unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); + return -EINVAL; + } + + + + return (0); + +} + +void cleanup_module(void) +{ + if(tdfx_mmio_base) + iounmap(tdfx_mmio_base); + agp_close(); + printk(KERN_INFO "tdfx_vid: Cleaning up module\n"); + unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); +} diff --git a/drivers/tdfx_vid.h b/drivers/tdfx_vid.h new file mode 100644 index 0000000000..cb8d4fbc5b --- /dev/null +++ b/drivers/tdfx_vid.h @@ -0,0 +1,74 @@ + + +#define TDFX_VID_VERSION 1 + +#define TDFX_VID_MOVE_2_PACKED 0 +#define TDFX_VID_MOVE_2_YUV 1 +#define TDFX_VID_MOVE_2_3D 2 +#define TDFX_VID_MOVE_2_TEXTURE 3 + +#define TDFX_VID_FORMAT_BGR1 (('B'<<24)|('G'<<16)|('R'<<8)|1) +#define TDFX_VID_FORMAT_BGR8 (('B'<<24)|('G'<<16)|('R'<<8)|8) +#define TDFX_VID_FORMAT_BGR16 (('B'<<24)|('G'<<16)|('R'<<8)|16) +#define TDFX_VID_FORMAT_BGR24 (('B'<<24)|('G'<<16)|('R'<<8)|24) +#define TDFX_VID_FORMAT_BGR32 (('B'<<24)|('G'<<16)|('R'<<8)|32) + +#define TDFX_VID_FORMAT_YUY2 (('2'<<24)|('Y'<<16)|('U'<<8)|'Y') +#define TDFX_VID_FORMAT_UYVY (('U'<<24)|('Y'<<16)|('V'<<8)|'Y') + +#define TDFX_VID_FORMAT_YV12 0x32315659 +#define TDFX_VID_FORMAT_IYUV (('I'<<24)|('Y'<<16)|('U'<<8)|'V') +#define TDFX_VID_FORMAT_I420 (('I'<<24)|('4'<<16)|('2'<<8)|'0') + +#define TDFX_VID_YUV_STRIDE (1024) +#define TDFX_VID_YUV_PLANE_SIZE (0x0100000) + + +typedef struct tdfx_vid_blit_s { + uint32_t src; + uint32_t src_stride; + uint16_t src_x,src_y; + uint16_t src_w,src_h; + uint32_t src_format; + + uint32_t dst; + uint32_t dst_stride; + uint16_t dst_x,dst_y; + uint16_t dst_w,dst_h; + uint32_t dst_format; +} tdfx_vid_blit_t; + +typedef struct tdfx_vid_config_s { + uint16_t version; + uint16_t card_type; + uint32_t ram_size; + uint16_t screen_width; + uint16_t screen_height; + uint16_t screen_stride; + uint32_t screen_format; + uint32_t screen_start; +} tdfx_vid_config_t; + +typedef struct tdfx_vid_agp_move_s { + uint16_t move2; + uint16_t width,height; + + uint32_t src; + uint32_t src_stride; + + uint32_t dst; + uint32_t dst_stride; +} tdfx_vid_agp_move_t; + +typedef struct tdfx_vid_yuv_s { + uint32_t base; + uint16_t stride; +} tdfx_vid_yuv_t; + +#define TDFX_VID_GET_CONFIG _IOR('J', 1, tdfx_vid_config_t) +#define TDFX_VID_AGP_MOVE _IOR('J', 2, tdfx_vid_agp_move_t) +#define TDFX_VID_BLIT _IOR('J', 3, tdfx_vid_blit_t) +#define TDFX_VID_SET_YUV _IOR('J', 4, tdfx_vid_blit_t) +#define TDFX_VID_GET_YUV _IOR('J', 5, tdfx_vid_blit_t) + +#define TDFX_VID_BUMP0 _IOR('J', 6, u16) diff --git a/drivers/tdfx_vid_tst.c b/drivers/tdfx_vid_tst.c new file mode 100644 index 0000000000..cc875148c8 --- /dev/null +++ b/drivers/tdfx_vid_tst.c @@ -0,0 +1,98 @@ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tdfx_vid.h" + + +static void print_tdfd_vid_cfg(tdfx_vid_config_t* cfg) { + printf("tdfx_vid version %d\n" + " Ram: %d\n" + " Screen: %d x %d\n", + cfg->version, + cfg->ram_size, + cfg->screen_width, cfg->screen_height); +} + + +int main(int argc, char** argv) { + int fd,i; + unsigned char *mem,*ptr; + tdfx_vid_agp_move_t move; + tdfx_vid_config_t cfg; + tdfx_vid_blit_t blit; + + fd = open("/dev/tdfx_vid", O_RDWR); + + if(fd <= 0) { + printf("Can't open /dev/tdfx_vid\n"); + return 1; + } + + if(ioctl(fd,TDFX_VID_GET_CONFIG,&cfg)) { + printf("Ioctl GET_CONFIG error\n"); + close(fd); + return 1; + } + + print_tdfd_vid_cfg(&cfg); + + mem = mmap( NULL, 640*480*2, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, 0); + + if(mem == MAP_FAILED) { + printf("Memmap failed !!!!!\n"); + return 1; + } + +/* for(ptr = mem, i = 0 ; i < 640*480 ; i++) { */ +/* ptr[0] = i & 0xFF; */ +/* ptr[1] = (i & 0xFF); */ +/* ptr += 2; */ +/* } */ + + memset(mem,0xFF,640*480*2); + + memset(&move, 0, sizeof(tdfx_vid_agp_move_t)); + move.width = 640; + move.height = 240; + move.src_stride = 640; + move.dst_stride = 640*2; + + if(ioctl(fd,TDFX_VID_AGP_MOVE,&move)) { + printf("AGP Move failed !!!!\n"); + return 0; + } + + printf("AGP Move ????\n"); + sleep(1); + + blit.src = 0; + blit.src_stride = 640*2; + blit.src_x = blit.src_y = 0; + blit.src_w = 320; + blit.src_h = 240; + blit.src_format = cfg.screen_format; + + blit.dst = 240*640*2+320; + blit.dst_stride = 640*2; + blit.dst_x = blit.dst_y = 0; + blit.dst_w = 320; + blit.dst_h = 240; + blit.dst_format = cfg.screen_format; + + if(ioctl(fd,TDFX_VID_BLIT,&blit)) { + printf("Blit failed !!!!\n"); + return 0; + } + + close(fd); + return 1; +} -- cgit v1.2.3